LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - batstr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1472 3728 39.5 %
Date: 2024-04-25 20:03:45 Functions: 79 116 68.1 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "gdk.h"
      15             : #include <ctype.h>
      16             : #include <string.h>
      17             : #include "mal_client.h"
      18             : #include "mal_interpreter.h"
      19             : #include "mal_exception.h"
      20             : #include "str.h"
      21             : #ifdef HAVE_ICONV
      22             : #include <iconv.h>
      23             : #endif
      24             : 
      25             : /* In order to make avaialble a bulk version of a string function with candidates, all possible combinations of scalar/vector
      26             :         version of each argument must be avaiable for the function. Obviously this won't scale for functions with a large number of
      27             :         arguments, so we keep a blacklist for functions without candidate versions. */
      28             : static const char *batstr_funcs_with_no_cands[8] =
      29             :                 { "lpad3", "rpad3", "splitpart", "substitute", "locate3", "insert",
      30             : "replace", NULL };
      31             : 
      32             : bool
      33         232 : batstr_func_has_candidates(const char *func)
      34             : {
      35        1842 :         for (size_t i = 0; batstr_funcs_with_no_cands[i]; i++)
      36        1622 :                 if (strcmp(batstr_funcs_with_no_cands[i], func) == 0)
      37             :                         return false;
      38             :         return true;
      39             : }
      40             : 
      41             : static inline void
      42        2869 : finalize_output(bat *res, BAT *bn, str msg, bool nils, BUN q)
      43             : {
      44        2869 :         if (bn && !msg) {
      45        2869 :                 BATsetcount(bn, q);
      46        2869 :                 bn->tnil = nils;
      47        2869 :                 bn->tnonil = !nils;
      48        2869 :                 bn->tkey = BATcount(bn) <= 1;
      49        2869 :                 bn->tsorted = BATcount(bn) <= 1;
      50        2869 :                 bn->trevsorted = BATcount(bn) <= 1;
      51        2869 :                 bn->theap->dirty |= BATcount(bn) > 0;
      52        2869 :                 *res = bn->batCacheid;
      53        2869 :                 BBPkeepref(bn);
      54           0 :         } else if (bn)
      55           0 :                 BBPreclaim(bn);
      56        2870 : }
      57             : 
      58             : static void
      59        2870 : unfix_inputs(int nargs, ...)
      60             : {
      61        2870 :         va_list valist;
      62             : 
      63        2870 :         va_start(valist, nargs);
      64        8830 :         for (int i = 0; i < nargs; i++) {
      65        5960 :                 BAT *b = va_arg(valist, BAT *);
      66        9094 :                 BBPreclaim(b);
      67             :         }
      68        2870 :         va_end(valist);
      69        2870 : }
      70             : 
      71             : static inline str
      72      102595 : str_prefix(str *buf, size_t *buflen, const char *s, int l)
      73             : {
      74      102595 :         return str_Sub_String(buf, buflen, s, 0, l);
      75             : }
      76             : 
      77             : static str
      78        1889 : do_batstr_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
      79             :                           const char *name, int (*func)(const char *restrict))
      80             : {
      81        1889 :         BATiter bi;
      82        1889 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
      83        1889 :         int *restrict vals;
      84        1889 :         str msg = MAL_SUCCEED;
      85        1889 :         bool nils = false;
      86        1889 :         struct canditer ci1 = { 0 };
      87        1889 :         oid off1;
      88        1889 :         bat *res = getArgReference_bat(stk, pci, 0),
      89        1889 :                 *bid = getArgReference_bat(stk, pci, 1),
      90        1889 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
      91             : 
      92        1889 :         (void) cntxt;
      93        1889 :         (void) mb;
      94        1889 :         if (!(b = BATdescriptor(*bid))) {
      95           0 :                 msg = createException(MAL, name,
      96             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      97           0 :                 goto bailout;
      98             :         }
      99        1888 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     100           0 :                 msg = createException(MAL, name,
     101             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     102           0 :                 goto bailout;
     103             :         }
     104        1889 :         canditer_init(&ci1, b, bs);
     105        1889 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
     106           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     107           0 :                 goto bailout;
     108             :         }
     109             : 
     110        1889 :         off1 = b->hseqbase;
     111        1889 :         bi = bat_iterator(b);
     112        1889 :         vals = Tloc(bn, 0);
     113        1889 :         if (ci1.tpe == cand_dense) {
     114     2259077 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     115     2257228 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     116     2257228 :                         const char *restrict x = BUNtvar(bi, p1);
     117             : 
     118     2255859 :                         if (strNil(x)) {
     119           0 :                                 vals[i] = int_nil;
     120           0 :                                 nils = true;
     121             :                         } else {
     122     2255859 :                                 vals[i] = func(x);
     123             :                         }
     124             :                 }
     125             :         } else {
     126     1938535 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     127     1938495 :                         oid p1 = (canditer_next(&ci1) - off1);
     128     1938156 :                         const char *restrict x = BUNtvar(bi, p1);
     129             : 
     130     1936958 :                         if (strNil(x)) {
     131           0 :                                 vals[i] = int_nil;
     132           0 :                                 nils = true;
     133             :                         } else {
     134     1936958 :                                 vals[i] = func(x);
     135             :                         }
     136             :                 }
     137             :         }
     138        1889 :         bat_iterator_end(&bi);
     139        1889 :   bailout:
     140        1889 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     141        1889 :         unfix_inputs(2, b, bs);
     142        1889 :         return msg;
     143             : }
     144             : 
     145             : static str
     146        1888 : STRbatLength(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     147             : {
     148        1888 :         return do_batstr_int(cntxt, mb, stk, pci, "batstr.length", UTF8_strlen);
     149             : }
     150             : 
     151             : static str
     152           1 : STRbatBytes(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     153             : {
     154           1 :         return do_batstr_int(cntxt, mb, stk, pci, "batstr.bytes", str_strlen);
     155             : }
     156             : 
     157             : static str
     158           3 : STRbatAscii(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     159             : {
     160           3 :         BATiter bi;
     161           3 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     162           3 :         int *restrict vals, next;
     163           3 :         str msg = MAL_SUCCEED;
     164           3 :         bool nils = false;
     165           3 :         struct canditer ci1 = { 0 };
     166           3 :         oid off1;
     167           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     168           3 :                 *bid = getArgReference_bat(stk, pci, 1),
     169           3 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     170             : 
     171           3 :         (void) cntxt;
     172           3 :         (void) mb;
     173           3 :         if (!(b = BATdescriptor(*bid))) {
     174           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     175             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     176           0 :                 goto bailout;
     177             :         }
     178           3 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     179           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     180             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     181           0 :                 goto bailout;
     182             :         }
     183           3 :         canditer_init(&ci1, b, bs);
     184           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
     185           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     186             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     187           0 :                 goto bailout;
     188             :         }
     189             : 
     190           3 :         off1 = b->hseqbase;
     191           3 :         bi = bat_iterator(b);
     192           3 :         vals = Tloc(bn, 0);
     193           3 :         if (ci1.tpe == cand_dense) {
     194          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     195           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     196           8 :                         const char *restrict x = BUNtvar(bi, p1);
     197             : 
     198           8 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     199           0 :                                 goto bailout1;
     200           8 :                         vals[i] = next;
     201           8 :                         nils |= is_int_nil(next);
     202             :                 }
     203             :         } else {
     204          15 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     205          14 :                         oid p1 = (canditer_next(&ci1) - off1);
     206          14 :                         const char *restrict x = BUNtvar(bi, p1);
     207             : 
     208          14 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     209           0 :                                 goto bailout1;
     210          14 :                         vals[i] = next;
     211          14 :                         nils |= is_int_nil(next);
     212             :                 }
     213             :         }
     214           1 :   bailout1:
     215           3 :         bat_iterator_end(&bi);
     216           3 :   bailout:
     217           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     218           3 :         unfix_inputs(2, b, bs);
     219           3 :         return msg;
     220             : }
     221             : 
     222             : static str
     223           1 : STRbatFromWChr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     224             : {
     225           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     226           1 :         size_t buflen = MAX(strlen(str_nil) + 1, 8);
     227           1 :         int *restrict vals, x;
     228           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     229           1 :         bool nils = false;
     230           1 :         struct canditer ci1 = { 0 };
     231           1 :         oid off1;
     232           1 :         bat *res = getArgReference_bat(stk, pci, 0),
     233           1 :                 *bid = getArgReference_bat(stk, pci, 1),
     234           1 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     235           1 :         BATiter bi;
     236             : 
     237           1 :         (void) cntxt;
     238           1 :         (void) mb;
     239           1 :         if (!buf) {
     240           0 :                 msg = createException(MAL, "batstr.unicode",
     241             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     242           0 :                 goto bailout;
     243             :         }
     244           1 :         if (!(b = BATdescriptor(*bid))) {
     245           0 :                 msg = createException(MAL, "batstr.unicode",
     246             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     247           0 :                 goto bailout;
     248             :         }
     249           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     250           0 :                 msg = createException(MAL, "batstr.unicode",
     251             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     252           0 :                 goto bailout;
     253             :         }
     254           1 :         canditer_init(&ci1, b, bs);
     255           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     256           0 :                 msg = createException(MAL, "batstr.unicode",
     257             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     258           0 :                 goto bailout;
     259             :         }
     260             : 
     261           1 :         bi = bat_iterator(b);
     262           1 :         off1 = b->hseqbase;
     263           1 :         vals = bi.base;
     264           1 :         if (ci1.tpe == cand_dense) {
     265           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     266           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     267           4 :                         x = vals[p1];
     268             : 
     269           4 :                         if (is_int_nil(x)) {
     270           2 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     271           0 :                                         msg = createException(MAL, "batstr.unicode",
     272             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     273           0 :                                         goto bailout1;
     274             :                                 }
     275             :                                 nils = true;
     276             :                         } else {
     277           2 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     278           0 :                                         goto bailout1;
     279             :                                 }
     280           2 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     281           0 :                                         msg = createException(MAL, "batstr.unicode",
     282             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     283           0 :                                         goto bailout1;
     284             :                                 }
     285             :                         }
     286             :                 }
     287             :         } else {
     288           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     289           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     290           0 :                         x = vals[p1];
     291             : 
     292           0 :                         if (is_int_nil(x)) {
     293           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     294           0 :                                         msg = createException(MAL, "batstr.unicode",
     295             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     296           0 :                                         goto bailout1;
     297             :                                 }
     298             :                                 nils = true;
     299             :                         } else {
     300           0 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     301           0 :                                         goto bailout1;
     302             :                                 }
     303           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     304           0 :                                         msg = createException(MAL, "batstr.unicode",
     305             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     306           0 :                                         goto bailout1;
     307             :                                 }
     308             :                         }
     309             :                 }
     310             :         }
     311           0 :   bailout1:
     312           1 :         bat_iterator_end(&bi);
     313           1 :   bailout:
     314           1 :         GDKfree(buf);
     315           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     316           1 :         unfix_inputs(2, b, bs);
     317           1 :         return msg;
     318             : }
     319             : 
     320             : static str
     321           0 : STRbatSpace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     322             : {
     323           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     324           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     325           0 :         int *restrict vals, x;
     326           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     327           0 :         bool nils = false;
     328           0 :         const char space[] = " ", *s = space;
     329           0 :         struct canditer ci1 = { 0 };
     330           0 :         oid off1;
     331           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     332           0 :                 *bid = getArgReference_bat(stk, pci, 1),
     333           0 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     334           0 :         BATiter bi;
     335             : 
     336           0 :         (void) cntxt;
     337           0 :         (void) mb;
     338           0 :         if (!buf) {
     339           0 :                 msg = createException(MAL, "batstr.space",
     340             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     341           0 :                 goto bailout;
     342             :         }
     343           0 :         if (!(b = BATdescriptor(*bid))) {
     344           0 :                 msg = createException(MAL, "batstr.space",
     345             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     346           0 :                 goto bailout;
     347             :         }
     348           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     349           0 :                 msg = createException(MAL, "batstr.search",
     350             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     351           0 :                 goto bailout;
     352             :         }
     353           0 :         canditer_init(&ci1, b, bs);
     354           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     355           0 :                 msg = createException(MAL, "batstr.space",
     356             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     357           0 :                 goto bailout;
     358             :         }
     359             : 
     360           0 :         off1 = b->hseqbase;
     361           0 :         bi = bat_iterator(b);
     362           0 :         vals = bi.base;
     363           0 :         if (ci1.tpe == cand_dense) {
     364           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     365           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     366           0 :                         x = vals[p1];
     367             : 
     368           0 :                         if (is_int_nil(x) || x < 0) {
     369           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     370           0 :                                         msg = createException(MAL, "batstr.space",
     371             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     372           0 :                                         goto bailout1;
     373             :                                 }
     374             :                                 nils = true;
     375             :                         } else {
     376           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     377           0 :                                         goto bailout1;
     378           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     379           0 :                                         msg = createException(MAL, "batstr.space",
     380             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     381           0 :                                         goto bailout1;
     382             :                                 }
     383             :                         }
     384             :                 }
     385             :         } else {
     386           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     387           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     388           0 :                         x = vals[p1];
     389             : 
     390           0 :                         if (is_int_nil(x) || x < 0) {
     391           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     392           0 :                                         msg = createException(MAL, "batstr.space",
     393             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     394           0 :                                         goto bailout1;
     395             :                                 }
     396             :                                 nils = true;
     397             :                         } else {
     398           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     399           0 :                                         goto bailout1;
     400           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     401           0 :                                         msg = createException(MAL, "batstr.space",
     402             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     403           0 :                                         goto bailout1;
     404             :                                 }
     405             :                         }
     406             :                 }
     407             :         }
     408           0 :   bailout1:
     409           0 :         bat_iterator_end(&bi);
     410           0 :   bailout:
     411           0 :         GDKfree(buf);
     412           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     413           0 :         unfix_inputs(2, b, bs);
     414           0 :         return msg;
     415             : }
     416             : 
     417             : static str
     418         128 : do_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     419             :                           const char *name, str (*func)(str *, size_t *, const char *))
     420             : {
     421         128 :         BATiter bi;
     422         128 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     423         128 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     424         128 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     425         128 :         bool nils = false;
     426         128 :         struct canditer ci1 = { 0 };
     427         128 :         oid off1;
     428         128 :         bat *res = getArgReference_bat(stk, pci, 0),
     429         128 :                 *bid = getArgReference_bat(stk, pci, 1),
     430         128 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     431             : 
     432         128 :         (void) cntxt;
     433         128 :         (void) mb;
     434         128 :         if (!buf) {
     435           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     436           0 :                 goto bailout;
     437             :         }
     438         128 :         if (!(b = BATdescriptor(*bid))) {
     439           0 :                 msg = createException(MAL, name,
     440             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     441           0 :                 goto bailout;
     442             :         }
     443         128 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     444           0 :                 msg = createException(MAL, name,
     445             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     446           0 :                 goto bailout;
     447             :         }
     448         128 :         canditer_init(&ci1, b, bs);
     449         128 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     450           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     451           0 :                 goto bailout;
     452             :         }
     453             : 
     454         128 :         off1 = b->hseqbase;
     455         128 :         bi = bat_iterator(b);
     456         128 :         if (ci1.tpe == cand_dense) {
     457      184720 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     458      184592 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     459      184592 :                         const char *restrict x = BUNtvar(bi, p1);
     460             : 
     461      184601 :                         if (strNil(x)) {
     462        3072 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     463           0 :                                         msg = createException(MAL, name,
     464             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     465           0 :                                         goto bailout1;
     466             :                                 }
     467             :                                 nils = true;
     468             :                         } else {
     469      181529 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     470           0 :                                         goto bailout1;
     471      181435 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     472           0 :                                         msg = createException(MAL, name,
     473             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     474           0 :                                         goto bailout1;
     475             :                                 }
     476             :                         }
     477             :                 }
     478             :         } else {
     479           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     480           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     481           0 :                         const char *restrict x = BUNtvar(bi, p1);
     482             : 
     483           0 :                         if (strNil(x)) {
     484           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     485           0 :                                         msg = createException(MAL, name,
     486             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     487           0 :                                         goto bailout1;
     488             :                                 }
     489             :                                 nils = true;
     490             :                         } else {
     491           0 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     492           0 :                                         goto bailout1;
     493           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     494           0 :                                         msg = createException(MAL, name,
     495             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     496           0 :                                         goto bailout1;
     497             :                                 }
     498             :                         }
     499             :                 }
     500             :         }
     501           0 :   bailout1:
     502         128 :         bat_iterator_end(&bi);
     503         128 :   bailout:
     504         128 :         GDKfree(buf);
     505         128 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     506         128 :         unfix_inputs(2, b, bs);
     507         128 :         return msg;
     508             : }
     509             : 
     510             : /* Input: a BAT of strings 'b' and a constant string 'y'
     511             :  * Output type: str (a BAT of strings)
     512             :  */
     513             : static str
     514           3 : do_batstr_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     515             :                                            const char *name, size_t buflen,
     516             :                                            str (*func)(str *, size_t *, const char *, const char *))
     517             : {
     518           3 :         BATiter bi;
     519           3 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     520           3 :         const char *y = *getArgReference_str(stk, pci, 2);
     521           3 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     522           3 :         bool nils = false;
     523           3 :         struct canditer ci1 = { 0 };
     524           3 :         oid off1;
     525           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     526           3 :                 *bid = getArgReference_bat(stk, pci, 1),
     527           3 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     528             : 
     529           3 :         (void) cntxt;
     530           3 :         (void) mb;
     531           3 :         if (!buf) {
     532           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     533           0 :                 goto bailout;
     534             :         }
     535           3 :         if (!(b = BATdescriptor(*bid))) {
     536           0 :                 msg = createException(MAL, name,
     537             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     538           0 :                 goto bailout;
     539             :         }
     540           3 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     541           0 :                 msg = createException(MAL, name,
     542             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     543           0 :                 goto bailout;
     544             :         }
     545           3 :         canditer_init(&ci1, b, bs);
     546           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     547           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     548           0 :                 goto bailout;
     549             :         }
     550             : 
     551           3 :         off1 = b->hseqbase;
     552           3 :         bi = bat_iterator(b);
     553           3 :         if (ci1.tpe == cand_dense) {
     554          12 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     555           9 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     556           9 :                         const char *x = BUNtvar(bi, p1);
     557             : 
     558          18 :                         if (strNil(x) || strNil(y)) {
     559           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     560           0 :                                         msg = createException(MAL, name,
     561             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     562           0 :                                         goto bailout1;
     563             :                                 }
     564             :                                 nils = true;
     565             :                         } else {
     566           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     567           0 :                                         goto bailout1;
     568           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     569           0 :                                         msg = createException(MAL, name,
     570             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     571           0 :                                         goto bailout1;
     572             :                                 }
     573             :                         }
     574             :                 }
     575             :         } else {
     576           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     577           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     578           0 :                         const char *x = BUNtvar(bi, p1);
     579             : 
     580           0 :                         if (strNil(x) || strNil(y)) {
     581           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     582           0 :                                         msg = createException(MAL, name,
     583             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     584           0 :                                         goto bailout1;
     585             :                                 }
     586             :                                 nils = true;
     587             :                         } else {
     588           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     589           0 :                                         goto bailout1;
     590           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     591           0 :                                         msg = createException(MAL, name,
     592             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     593           0 :                                         goto bailout1;
     594             :                                 }
     595             :                         }
     596             :                 }
     597             :         }
     598           0 :   bailout1:
     599           3 :         bat_iterator_end(&bi);
     600           3 :   bailout:
     601           3 :         GDKfree(buf);
     602           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     603           3 :         unfix_inputs(2, b, bs);
     604           3 :         return msg;
     605             : }
     606             : 
     607             : /* Input: a const string 'x' and a BAT of strings 'y'
     608             :  * Output type: str (a BAT of strings)
     609             :  */
     610             : static str
     611           0 : do_batstr_str_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     612             :                                            const char *name, size_t buflen,
     613             :                                            str (*func)(str *, size_t *, const char *, const char *))
     614             : {
     615           0 :         BATiter bi;
     616           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     617           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     618           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     619           0 :         bool nils = false;
     620           0 :         struct canditer ci1 = { 0 };
     621           0 :         oid off1;
     622           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     623           0 :                 *bid = getArgReference_bat(stk, pci, 2),
     624           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     625             : 
     626           0 :         (void) cntxt;
     627           0 :         (void) mb;
     628           0 :         if (!buf) {
     629           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     630           0 :                 goto bailout;
     631             :         }
     632           0 :         if (!(b = BATdescriptor(*bid))) {
     633           0 :                 msg = createException(MAL, name,
     634             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     635           0 :                 goto bailout;
     636             :         }
     637           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     638           0 :                 msg = createException(MAL, name,
     639             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     640           0 :                 goto bailout;
     641             :         }
     642           0 :         canditer_init(&ci1, b, bs);
     643           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     644           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     645           0 :                 goto bailout;
     646             :         }
     647             : 
     648           0 :         off1 = b->hseqbase;
     649           0 :         bi = bat_iterator(b);
     650           0 :         if (ci1.tpe == cand_dense) {
     651           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     652           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     653           0 :                         const char *y = BUNtvar(bi, p1);
     654             : 
     655           0 :                         if (strNil(x) || strNil(y)) {
     656           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     657           0 :                                         msg = createException(MAL, name,
     658             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     659           0 :                                         goto bailout1;
     660             :                                 }
     661             :                                 nils = true;
     662             :                         } else {
     663           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     664           0 :                                         goto bailout1;
     665           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     666           0 :                                         msg = createException(MAL, name,
     667             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     668           0 :                                         goto bailout1;
     669             :                                 }
     670             :                         }
     671             :                 }
     672             :         } else {
     673           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     674           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     675           0 :                         const char *y = BUNtvar(bi, p1);
     676             : 
     677           0 :                         if (strNil(x) || strNil(y)) {
     678           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     679           0 :                                         msg = createException(MAL, name,
     680             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     681           0 :                                         goto bailout1;
     682             :                                 }
     683             :                                 nils = true;
     684             :                         } else {
     685           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     686           0 :                                         goto bailout1;
     687           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     688           0 :                                         msg = createException(MAL, name,
     689             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     690           0 :                                         goto bailout1;
     691             :                                 }
     692             :                         }
     693             :                 }
     694             :         }
     695           0 :   bailout1:
     696           0 :         bat_iterator_end(&bi);
     697           0 :   bailout:
     698           0 :         GDKfree(buf);
     699           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     700           0 :         unfix_inputs(2, b, bs);
     701           0 :         return msg;
     702             : }
     703             : 
     704             : /* Input: two BATs of strings 'l' and 'l2'
     705             :  * Output type: str (a BAT of strings)
     706             :  */
     707             : static str
     708           7 : do_batstr_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     709             :                                          const char *name, size_t buflen,
     710             :                                          str (*func)(str *, size_t *, const char *, const char *))
     711             : {
     712           7 :         BATiter lefti, righti;
     713           7 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
     714           7 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     715           7 :         bool nils = false;
     716           7 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
     717           7 :         oid off1, off2;
     718           7 :         bat *res = getArgReference_bat(stk, pci, 0),
     719           7 :                 *l = getArgReference_bat(stk, pci, 1),
     720           7 :                 *l2 = getArgReference_bat(stk, pci, 2),
     721           7 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
     722           7 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
     723             : 
     724           7 :         (void) cntxt;
     725           7 :         (void) mb;
     726           7 :         if (!buf) {
     727           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     728           0 :                 goto bailout;
     729             :         }
     730           7 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*l2))) {
     731           0 :                 msg = createException(MAL, name,
     732             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     733           0 :                 goto bailout;
     734             :         }
     735           7 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
     736           7 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
     737           0 :                 msg = createException(MAL, name,
     738             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     739           0 :                 goto bailout;
     740             :         }
     741           7 :         canditer_init(&ci1, left, lefts);
     742           7 :         canditer_init(&ci2, right, rights);
     743           7 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
     744           0 :                 msg = createException(MAL, name,
     745             :                                                           ILLEGAL_ARGUMENT
     746             :                                                           " Requires bats of identical size");
     747           0 :                 goto bailout;
     748             :         }
     749           7 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     750           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     751           0 :                 goto bailout;
     752             :         }
     753             : 
     754           7 :         off1 = left->hseqbase;
     755           7 :         off2 = right->hseqbase;
     756           7 :         lefti = bat_iterator(left);
     757           7 :         righti = bat_iterator(right);
     758           7 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
     759          25 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     760          18 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
     761          18 :                                 p2 = (canditer_next_dense(&ci2) - off2);
     762          18 :                         const char *x = BUNtvar(lefti, p1);
     763          18 :                         const char *y = BUNtvar(righti, p2);
     764             : 
     765          36 :                         if (strNil(x) || strNil(y)) {
     766           9 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     767           0 :                                         msg = createException(MAL, name,
     768             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     769           0 :                                         goto bailout1;
     770             :                                 }
     771             :                                 nils = true;
     772             :                         } else {
     773           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     774           0 :                                         goto bailout1;
     775           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     776           0 :                                         msg = createException(MAL, name,
     777             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     778           0 :                                         goto bailout1;
     779             :                                 }
     780             :                         }
     781             :                 }
     782             :         } else {
     783           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     784           0 :                         oid p1 = (canditer_next(&ci1) - off1),
     785           0 :                                 p2 = (canditer_next(&ci2) - off2);
     786           0 :                         const char *x = BUNtvar(lefti, p1);
     787           0 :                         const char *y = BUNtvar(righti, p2);
     788             : 
     789           0 :                         if (strNil(x) || strNil(y)) {
     790           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     791           0 :                                         msg = createException(MAL, name,
     792             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     793           0 :                                         goto bailout1;
     794             :                                 }
     795             :                                 nils = true;
     796             :                         } else {
     797           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     798           0 :                                         goto bailout1;
     799           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     800           0 :                                         msg = createException(MAL, name,
     801             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     802           0 :                                         goto bailout1;
     803             :                                 }
     804             :                         }
     805             :                 }
     806             :         }
     807           0 :   bailout1:
     808           7 :         bat_iterator_end(&lefti);
     809           7 :         bat_iterator_end(&righti);
     810           7 :   bailout:
     811           7 :         GDKfree(buf);
     812           7 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     813           7 :         unfix_inputs(4, left, lefts, right, rights);
     814           7 :         return msg;
     815             : }
     816             : 
     817             : /* Input: a BAT of strings 'l' and a constant int 'y'
     818             :  * Output type: str (a BAT of strings)
     819             :  */
     820             : static str
     821           2 : do_batstr_constint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     822             :                                            const char *name,
     823             :                                            str (*func)(str *, size_t *, const char *, int))
     824             : {
     825           2 :         BATiter bi;
     826           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     827           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     828           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     829           2 :         int y = *getArgReference_int(stk, pci, 2);
     830           2 :         bool nils = false;
     831           2 :         struct canditer ci1 = { 0 };
     832           2 :         oid off1;
     833           2 :         bat *res = getArgReference_bat(stk, pci, 0),
     834           2 :                 *bid = getArgReference_bat(stk, pci, 1),
     835           2 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     836             : 
     837           2 :         (void) cntxt;
     838           2 :         (void) mb;
     839           2 :         if (!buf) {
     840           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     841           0 :                 goto bailout;
     842             :         }
     843           2 :         if (!(b = BATdescriptor(*bid))) {
     844           0 :                 msg = createException(MAL, name,
     845             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     846           0 :                 goto bailout;
     847             :         }
     848           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     849           0 :                 msg = createException(MAL, name,
     850             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     851           0 :                 goto bailout;
     852             :         }
     853           2 :         canditer_init(&ci1, b, bs);
     854           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     855           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     856           0 :                 goto bailout;
     857             :         }
     858             : 
     859           2 :         off1 = b->hseqbase;
     860           2 :         bi = bat_iterator(b);
     861           2 :         if (ci1.tpe == cand_dense) {
     862           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     863           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     864           4 :                         const char *x = BUNtvar(bi, p1);
     865             : 
     866           8 :                         if (strNil(x) || is_int_nil(y)) {
     867           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     868           0 :                                         msg = createException(MAL, name,
     869             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     870           0 :                                         goto bailout1;
     871             :                                 }
     872             :                                 nils = true;
     873             :                         } else {
     874           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     875           0 :                                         goto bailout1;
     876           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     877           0 :                                         msg = createException(MAL, name,
     878             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     879           0 :                                         goto bailout1;
     880             :                                 }
     881             :                         }
     882             :                 }
     883             :         } else {
     884           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     885           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     886           0 :                         const char *x = BUNtvar(bi, p1);
     887             : 
     888           0 :                         if (strNil(x) || is_int_nil(y)) {
     889           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     890           0 :                                         msg = createException(MAL, name,
     891             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     892           0 :                                         goto bailout1;
     893             :                                 }
     894             :                                 nils = true;
     895             :                         } else {
     896           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     897           0 :                                         goto bailout1;
     898           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     899           0 :                                         msg = createException(MAL, name,
     900             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     901           0 :                                         goto bailout1;
     902             :                                 }
     903             :                         }
     904             :                 }
     905             :         }
     906           0 :   bailout1:
     907           2 :         bat_iterator_end(&bi);
     908           2 :   bailout:
     909           2 :         GDKfree(buf);
     910           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     911           2 :         unfix_inputs(2, b, bs);
     912           2 :         return msg;
     913             : }
     914             : 
     915             : /* Input: a constant string 'x' and a BAT of integers 'y'
     916             :  * Output type: str (a BAT of strings)
     917             :  */
     918             : static str
     919           0 : do_batstr_int_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     920             :                                            const char *name,
     921             :                                            str (*func)(str *, size_t *, const char *, int))
     922             : {
     923           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     924           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     925           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     926           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     927           0 :         int y, *restrict inputs;
     928           0 :         bool nils = false;
     929           0 :         struct canditer ci1 = { 0 };
     930           0 :         oid off1;
     931           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     932           0 :                 *bid = getArgReference_bat(stk, pci, 2),
     933           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     934           0 :         BATiter bi;
     935             : 
     936           0 :         (void) cntxt;
     937           0 :         (void) mb;
     938           0 :         if (!buf) {
     939           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     940           0 :                 goto bailout;
     941             :         }
     942           0 :         if (!(b = BATdescriptor(*bid))) {
     943           0 :                 msg = createException(MAL, name,
     944             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     945           0 :                 goto bailout;
     946             :         }
     947           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     948           0 :                 msg = createException(MAL, name,
     949             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     950           0 :                 goto bailout;
     951             :         }
     952           0 :         canditer_init(&ci1, b, bs);
     953           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     954           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     955           0 :                 goto bailout;
     956             :         }
     957             : 
     958           0 :         off1 = b->hseqbase;
     959           0 :         bi = bat_iterator(b);
     960           0 :         inputs = bi.base;
     961           0 :         if (ci1.tpe == cand_dense) {
     962           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     963           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     964           0 :                         y = inputs[p1];
     965             : 
     966           0 :                         if (strNil(x) || is_int_nil(y)) {
     967           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     968           0 :                                         msg = createException(MAL, name,
     969             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     970           0 :                                         goto bailout1;
     971             :                                 }
     972             :                                 nils = true;
     973             :                         } else {
     974           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     975           0 :                                         goto bailout1;
     976           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     977           0 :                                         msg = createException(MAL, name,
     978             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     979           0 :                                         goto bailout1;
     980             :                                 }
     981             :                         }
     982             :                 }
     983             :         } else {
     984           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     985           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     986           0 :                         y = inputs[p1];
     987             : 
     988           0 :                         if (strNil(x) || is_int_nil(y)) {
     989           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     990           0 :                                         msg = createException(MAL, name,
     991             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     992           0 :                                         goto bailout1;
     993             :                                 }
     994             :                                 nils = true;
     995             :                         } else {
     996           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     997           0 :                                         goto bailout1;
     998           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     999           0 :                                         msg = createException(MAL, name,
    1000             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1001           0 :                                         goto bailout1;
    1002             :                                 }
    1003             :                         }
    1004             :                 }
    1005             :         }
    1006           0 :   bailout1:
    1007           0 :         bat_iterator_end(&bi);
    1008           0 :   bailout:
    1009           0 :         GDKfree(buf);
    1010           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1011           0 :         unfix_inputs(2, b, bs);
    1012           0 :         return msg;
    1013             : }
    1014             : 
    1015             : /* Input: a BAT of strings 'l' and a BAT of integers 'n'
    1016             :  * Output type: str (a BAT of strings)
    1017             :  */
    1018             : static str
    1019           2 : do_batstr_batint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1020             :                                          const char *name,
    1021             :                                          str (*func)(str *, size_t *, const char *, int))
    1022             : {
    1023           2 :         BATiter lefti;
    1024           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1025           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1026           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1027           2 :         bool nils = false;
    1028           2 :         int *restrict righti, y;
    1029           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1030           2 :         oid off1, off2;
    1031           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1032           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1033           2 :                 *n = getArgReference_bat(stk, pci, 2),
    1034           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    1035           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1036           2 :         BATiter bi;
    1037             : 
    1038           2 :         (void) cntxt;
    1039           2 :         (void) mb;
    1040           2 :         if (!buf) {
    1041           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1042           0 :                 goto bailout;
    1043             :         }
    1044           2 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*n))) {
    1045           0 :                 msg = createException(MAL, name,
    1046             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1047           0 :                 goto bailout;
    1048             :         }
    1049           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1050           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1051           0 :                 msg = createException(MAL, name,
    1052             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1053           0 :                 goto bailout;
    1054             :         }
    1055           2 :         canditer_init(&ci1, left, ls);
    1056           2 :         canditer_init(&ci2, right, rs);
    1057           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1058           0 :                 msg = createException(MAL, name,
    1059             :                                                           ILLEGAL_ARGUMENT
    1060             :                                                           " Requires bats of identical size");
    1061           0 :                 goto bailout;
    1062             :         }
    1063           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1064           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1065           0 :                 goto bailout;
    1066             :         }
    1067             : 
    1068           2 :         off1 = left->hseqbase;
    1069           2 :         off2 = right->hseqbase;
    1070           2 :         lefti = bat_iterator(left);
    1071           2 :         bi = bat_iterator(right);
    1072           2 :         righti = bi.base;
    1073           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1074           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1075           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1076           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1077           4 :                         const char *x = BUNtvar(lefti, p1);
    1078           4 :                         y = righti[p2];
    1079             : 
    1080           8 :                         if (strNil(x) || is_int_nil(y)) {
    1081           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1082           0 :                                         msg = createException(MAL, name,
    1083             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1084           0 :                                         goto bailout1;
    1085             :                                 }
    1086             :                                 nils = true;
    1087             :                         } else {
    1088           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1089           0 :                                         goto bailout1;
    1090           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1091           0 :                                         msg = createException(MAL, name,
    1092             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1093           0 :                                         goto bailout1;
    1094             :                                 }
    1095             :                         }
    1096             :                 }
    1097             :         } else {
    1098           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1099           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1100           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1101           0 :                         const char *x = BUNtvar(lefti, p1);
    1102           0 :                         y = righti[p2];
    1103             : 
    1104           0 :                         if (strNil(x) || is_int_nil(y)) {
    1105           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1106           0 :                                         msg = createException(MAL, name,
    1107             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1108           0 :                                         goto bailout1;
    1109             :                                 }
    1110             :                                 nils = true;
    1111             :                         } else {
    1112           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1113           0 :                                         goto bailout1;
    1114           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1115           0 :                                         msg = createException(MAL, name,
    1116             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1117           0 :                                         goto bailout1;
    1118             :                                 }
    1119             :                         }
    1120             :                 }
    1121             :         }
    1122           0 :   bailout1:
    1123           2 :         bat_iterator_end(&bi);
    1124           2 :         bat_iterator_end(&lefti);
    1125           2 :   bailout:
    1126           2 :         GDKfree(buf);
    1127           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1128           2 :         unfix_inputs(4, left, ls, right, rs);
    1129           2 :         return msg;
    1130             : }
    1131             : 
    1132             : /* Input: a BAT of strings 'l', a constant int 'y' and a constant str 'z'
    1133             :  * Output type: str (a BAT of strings)
    1134             :  */
    1135             : static str
    1136           2 : do_batstr_constint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1137             :                                                                 InstrPtr pci, const char *name,
    1138             :                                                                 str (*func)(str *, size_t *, const char *, int, const char *))
    1139             : {
    1140           2 :         BATiter bi;
    1141           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1142           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1143           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1144           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1145           2 :         int y = *getArgReference_int(stk, pci, 2);
    1146           2 :         bool nils = false;
    1147           2 :         struct canditer ci1 = { 0 };
    1148           2 :         oid off1;
    1149           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1150           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1151           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1152             : 
    1153           2 :         (void) cntxt;
    1154           2 :         (void) mb;
    1155           2 :         if (!buf) {
    1156           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1157           0 :                 goto bailout;
    1158             :         }
    1159           2 :         if (!(b = BATdescriptor(*l))) {
    1160           0 :                 msg = createException(MAL, name,
    1161             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1162           0 :                 goto bailout;
    1163             :         }
    1164           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    1165           0 :                 msg = createException(MAL, name,
    1166             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1167           0 :                 goto bailout;
    1168             :         }
    1169           2 :         canditer_init(&ci1, b, bs);
    1170           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1171           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1172           0 :                 goto bailout;
    1173             :         }
    1174             : 
    1175           2 :         off1 = b->hseqbase;
    1176           2 :         bi = bat_iterator(b);
    1177           2 :         if (ci1.tpe == cand_dense) {
    1178          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1179           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    1180           8 :                         const char *x = BUNtvar(bi, p1);
    1181             : 
    1182          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1183           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1184           0 :                                         msg = createException(MAL, name,
    1185             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1186           0 :                                         goto bailout1;
    1187             :                                 }
    1188             :                                 nils = true;
    1189             :                         } else {
    1190           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1191           0 :                                         goto bailout1;
    1192           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1193           0 :                                         msg = createException(MAL, name,
    1194             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1195           0 :                                         goto bailout1;
    1196             :                                 }
    1197             :                         }
    1198             :                 }
    1199             :         } else {
    1200           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1201           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    1202           0 :                         const char *x = BUNtvar(bi, p1);
    1203             : 
    1204           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1205           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1206           0 :                                         msg = createException(MAL, name,
    1207             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1208           0 :                                         goto bailout1;
    1209             :                                 }
    1210             :                                 nils = true;
    1211             :                         } else {
    1212           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1213           0 :                                         goto bailout1;
    1214           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1215           0 :                                         msg = createException(MAL, name,
    1216             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1217           0 :                                         goto bailout1;
    1218             :                                 }
    1219             :                         }
    1220             :                 }
    1221             :         }
    1222           0 :   bailout1:
    1223           2 :         bat_iterator_end(&bi);
    1224           2 :   bailout:
    1225           2 :         GDKfree(buf);
    1226           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1227           2 :         unfix_inputs(2, b, bs);
    1228           2 :         return msg;
    1229             : }
    1230             : 
    1231             : /* Input: a BAT of strings 'l', a BAT of integers 'n' and a constant str 'z'
    1232             :  * Output type: str (a BAT of strings)
    1233             :  */
    1234             : static str
    1235           2 : do_batstr_batint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1236             :                                                           InstrPtr pci, const char *name,
    1237             :                                                           str (*func)(str *, size_t *, const char *,
    1238             :                                                                                   int, const char *))
    1239             : {
    1240           2 :         BATiter lefti;
    1241           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1242           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1243           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1244           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1245           2 :         bool nils = false;
    1246           2 :         int *restrict righti, y;
    1247           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1248           2 :         oid off1, off2;
    1249           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1250           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1251           2 :                 *n = getArgReference_bat(stk, pci, 2),
    1252           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1253           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1254           2 :         BATiter bi;
    1255             : 
    1256           2 :         (void) cntxt;
    1257           2 :         (void) mb;
    1258           2 :         if (!buf) {
    1259           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1260           0 :                 goto bailout;
    1261             :         }
    1262           2 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*n))) {
    1263           0 :                 msg = createException(MAL, name,
    1264             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1265           0 :                 goto bailout;
    1266             :         }
    1267           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1268           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1269           0 :                 msg = createException(MAL, name,
    1270             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1271           0 :                 goto bailout;
    1272             :         }
    1273           2 :         canditer_init(&ci1, left, ls);
    1274           2 :         canditer_init(&ci2, right, rs);
    1275           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1276           0 :                 msg = createException(MAL, name,
    1277             :                                                           ILLEGAL_ARGUMENT
    1278             :                                                           " Requires bats of identical size");
    1279           0 :                 goto bailout;
    1280             :         }
    1281           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1282           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1283           0 :                 goto bailout;
    1284             :         }
    1285             : 
    1286           2 :         off1 = left->hseqbase;
    1287           2 :         off2 = right->hseqbase;
    1288           2 :         lefti = bat_iterator(left);
    1289           2 :         bi = bat_iterator(right);
    1290           2 :         righti = bi.base;
    1291           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1292          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1293           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1294           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1295           8 :                         const char *x = BUNtvar(lefti, p1);
    1296           8 :                         y = righti[p2];
    1297             : 
    1298          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1299           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1300           0 :                                         msg = createException(MAL, name,
    1301             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1302           0 :                                         goto bailout1;
    1303             :                                 }
    1304             :                                 nils = true;
    1305             :                         } else {
    1306           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1307           0 :                                         goto bailout1;
    1308           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1309           0 :                                         msg = createException(MAL, name,
    1310             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1311           0 :                                         goto bailout1;
    1312             :                                 }
    1313             :                         }
    1314             :                 }
    1315             :         } else {
    1316           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1317           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1318           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1319           0 :                         const char *x = BUNtvar(lefti, p1);
    1320           0 :                         y = righti[p2];
    1321             : 
    1322           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1323           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1324           0 :                                         msg = createException(MAL, name,
    1325             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1326           0 :                                         goto bailout1;
    1327             :                                 }
    1328             :                                 nils = true;
    1329             :                         } else {
    1330           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1331           0 :                                         goto bailout1;
    1332           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1333           0 :                                         msg = createException(MAL, name,
    1334             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1335           0 :                                         goto bailout1;
    1336             :                                 }
    1337             :                         }
    1338             :                 }
    1339             :         }
    1340           0 :   bailout1:
    1341           2 :         bat_iterator_end(&bi);
    1342           2 :         bat_iterator_end(&lefti);
    1343           2 :   bailout:
    1344           2 :         GDKfree(buf);
    1345           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1346           2 :         unfix_inputs(4, left, ls, right, rs);
    1347           2 :         return msg;
    1348             : }
    1349             : 
    1350             : /* Input: a BAT of strings 'l', a constant int 'y' and a BAT of strings 'l2'
    1351             :  * Output type: str (a BAT of strings)
    1352             :  */
    1353             : static str
    1354           2 : do_batstr_constint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1355             :                                                           InstrPtr pci, const char *name,
    1356             :                                                           str (*func)(str *, size_t *, const char *,
    1357             :                                                                                   int, const char *))
    1358             : {
    1359           2 :         BATiter lefti, righti;
    1360           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1361           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1362           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1363           2 :         bool nils = false;
    1364           2 :         int y = *getArgReference_int(stk, pci, 2);
    1365           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1366           2 :         oid off1, off2;
    1367           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1368           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1369           2 :                 *l2 = getArgReference_bat(stk, pci, 3),
    1370           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1371           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1372             : 
    1373           2 :         (void) cntxt;
    1374           2 :         (void) mb;
    1375           2 :         if (!buf) {
    1376           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1377           0 :                 goto bailout;
    1378             :         }
    1379           2 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*l2))) {
    1380           0 :                 msg = createException(MAL, name,
    1381             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1382           0 :                 goto bailout;
    1383             :         }
    1384           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1385           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1386           0 :                 msg = createException(MAL, name,
    1387             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1388           0 :                 goto bailout;
    1389             :         }
    1390           2 :         canditer_init(&ci1, left, ls);
    1391           2 :         canditer_init(&ci2, right, rs);
    1392           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1393           0 :                 msg = createException(MAL, name,
    1394             :                                                           ILLEGAL_ARGUMENT
    1395             :                                                           " Requires bats of identical size");
    1396           0 :                 goto bailout;
    1397             :         }
    1398           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1399           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1400           0 :                 goto bailout;
    1401             :         }
    1402             : 
    1403           2 :         off1 = left->hseqbase;
    1404           2 :         off2 = right->hseqbase;
    1405           2 :         lefti = bat_iterator(left);
    1406           2 :         righti = bat_iterator(right);
    1407           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1408          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1409           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1410           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1411           8 :                         const char *x = BUNtvar(lefti, p1);
    1412           8 :                         const char *z = BUNtvar(righti, p2);
    1413             : 
    1414          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1415           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1416           0 :                                         msg = createException(MAL, name,
    1417             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1418           0 :                                         goto bailout1;
    1419             :                                 }
    1420             :                                 nils = true;
    1421             :                         } else {
    1422           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1423           0 :                                         goto bailout1;
    1424           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1425           0 :                                         msg = createException(MAL, name,
    1426             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1427           0 :                                         goto bailout1;
    1428             :                                 }
    1429             :                         }
    1430             :                 }
    1431             :         } else {
    1432           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1433           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1434           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1435           0 :                         const char *x = BUNtvar(lefti, p1);
    1436           0 :                         const char *z = BUNtvar(righti, p2);
    1437             : 
    1438           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1439           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1440           0 :                                         msg = createException(MAL, name,
    1441             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1442           0 :                                         goto bailout1;
    1443             :                                 }
    1444             :                                 nils = true;
    1445             :                         } else {
    1446           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1447           0 :                                         goto bailout1;
    1448           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1449           0 :                                         msg = createException(MAL, name,
    1450             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1451           0 :                                         goto bailout1;
    1452             :                                 }
    1453             :                         }
    1454             :                 }
    1455             :         }
    1456           0 :   bailout1:
    1457           2 :         bat_iterator_end(&lefti);
    1458           2 :         bat_iterator_end(&righti);
    1459           2 :   bailout:
    1460           2 :         GDKfree(buf);
    1461           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1462           2 :         unfix_inputs(4, left, ls, right, rs);
    1463           2 :         return msg;
    1464             : }
    1465             : 
    1466             : /* Input: a BAT of strings 'l', a BAT of int 'n' and a BAT of strings 'l2'
    1467             :  * Output type: str (a BAT of strings)
    1468             :  */
    1469             : static str
    1470           2 : do_batstr_batint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1471             :                                                         InstrPtr pci, const char *name,
    1472             :                                                         str (*func)(str *, size_t *, const char *,
    1473             :                                                                                 int, const char *))
    1474             : {
    1475           2 :         BATiter arg1i, arg3i, bi;
    1476           2 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL, *arg2s = NULL,
    1477           2 :                 *arg3 = NULL, *arg3s = NULL;
    1478           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1479           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1480           2 :         bool nils = false;
    1481           2 :         int *restrict arg2i, y;
    1482           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    1483           2 :         oid off1, off2, off3;
    1484           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1485           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1486           2 :                 *n = getArgReference_bat(stk, pci, 2),
    1487           2 :                 *l2 = getArgReference_bat(stk, pci, 3),
    1488           2 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    1489           2 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    1490           2 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    1491             : 
    1492           2 :         (void) cntxt;
    1493           2 :         (void) mb;
    1494           2 :         if (!buf) {
    1495           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1496           0 :                 goto bailout;
    1497             :         }
    1498           2 :         if (!(arg1 = BATdescriptor(*l)) || !(arg2 = BATdescriptor(*n))
    1499           2 :                 || !(arg3 = BATdescriptor(*l2))) {
    1500           0 :                 msg = createException(MAL, name,
    1501             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1502           0 :                 goto bailout;
    1503             :         }
    1504           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1)))
    1505           2 :                 || (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2)))
    1506           2 :                 || (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3)))) {
    1507           0 :                 msg = createException(MAL, name,
    1508             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1509           0 :                 goto bailout;
    1510             :         }
    1511           2 :         canditer_init(&ci1, arg1, arg1s);
    1512           2 :         canditer_init(&ci2, arg2, arg2s);
    1513           2 :         canditer_init(&ci3, arg3, arg3s);
    1514           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    1515           2 :                 || ci2.hseq != ci3.hseq) {
    1516           0 :                 msg = createException(MAL, name,
    1517             :                                                           ILLEGAL_ARGUMENT
    1518             :                                                           " Requires bats of identical size");
    1519           0 :                 goto bailout;
    1520             :         }
    1521           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1522           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1523           0 :                 goto bailout;
    1524             :         }
    1525             : 
    1526           2 :         off1 = arg1->hseqbase;
    1527           2 :         off2 = arg2->hseqbase;
    1528           2 :         off3 = arg3->hseqbase;
    1529           2 :         arg1i = bat_iterator(arg1);
    1530           2 :         bi = bat_iterator(arg2);
    1531           2 :         arg2i = bi.base;
    1532           2 :         arg3i = bat_iterator(arg3);
    1533           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    1534          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1535           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1536           8 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    1537           8 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    1538           8 :                         const char *x = BUNtvar(arg1i, p1);
    1539           8 :                         y = arg2i[p2];
    1540           8 :                         const char *z = BUNtvar(arg3i, p3);
    1541             : 
    1542          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1543           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1544           0 :                                         msg = createException(MAL, name,
    1545             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1546           0 :                                         goto bailout1;
    1547             :                                 }
    1548             :                                 nils = true;
    1549             :                         } else {
    1550           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1551           0 :                                         goto bailout1;
    1552           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1553           0 :                                         msg = createException(MAL, name,
    1554             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1555           0 :                                         goto bailout1;
    1556             :                                 }
    1557             :                         }
    1558             :                 }
    1559             :         } else {
    1560           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1561           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1562           0 :                                 p2 = (canditer_next(&ci2) - off2),
    1563           0 :                                 p3 = (canditer_next(&ci3) - off3);
    1564           0 :                         const char *x = BUNtvar(arg1i, p1);
    1565           0 :                         y = arg2i[p2];
    1566           0 :                         const char *z = BUNtvar(arg3i, p3);
    1567             : 
    1568           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1569           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1570           0 :                                         msg = createException(MAL, name,
    1571             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1572           0 :                                         goto bailout1;
    1573             :                                 }
    1574             :                                 nils = true;
    1575             :                         } else {
    1576           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1577           0 :                                         goto bailout1;
    1578           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1579           0 :                                         msg = createException(MAL, name,
    1580             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1581           0 :                                         goto bailout1;
    1582             :                                 }
    1583             :                         }
    1584             :                 }
    1585             :         }
    1586           0 :   bailout1:
    1587           2 :         bat_iterator_end(&arg1i);
    1588           2 :         bat_iterator_end(&arg3i);
    1589           2 :         bat_iterator_end(&bi);
    1590           2 :   bailout:
    1591           2 :         GDKfree(buf);
    1592           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1593           2 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    1594           2 :         return msg;
    1595             : }
    1596             : 
    1597             : static str
    1598          76 : STRbatLower(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1599             : {
    1600          76 :         str msg = MAL_SUCCEED;
    1601             : 
    1602          76 :         if ((msg = str_case_hash_lock(false)))
    1603             :                 return msg;
    1604          76 :         msg = do_batstr_str(cntxt, mb, stk, pci, "batstr.lower", str_lower);
    1605          76 :         str_case_hash_unlock(false);
    1606          76 :         return msg;
    1607             : }
    1608             : 
    1609             : static str
    1610          14 : STRbatUpper(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1611             : {
    1612          14 :         str msg = MAL_SUCCEED;
    1613             : 
    1614          14 :         if ((msg = str_case_hash_lock(true)))
    1615             :                 return msg;
    1616          14 :         msg = do_batstr_str(cntxt, mb, stk, pci, "batstr.upper", str_upper);
    1617          14 :         str_case_hash_unlock(true);
    1618          14 :         return msg;
    1619             : }
    1620             : 
    1621             : static str
    1622          10 : STRbatStrip(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1623             : {
    1624          10 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.strip", str_strip);
    1625             : }
    1626             : 
    1627             : static str
    1628           2 : STRbatLtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1629             : {
    1630           2 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim", str_ltrim);
    1631             : }
    1632             : 
    1633             : static str
    1634          26 : STRbatRtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1635             : {
    1636          26 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim", str_rtrim);
    1637             : }
    1638             : 
    1639             : static str
    1640           1 : STRbatStrip2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1641             : {
    1642           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.strip",
    1643             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1644             :                                                                   str_strip2);
    1645             : }
    1646             : 
    1647             : static str
    1648           1 : STRbatLtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1649             : {
    1650           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1651             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1652             :                                                                   str_ltrim2);
    1653             : }
    1654             : 
    1655             : static str
    1656           1 : STRbatRtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1657             : {
    1658           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1659             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1660             :                                                                   str_rtrim2);
    1661             : }
    1662             : 
    1663             : static str
    1664           0 : STRbatStrip2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1665             : {
    1666           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.strip",
    1667             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1668             :                                                                   str_strip2);
    1669             : }
    1670             : 
    1671             : static str
    1672           0 : STRbatLtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1673             : {
    1674           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.ltrim",
    1675             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1676             :                                                                   str_ltrim2);
    1677             : }
    1678             : 
    1679             : static str
    1680           0 : STRbatRtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1681             : {
    1682           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.rtrim",
    1683             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1684             :                                                                   str_rtrim2);
    1685             : }
    1686             : 
    1687             : static str
    1688           5 : STRbatStrip2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1689             : {
    1690           5 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.strip",
    1691             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1692             :                                                                 str_strip2);
    1693             : }
    1694             : 
    1695             : static str
    1696           1 : STRbatLtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1697             : {
    1698           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1699             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1700             :                                                                 str_ltrim2);
    1701             : }
    1702             : 
    1703             : static str
    1704           1 : STRbatRtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1705             : {
    1706           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1707             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1708             :                                                                 str_rtrim2);
    1709             : }
    1710             : 
    1711             : static str
    1712           1 : STRbatLpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1713             : {
    1714           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1715             : }
    1716             : 
    1717             : static str
    1718           1 : STRbatRpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1719             : {
    1720           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1721             : }
    1722             : 
    1723             : static str
    1724           0 : STRbatLpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1725             : {
    1726           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1727             : }
    1728             : 
    1729             : static str
    1730           0 : STRbatRpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1731             : {
    1732           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1733             : }
    1734             : 
    1735             : static str
    1736           1 : STRbatLpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1737             : {
    1738           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1739             : }
    1740             : 
    1741             : static str
    1742           1 : STRbatRpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1743             : {
    1744           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1745             : }
    1746             : 
    1747             : static str
    1748           1 : STRbatLpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1749             : {
    1750           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1751             :                                                                                    str_lpad3);
    1752             : }
    1753             : 
    1754             : static str
    1755           1 : STRbatRpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1756             : {
    1757           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1758             :                                                                                    str_rpad3);
    1759             : }
    1760             : 
    1761             : static str
    1762           1 : STRbatLpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1763             : {
    1764           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1765             :                                                                                  str_lpad3);
    1766             : }
    1767             : 
    1768             : static str
    1769           1 : STRbatRpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1770             : {
    1771           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1772             :                                                                                  str_rpad3);
    1773             : }
    1774             : 
    1775             : static str
    1776           1 : STRbatLpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1777             : {
    1778           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1779             :                                                                                  str_lpad3);
    1780             : }
    1781             : 
    1782             : static str
    1783           1 : STRbatRpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1784             : {
    1785           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1786             :                                                                                  str_rpad3);
    1787             : }
    1788             : 
    1789             : static str
    1790           1 : STRbatLpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1791             : {
    1792           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1793             :                                                                            str_lpad3);
    1794             : }
    1795             : 
    1796             : static str
    1797           1 : STRbatRpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1798             : {
    1799           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1800             :                                                                            str_rpad3);
    1801             : }
    1802             : 
    1803             : /*
    1804             :  * A general assumption in all cases is the bats are synchronized on their
    1805             :  * head column. This is not checked and may be mis-used to deploy the
    1806             :  * implementation for shifted window arithmetic as well.
    1807             :  */
    1808             : static str
    1809           2 : prefix_or_suffix(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1810             :                                  const char *name, int (*func)(const char *, const char *, int),
    1811             :                                  bit *icase)
    1812             : {
    1813           2 :          (void) cntxt;
    1814           2 :         (void) mb;
    1815             : 
    1816           2 :         BATiter lefti, righti;
    1817           2 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    1818           2 :         bit *restrict vals;
    1819           2 :         str msg = MAL_SUCCEED;
    1820           2 :         bool nils = false;
    1821           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1822           2 :         oid off1, off2;
    1823           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1824           2 :                 *l = getArgReference_bat(stk, pci, 1),
    1825           2 :                 *r = getArgReference_bat(stk, pci, 2),
    1826           4 :                 *sid1 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 4 : 3) : NULL,
    1827           4 :                 *sid2 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 5 : 4) : NULL;
    1828             : 
    1829           2 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    1830           0 :                 msg = createException(MAL, name,
    1831             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1832           0 :                 goto exit2;
    1833             :         }
    1834           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) ||
    1835           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    1836           0 :                 msg = createException(MAL, name,
    1837             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1838           0 :                 goto exit2;
    1839             :         }
    1840           2 :         canditer_init(&ci1, left, lefts);
    1841           2 :         canditer_init(&ci2, right, rights);
    1842           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1843           0 :                 msg = createException(MAL, name,
    1844             :                                                           ILLEGAL_ARGUMENT
    1845             :                                                           " Requires bats of identical size");
    1846           0 :                 goto exit2;
    1847             :         }
    1848           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    1849           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1850           0 :                 goto exit2;
    1851             :         }
    1852             : 
    1853           2 :         off1 = left->hseqbase;
    1854           2 :         off2 = right->hseqbase;
    1855           2 :         lefti = bat_iterator(left);
    1856           2 :         righti = bat_iterator(right);
    1857           2 :         vals = Tloc(bn, 0);
    1858           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1859           4 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1860           2 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1861           2 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1862           2 :                         char *x = BUNtvar(lefti, p1);
    1863           2 :                         char *y = BUNtvar(righti, p2);
    1864             : 
    1865           4 :                         if (strNil(x) || strNil(y)) {
    1866           0 :                                 vals[i] = bit_nil;
    1867           0 :                                 nils = true;
    1868             :                         } else {
    1869           2 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    1870             :                         }
    1871             :                 }
    1872             :         } else {
    1873           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1874           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1875           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1876           0 :                         char *x = BUNtvar(lefti, p1);
    1877           0 :                         char *y = BUNtvar(righti, p2);
    1878             : 
    1879           0 :                         if (strNil(x) || strNil(y)) {
    1880           0 :                                 vals[i] = bit_nil;
    1881           0 :                                 nils = true;
    1882             :                         } else {
    1883           0 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    1884             :                         }
    1885             :                 }
    1886             :         }
    1887           2 :         bat_iterator_end(&lefti);
    1888           2 :         bat_iterator_end(&righti);
    1889           2 :   exit2:
    1890           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1891           2 :         unfix_inputs(4, left, lefts, right, rights);
    1892           2 :         return msg;
    1893             : }
    1894             : 
    1895             : static str
    1896           0 : BATSTRstarts_with(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1897             : {
    1898           0 :         bit *icase = NULL;
    1899           0 :         if (pci->argc == 4 || pci->argc == 6) {
    1900           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1901           0 :                 icase = getArgReference_bit(stk, pci, 3);
    1902             :         }
    1903           0 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.startswith",
    1904             :                                                         (icase
    1905           0 :                                                          && *icase) ? str_is_iprefix : str_is_prefix,
    1906             :                                                         icase);
    1907             : }
    1908             : 
    1909             : static str
    1910           0 : BATSTRends_with(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1911             : {
    1912           0 :         bit *icase = NULL;
    1913           0 :         if (pci->argc == 4 || pci->argc == 6) {
    1914           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1915           0 :                 icase = getArgReference_bit(stk, pci, 3);
    1916             :         }
    1917           0 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.endswith",
    1918             :                                                         (icase
    1919           0 :                                                          && *icase) ? str_is_isuffix : str_is_suffix,
    1920             :                                                         icase);
    1921             : }
    1922             : 
    1923             : static str
    1924           2 : BATSTRcontains(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1925             : {
    1926           2 :         bit *icase = NULL;
    1927           2 :         if (pci->argc == 4 || pci->argc == 6) {
    1928           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1929           0 :                 icase = getArgReference_bit(stk, pci, 3);
    1930             :         }
    1931           2 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.contains",
    1932             :                                                         (icase
    1933           0 :                                                          && *icase) ? str_icontains : str_contains, icase);
    1934             : }
    1935             : 
    1936             : static str
    1937          19 : prefix_or_suffix_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1938             :                                          const char *name, int (*func)(const char *, const char *,
    1939             :                                                                                                    int), bit *icase)
    1940             : {
    1941          19 :          (void) cntxt;
    1942          19 :         (void) mb;
    1943             : 
    1944          19 :         BATiter bi;
    1945          19 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1946          19 :         bit *restrict vals;
    1947          19 :         str y = *getArgReference_str(stk, pci, 2), msg = MAL_SUCCEED;
    1948          19 :         bool nils = false;
    1949          19 :         struct canditer ci1 = { 0 };
    1950          19 :         oid off1;
    1951          19 :         bat *res = getArgReference_bat(stk, pci, 0),
    1952          19 :                         *bid = getArgReference_bat(stk, pci, 1), *sid1 = NULL;
    1953          19 :         int ynil, ylen;
    1954             : 
    1955          19 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    1956          33 :                 assert(getArgType(mb, pci, icase ? 4 : 3) == TYPE_bat ||
    1957             :                            isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    1958          17 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    1959             :         }
    1960             : 
    1961          19 :         if (!(b = BATdescriptor(*bid))) {
    1962           0 :                 msg = createException(MAL, name,
    1963             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1964           0 :                 goto exit2;
    1965             :         }
    1966          19 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    1967           0 :                 msg = createException(MAL, name,
    1968             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1969           0 :                 goto exit2;
    1970             :         }
    1971          19 :         canditer_init(&ci1, b, bs);
    1972          19 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    1973           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1974           0 :                 goto exit2;
    1975             :         }
    1976             : 
    1977          19 :         off1 = b->hseqbase;
    1978          19 :         bi = bat_iterator(b);
    1979          19 :         vals = Tloc(bn, 0);
    1980          19 :         ynil = strNil(y);
    1981          19 :         ylen = str_strlen(y);
    1982          19 :         if (ci1.tpe == cand_dense) {
    1983        3653 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1984        3634 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    1985        3634 :                         char *x = BUNtvar(bi, p1);
    1986             : 
    1987        3634 :                         if (ynil || strNil(x)) {
    1988           0 :                                 vals[i] = bit_nil;
    1989           0 :                                 nils = true;
    1990             :                         } else {
    1991        3634 :                                 vals[i] = func(x, y, ylen) == 0;
    1992             :                         }
    1993             :                 }
    1994             :         } else {
    1995           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1996           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    1997           0 :                         char *x = BUNtvar(bi, p1);
    1998             : 
    1999           0 :                         if (ynil || strNil(x)) {
    2000           0 :                                 vals[i] = bit_nil;
    2001           0 :                                 nils = true;
    2002             :                         } else {
    2003           0 :                                 vals[i] = func(x, y, ylen) == 0;
    2004             :                         }
    2005             :                 }
    2006             :         }
    2007          19 :         bat_iterator_end(&bi);
    2008          19 :   exit2:
    2009          19 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2010          19 :         unfix_inputs(2, b, bs);
    2011          19 :         return msg;
    2012             : }
    2013             : 
    2014             : static str
    2015           3 : BATSTRstarts_with_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2016             : {
    2017           3 :         bit *icase = NULL;
    2018           3 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2019           3 :                 || pci->argc == 5) {
    2020           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2021           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2022             :         }
    2023           3 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.startswith",
    2024             :                                                                 (icase
    2025           0 :                                                                  && *icase) ? str_is_iprefix : str_is_prefix,
    2026             :                                                                 icase);
    2027             : }
    2028             : 
    2029             : static str
    2030           5 : BATSTRends_with_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2031             : {
    2032           5 :         bit *icase = NULL;
    2033           5 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2034           5 :                 || pci->argc == 5) {
    2035           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2036           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2037             :         }
    2038           5 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.endswith",
    2039             :                                                                 (icase
    2040           0 :                                                                  && *icase) ? str_is_isuffix : str_is_suffix,
    2041             :                                                                 icase);
    2042             : }
    2043             : 
    2044             : static str
    2045          11 : BATSTRcontains_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2046             : {
    2047          11 :         bit *icase = NULL;
    2048          11 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2049           9 :                 || pci->argc == 5) {
    2050           3 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2051           3 :                 icase = getArgReference_bit(stk, pci, 3);
    2052             :         }
    2053          11 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.contains",
    2054             :                                                                 (icase
    2055           3 :                                                                  && *icase) ? str_icontains : str_contains,
    2056             :                                                                 icase);
    2057             : }
    2058             : 
    2059             : static str
    2060          13 : prefix_or_suffix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2061             :                                                 const char *name, int (*func)(const char *,
    2062             :                                                                                                           const char *, int),
    2063             :                                                 bit *icase)
    2064             : {
    2065          13 :          (void) cntxt;
    2066          13 :         (void) mb;
    2067             : 
    2068          13 :         BATiter bi;
    2069          13 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2070          13 :         bit *restrict vals;
    2071          13 :         char *x = *getArgReference_str(stk, pci, 1);
    2072          13 :         str msg = MAL_SUCCEED;
    2073          13 :         bool nils = false;
    2074          13 :         struct canditer ci1 = { 0 };
    2075          13 :         oid off1;
    2076          13 :         bat *res = getArgReference_bat(stk, pci, 0),
    2077          13 :                         *bid = getArgReference_bat(stk, pci, 2), *sid1 = NULL;
    2078          13 :         int xnil;
    2079             : 
    2080          13 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2081          22 :                 assert(getArgType(mb, pci, icase ? 4 : 3) == TYPE_bat ||
    2082             :                            isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2083          11 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2084             :         }
    2085             : 
    2086          13 :         if (!(b = BATdescriptor(*bid))) {
    2087           0 :                 msg = createException(MAL, name,
    2088             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2089           0 :                 goto exit2;
    2090             :         }
    2091          13 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2092           0 :                 msg = createException(MAL, name,
    2093             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2094           0 :                 goto exit2;
    2095             :         }
    2096          13 :         canditer_init(&ci1, b, bs);
    2097          13 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    2098           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2099           0 :                 goto exit2;
    2100             :         }
    2101             : 
    2102          13 :         off1 = b->hseqbase;
    2103          13 :         bi = bat_iterator(b);
    2104          13 :         vals = Tloc(bn, 0);
    2105          13 :         xnil = strNil(x);
    2106          13 :         if (ci1.tpe == cand_dense) {
    2107          41 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2108          28 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2109          28 :                         char *y = BUNtvar(bi, p1);
    2110             : 
    2111          28 :                         if (xnil || strNil(y)) {
    2112           0 :                                 vals[i] = bit_nil;
    2113           0 :                                 nils = true;
    2114             :                         } else {
    2115          28 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    2116             :                         }
    2117             :                 }
    2118             :         } else {
    2119           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2120           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2121           0 :                         char *y = BUNtvar(bi, p1);
    2122             : 
    2123           0 :                         if (xnil || strNil(y)) {
    2124           0 :                                 vals[i] = bit_nil;
    2125           0 :                                 nils = true;
    2126             :                         } else {
    2127           0 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    2128             :                         }
    2129             :                 }
    2130             :         }
    2131          13 :         bat_iterator_end(&bi);
    2132          13 :   exit2:
    2133          13 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2134          13 :         unfix_inputs(2, b, bs);
    2135          13 :         return msg;
    2136             : }
    2137             : 
    2138             : static str
    2139           2 : BATSTRstarts_with_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2140             :                                                  InstrPtr pci)
    2141             : {
    2142           2 :         bit *icase = NULL;
    2143           2 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2144           2 :                 || pci->argc == 5) {
    2145           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2146           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2147             :         }
    2148           2 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.startsWith",
    2149             :                                                                    (icase
    2150           0 :                                                                         && *icase) ? str_is_iprefix : str_is_prefix,
    2151             :                                                                    icase);
    2152             : }
    2153             : 
    2154             : static str
    2155           1 : BATSTRends_with_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2156             : {
    2157           1 :         bit *icase = NULL;
    2158           1 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2159           1 :                 || pci->argc == 5) {
    2160           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2161           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2162             :         }
    2163           1 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.endsWith",
    2164             :                                                                    (icase
    2165           0 :                                                                         && *icase) ? str_is_isuffix : str_is_suffix,
    2166             :                                                                    icase);
    2167             : }
    2168             : 
    2169             : static str
    2170          10 : BATSTRcontains_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2171             : {
    2172          10 :         bit *icase = NULL;
    2173          10 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2174           8 :                 || pci->argc == 5) {
    2175           2 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2176           2 :                 icase = getArgReference_bit(stk, pci, 3);
    2177             :         }
    2178          10 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.contains",
    2179             :                                                                    (icase
    2180           2 :                                                                         && *icase) ? str_icontains : str_contains,
    2181             :                                                                    icase);
    2182             : }
    2183             : 
    2184             : static str
    2185           1 : search_string_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2186             :                                   const char *name, int (*func)(const char *, const char *,
    2187             :                                                                                                 int), bit *icase)
    2188             : {
    2189           1 :          (void) cntxt;
    2190           1 :         (void) mb;
    2191             : 
    2192           1 :         BATiter lefti, righti;
    2193           1 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    2194           1 :         int *restrict vals;
    2195           1 :         str msg = MAL_SUCCEED;
    2196           1 :         bool nils = false;
    2197           1 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    2198           1 :         oid off1, off2;
    2199           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2200           1 :                 *l = getArgReference_bat(stk, pci, 1),
    2201           1 :                 *r = getArgReference_bat(stk, pci, 2),
    2202           1 :                 *sid1 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 4 : 3) : NULL,
    2203           1 :                 *sid2 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 5 : 4) : NULL;
    2204             : 
    2205           1 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    2206           0 :                 msg = createException(MAL, name,
    2207             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2208           0 :                 goto exit2;
    2209             :         }
    2210           1 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) ||
    2211           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    2212           0 :                 msg = createException(MAL, name,
    2213             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2214           0 :                 goto exit2;
    2215             :         }
    2216           1 :         canditer_init(&ci1, left, lefts);
    2217           1 :         canditer_init(&ci2, right, rights);
    2218           1 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    2219           0 :                 msg = createException(MAL, name,
    2220             :                                                           ILLEGAL_ARGUMENT
    2221             :                                                           " Requires bats of identical size");
    2222           0 :                 goto exit2;
    2223             :         }
    2224           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2225           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2226           0 :                 goto exit2;
    2227             :         }
    2228             : 
    2229           1 :         off1 = left->hseqbase;
    2230           1 :         off2 = right->hseqbase;
    2231           1 :         lefti = bat_iterator(left);
    2232           1 :         righti = bat_iterator(right);
    2233           1 :         vals = Tloc(bn, 0);
    2234           1 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    2235           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2236           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    2237           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    2238           4 :                         char *x = BUNtvar(lefti, p1);
    2239           4 :                         char *y = BUNtvar(righti, p2);
    2240             : 
    2241           8 :                         if (strNil(x) || strNil(y)) {
    2242           0 :                                 vals[i] = int_nil;
    2243           0 :                                 nils = true;
    2244             :                         } else {
    2245           4 :                                 vals[i] = func(x, y, str_strlen(y));
    2246             :                         }
    2247             :                 }
    2248             :         } else {
    2249           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2250           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    2251           0 :                                 p2 = (canditer_next(&ci2) - off2);
    2252           0 :                         char *x = BUNtvar(lefti, p1);
    2253           0 :                         char *y = BUNtvar(righti, p2);
    2254             : 
    2255           0 :                         if (strNil(x) || strNil(y)) {
    2256           0 :                                 vals[i] = int_nil;
    2257           0 :                                 nils = true;
    2258             :                         } else {
    2259           0 :                                 vals[i] = func(x, y, str_strlen(y));
    2260             :                         }
    2261             :                 }
    2262             :         }
    2263           1 :         bat_iterator_end(&lefti);
    2264           1 :         bat_iterator_end(&righti);
    2265           1 :   exit2:
    2266           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2267           1 :         unfix_inputs(4, left, lefts, right, rights);
    2268           1 :         return msg;
    2269             : }
    2270             : 
    2271             : static str
    2272           1 : BATSTRstr_search(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2273             : {
    2274           1 :         bit *icase = NULL;
    2275           1 :         switch (pci->argc) {
    2276           0 :         case 4:
    2277           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2278           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2279             :                 break;
    2280           0 :         case 6:
    2281           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2282           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2283           0 :                 break;
    2284             :         }
    2285           1 :         return search_string_bat(cntxt, mb, stk, pci, "batstr.search",
    2286             :                                                          (icase
    2287           0 :                                                           && *icase) ? str_isearch : str_search, icase);
    2288             : }
    2289             : 
    2290             : static str
    2291           0 : BATSTRrevstr_search(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2292             : {
    2293           0 :         bit *icase = NULL;
    2294           0 :         switch (pci->argc) {
    2295           0 :         case 4:
    2296           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2297           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2298             :                 break;
    2299           0 :         case 6:
    2300           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2301           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2302           0 :                 break;
    2303             :         }
    2304           0 :         return search_string_bat(cntxt, mb, stk, pci, "batstr.r_search",
    2305             :                                                          (icase
    2306           0 :                                                           && *icase) ? str_reverse_str_isearch :
    2307             :                                                          str_reverse_str_search, icase);
    2308             : }
    2309             : 
    2310             : static str
    2311           1 : search_string_bat_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2312             :                                           const char *name, int (*func)(const char *, const char *,
    2313             :                                                                                                         int), bit *icase)
    2314             : {
    2315           1 :          (void) cntxt;
    2316           1 :         (void) mb;
    2317             : 
    2318           1 :         BATiter bi;
    2319           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2320           1 :         int *restrict vals;
    2321           1 :         const char *y = *getArgReference_str(stk, pci, 2);
    2322           1 :         str msg = MAL_SUCCEED;
    2323           1 :         bool nils = false;
    2324           1 :         struct canditer ci1 = { 0 };
    2325           1 :         oid off1;
    2326           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2327           1 :                 *bid = getArgReference_bat(stk, pci, 1),
    2328           1 :                 *sid1 = NULL;
    2329           1 :         int ynil, ylen;
    2330             : 
    2331           1 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2332           0 :                 assert(getArgType(mb, pci, icase ? 4 : 3) == TYPE_bat ||
    2333             :                            isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2334           0 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2335             :         }
    2336             : 
    2337           1 :         if (!(b = BATdescriptor(*bid))) {
    2338           0 :                 msg = createException(MAL, name,
    2339             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2340           0 :                 goto exit2;
    2341             :         }
    2342           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2343           0 :                 msg = createException(MAL, name,
    2344             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2345           0 :                 goto exit2;
    2346             :         }
    2347           1 :         canditer_init(&ci1, b, bs);
    2348           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2349           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2350           0 :                 goto exit2;
    2351             :         }
    2352             : 
    2353           1 :         off1 = b->hseqbase;
    2354           1 :         bi = bat_iterator(b);
    2355           1 :         vals = Tloc(bn, 0);
    2356           1 :         ynil = strNil(y);
    2357           1 :         ylen = str_strlen(y);
    2358           1 :         if (ci1.tpe == cand_dense) {
    2359           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2360           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2361           4 :                         char *x = BUNtvar(bi, p1);
    2362             : 
    2363           4 :                         if (ynil || strNil(x)) {
    2364           0 :                                 vals[i] = int_nil;
    2365           0 :                                 nils = true;
    2366             :                         } else {
    2367           4 :                                 vals[i] = func(x, y, ylen);
    2368             :                         }
    2369             :                 }
    2370             :         } else {
    2371           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2372           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2373           0 :                         char *x = BUNtvar(bi, p1);
    2374             : 
    2375           0 :                         if (ynil || strNil(x)) {
    2376           0 :                                 vals[i] = int_nil;
    2377           0 :                                 nils = true;
    2378             :                         } else {
    2379           0 :                                 vals[i] = func(x, y, ylen);
    2380             :                         }
    2381             :                 }
    2382             :         }
    2383           1 :         bat_iterator_end(&bi);
    2384           1 :   exit2:
    2385           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2386           1 :         unfix_inputs(2, b, bs);
    2387           1 :         return msg;
    2388             : }
    2389             : 
    2390             : static str
    2391           1 : BATSTRstr_search_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2392             : {
    2393           1 :         bit *icase = NULL;
    2394           1 :         switch (pci->argc) {
    2395           0 :         case 4:
    2396           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2397           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2398             :                 break;
    2399           0 :         case 5:
    2400           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2401           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2402           0 :                 break;
    2403             :         }
    2404           1 :         return search_string_bat_cst(cntxt, mb, stk, pci, "batstr.search",
    2405             :                                                                  (icase
    2406           0 :                                                                   && *icase) ? str_isearch : str_search, icase);
    2407             : }
    2408             : 
    2409             : static str
    2410           0 : BATSTRrevstr_search_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2411             : {
    2412           0 :         bit *icase = NULL;
    2413           0 :         switch (pci->argc) {
    2414           0 :         case 4:
    2415           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2416           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2417             :                 break;
    2418           0 :         case 5:
    2419           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2420           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2421           0 :                 break;
    2422             :         }
    2423           0 :         return search_string_bat_cst(cntxt, mb, stk, pci, "batstr.r_search",
    2424             :                                                                  (icase
    2425           0 :                                                                   && *icase) ? str_reverse_str_isearch :
    2426             :                                                                  str_reverse_str_search, icase);
    2427             : }
    2428             : 
    2429             : static str
    2430           0 : search_string_bat_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2431             :                                                  InstrPtr pci, const char *name,
    2432             :                                                  int (*func)(const char *, const char *, int),
    2433             :                                                  bit *icase)
    2434             : {
    2435           0 :          (void) cntxt;
    2436           0 :         (void) mb;
    2437             : 
    2438           0 :         BATiter bi;
    2439           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2440           0 :         int *restrict vals;
    2441           0 :         char *x = *getArgReference_str(stk, pci, 1);
    2442           0 :         str msg = MAL_SUCCEED;
    2443           0 :         bool nils = false;
    2444           0 :         struct canditer ci1 = { 0 };
    2445           0 :         oid off1;
    2446           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2447           0 :                         *bid = getArgReference_bat(stk, pci, 2), *sid1 = NULL;
    2448           0 :         int xnil;
    2449             : 
    2450           0 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2451           0 :                 assert(getArgType(mb, pci, icase ? 4 : 3) == TYPE_bat ||
    2452             :                            isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2453           0 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2454             :         }
    2455             : 
    2456           0 :         if (!(b = BATdescriptor(*bid))) {
    2457           0 :                 msg = createException(MAL, name,
    2458             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2459           0 :                 goto exit2;
    2460             :         }
    2461           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2462           0 :                 msg = createException(MAL, name,
    2463             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2464           0 :                 goto exit2;
    2465             :         }
    2466           0 :         canditer_init(&ci1, b, bs);
    2467           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2468           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2469           0 :                 goto exit2;
    2470             :         }
    2471             : 
    2472           0 :         off1 = b->hseqbase;
    2473           0 :         bi = bat_iterator(b);
    2474           0 :         vals = Tloc(bn, 0);
    2475           0 :         xnil = strNil(x);
    2476           0 :         if (ci1.tpe == cand_dense) {
    2477           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2478           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2479           0 :                         char *y = BUNtvar(bi, p1);
    2480             : 
    2481           0 :                         if (xnil || strNil(y)) {
    2482           0 :                                 vals[i] = int_nil;
    2483           0 :                                 nils = true;
    2484             :                         } else {
    2485           0 :                                 vals[i] = func(x, y, str_strlen(y));
    2486             :                         }
    2487             :                 }
    2488             :         } else {
    2489           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2490           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2491           0 :                         char *y = BUNtvar(bi, p1);
    2492             : 
    2493           0 :                         if (xnil || strNil(y)) {
    2494           0 :                                 vals[i] = int_nil;
    2495           0 :                                 nils = true;
    2496             :                         } else {
    2497           0 :                                 vals[i] = func(x, y, str_strlen(y));
    2498             :                         }
    2499             :                 }
    2500             :         }
    2501           0 :         bat_iterator_end(&bi);
    2502           0 :   exit2:
    2503           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2504           0 :         unfix_inputs(2, b, bs);
    2505           0 :         return msg;
    2506             : }
    2507             : 
    2508             : static str
    2509           0 : BATSTRstr_search_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2510             : {
    2511           0 :         bit *icase = NULL;
    2512           0 :         switch (pci->argc) {
    2513           0 :         case 4:
    2514           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2515           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2516             :                 break;
    2517           0 :         case 5:
    2518           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2519           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2520           0 :                 break;
    2521             :         }
    2522           0 :         return search_string_bat_strcst(cntxt, mb, stk, pci, "batstr.search",
    2523             :                                                                         (icase
    2524           0 :                                                                          && *icase) ? str_isearch : str_search,
    2525             :                                                                         icase);
    2526             : }
    2527             : 
    2528             : static str
    2529           0 : BATSTRrevstr_search_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2530             :                                                    InstrPtr pci)
    2531             : {
    2532           0 :         bit *icase = NULL;
    2533           0 :         switch (pci->argc) {
    2534           0 :         case 4:
    2535           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2536           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2537             :                 break;
    2538           0 :         case 5:
    2539           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2540           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2541           0 :                 break;
    2542             :         }
    2543           0 :         return search_string_bat_strcst(cntxt, mb, stk, pci, "batstr.r_search",
    2544             :                                                                         (icase
    2545           0 :                                                                          && *icase) ? str_reverse_str_isearch :
    2546             :                                                                         str_reverse_str_search, icase);
    2547             : }
    2548             : 
    2549             : static str
    2550           0 : STRbatWChrAt(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2551             : {
    2552           0 :         BATiter lefti, bi;
    2553           0 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    2554           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2555           0 :         int *restrict righti, *restrict vals, next, y;
    2556           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2557           0 :         bool nils = false;
    2558           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    2559           0 :         oid off1, off2;
    2560           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2561           0 :                 *l = getArgReference_bat(stk, pci, 1),
    2562           0 :                 *r = getArgReference_bat(stk, pci, 2),
    2563           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    2564           0 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    2565             : 
    2566           0 :         (void) cntxt;
    2567           0 :         (void) mb;
    2568           0 :         if (!buf) {
    2569           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2570             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2571           0 :                 goto bailout;
    2572             :         }
    2573           0 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    2574           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2575             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2576           0 :                 goto bailout;
    2577             :         }
    2578           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    2579           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    2580           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2581             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2582           0 :                 goto bailout;
    2583             :         }
    2584           0 :         canditer_init(&ci1, left, lefts);
    2585           0 :         canditer_init(&ci2, right, rights);
    2586           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    2587           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2588             :                                                           ILLEGAL_ARGUMENT
    2589             :                                                           " Requires bats of identical size");
    2590           0 :                 goto bailout;
    2591             :         }
    2592           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2593           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2594             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2595           0 :                 goto bailout;
    2596             :         }
    2597             : 
    2598           0 :         off1 = left->hseqbase;
    2599           0 :         off2 = right->hseqbase;
    2600           0 :         lefti = bat_iterator(left);
    2601           0 :         bi = bat_iterator(right);
    2602           0 :         righti = bi.base;
    2603           0 :         vals = Tloc(bn, 0);
    2604           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    2605           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2606           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    2607           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    2608           0 :                         const char *x = BUNtvar(lefti, p1);
    2609           0 :                         y = righti[p2];
    2610             : 
    2611           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2612           0 :                                 goto bailout1;
    2613           0 :                         vals[i] = next;
    2614           0 :                         nils |= is_int_nil(next);
    2615             :                 }
    2616             :         } else {
    2617           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2618           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    2619           0 :                                 p2 = (canditer_next(&ci2) - off2);
    2620           0 :                         const char *x = BUNtvar(lefti, p1);
    2621           0 :                         y = righti[p2];
    2622             : 
    2623           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2624           0 :                                 goto bailout1;
    2625           0 :                         vals[i] = next;
    2626           0 :                         nils |= is_int_nil(next);
    2627             :                 }
    2628             :         }
    2629           0 :   bailout1:
    2630           0 :         bat_iterator_end(&bi);
    2631           0 :         bat_iterator_end(&lefti);
    2632           0 :   bailout:
    2633           0 :         GDKfree(buf);
    2634           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2635           0 :         unfix_inputs(4, left, lefts, right, rights);
    2636           0 :         return msg;
    2637             : }
    2638             : 
    2639             : static str
    2640           0 : STRbatWChrAtcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2641             : {
    2642           0 :         BATiter bi;
    2643           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2644           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2645           0 :         int y = *getArgReference_int(stk, pci, 2), *restrict vals, next;
    2646           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2647           0 :         bool nils = false;
    2648           0 :         struct canditer ci1 = { 0 };
    2649           0 :         oid off1;
    2650           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2651           0 :                 *l = getArgReference_bat(stk, pci, 1),
    2652           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2653             : 
    2654           0 :         (void) cntxt;
    2655           0 :         (void) mb;
    2656           0 :         if (!buf) {
    2657           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2658             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2659           0 :                 goto bailout;
    2660             :         }
    2661           0 :         if (!(b = BATdescriptor(*l))) {
    2662           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2663             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2664           0 :                 goto bailout;
    2665             :         }
    2666           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2667           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2668             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2669           0 :                 goto bailout;
    2670             :         }
    2671           0 :         canditer_init(&ci1, b, bs);
    2672           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2673           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2674             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2675           0 :                 goto bailout;
    2676             :         }
    2677             : 
    2678           0 :         off1 = b->hseqbase;
    2679           0 :         bi = bat_iterator(b);
    2680           0 :         vals = Tloc(bn, 0);
    2681           0 :         if (ci1.tpe == cand_dense) {
    2682           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2683           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2684           0 :                         const char *x = BUNtvar(bi, p1);
    2685             : 
    2686           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2687           0 :                                 goto bailout1;
    2688           0 :                         vals[i] = next;
    2689           0 :                         nils |= is_int_nil(next);
    2690             :                 }
    2691             :         } else {
    2692           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2693           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2694           0 :                         const char *x = BUNtvar(bi, p1);
    2695             : 
    2696           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2697           0 :                                 goto bailout1;
    2698           0 :                         vals[i] = next;
    2699           0 :                         nils |= is_int_nil(next);
    2700             :                 }
    2701             :         }
    2702           0 :   bailout1:
    2703           0 :         bat_iterator_end(&bi);
    2704           0 :   bailout:
    2705           0 :         GDKfree(buf);
    2706           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2707           0 :         unfix_inputs(2, b, bs);
    2708           0 :         return msg;
    2709             : }
    2710             : 
    2711             : static str
    2712           0 : STRbatWChrAt_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2713             : {
    2714           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2715           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2716           0 :         int y, *restrict vals, *restrict input, next;
    2717           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    2718           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2719           0 :         bool nils = false;
    2720           0 :         struct canditer ci1 = { 0 };
    2721           0 :         oid off1;
    2722           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2723           0 :                 *l = getArgReference_bat(stk, pci, 2),
    2724           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2725           0 :         BATiter bi;
    2726             : 
    2727           0 :         (void) cntxt;
    2728           0 :         (void) mb;
    2729           0 :         if (!buf) {
    2730           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2731             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2732           0 :                 goto bailout;
    2733             :         }
    2734           0 :         if (!(b = BATdescriptor(*l))) {
    2735           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2736             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2737           0 :                 goto bailout;
    2738             :         }
    2739           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2740           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2741             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2742           0 :                 goto bailout;
    2743             :         }
    2744           0 :         canditer_init(&ci1, b, bs);
    2745           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2746           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2747             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2748           0 :                 goto bailout;
    2749             :         }
    2750             : 
    2751           0 :         off1 = b->hseqbase;
    2752           0 :         bi = bat_iterator(b);
    2753           0 :         input = bi.base;
    2754           0 :         vals = Tloc(bn, 0);
    2755           0 :         if (ci1.tpe == cand_dense) {
    2756           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2757           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2758           0 :                         y = input[p1];
    2759             : 
    2760           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2761           0 :                                 goto bailout1;
    2762           0 :                         vals[i] = next;
    2763           0 :                         nils |= is_int_nil(next);
    2764             :                 }
    2765             :         } else {
    2766           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2767           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2768           0 :                         y = input[p1];
    2769             : 
    2770           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2771           0 :                                 goto bailout1;
    2772           0 :                         vals[i] = next;
    2773           0 :                         nils |= is_int_nil(next);
    2774             :                 }
    2775             :         }
    2776           0 :   bailout1:
    2777           0 :         bat_iterator_end(&bi);
    2778           0 :   bailout:
    2779           0 :         GDKfree(buf);
    2780           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2781           0 :         unfix_inputs(2, b, bs);
    2782           0 :         return msg;
    2783             : }
    2784             : 
    2785             : static str
    2786         158 : do_batstr_str_int_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2787             :                                           const char *name, str (*func)(str *, size_t *,
    2788             :                                                                                                         const char *, int))
    2789             : {
    2790         158 :         BATiter bi;
    2791         158 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2792         158 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2793         158 :         int y = *getArgReference_int(stk, pci, 2);
    2794         158 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2795         158 :         bool nils = false;
    2796         158 :         struct canditer ci1 = { 0 };
    2797         158 :         oid off1;
    2798         158 :         bat *res = getArgReference_bat(stk, pci, 0),
    2799         158 :                 *l = getArgReference_bat(stk, pci, 1),
    2800         158 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2801             : 
    2802         158 :         (void) cntxt;
    2803         158 :         (void) mb;
    2804         158 :         if (!buf) {
    2805           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2806           0 :                 goto bailout;
    2807             :         }
    2808         158 :         if (!(b = BATdescriptor(*l))) {
    2809           0 :                 msg = createException(MAL, name,
    2810             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2811           0 :                 goto bailout;
    2812             :         }
    2813         158 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2814           0 :                 msg = createException(MAL, name,
    2815             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2816           0 :                 goto bailout;
    2817             :         }
    2818         158 :         canditer_init(&ci1, b, bs);
    2819         158 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2820           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2821           0 :                 goto bailout;
    2822             :         }
    2823             : 
    2824         158 :         off1 = b->hseqbase;
    2825         158 :         bi = bat_iterator(b);
    2826         158 :         if (ci1.tpe == cand_dense) {
    2827      125412 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2828      125254 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2829      125254 :                         const char *x = BUNtvar(bi, p1);
    2830             : 
    2831      227776 :                         if (strNil(x) || is_int_nil(y)) {
    2832       22535 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2833           0 :                                         msg = createException(MAL, name,
    2834             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2835           0 :                                         goto bailout1;
    2836             :                                 }
    2837             :                                 nils = true;
    2838             :                         } else {
    2839      102619 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    2840           0 :                                         goto bailout1;
    2841      102615 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2842           0 :                                         msg = createException(MAL, name,
    2843             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2844           0 :                                         goto bailout1;
    2845             :                                 }
    2846             :                         }
    2847             :                 }
    2848             :         } else {
    2849           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2850           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2851           0 :                         const char *x = BUNtvar(bi, p1);
    2852             : 
    2853           0 :                         if (strNil(x) || is_int_nil(y)) {
    2854           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2855           0 :                                         msg = createException(MAL, name,
    2856             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2857           0 :                                         goto bailout1;
    2858             :                                 }
    2859             :                                 nils = true;
    2860             :                         } else {
    2861           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    2862           0 :                                         goto bailout1;
    2863           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2864           0 :                                         msg = createException(MAL, name,
    2865             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2866           0 :                                         goto bailout1;
    2867             :                                 }
    2868             :                         }
    2869             :                 }
    2870             :         }
    2871           0 :   bailout1:
    2872         158 :         bat_iterator_end(&bi);
    2873         158 :   bailout:
    2874         158 :         GDKfree(buf);
    2875         158 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2876         158 :         unfix_inputs(2, b, bs);
    2877         158 :         return msg;
    2878             : }
    2879             : 
    2880             : static str
    2881         148 : STRbatprefixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2882             : {
    2883         148 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.prefix",
    2884             :                                                                  str_prefix);
    2885             : }
    2886             : 
    2887             : static str
    2888           1 : STRbatsuffixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2889             : {
    2890           1 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.suffix",
    2891             :                                                                  str_suffix);
    2892             : }
    2893             : 
    2894             : static str
    2895           5 : STRbatTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2896             : {
    2897           5 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    2898             : }
    2899             : 
    2900             : static str
    2901           4 : STRbatsubstringTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2902             : {
    2903           4 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.substring",
    2904             :                                                                  str_substring_tail);
    2905             : }
    2906             : 
    2907             : static str
    2908           1 : STRbatrepeatcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2909             : {
    2910           1 :         BATiter bi;
    2911           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2912           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2913           1 :         int y = *getArgReference_int(stk, pci, 2);
    2914           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2915           1 :         bool nils = false;
    2916           1 :         struct canditer ci1 = { 0 };
    2917           1 :         oid off1;
    2918           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2919           1 :                 *l = getArgReference_bat(stk, pci, 1),
    2920           1 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2921             : 
    2922           1 :         (void) cntxt;
    2923           1 :         (void) mb;
    2924           1 :         if (!buf) {
    2925           0 :                 msg = createException(MAL, "batstr.repeat",
    2926             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2927           0 :                 goto bailout;
    2928             :         }
    2929           1 :         if (!(b = BATdescriptor(*l))) {
    2930           0 :                 msg = createException(MAL, "batstr.repeat",
    2931             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2932           0 :                 goto bailout;
    2933             :         }
    2934           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2935           0 :                 msg = createException(MAL, "batstr.repeat",
    2936             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2937           0 :                 goto bailout;
    2938             :         }
    2939           1 :         canditer_init(&ci1, b, bs);
    2940           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2941           0 :                 msg = createException(MAL, "batstr.repeat",
    2942             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2943           0 :                 goto bailout;
    2944             :         }
    2945             : 
    2946           1 :         off1 = b->hseqbase;
    2947           1 :         bi = bat_iterator(b);
    2948           1 :         if (ci1.tpe == cand_dense) {
    2949           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2950           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2951           4 :                         const char *x = BUNtvar(bi, p1);
    2952             : 
    2953           8 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    2954           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2955           0 :                                         msg = createException(MAL, "batstr.repeat",
    2956             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2957           0 :                                         goto bailout1;
    2958             :                                 }
    2959             :                                 nils = true;
    2960             :                         } else {
    2961           4 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    2962           0 :                                         goto bailout1;
    2963           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2964           0 :                                         msg = createException(MAL, "batstr.repeat",
    2965             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2966           0 :                                         goto bailout1;
    2967             :                                 }
    2968             :                         }
    2969             :                 }
    2970             :         } else {
    2971           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2972           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2973           0 :                         const char *x = BUNtvar(bi, p1);
    2974             : 
    2975           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    2976           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2977           0 :                                         msg = createException(MAL, "batstr.repeat",
    2978             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2979           0 :                                         goto bailout1;
    2980             :                                 }
    2981             :                                 nils = true;
    2982             :                         } else {
    2983           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    2984           0 :                                         goto bailout1;
    2985           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2986           0 :                                         msg = createException(MAL, "batstr.repeat",
    2987             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2988           0 :                                         goto bailout1;
    2989             :                                 }
    2990             :                         }
    2991             :                 }
    2992             :         }
    2993           0 :   bailout1:
    2994           1 :         bat_iterator_end(&bi);
    2995           1 :   bailout:
    2996           1 :         GDKfree(buf);
    2997           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2998           1 :         unfix_inputs(2, b, bs);
    2999           1 :         return msg;
    3000             : }
    3001             : 
    3002             : static str
    3003           4 : do_batstr_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3004             :                                  const char *name,
    3005             :                                  str (*func)(str *, size_t *, const char *, int))
    3006             : {
    3007           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3008           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3009           4 :         int *restrict vals, y;
    3010           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    3011           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3012           4 :         bool nils = false;
    3013           4 :         struct canditer ci1 = { 0 };
    3014           4 :         oid off1;
    3015           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    3016           4 :                 *l = getArgReference_bat(stk, pci, 2),
    3017           4 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3018           4 :         BATiter bi;
    3019             : 
    3020           4 :         (void) cntxt;
    3021           4 :         (void) mb;
    3022           4 :         if (!buf) {
    3023           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3024           0 :                 goto bailout;
    3025             :         }
    3026           4 :         if (!(b = BATdescriptor(*l))) {
    3027           0 :                 msg = createException(MAL, name,
    3028             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3029           0 :                 goto bailout;
    3030             :         }
    3031           4 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3032           0 :                 msg = createException(MAL, name,
    3033             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3034           0 :                 goto bailout;
    3035             :         }
    3036           4 :         canditer_init(&ci1, b, bs);
    3037           4 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3038           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3039           0 :                 goto bailout;
    3040             :         }
    3041             : 
    3042           4 :         off1 = b->hseqbase;
    3043           4 :         bi = bat_iterator(b);
    3044           4 :         vals = bi.base;
    3045           4 :         if (ci1.tpe == cand_dense) {
    3046           9 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3047           5 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3048           5 :                         y = vals[p1];
    3049             : 
    3050          10 :                         if (strNil(x) || is_int_nil(y)) {
    3051           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3052           0 :                                         msg = createException(MAL, name,
    3053             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3054           0 :                                         goto bailout1;
    3055             :                                 }
    3056             :                                 nils = true;
    3057             :                         } else {
    3058           5 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3059           0 :                                         goto bailout1;
    3060           5 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3061           0 :                                         msg = createException(MAL, name,
    3062             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3063           0 :                                         goto bailout1;
    3064             :                                 }
    3065             :                         }
    3066             :                 }
    3067             :         } else {
    3068           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3069           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3070           0 :                         y = vals[p1];
    3071             : 
    3072           0 :                         if (strNil(x) || is_int_nil(y)) {
    3073           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3074           0 :                                         msg = createException(MAL, name,
    3075             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3076           0 :                                         goto bailout1;
    3077             :                                 }
    3078             :                                 nils = true;
    3079             :                         } else {
    3080           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3081           0 :                                         goto bailout1;
    3082           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3083           0 :                                         msg = createException(MAL, name,
    3084             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3085           0 :                                         goto bailout1;
    3086             :                                 }
    3087             :                         }
    3088             :                 }
    3089             :         }
    3090           0 :   bailout1:
    3091           4 :         bat_iterator_end(&bi);
    3092           4 :   bailout:
    3093           4 :         GDKfree(buf);
    3094           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3095           4 :         unfix_inputs(2, b, bs);
    3096           4 :         return msg;
    3097             : }
    3098             : 
    3099             : static str
    3100           4 : STRbatprefix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3101             : {
    3102           4 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.prefix", str_prefix);
    3103             : }
    3104             : 
    3105             : static str
    3106           0 : STRbatsuffix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3107             : {
    3108           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.suffix", str_suffix);
    3109             : }
    3110             : 
    3111             : static str
    3112           0 : STRbatTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3113             : {
    3114           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    3115             : }
    3116             : 
    3117             : static str
    3118           0 : STRbatsubstringTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3119             :                                                    InstrPtr pci)
    3120             : {
    3121           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.substring",
    3122             :                                                         str_substring_tail);
    3123             : }
    3124             : 
    3125             : static str
    3126           0 : STRbatrepeat_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3127             : {
    3128           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3129           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3130           0 :         int *restrict vals, y;
    3131           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    3132           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3133           0 :         bool nils = false;
    3134           0 :         struct canditer ci1 = { 0 };
    3135           0 :         oid off1;
    3136           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3137           0 :                 *l = getArgReference_bat(stk, pci, 2),
    3138           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3139           0 :         BATiter bi;
    3140             : 
    3141           0 :         (void) cntxt;
    3142           0 :         (void) mb;
    3143           0 :         if (!buf) {
    3144           0 :                 msg = createException(MAL, "batstr.repeat",
    3145             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3146           0 :                 goto bailout;
    3147             :         }
    3148           0 :         if (!(b = BATdescriptor(*l))) {
    3149           0 :                 msg = createException(MAL, "batstr.repeat",
    3150             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3151           0 :                 goto bailout;
    3152             :         }
    3153           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3154           0 :                 msg = createException(MAL, "batstr.repeat",
    3155             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3156           0 :                 goto bailout;
    3157             :         }
    3158           0 :         canditer_init(&ci1, b, bs);
    3159           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3160           0 :                 msg = createException(MAL, "batstr.repeat",
    3161             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3162           0 :                 goto bailout;
    3163             :         }
    3164             : 
    3165           0 :         off1 = b->hseqbase;
    3166           0 :         bi = bat_iterator(b);
    3167           0 :         vals = bi.base;
    3168           0 :         if (ci1.tpe == cand_dense) {
    3169           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3170           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3171           0 :                         y = vals[p1];
    3172             : 
    3173           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3174           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3175           0 :                                         msg = createException(MAL, "batstr.repeat",
    3176             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3177           0 :                                         goto bailout1;
    3178             :                                 }
    3179             :                                 nils = true;
    3180             :                         } else {
    3181           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3182           0 :                                         goto bailout1;
    3183           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3184           0 :                                         msg = createException(MAL, "batstr.repeat",
    3185             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3186           0 :                                         goto bailout1;
    3187             :                                 }
    3188             :                         }
    3189             :                 }
    3190             :         } else {
    3191           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3192           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3193           0 :                         y = vals[p1];
    3194             : 
    3195           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3196           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3197           0 :                                         msg = createException(MAL, "batstr.repeat",
    3198             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3199           0 :                                         goto bailout1;
    3200             :                                 }
    3201             :                                 nils = true;
    3202             :                         } else {
    3203           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3204           0 :                                         goto bailout1;
    3205           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3206           0 :                                         msg = createException(MAL, "batstr.repeat",
    3207             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3208           0 :                                         goto bailout1;
    3209             :                                 }
    3210             :                         }
    3211             :                 }
    3212             :         }
    3213           0 :   bailout1:
    3214           0 :         bat_iterator_end(&bi);
    3215           0 :   bailout:
    3216           0 :         GDKfree(buf);
    3217           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3218           0 :         unfix_inputs(2, b, bs);
    3219           0 :         return msg;
    3220             : }
    3221             : 
    3222             : static str
    3223          32 : do_batstr_str_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3224             :                                   const char *name, str (*func)(str *, size_t *, const char *,
    3225             :                                                                                                 int))
    3226             : {
    3227          32 :         BATiter lefti;
    3228          32 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    3229          32 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3230          32 :         int *restrict righti, y;
    3231          32 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3232          32 :         bool nils = false;
    3233          32 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3234          32 :         oid off1, off2;
    3235          32 :         bat *res = getArgReference_bat(stk, pci, 0),
    3236          32 :                 *l = getArgReference_bat(stk, pci, 1),
    3237          32 :                 *r = getArgReference_bat(stk, pci, 2),
    3238          32 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    3239          32 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3240          32 :         BATiter bi;
    3241             : 
    3242          32 :         (void) cntxt;
    3243          32 :         (void) mb;
    3244          32 :         if (!buf) {
    3245           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3246           0 :                 goto bailout;
    3247             :         }
    3248          32 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    3249           0 :                 msg = createException(MAL, name,
    3250             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3251           0 :                 goto bailout;
    3252             :         }
    3253          32 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    3254          32 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    3255           0 :                 msg = createException(MAL, name,
    3256             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3257           0 :                 goto bailout;
    3258             :         }
    3259          32 :         canditer_init(&ci1, left, lefts);
    3260          32 :         canditer_init(&ci2, right, rights);
    3261          32 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3262           0 :                 msg = createException(MAL, name,
    3263             :                                                           ILLEGAL_ARGUMENT
    3264             :                                                           " Requires bats of identical size");
    3265           0 :                 goto bailout;
    3266             :         }
    3267          32 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3268           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3269           0 :                 goto bailout;
    3270             :         }
    3271             : 
    3272          32 :         off1 = left->hseqbase;
    3273          32 :         off2 = right->hseqbase;
    3274          32 :         lefti = bat_iterator(left);
    3275          32 :         bi = bat_iterator(right);
    3276          32 :         righti = bi.base;
    3277          32 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3278       31419 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3279       31387 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3280       31387 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3281       31387 :                         const char *x = BUNtvar(lefti, p1);
    3282       31387 :                         y = righti[p2];
    3283             : 
    3284       35621 :                         if (strNil(x) || is_int_nil(y)) {
    3285       27153 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3286           0 :                                         msg = createException(MAL, name,
    3287             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3288           0 :                                         goto bailout1;
    3289             :                                 }
    3290             :                                 nils = true;
    3291             :                         } else {
    3292        4234 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3293           0 :                                         goto bailout1;
    3294        4234 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3295           0 :                                         msg = createException(MAL, name,
    3296             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3297           0 :                                         goto bailout1;
    3298             :                                 }
    3299             :                         }
    3300             :                 }
    3301             :         } else {
    3302           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3303           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3304           0 :                                 p2 = (canditer_next(&ci2) - off2);
    3305           0 :                         const char *x = BUNtvar(lefti, p1);
    3306           0 :                         y = righti[p2];
    3307             : 
    3308           0 :                         if (strNil(x) || is_int_nil(y)) {
    3309           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3310           0 :                                         msg = createException(MAL, name,
    3311             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3312           0 :                                         goto bailout1;
    3313             :                                 }
    3314             :                                 nils = true;
    3315             :                         } else {
    3316           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3317           0 :                                         goto bailout1;
    3318           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3319           0 :                                         msg = createException(MAL, name,
    3320             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3321           0 :                                         goto bailout1;
    3322             :                                 }
    3323             :                         }
    3324             :                 }
    3325             :         }
    3326           0 :   bailout1:
    3327          32 :         bat_iterator_end(&bi);
    3328          32 :         bat_iterator_end(&lefti);
    3329          32 :   bailout:
    3330          32 :         GDKfree(buf);
    3331          32 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3332          32 :         unfix_inputs(4, left, lefts, right, rights);
    3333          32 :         return msg;
    3334             : }
    3335             : 
    3336             : static str
    3337           0 : STRbatprefix(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3338             : {
    3339           0 :         return do_batstr_str_int(cntxt, mb, stk, pci, "batstr.prefix", str_prefix);
    3340             : }
    3341             : 
    3342             : static str
    3343           0 : STRbatsuffix(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3344             : {
    3345           0 :         return do_batstr_str_int(cntxt, mb, stk, pci, "batstr.suffix", str_suffix);
    3346             : }
    3347             : 
    3348             : static str
    3349           0 : STRbatTail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3350             : {
    3351           0 :         return do_batstr_str_int(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    3352             : }
    3353             : 
    3354             : static str
    3355          32 : STRbatsubstringTail(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3356             : {
    3357          32 :         return do_batstr_str_int(cntxt, mb, stk, pci, "batstr.substring",
    3358             :                                                          str_substring_tail);
    3359             : }
    3360             : 
    3361             : static str
    3362           0 : STRbatrepeat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3363             : {
    3364           0 :         BATiter lefti;
    3365           0 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    3366           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3367           0 :         int *restrict righti, y;
    3368           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3369           0 :         bool nils = false;
    3370           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3371           0 :         oid off1, off2;
    3372           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3373           0 :                 *l = getArgReference_bat(stk, pci, 1),
    3374           0 :                 *r = getArgReference_bat(stk, pci, 2),
    3375           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    3376           0 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3377           0 :         BATiter bi;
    3378             : 
    3379           0 :         (void) cntxt;
    3380           0 :         (void) mb;
    3381           0 :         if (!buf) {
    3382           0 :                 msg = createException(MAL, "batstr.repeat",
    3383             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3384           0 :                 goto bailout;
    3385             :         }
    3386           0 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    3387           0 :                 msg = createException(MAL, "batstr.repeat",
    3388             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3389           0 :                 goto bailout;
    3390             :         }
    3391           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    3392           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    3393           0 :                 msg = createException(MAL, "batstr.repeat",
    3394             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3395           0 :                 goto bailout;
    3396             :         }
    3397           0 :         canditer_init(&ci1, left, lefts);
    3398           0 :         canditer_init(&ci2, right, rights);
    3399           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3400           0 :                 msg = createException(MAL, "batstr.repeat",
    3401             :                                                           ILLEGAL_ARGUMENT
    3402             :                                                           " Requires bats of identical size");
    3403           0 :                 goto bailout;
    3404             :         }
    3405           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3406           0 :                 msg = createException(MAL, "batstr.repeat",
    3407             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3408           0 :                 goto bailout;
    3409             :         }
    3410             : 
    3411           0 :         off1 = left->hseqbase;
    3412           0 :         off2 = right->hseqbase;
    3413           0 :         lefti = bat_iterator(left);
    3414           0 :         bi = bat_iterator(right);
    3415           0 :         righti = bi.base;
    3416           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3417           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3418           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3419           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3420           0 :                         const char *x = BUNtvar(lefti, p1);
    3421           0 :                         y = righti[p2];
    3422             : 
    3423           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3424           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3425           0 :                                         msg = createException(MAL, "batstr.repeat",
    3426             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3427           0 :                                         goto bailout1;
    3428             :                                 }
    3429             :                                 nils = true;
    3430             :                         } else {
    3431           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3432           0 :                                         goto bailout1;
    3433           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3434           0 :                                         msg = createException(MAL, "batstr.repeat",
    3435             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3436           0 :                                         goto bailout1;
    3437             :                                 }
    3438             :                         }
    3439             :                 }
    3440             :         } else {
    3441           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3442           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3443           0 :                                 p2 = (canditer_next(&ci2) - off2);
    3444           0 :                         const char *x = BUNtvar(lefti, p1);
    3445           0 :                         y = righti[p2];
    3446             : 
    3447           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3448           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3449           0 :                                         msg = createException(MAL, "batstr.repeat",
    3450             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3451           0 :                                         goto bailout1;
    3452             :                                 }
    3453             :                                 nils = true;
    3454             :                         } else {
    3455           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3456           0 :                                         goto bailout1;
    3457           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3458           0 :                                         msg = createException(MAL, "batstr.repeat",
    3459             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3460           0 :                                         goto bailout1;
    3461             :                                 }
    3462             :                         }
    3463             :                 }
    3464             :         }
    3465           0 :   bailout1:
    3466           0 :         bat_iterator_end(&bi);
    3467           0 :         bat_iterator_end(&lefti);
    3468           0 :   bailout:
    3469           0 :         GDKfree(buf);
    3470           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3471           0 :         unfix_inputs(4, left, lefts, right, rights);
    3472           0 :         return msg;
    3473             : }
    3474             : 
    3475             : static str
    3476         426 : STRbatSubstitutecst_imp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3477             :                                                 int cand_nargs, const bit *rep)
    3478             : {
    3479         426 :         BATiter bi;
    3480         426 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3481         426 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3482         426 :         const char *y = *getArgReference_str(stk, pci, 2),
    3483         426 :                 *z = *getArgReference_str(stk, pci, 3);
    3484         426 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3485         426 :         bool nils = false;
    3486         426 :         bit w = *rep;
    3487         426 :         struct canditer ci1 = { 0 };
    3488         426 :         oid off1;
    3489         426 :         bat *res = getArgReference_bat(stk, pci, 0),
    3490         426 :                 *bid = getArgReference_bat(stk, pci, 1),
    3491         426 :                 *sid1 = pci->argc == cand_nargs ? getArgReference_bat(stk, pci, cand_nargs - 1) : NULL;
    3492             : 
    3493         426 :         if (!buf) {
    3494           0 :                 msg = createException(MAL, "batstr.substritute",
    3495             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3496           0 :                 goto bailout;
    3497             :         }
    3498         426 :         if (!(b = BATdescriptor(*bid))) {
    3499           0 :                 msg = createException(MAL, "batstr.substritute",
    3500             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3501           0 :                 goto bailout;
    3502             :         }
    3503         426 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3504           0 :                 msg = createException(MAL, "batstr.splitpart",
    3505             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3506           0 :                 goto bailout;
    3507             :         }
    3508         426 :         canditer_init(&ci1, b, bs);
    3509         426 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3510           0 :                 msg = createException(MAL, "batstr.substritute",
    3511             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3512           0 :                 goto bailout;
    3513             :         }
    3514             : 
    3515         426 :         (void) cntxt;
    3516         426 :         (void) mb;
    3517         426 :         off1 = b->hseqbase;
    3518         426 :         bi = bat_iterator(b);
    3519         426 :         if (ci1.tpe == cand_dense) {
    3520      101277 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3521      100851 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3522      100851 :                         const char *x = BUNtvar(bi, p1);
    3523             : 
    3524      401766 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3525         470 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3526           0 :                                         msg = createException(MAL, "batstr.substritute",
    3527             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3528           0 :                                         goto bailout1;
    3529             :                                 }
    3530             :                                 nils = true;
    3531             :                         } else {
    3532      100324 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3533           0 :                                         goto bailout1;
    3534      100301 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3535           0 :                                         msg = createException(MAL, "batstr.substritute",
    3536             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3537           0 :                                         goto bailout1;
    3538             :                                 }
    3539             :                         }
    3540             :                 }
    3541             :         } else {
    3542           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3543           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3544           0 :                         const char *x = BUNtvar(bi, p1);
    3545             : 
    3546           0 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3547           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3548           0 :                                         msg = createException(MAL, "batstr.substritute",
    3549             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3550           0 :                                         goto bailout1;
    3551             :                                 }
    3552             :                                 nils = true;
    3553             :                         } else {
    3554           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3555           0 :                                         goto bailout1;
    3556           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3557           0 :                                         msg = createException(MAL, "batstr.substritute",
    3558             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3559           0 :                                         goto bailout1;
    3560             :                                 }
    3561             :                         }
    3562             :                 }
    3563             :         }
    3564           0 :   bailout1:
    3565         426 :         bat_iterator_end(&bi);
    3566         426 :   bailout:
    3567         426 :         GDKfree(buf);
    3568         426 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3569         426 :         unfix_inputs(2, b, bs);
    3570         426 :         return msg;
    3571             : }
    3572             : 
    3573             : static str
    3574           0 : STRbatSubstitutecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3575             : {
    3576           0 :         const bit *rep = getArgReference_bit(stk, pci, 4);
    3577           0 :         return STRbatSubstitutecst_imp(cntxt, mb, stk, pci, 6, rep);
    3578             : }
    3579             : 
    3580             : static str
    3581           0 : STRbatSubstitute(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3582             : {
    3583           0 :         BATiter arg1i, arg2i, arg3i;
    3584           0 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL, *arg2s = NULL,
    3585           0 :                 *arg3 = NULL, *arg3s = NULL, *arg4 = NULL, *arg4s = NULL;
    3586           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3587           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3588           0 :         bool nils = false;
    3589           0 :         bit *restrict arg4i, w;
    3590           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 }, ci4 = { 0 };
    3591           0 :         oid off1, off2, off3, off4;
    3592           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3593           0 :                 *l = getArgReference_bat(stk, pci, 1),
    3594           0 :                 *r = getArgReference_bat(stk, pci, 2),
    3595           0 :                 *s = getArgReference_bat(stk, pci, 3),
    3596           0 :                 *rep = getArgReference_bat(stk, pci, 4),
    3597           0 :                 *sid1 = pci->argc == 9 ? getArgReference_bat(stk, pci, 5) : NULL,
    3598           0 :                 *sid2 = pci->argc == 9 ? getArgReference_bat(stk, pci, 6) : NULL,
    3599           0 :                 *sid3 = pci->argc == 9 ? getArgReference_bat(stk, pci, 7) : NULL,
    3600           0 :                 *sid4 = pci->argc == 9 ? getArgReference_bat(stk, pci, 8) : NULL;
    3601           0 :         BATiter bi;
    3602             : 
    3603           0 :         if (!buf) {
    3604           0 :                 msg = createException(MAL, "batstr.substritute",
    3605             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3606           0 :                 goto bailout;
    3607             :         }
    3608           0 :         if (!(arg1 = BATdescriptor(*l)) || !(arg2 = BATdescriptor(*r))
    3609           0 :                 || !(arg3 = BATdescriptor(*s)) || !(arg4 = BATdescriptor(*rep))) {
    3610           0 :                 msg = createException(MAL, "batstr.substritute",
    3611             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3612           0 :                 goto bailout;
    3613             :         }
    3614           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1)))
    3615           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2)))
    3616           0 :                 || (sid3 && !is_bat_nil(*sid3) && !(arg2s = BATdescriptor(*sid3)))
    3617           0 :                 || (sid4 && !is_bat_nil(*sid4) && !(arg4s = BATdescriptor(*sid4)))) {
    3618           0 :                 msg = createException(MAL, "batstr.substritute",
    3619             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3620           0 :                 goto bailout;
    3621             :         }
    3622           0 :         canditer_init(&ci1, arg1, arg1s);
    3623           0 :         canditer_init(&ci2, arg2, arg2s);
    3624           0 :         canditer_init(&ci3, arg3, arg3s);
    3625           0 :         canditer_init(&ci4, arg4, arg4s);
    3626           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    3627           0 :                 || ci2.hseq != ci3.hseq || ci4.ncand != ci1.ncand
    3628           0 :                 || ci3.hseq != ci4.hseq) {
    3629           0 :                 msg = createException(MAL, "batstr.substritute",
    3630             :                                                           ILLEGAL_ARGUMENT
    3631             :                                                           " Requires bats of identical size");
    3632           0 :                 goto bailout;
    3633             :         }
    3634           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3635           0 :                 msg = createException(MAL, "batstr.substritute",
    3636             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3637           0 :                 goto bailout;
    3638             :         }
    3639             : 
    3640           0 :         (void) cntxt;
    3641           0 :         (void) mb;
    3642           0 :         off1 = arg1->hseqbase;
    3643           0 :         off2 = arg2->hseqbase;
    3644           0 :         off3 = arg3->hseqbase;
    3645           0 :         off4 = arg4->hseqbase;
    3646           0 :         arg1i = bat_iterator(arg1);
    3647           0 :         arg2i = bat_iterator(arg2);
    3648           0 :         arg3i = bat_iterator(arg3);
    3649           0 :         bi = bat_iterator(arg4);
    3650           0 :         arg4i = bi.base;
    3651           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense
    3652           0 :                 && ci4.tpe == cand_dense) {
    3653           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3654           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3655           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    3656           0 :                                 p3 = (canditer_next_dense(&ci3) - off3),
    3657           0 :                                 p4 = (canditer_next_dense(&ci4) - off4);
    3658           0 :                         const char *x = BUNtvar(arg1i, p1);
    3659           0 :                         const char *y = BUNtvar(arg2i, p2);
    3660           0 :                         const char *z = BUNtvar(arg3i, p3);
    3661           0 :                         w = arg4i[p4];
    3662             : 
    3663           0 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3664           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3665           0 :                                         msg = createException(MAL, "batstr.substritute",
    3666             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3667           0 :                                         goto bailout1;
    3668             :                                 }
    3669             :                                 nils = true;
    3670             :                         } else {
    3671           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3672           0 :                                         goto bailout1;
    3673           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3674           0 :                                         msg = createException(MAL, "batstr.substritute",
    3675             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3676           0 :                                         goto bailout1;
    3677             :                                 }
    3678             :                         }
    3679             :                 }
    3680             :         } else {
    3681           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3682           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3683           0 :                                 p2 = (canditer_next(&ci2) - off2),
    3684           0 :                                 p3 = (canditer_next(&ci3) - off3),
    3685           0 :                                 p4 = (canditer_next(&ci4) - off4);
    3686           0 :                         const char *x = BUNtvar(arg1i, p1);
    3687           0 :                         const char *y = BUNtvar(arg2i, p2);
    3688           0 :                         const char *z = BUNtvar(arg3i, p3);
    3689           0 :                         w = arg4i[p4];
    3690             : 
    3691           0 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3692           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3693           0 :                                         msg = createException(MAL, "batstr.substritute",
    3694             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3695           0 :                                         goto bailout1;
    3696             :                                 }
    3697             :                                 nils = true;
    3698             :                         } else {
    3699           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3700           0 :                                         goto bailout1;
    3701           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3702           0 :                                         msg = createException(MAL, "batstr.substritute",
    3703             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3704           0 :                                         goto bailout1;
    3705             :                                 }
    3706             :                         }
    3707             :                 }
    3708             :         }
    3709           0 :   bailout1:
    3710           0 :         bat_iterator_end(&bi);
    3711           0 :         bat_iterator_end(&arg1i);
    3712           0 :         bat_iterator_end(&arg2i);
    3713           0 :         bat_iterator_end(&arg3i);
    3714           0 :   bailout:
    3715           0 :         GDKfree(buf);
    3716           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3717           0 :         unfix_inputs(8, arg1, arg1, arg2, arg2s, arg3, arg3s, arg4, arg4s);
    3718           0 :         return msg;
    3719             : }
    3720             : 
    3721             : static str
    3722           2 : STRbatsplitpartcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3723             : {
    3724           2 :         BATiter bi;
    3725           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3726           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3727           2 :         int z = *getArgReference_int(stk, pci, 3);
    3728           2 :         const char *y = *getArgReference_str(stk, pci, 2);
    3729           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3730           2 :         bool nils = false;
    3731           2 :         struct canditer ci1 = { 0 };
    3732           2 :         oid off1;
    3733           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    3734           2 :                 *bid = getArgReference_bat(stk, pci, 1),
    3735           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3736             : 
    3737           2 :         (void) cntxt;
    3738           2 :         (void) mb;
    3739           2 :         if (!buf) {
    3740           0 :                 msg = createException(MAL, "batstr.splitpart",
    3741             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3742           0 :                 goto bailout;
    3743             :         }
    3744           2 :         if (!(b = BATdescriptor(*bid))) {
    3745           0 :                 msg = createException(MAL, "batstr.splitpart",
    3746             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3747           0 :                 goto bailout;
    3748             :         }
    3749           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3750           0 :                 msg = createException(MAL, "batstr.splitpart",
    3751             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3752           0 :                 goto bailout;
    3753             :         }
    3754           2 :         canditer_init(&ci1, b, bs);
    3755           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3756           0 :                 msg = createException(MAL, "batstr.splitpart",
    3757             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3758           0 :                 goto bailout;
    3759             :         }
    3760             : 
    3761           2 :         off1 = b->hseqbase;
    3762           2 :         bi = bat_iterator(b);
    3763           2 :         if (ci1.tpe == cand_dense) {
    3764          16 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3765          14 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3766          14 :                         const char *x = BUNtvar(bi, p1);
    3767             : 
    3768          42 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3769           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3770           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3771             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3772           0 :                                         goto bailout1;
    3773             :                                 }
    3774             :                                 nils = true;
    3775             :                         } else {
    3776          14 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3777           0 :                                         goto bailout1;
    3778          14 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3779           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3780             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3781           0 :                                         goto bailout1;
    3782             :                                 }
    3783             :                         }
    3784             :                 }
    3785             :         } else {
    3786           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3787           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3788           0 :                         const char *x = BUNtvar(bi, p1);
    3789             : 
    3790           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3791           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3792           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3793             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3794           0 :                                         goto bailout1;
    3795             :                                 }
    3796             :                                 nils = true;
    3797             :                         } else {
    3798           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3799           0 :                                         goto bailout1;
    3800           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3801           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3802             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3803           0 :                                         goto bailout1;
    3804             :                                 }
    3805             :                         }
    3806             :                 }
    3807             :         }
    3808           0 :   bailout1:
    3809           2 :         bat_iterator_end(&bi);
    3810           2 :   bailout:
    3811           2 :         GDKfree(buf);
    3812           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3813           2 :         unfix_inputs(2, b, bs);
    3814           2 :         return msg;
    3815             : }
    3816             : 
    3817             : static str
    3818           0 : STRbatsplitpart_needlecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3819             :                                                   InstrPtr pci)
    3820             : {
    3821           0 :         BATiter bi, fi;
    3822           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *f = NULL, *fs = NULL;
    3823           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3824           0 :         int *restrict field, z;
    3825           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    3826           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3827           0 :         bool nils = false;
    3828           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3829           0 :         oid off1, off2;
    3830           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3831           0 :                 *bid = getArgReference_bat(stk, pci, 1),
    3832           0 :                 *fid = getArgReference_bat(stk, pci, 3),
    3833           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    3834           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    3835             : 
    3836           0 :         if (!buf) {
    3837           0 :                 msg = createException(MAL, "batstr.splitpart",
    3838             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3839           0 :                 goto bailout;
    3840             :         }
    3841           0 :         if (!(b = BATdescriptor(*bid)) || !(f = BATdescriptor(*fid))) {
    3842           0 :                 msg = createException(MAL, "batstr.splitpart",
    3843             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3844           0 :                 goto bailout;
    3845             :         }
    3846           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    3847           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(fs = BATdescriptor(*sid2)))) {
    3848           0 :                 msg = createException(MAL, "batstr.splitpart",
    3849             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3850           0 :                 goto bailout;
    3851             :         }
    3852           0 :         canditer_init(&ci1, b, bs);
    3853           0 :         canditer_init(&ci2, f, fs);
    3854           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3855           0 :                 msg = createException(MAL, "batstr.splitpart",
    3856             :                                                           ILLEGAL_ARGUMENT
    3857             :                                                           " Requires bats of identical size");
    3858           0 :                 goto bailout;
    3859             :         }
    3860           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3861           0 :                 msg = createException(MAL, "batstr.splitpart",
    3862             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3863           0 :                 goto bailout;
    3864             :         }
    3865             : 
    3866           0 :         (void) cntxt;
    3867           0 :         (void) mb;
    3868           0 :         off1 = b->hseqbase;
    3869           0 :         off2 = f->hseqbase;
    3870           0 :         bi = bat_iterator(b);
    3871           0 :         fi = bat_iterator(f);
    3872           0 :         field = fi.base;
    3873           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3874           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3875           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3876           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3877           0 :                         const char *x = BUNtvar(bi, p1);
    3878           0 :                         z = field[p2];
    3879             : 
    3880           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3881           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3882           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3883             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3884           0 :                                         goto bailout1;
    3885             :                                 }
    3886             :                                 nils = true;
    3887             :                         } else {
    3888           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3889           0 :                                         goto bailout1;
    3890           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3891           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3892             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3893           0 :                                         goto bailout1;
    3894             :                                 }
    3895             :                         }
    3896             :                 }
    3897             :         } else {
    3898           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3899           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3900           0 :                                 p2 = (canditer_next(&ci2) - off2);
    3901           0 :                         const char *x = BUNtvar(bi, p1);
    3902           0 :                         z = field[p2];
    3903             : 
    3904           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3905           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3906           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3907             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3908           0 :                                         goto bailout1;
    3909             :                                 }
    3910             :                                 nils = true;
    3911             :                         } else {
    3912           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3913           0 :                                         goto bailout1;
    3914           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3915           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3916             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3917           0 :                                         goto bailout1;
    3918             :                                 }
    3919             :                         }
    3920             :                 }
    3921             :         }
    3922           0 :   bailout1:
    3923           0 :         bat_iterator_end(&fi);
    3924           0 :         bat_iterator_end(&bi);
    3925           0 :   bailout:
    3926           0 :         GDKfree(buf);
    3927           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3928           0 :         unfix_inputs(4, b, bs, f, fs);
    3929           0 :         return msg;
    3930             : }
    3931             : 
    3932             : static str
    3933           0 : STRbatsplitpart_fieldcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3934             :                                                  InstrPtr pci)
    3935             : {
    3936           0 :         BATiter bi, ni;
    3937           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *n = NULL, *ns = NULL;
    3938           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3939           0 :         int z = *getArgReference_int(stk, pci, 3);
    3940           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3941           0 :         bool nils = false;
    3942           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3943           0 :         oid off1, off2;
    3944           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3945           0 :                 *bid = getArgReference_bat(stk, pci, 1),
    3946           0 :                 *nid = getArgReference_bat(stk, pci, 2),
    3947           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    3948           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    3949             : 
    3950           0 :         (void) cntxt;
    3951           0 :         (void) mb;
    3952           0 :         if (!buf) {
    3953           0 :                 msg = createException(MAL, "batstr.splitpart",
    3954             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3955           0 :                 goto bailout;
    3956             :         }
    3957           0 :         if (!(b = BATdescriptor(*bid)) || !(n = BATdescriptor(*nid))) {
    3958           0 :                 msg = createException(MAL, "batstr.splitpart",
    3959             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3960           0 :                 goto bailout;
    3961             :         }
    3962           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    3963           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(ns = BATdescriptor(*sid2)))) {
    3964           0 :                 msg = createException(MAL, "batstr.splitpart",
    3965             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3966           0 :                 goto bailout;
    3967             :         }
    3968           0 :         canditer_init(&ci1, b, bs);
    3969           0 :         canditer_init(&ci2, n, ns);
    3970           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3971           0 :                 msg = createException(MAL, "batstr.splitpart",
    3972             :                                                           ILLEGAL_ARGUMENT
    3973             :                                                           " Requires bats of identical size");
    3974           0 :                 goto bailout;
    3975             :         }
    3976           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3977           0 :                 msg = createException(MAL, "batstr.splitpart",
    3978             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3979           0 :                 goto bailout;
    3980             :         }
    3981             : 
    3982           0 :         off1 = b->hseqbase;
    3983           0 :         off2 = n->hseqbase;
    3984           0 :         bi = bat_iterator(b);
    3985           0 :         ni = bat_iterator(n);
    3986           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3987           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3988           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3989           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3990           0 :                         const char *x = BUNtvar(bi, p1);
    3991           0 :                         const char *y = BUNtvar(ni, p2);
    3992             : 
    3993           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3994           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3995           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3996             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3997           0 :                                         goto bailout1;
    3998             :                                 }
    3999             :                                 nils = true;
    4000             :                         } else {
    4001           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4002           0 :                                         goto bailout1;
    4003           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4004           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4005             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4006           0 :                                         goto bailout1;
    4007             :                                 }
    4008             :                         }
    4009             :                 }
    4010             :         } else {
    4011           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4012           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4013           0 :                                 p2 = (canditer_next(&ci2) - off2);
    4014           0 :                         const char *x = BUNtvar(bi, p1);
    4015           0 :                         const char *y = BUNtvar(ni, p2);
    4016             : 
    4017           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4018           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4019           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4020             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4021           0 :                                         goto bailout1;
    4022             :                                 }
    4023             :                                 nils = true;
    4024             :                         } else {
    4025           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4026           0 :                                         goto bailout1;
    4027           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4028           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4029             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4030           0 :                                         goto bailout1;
    4031             :                                 }
    4032             :                         }
    4033             :                 }
    4034             :         }
    4035           0 :   bailout1:
    4036           0 :         bat_iterator_end(&bi);
    4037           0 :         bat_iterator_end(&ni);
    4038           0 :   bailout:
    4039           0 :         GDKfree(buf);
    4040           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4041           0 :         unfix_inputs(4, b, bs, n, ns);
    4042           0 :         return msg;
    4043             : }
    4044             : 
    4045             : static str
    4046           0 : STRbatsplitpart(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4047             : {
    4048           0 :         BATiter arg1i, arg2i;
    4049           0 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL,
    4050           0 :                 *arg2s = NULL, *arg3 = NULL, *arg3s = NULL;
    4051           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4052           0 :         int *restrict arg3i, z;
    4053           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4054           0 :         bool nils = false;
    4055           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    4056           0 :         oid off1, off2, off3;
    4057           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    4058           0 :                 *l = getArgReference_bat(stk, pci, 1),
    4059           0 :                 *r = getArgReference_bat(stk, pci, 2),
    4060           0 :                 *t = getArgReference_bat(stk, pci, 3),
    4061           0 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    4062           0 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    4063           0 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    4064           0 :         BATiter bi;
    4065             : 
    4066           0 :         (void) cntxt;
    4067           0 :         (void) mb;
    4068           0 :         if (!buf) {
    4069           0 :                 msg = createException(MAL, "batstr.splitpart",
    4070             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4071           0 :                 goto bailout;
    4072             :         }
    4073           0 :         if (!(arg1 = BATdescriptor(*l)) || !(arg2 = BATdescriptor(*r))
    4074           0 :                 || !(arg3 = BATdescriptor(*t))) {
    4075           0 :                 msg = createException(MAL, "batstr.splitpart",
    4076             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4077           0 :                 goto bailout;
    4078             :         }
    4079           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1))) ||
    4080           0 :                 (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2))) ||
    4081           0 :                 (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3))))
    4082             :         {
    4083           0 :                 msg = createException(MAL, "batstr.splitpart",
    4084             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4085           0 :                 goto bailout;
    4086             :         }
    4087           0 :         canditer_init(&ci1, arg1, arg1s);
    4088           0 :         canditer_init(&ci2, arg2, arg2s);
    4089           0 :         canditer_init(&ci3, arg3, arg3s);
    4090           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    4091           0 :                 || ci2.hseq != ci3.hseq) {
    4092           0 :                 msg = createException(MAL, "batstr.splitpart",
    4093             :                                                           ILLEGAL_ARGUMENT
    4094             :                                                           " Requires bats of identical size");
    4095           0 :                 goto bailout;
    4096             :         }
    4097           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4098           0 :                 msg = createException(MAL, "batstr.splitpart",
    4099             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4100           0 :                 goto bailout;
    4101             :         }
    4102             : 
    4103           0 :         off1 = arg1->hseqbase;
    4104           0 :         off2 = arg2->hseqbase;
    4105           0 :         off3 = arg3->hseqbase;
    4106           0 :         arg1i = bat_iterator(arg1);
    4107           0 :         arg2i = bat_iterator(arg2);
    4108           0 :         bi = bat_iterator(arg3);
    4109           0 :         arg3i = bi.base;
    4110           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    4111           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4112           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4113           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    4114           0 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    4115           0 :                         const char *x = BUNtvar(arg1i, p1);
    4116           0 :                         const char *y = BUNtvar(arg2i, p2);
    4117           0 :                         z = arg3i[p3];
    4118             : 
    4119           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4120           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4121           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4122             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4123           0 :                                         goto bailout1;
    4124             :                                 }
    4125             :                                 nils = true;
    4126             :                         } else {
    4127           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4128           0 :                                         goto bailout1;
    4129           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4130           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4131             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4132           0 :                                         goto bailout1;
    4133             :                                 }
    4134             :                         }
    4135             :                 }
    4136             :         } else {
    4137           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4138           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4139           0 :                                 p2 = (canditer_next(&ci2) - off2),
    4140           0 :                                 p3 = (canditer_next(&ci3) - off3);
    4141           0 :                         const char *x = BUNtvar(arg1i, p1);
    4142           0 :                         const char *y = BUNtvar(arg2i, p2);
    4143           0 :                         z = arg3i[p3];
    4144             : 
    4145           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4146           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4147           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4148             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4149           0 :                                         goto bailout1;
    4150             :                                 }
    4151             :                                 nils = true;
    4152             :                         } else {
    4153           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4154           0 :                                         goto bailout1;
    4155           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4156           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4157             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4158           0 :                                         goto bailout1;
    4159             :                                 }
    4160             :                         }
    4161             :                 }
    4162             :         }
    4163           0 :   bailout1:
    4164           0 :         bat_iterator_end(&bi);
    4165           0 :         bat_iterator_end(&arg1i);
    4166           0 :         bat_iterator_end(&arg2i);
    4167           0 :   bailout:
    4168           0 :         GDKfree(buf);
    4169           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4170           0 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    4171           0 :         return msg;
    4172             : }
    4173             : 
    4174             : static str
    4175         426 : STRbatReplacecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4176             : {
    4177         426 :         bit rep = TRUE;
    4178             : 
    4179         426 :         return STRbatSubstitutecst_imp(cntxt, mb, stk, pci, 5, &rep);
    4180             : }
    4181             : 
    4182             : static str
    4183           2 : STRbatReplace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4184             : {
    4185           2 :         BATiter arg1i, arg2i, arg3i;
    4186           2 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL,
    4187           2 :                 *arg2s = NULL, *arg3 = NULL, *arg3s = NULL;
    4188           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4189           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4190           2 :         bool nils = false;
    4191           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    4192           2 :         oid off1, off2, off3;
    4193           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    4194           2 :                 *l = getArgReference_bat(stk, pci, 1),
    4195           2 :                 *s = getArgReference_bat(stk, pci, 2),
    4196           2 :                 *s2 = getArgReference_bat(stk, pci, 3),
    4197           2 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    4198           2 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    4199           2 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    4200             : 
    4201           2 :         (void) cntxt;
    4202           2 :         (void) mb;
    4203           2 :         if (!buf) {
    4204           0 :                 msg = createException(MAL, "batstr.replace",
    4205             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4206           0 :                 goto bailout;
    4207             :         }
    4208           2 :         if (!(arg1 = BATdescriptor(*l)) || !(arg2 = BATdescriptor(*s))
    4209           2 :                 || !(arg3 = BATdescriptor(*s2))) {
    4210           0 :                 msg = createException(MAL, "batstr.replace",
    4211             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4212           0 :                 goto bailout;
    4213             :         }
    4214           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1))) ||
    4215           2 :                 (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2))) ||
    4216           0 :                 (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3))))
    4217             :         {
    4218           0 :                 msg = createException(MAL, "batstr.replace",
    4219             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4220           0 :                 goto bailout;
    4221             :         }
    4222           2 :         canditer_init(&ci1, arg1, arg1s);
    4223           2 :         canditer_init(&ci2, arg2, arg2s);
    4224           2 :         canditer_init(&ci3, arg3, arg3s);
    4225           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    4226           2 :                 || ci2.hseq != ci3.hseq) {
    4227           0 :                 msg = createException(MAL, "batstr.replace",
    4228             :                                                           ILLEGAL_ARGUMENT
    4229             :                                                           " Requires bats of identical size");
    4230           0 :                 goto bailout;
    4231             :         }
    4232           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4233           0 :                 msg = createException(MAL, "batstr.replace",
    4234             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4235           0 :                 goto bailout;
    4236             :         }
    4237             : 
    4238           2 :         off1 = arg1->hseqbase;
    4239           2 :         off2 = arg2->hseqbase;
    4240           2 :         off3 = arg3->hseqbase;
    4241           2 :         arg1i = bat_iterator(arg1);
    4242           2 :         arg2i = bat_iterator(arg2);
    4243           2 :         arg3i = bat_iterator(arg3);
    4244           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    4245           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4246           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4247           4 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    4248           4 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    4249           4 :                         const char *x = BUNtvar(arg1i, p1);
    4250           4 :                         const char *y = BUNtvar(arg2i, p2);
    4251           4 :                         const char *z = BUNtvar(arg3i, p3);
    4252             : 
    4253          12 :                         if (strNil(x) || strNil(y) || strNil(z)) {
    4254           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4255           0 :                                         msg = createException(MAL, "batstr.replace",
    4256             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4257           0 :                                         goto bailout1;
    4258             :                                 }
    4259             :                                 nils = true;
    4260             :                         } else {
    4261           4 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, TRUE)) != MAL_SUCCEED)
    4262           0 :                                         goto bailout1;
    4263           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4264           0 :                                         msg = createException(MAL, "batstr.replace",
    4265             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4266           0 :                                         goto bailout1;
    4267             :                                 }
    4268             :                         }
    4269             :                 }
    4270             :         } else {
    4271           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4272           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4273           0 :                                 p2 = (canditer_next(&ci2) - off2),
    4274           0 :                                 p3 = (canditer_next(&ci3) - off3);
    4275           0 :                         const char *x = BUNtvar(arg1i, p1);
    4276           0 :                         const char *y = BUNtvar(arg2i, p2);
    4277           0 :                         const char *z = BUNtvar(arg3i, p3);
    4278             : 
    4279           0 :                         if (strNil(x) || strNil(y) || strNil(z)) {
    4280           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4281           0 :                                         msg = createException(MAL, "batstr.replace",
    4282             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4283           0 :                                         goto bailout1;
    4284             :                                 }
    4285             :                                 nils = true;
    4286             :                         } else {
    4287           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, TRUE)) != MAL_SUCCEED)
    4288           0 :                                         goto bailout1;
    4289           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4290           0 :                                         msg = createException(MAL, "batstr.replace",
    4291             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4292           0 :                                         goto bailout1;
    4293             :                                 }
    4294             :                         }
    4295             :                 }
    4296             :         }
    4297           0 :   bailout1:
    4298           2 :         bat_iterator_end(&arg1i);
    4299           2 :         bat_iterator_end(&arg2i);
    4300           2 :         bat_iterator_end(&arg3i);
    4301           2 :   bailout:
    4302           2 :         GDKfree(buf);
    4303           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4304           2 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    4305           2 :         return msg;
    4306             : }
    4307             : 
    4308             : static str
    4309           0 : STRbatInsert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4310             : {
    4311           0 :         BATiter lefti, righti, starti, ncharsi;
    4312           0 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *start = NULL,
    4313           0 :                 *ss = NULL, *nchars = NULL, *ns = NULL, *right = NULL, *rs = NULL;
    4314           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4315           0 :         int *sval, *lval, y, z;
    4316           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4317           0 :         bool nils = false;
    4318           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 }, ci4 = { 0 };
    4319           0 :         oid off1, off2, off3, off4;
    4320           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    4321           0 :                 *l = getArgReference_bat(stk, pci, 1),
    4322           0 :                 *s = getArgReference_bat(stk, pci, 2),
    4323           0 :                 *chars = getArgReference_bat(stk, pci, 3),
    4324           0 :                 *s2 = getArgReference_bat(stk, pci, 4),
    4325           0 :                 *sid1 = pci->argc == 9 ? getArgReference_bat(stk, pci, 5) : NULL,
    4326           0 :                 *sid2 = pci->argc == 9 ? getArgReference_bat(stk, pci, 6) : NULL,
    4327           0 :                 *sid3 = pci->argc == 9 ? getArgReference_bat(stk, pci, 7) : NULL,
    4328           0 :                 *sid4 = pci->argc == 9 ? getArgReference_bat(stk, pci, 8) : NULL;
    4329             : 
    4330           0 :         (void) cntxt;
    4331           0 :         (void) mb;
    4332           0 :         if (!buf) {
    4333           0 :                 msg = createException(MAL, "batstr.insert",
    4334             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4335           0 :                 goto bailout;
    4336             :         }
    4337           0 :         if (!(left = BATdescriptor(*l)) || !(start = BATdescriptor(*s))
    4338           0 :                 || !(nchars = BATdescriptor(*chars)) || !(right = BATdescriptor(*s2))) {
    4339           0 :                 msg = createException(MAL, "batstr.insert",
    4340             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4341           0 :                 goto bailout;
    4342             :         }
    4343           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1)))
    4344           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))
    4345           0 :                 || (sid3 && !is_bat_nil(*sid3) && !(ss = BATdescriptor(*sid3)))
    4346           0 :                 || (sid4 && !is_bat_nil(*sid4) && !(ns = BATdescriptor(*sid4)))) {
    4347           0 :                 msg = createException(MAL, "batstr.insert",
    4348             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4349           0 :                 goto bailout;
    4350             :         }
    4351           0 :         canditer_init(&ci1, left, ls);
    4352           0 :         canditer_init(&ci2, start, ss);
    4353           0 :         canditer_init(&ci3, nchars, ns);
    4354           0 :         canditer_init(&ci4, right, rs);
    4355           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    4356           0 :                 || ci2.hseq != ci3.hseq || ci4.ncand != ci1.ncand
    4357           0 :                 || ci3.hseq != ci4.hseq) {
    4358           0 :                 msg = createException(MAL, "batstr.insert",
    4359             :                                                           ILLEGAL_ARGUMENT
    4360             :                                                           " Requires bats of identical size");
    4361           0 :                 goto bailout;
    4362             :         }
    4363           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4364           0 :                 msg = createException(MAL, "batstr.insert",
    4365             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4366           0 :                 goto bailout;
    4367             :         }
    4368             : 
    4369           0 :         off1 = left->hseqbase;
    4370           0 :         off2 = start->hseqbase;
    4371           0 :         off3 = nchars->hseqbase;
    4372           0 :         off4 = right->hseqbase;
    4373           0 :         lefti = bat_iterator(left);
    4374           0 :         starti = bat_iterator(start);
    4375           0 :         ncharsi = bat_iterator(nchars);
    4376           0 :         sval = starti.base;
    4377           0 :         lval = ncharsi.base;
    4378           0 :         righti = bat_iterator(right);
    4379           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense
    4380           0 :                 && ci4.tpe == cand_dense) {
    4381           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4382           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4383           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    4384           0 :                                 p3 = (canditer_next_dense(&ci3) - off3),
    4385           0 :                                 p4 = (canditer_next_dense(&ci4) - off4);
    4386           0 :                         const char *x = BUNtvar(lefti, p1);
    4387           0 :                         y = sval[p2];
    4388           0 :                         z = lval[p3];
    4389           0 :                         const char *w = BUNtvar(righti, p4);
    4390             : 
    4391           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z) || strNil(w)) {
    4392           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4393           0 :                                         msg = createException(MAL, "batstr.insert",
    4394             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4395           0 :                                         goto bailout1;
    4396             :                                 }
    4397             :                                 nils = true;
    4398             :                         } else {
    4399           0 :                                 if ((msg = str_insert(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    4400           0 :                                         goto bailout1;
    4401           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4402           0 :                                         msg = createException(MAL, "batstr.insert",
    4403             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4404           0 :                                         goto bailout1;
    4405             :                                 }
    4406             :                         }
    4407             :                 }
    4408             :         } else {
    4409           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4410           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4411           0 :                                 p2 = (canditer_next(&ci2) - off2),
    4412           0 :                                 p3 = (canditer_next(&ci3) - off3),
    4413           0 :                                 p4 = (canditer_next(&ci4) - off4);
    4414           0 :                         const char *x = BUNtvar(lefti, p1);
    4415           0 :                         y = sval[p2];
    4416           0 :                         z = lval[p3];
    4417           0 :                         const char *w = BUNtvar(righti, p4);
    4418             : 
    4419           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z) || strNil(w)) {
    4420           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4421           0 :                                         msg = createException(MAL, "batstr.insert",
    4422             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4423           0 :                                         goto bailout1;
    4424             :                                 }
    4425             :                                 nils = true;
    4426             :                         } else {
    4427           0 :                                 if ((msg = str_insert(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    4428           0 :                                         goto bailout1;
    4429           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4430           0 :                                         msg = createException(MAL, "batstr.insert",
    4431             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4432           0 :                                         goto bailout1;
    4433             :                                 }
    4434             :                         }
    4435             :                 }
    4436             :         }
    4437           0 :   bailout1:
    4438           0 :         bat_iterator_end(&starti);
    4439           0 :         bat_iterator_end(&ncharsi);
    4440           0 :         bat_iterator_end(&lefti);
    4441           0 :         bat_iterator_end(&righti);
    4442           0 :   bailout:
    4443           0 :         GDKfree(buf);
    4444           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4445           0 :         unfix_inputs(8, left, ls, start, ss, nchars, ns, right, rs);
    4446           0 :         return msg;
    4447             : }
    4448             : 
    4449             : static str
    4450           0 : STRbatInsertcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4451             : {
    4452           0 :         BATiter bi;
    4453           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4454           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4455           0 :         int y = *getArgReference_int(stk, pci, 2),
    4456           0 :                 z = *getArgReference_int(stk, pci, 3);
    4457           0 :         const char *w = *getArgReference_str(stk, pci, 4);
    4458           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4459           0 :         bool nils = false;
    4460           0 :         struct canditer ci1 = { 0 };
    4461           0 :         oid off1;
    4462           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    4463           0 :                 *bid = getArgReference_bat(stk, pci, 1),
    4464           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4465             : 
    4466           0 :         (void) cntxt;
    4467           0 :         (void) mb;
    4468           0 :         if (!buf) {
    4469           0 :                 msg = createException(MAL, "batstr.insert",
    4470             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4471           0 :                 goto bailout;
    4472             :         }
    4473           0 :         if (!(b = BATdescriptor(*bid))) {
    4474           0 :                 msg = createException(MAL, "batstr.insert",
    4475             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4476           0 :                 goto bailout;
    4477             :         }
    4478           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4479           0 :                 msg = createException(MAL, "batstr.insert",
    4480             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4481           0 :                 goto bailout;
    4482             :         }
    4483           0 :         canditer_init(&ci1, b, bs);
    4484           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4485           0 :                 msg = createException(MAL, "batstr.insert",
    4486             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4487           0 :                 goto bailout;
    4488             :         }
    4489             : 
    4490           0 :         off1 = b->hseqbase;
    4491           0 :         bi = bat_iterator(b);
    4492           0 :         if (ci1.tpe == cand_dense) {
    4493           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4494           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4495           0 :                         const char *x = BUNtvar(bi, p1);
    4496             : 
    4497           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z) || strNil(w)) {
    4498           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4499           0 :                                         msg = createException(MAL, "batstr.insert",
    4500             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4501           0 :                                         goto bailout1;
    4502             :                                 }
    4503             :                                 nils = true;
    4504             :                         } else {
    4505           0 :                                 if ((msg = str_insert(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    4506           0 :                                         goto bailout1;
    4507           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4508           0 :                                         msg = createException(MAL, "batstr.insert",
    4509             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4510           0 :                                         goto bailout1;
    4511             :                                 }
    4512             :                         }
    4513             :                 }
    4514             :         } else {
    4515           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4516           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4517           0 :                         const char *x = BUNtvar(bi, p1);
    4518             : 
    4519           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z) || strNil(w)) {
    4520           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4521           0 :                                         msg = createException(MAL, "batstr.insert",
    4522             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4523           0 :                                         goto bailout1;
    4524             :                                 }
    4525             :                                 nils = true;
    4526             :                         } else {
    4527           0 :                                 if ((msg = str_insert(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    4528           0 :                                         goto bailout1;
    4529           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4530           0 :                                         msg = createException(MAL, "batstr.insert",
    4531             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4532           0 :                                         goto bailout1;
    4533             :                                 }
    4534             :                         }
    4535             :                 }
    4536             :         }
    4537           0 :   bailout1:
    4538           0 :         bat_iterator_end(&bi);
    4539           0 :   bailout:
    4540           0 :         GDKfree(buf);
    4541           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4542           0 :         unfix_inputs(2, b, bs);
    4543           0 :         return msg;
    4544             : }
    4545             : 
    4546             : /*
    4547             :  * The substring functions require slightly different arguments
    4548             :  */
    4549             : static str
    4550          83 : STRbatsubstring_2nd_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4551             :                                                         InstrPtr pci)
    4552             : {
    4553          83 :         BATiter bi;
    4554          83 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4555          83 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4556          83 :         int y = *getArgReference_int(stk, pci, 2),
    4557          83 :                 z = *getArgReference_int(stk, pci, 3);
    4558          83 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4559          83 :         bool nils = false;
    4560          83 :         struct canditer ci1 = { 0 };
    4561          83 :         oid off1;
    4562          83 :         bat *res = getArgReference_bat(stk, pci, 0),
    4563          83 :                 *bid = getArgReference_bat(stk, pci, 1),
    4564          83 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4565             : 
    4566          83 :         (void) cntxt;
    4567          83 :         (void) mb;
    4568          83 :         if (!buf) {
    4569           0 :                 msg = createException(MAL, "batstr.substring",
    4570             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4571           0 :                 goto bailout;
    4572             :         }
    4573          83 :         if (!(b = BATdescriptor(*bid))) {
    4574           0 :                 msg = createException(MAL, "batstr.substring",
    4575             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4576           0 :                 goto bailout;
    4577             :         }
    4578          83 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4579           0 :                 msg = createException(MAL, "batstr.substring",
    4580             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4581           0 :                 goto bailout;
    4582             :         }
    4583          83 :         canditer_init(&ci1, b, bs);
    4584          83 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4585           0 :                 msg = createException(MAL, "batstr.substring",
    4586             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4587           0 :                 goto bailout;
    4588             :         }
    4589             : 
    4590          83 :         off1 = b->hseqbase;
    4591          83 :         bi = bat_iterator(b);
    4592          83 :         if (ci1.tpe == cand_dense) {
    4593     3922647 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4594     3922564 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4595     3922564 :                         const char *x = BUNtvar(bi, p1);
    4596             : 
    4597     7705774 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4598       96579 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4599           0 :                                         msg = createException(MAL, "batstr.substring",
    4600             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4601           0 :                                         goto bailout1;
    4602             :                                 }
    4603             :                                 nils = true;
    4604             :                         } else {
    4605     3806012 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4606           0 :                                         goto bailout1;
    4607     3845965 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4608           0 :                                         msg = createException(MAL, "batstr.substring",
    4609             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4610           0 :                                         goto bailout1;
    4611             :                                 }
    4612             :                         }
    4613             :                 }
    4614             :         } else {
    4615           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4616           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4617           0 :                         const char *x = BUNtvar(bi, p1);
    4618             : 
    4619           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4620           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4621           0 :                                         msg = createException(MAL, "batstr.substring",
    4622             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4623           0 :                                         goto bailout1;
    4624             :                                 }
    4625             :                                 nils = true;
    4626             :                         } else {
    4627           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4628           0 :                                         goto bailout1;
    4629           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4630           0 :                                         msg = createException(MAL, "batstr.substring",
    4631             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4632           0 :                                         goto bailout1;
    4633             :                                 }
    4634             :                         }
    4635             :                 }
    4636             :         }
    4637           0 :   bailout1:
    4638          83 :         bat_iterator_end(&bi);
    4639          83 :   bailout:
    4640          83 :         GDKfree(buf);
    4641          83 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4642          83 :         unfix_inputs(2, b, bs);
    4643          83 :         return msg;
    4644             : }
    4645             : 
    4646             : static str
    4647           1 : STRbatsubstring_1st_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4648             :                                                         InstrPtr pci)
    4649             : {
    4650           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4651           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4652           1 :         int y = *getArgReference_int(stk, pci, 2), z, *restrict input;
    4653           1 :         const char *x = *getArgReference_str(stk, pci, 1);
    4654           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4655           1 :         bool nils = false;
    4656           1 :         struct canditer ci1 = { 0 };
    4657           1 :         oid off1;
    4658           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    4659           1 :                 *bid = getArgReference_bat(stk, pci, 3),
    4660           1 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4661           1 :         BATiter bi;
    4662             : 
    4663           1 :         (void) cntxt;
    4664           1 :         (void) mb;
    4665           1 :         if (!buf) {
    4666           0 :                 msg = createException(MAL, "batstr.substring",
    4667             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4668           0 :                 goto bailout;
    4669             :         }
    4670           1 :         if (!(b = BATdescriptor(*bid))) {
    4671           0 :                 msg = createException(MAL, "batstr.substring",
    4672             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4673           0 :                 goto bailout;
    4674             :         }
    4675           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4676           0 :                 msg = createException(MAL, "batstr.substring",
    4677             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4678           0 :                 goto bailout;
    4679             :         }
    4680           1 :         canditer_init(&ci1, b, bs);
    4681           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4682           0 :                 msg = createException(MAL, "batstr.substring",
    4683             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4684           0 :                 goto bailout;
    4685             :         }
    4686             : 
    4687           1 :         off1 = b->hseqbase;
    4688           1 :         bi = bat_iterator(b);
    4689           1 :         input = bi.base;
    4690           1 :         if (ci1.tpe == cand_dense) {
    4691           2 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4692           1 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4693           1 :                         z = input[p1];
    4694             : 
    4695           2 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4696           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4697           0 :                                         msg = createException(MAL, "batstr.substring",
    4698             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4699           0 :                                         goto bailout1;
    4700             :                                 }
    4701             :                                 nils = true;
    4702             :                         } else {
    4703           1 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4704           0 :                                         goto bailout1;
    4705           1 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4706           0 :                                         msg = createException(MAL, "batstr.substring",
    4707             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4708           0 :                                         goto bailout1;
    4709             :                                 }
    4710             :                         }
    4711             :                 }
    4712             :         } else {
    4713           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4714           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4715           0 :                         z = input[p1];
    4716             : 
    4717           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4718           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4719           0 :                                         msg = createException(MAL, "batstr.substring",
    4720             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4721           0 :                                         goto bailout1;
    4722             :                                 }
    4723             :                                 nils = true;
    4724             :                         } else {
    4725           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4726           0 :                                         goto bailout1;
    4727           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4728           0 :                                         msg = createException(MAL, "batstr.substring",
    4729             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4730           0 :                                         goto bailout1;
    4731             :                                 }
    4732             :                         }
    4733             :                 }
    4734             :         }
    4735           0 :   bailout1:
    4736           1 :         bat_iterator_end(&bi);
    4737           1 :   bailout:
    4738           1 :         GDKfree(buf);
    4739           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4740           1 :         unfix_inputs(2, b, bs);
    4741           1 :         return msg;
    4742             : }
    4743             : 
    4744             : static str
    4745           4 : STRbatsubstring_1st_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4746             :                                                         InstrPtr pci)
    4747             : {
    4748           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4749           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4750           4 :         int y, z = *getArgReference_int(stk, pci, 3), *restrict input;
    4751           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    4752           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4753           4 :         bool nils = false;
    4754           4 :         struct canditer ci1 = { 0 };
    4755           4 :         oid off1;
    4756           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    4757           4 :                 *bid = getArgReference_bat(stk, pci, 2),
    4758           4 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4759           4 :         BATiter bi;
    4760             : 
    4761           4 :         (void) cntxt;
    4762           4 :         (void) mb;
    4763           4 :         if (!buf) {
    4764           0 :                 msg = createException(MAL, "batstr.substring",
    4765             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4766           0 :                 goto bailout;
    4767             :         }
    4768           4 :         if (!(b = BATdescriptor(*bid))) {
    4769           0 :                 msg = createException(MAL, "batstr.substring",
    4770             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4771           0 :                 goto bailout;
    4772             :         }
    4773           4 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4774           0 :                 msg = createException(MAL, "batstr.substring",
    4775             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4776           0 :                 goto bailout;
    4777             :         }
    4778           4 :         canditer_init(&ci1, b, bs);
    4779           4 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4780           0 :                 msg = createException(MAL, "batstr.substring",
    4781             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4782           0 :                 goto bailout;
    4783             :         }
    4784             : 
    4785           4 :         off1 = b->hseqbase;
    4786           4 :         bi = bat_iterator(b);
    4787           4 :         input = bi.base;
    4788           4 :         if (ci1.tpe == cand_dense) {
    4789           8 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4790           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4791           4 :                         y = input[p1];
    4792             : 
    4793           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4794           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4795           0 :                                         msg = createException(MAL, "batstr.substring",
    4796             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4797           0 :                                         goto bailout1;
    4798             :                                 }
    4799             :                                 nils = true;
    4800             :                         } else {
    4801           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4802           0 :                                         goto bailout1;
    4803           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4804           0 :                                         msg = createException(MAL, "batstr.substring",
    4805             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4806           0 :                                         goto bailout1;
    4807             :                                 }
    4808             :                         }
    4809             :                 }
    4810             :         } else {
    4811           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4812           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4813           0 :                         y = input[p1];
    4814             : 
    4815           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4816           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4817           0 :                                         msg = createException(MAL, "batstr.substring",
    4818             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4819           0 :                                         goto bailout1;
    4820             :                                 }
    4821             :                                 nils = true;
    4822             :                         } else {
    4823           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4824           0 :                                         goto bailout1;
    4825           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4826           0 :                                         msg = createException(MAL, "batstr.substring",
    4827             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4828           0 :                                         goto bailout1;
    4829             :                                 }
    4830             :                         }
    4831             :                 }
    4832             :         }
    4833           0 :   bailout1:
    4834           4 :         bat_iterator_end(&bi);
    4835           4 :   bailout:
    4836           4 :         GDKfree(buf);
    4837           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4838           4 :         unfix_inputs(2, b, bs);
    4839           4 :         return msg;
    4840             : }
    4841             : 
    4842             : static str
    4843           4 : STRbatsubstring_1st_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4844             : {
    4845           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4846           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4847           4 :         int y, z, *vals1, *vals2;
    4848           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    4849           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4850           4 :         bool nils = false;
    4851           4 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4852           4 :         oid off1, off2;
    4853           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    4854           4 :                 *bid = getArgReference_bat(stk, pci, 2),
    4855           4 :                 *l = getArgReference_bat(stk, pci, 3),
    4856           4 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4857           4 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4858           4 :         BATiter bi;
    4859           4 :         BATiter lbi;
    4860             : 
    4861           4 :         (void) cntxt;
    4862           4 :         (void) mb;
    4863           4 :         if (!buf) {
    4864           0 :                 msg = createException(MAL, "batstr.substring",
    4865             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4866           0 :                 goto bailout;
    4867             :         }
    4868           4 :         if (!(b = BATdescriptor(*bid)) || !(lb = BATdescriptor(*l))) {
    4869           0 :                 msg = createException(MAL, "batstr.substring",
    4870             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4871           0 :                 goto bailout;
    4872             :         }
    4873           4 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    4874           4 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    4875           0 :                 msg = createException(MAL, "batstr.substring",
    4876             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4877           0 :                 goto bailout;
    4878             :         }
    4879           4 :         canditer_init(&ci1, b, bs);
    4880           4 :         canditer_init(&ci2, lb, lbs);
    4881           4 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    4882           0 :                 msg = createException(MAL, "batstr.substring",
    4883             :                                                           ILLEGAL_ARGUMENT
    4884             :                                                           " Requires bats of identical size");
    4885           0 :                 goto bailout;
    4886             :         }
    4887           4 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4888           0 :                 msg = createException(MAL, "batstr.substring",
    4889             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4890           0 :                 goto bailout;
    4891             :         }
    4892             : 
    4893           4 :         off1 = b->hseqbase;
    4894           4 :         off2 = lb->hseqbase;
    4895           4 :         bi = bat_iterator(b);
    4896           4 :         lbi = bat_iterator(lb);
    4897           4 :         vals1 = bi.base;
    4898           4 :         vals2 = lbi.base;
    4899           4 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    4900          12 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4901           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4902           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    4903           8 :                         y = vals1[p1];
    4904           8 :                         z = vals2[p2];
    4905             : 
    4906          16 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4907           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4908           0 :                                         msg = createException(MAL, "batstr.substring",
    4909             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4910           0 :                                         goto bailout1;
    4911             :                                 }
    4912             :                                 nils = true;
    4913             :                         } else {
    4914           8 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4915           0 :                                         goto bailout1;
    4916           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4917           0 :                                         msg = createException(MAL, "batstr.substring",
    4918             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4919           0 :                                         goto bailout1;
    4920             :                                 }
    4921             :                         }
    4922             :                 }
    4923             :         } else {
    4924           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4925           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4926           0 :                                 p2 = (canditer_next(&ci2) - off2);
    4927           0 :                         y = vals1[p1];
    4928           0 :                         z = vals2[p2];
    4929             : 
    4930           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4931           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4932           0 :                                         msg = createException(MAL, "batstr.substring",
    4933             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4934           0 :                                         goto bailout1;
    4935             :                                 }
    4936             :                                 nils = true;
    4937             :                         } else {
    4938           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4939           0 :                                         goto bailout1;
    4940           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4941           0 :                                         msg = createException(MAL, "batstr.substring",
    4942             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4943           0 :                                         goto bailout1;
    4944             :                                 }
    4945             :                         }
    4946             :                 }
    4947             :         }
    4948           0 :   bailout1:
    4949           4 :         bat_iterator_end(&bi);
    4950           4 :         bat_iterator_end(&lbi);
    4951           4 :   bailout:
    4952           4 :         GDKfree(buf);
    4953           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4954           4 :         unfix_inputs(4, b, bs, lb, lbs);
    4955           4 :         return msg;
    4956             : }
    4957             : 
    4958             : static str
    4959          16 : STRbatsubstring_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4960             : {
    4961          16 :         BATiter bi;
    4962          16 :         BATiter lbi;
    4963          16 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4964          16 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4965          16 :         int y = *getArgReference_int(stk, pci, 2), *len, z;
    4966          16 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4967          16 :         bool nils = false;
    4968          16 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4969          16 :         oid off1, off2;
    4970          16 :         bat *res = getArgReference_bat(stk, pci, 0),
    4971          16 :                 *bid = getArgReference_bat(stk, pci, 1),
    4972          16 :                 *l = getArgReference_bat(stk, pci, 3),
    4973          16 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4974          16 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4975             : 
    4976          16 :         (void) cntxt;
    4977          16 :         (void) mb;
    4978          16 :         if (!buf) {
    4979           0 :                 msg = createException(MAL, "batstr.substring",
    4980             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4981           0 :                 goto bailout;
    4982             :         }
    4983          16 :         if (!(b = BATdescriptor(*bid)) || !(lb = BATdescriptor(*l))) {
    4984           0 :                 msg = createException(MAL, "batstr.substring",
    4985             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4986           0 :                 goto bailout;
    4987             :         }
    4988          16 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    4989          16 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    4990           0 :                 msg = createException(MAL, "batstr.substring",
    4991             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4992           0 :                 goto bailout;
    4993             :         }
    4994          16 :         canditer_init(&ci1, b, bs);
    4995          16 :         canditer_init(&ci2, lb, lbs);
    4996          16 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    4997           0 :                 msg = createException(MAL, "batstr.substring",
    4998             :                                                           ILLEGAL_ARGUMENT
    4999             :                                                           " Requires bats of identical size");
    5000           0 :                 goto bailout;
    5001             :         }
    5002          16 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5003           0 :                 msg = createException(MAL, "batstr.substring",
    5004             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5005           0 :                 goto bailout;
    5006             :         }
    5007             : 
    5008          16 :         off1 = b->hseqbase;
    5009          16 :         off2 = lb->hseqbase;
    5010          16 :         bi = bat_iterator(b);
    5011          16 :         lbi = bat_iterator(lb);
    5012          16 :         len = lbi.base;
    5013          16 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5014          20 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5015           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5016           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5017           4 :                         const char *x = BUNtvar(bi, p1);
    5018           4 :                         z = len[p2];
    5019             : 
    5020           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5021           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5022           0 :                                         msg = createException(MAL, "batstr.substring",
    5023             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5024           0 :                                         goto bailout1;
    5025             :                                 }
    5026             :                                 nils = true;
    5027             :                         } else {
    5028           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5029           0 :                                         goto bailout1;
    5030           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5031           0 :                                         msg = createException(MAL, "batstr.substring",
    5032             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5033           0 :                                         goto bailout1;
    5034             :                                 }
    5035             :                         }
    5036             :                 }
    5037             :         } else {
    5038           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5039           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5040           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5041           0 :                         const char *x = BUNtvar(bi, p1);
    5042           0 :                         z = len[p2];
    5043             : 
    5044           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5045           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5046           0 :                                         msg = createException(MAL, "batstr.substring",
    5047             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5048           0 :                                         goto bailout1;
    5049             :                                 }
    5050             :                                 nils = true;
    5051             :                         } else {
    5052           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5053           0 :                                         goto bailout1;
    5054           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5055           0 :                                         msg = createException(MAL, "batstr.substring",
    5056             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5057           0 :                                         goto bailout1;
    5058             :                                 }
    5059             :                         }
    5060             :                 }
    5061             :         }
    5062           0 :   bailout1:
    5063          16 :         bat_iterator_end(&lbi);
    5064          16 :         bat_iterator_end(&bi);
    5065          16 :   bailout:
    5066          16 :         GDKfree(buf);
    5067          16 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5068          16 :         unfix_inputs(4, b, bs, lb, lbs);
    5069          16 :         return msg;
    5070             : }
    5071             : 
    5072             : static str
    5073           0 : STRbatsubstring_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5074             : {
    5075           0 :         BATiter bi, lbi;
    5076           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    5077           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5078           0 :         int *start, y, z = *getArgReference_int(stk, pci, 3);
    5079           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5080           0 :         bool nils = false;
    5081           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5082           0 :         oid off1, off2;
    5083           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5084           0 :                 *bid = getArgReference_bat(stk, pci, 1),
    5085           0 :                 *l = getArgReference_bat(stk, pci, 2),
    5086           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    5087           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    5088             : 
    5089           0 :         (void) cntxt;
    5090           0 :         (void) mb;
    5091           0 :         if (!buf) {
    5092           0 :                 msg = createException(MAL, "batstr.substring",
    5093             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5094           0 :                 goto bailout;
    5095             :         }
    5096           0 :         if (!(b = BATdescriptor(*bid)) || !(lb = BATdescriptor(*l))) {
    5097           0 :                 msg = createException(MAL, "batstr.substring",
    5098             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5099           0 :                 goto bailout;
    5100             :         }
    5101           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5102           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    5103           0 :                 msg = createException(MAL, "batstr.substring",
    5104             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5105           0 :                 goto bailout;
    5106             :         }
    5107           0 :         canditer_init(&ci1, b, bs);
    5108           0 :         canditer_init(&ci2, lb, lbs);
    5109           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5110           0 :                 msg = createException(MAL, "batstr.substring",
    5111             :                                                           ILLEGAL_ARGUMENT
    5112             :                                                           " Requires bats of identical size");
    5113           0 :                 goto bailout;
    5114             :         }
    5115           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5116           0 :                 msg = createException(MAL, "batstr.substring",
    5117             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5118           0 :                 goto bailout;
    5119             :         }
    5120             : 
    5121           0 :         off1 = b->hseqbase;
    5122           0 :         off2 = lb->hseqbase;
    5123           0 :         bi = bat_iterator(b);
    5124           0 :         lbi = bat_iterator(lb);
    5125           0 :         start = lbi.base;
    5126           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5127           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5128           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5129           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5130           0 :                         const char *x = BUNtvar(bi, p1);
    5131           0 :                         y = start[p2];
    5132             : 
    5133           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5134           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5135           0 :                                         msg = createException(MAL, "batstr.substring",
    5136             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5137           0 :                                         goto bailout1;
    5138             :                                 }
    5139             :                                 nils = true;
    5140             :                         } else {
    5141           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5142           0 :                                         goto bailout1;
    5143           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5144           0 :                                         msg = createException(MAL, "batstr.substring",
    5145             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5146           0 :                                         goto bailout1;
    5147             :                                 }
    5148             :                         }
    5149             :                 }
    5150             :         } else {
    5151           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5152           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5153           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5154           0 :                         const char *x = BUNtvar(bi, p1);
    5155           0 :                         y = start[p2];
    5156             : 
    5157           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5158           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5159           0 :                                         msg = createException(MAL, "batstr.substring",
    5160             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5161           0 :                                         goto bailout1;
    5162             :                                 }
    5163             :                                 nils = true;
    5164             :                         } else {
    5165           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5166           0 :                                         goto bailout1;
    5167           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5168           0 :                                         msg = createException(MAL, "batstr.substring",
    5169             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5170           0 :                                         goto bailout1;
    5171             :                                 }
    5172             :                         }
    5173             :                 }
    5174             :         }
    5175           0 :   bailout1:
    5176           0 :         bat_iterator_end(&lbi);
    5177           0 :         bat_iterator_end(&bi);
    5178           0 :   bailout:
    5179           0 :         GDKfree(buf);
    5180           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5181           0 :         unfix_inputs(4, b, bs, lb, lbs);
    5182           0 :         return msg;
    5183             : }
    5184             : 
    5185             : static str
    5186          16 : STRbatsubstring(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5187             : {
    5188          16 :         BATiter lefti, starti, lengthi;
    5189          16 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *start = NULL,
    5190          16 :                 *ss = NULL, *length = NULL, *lens = NULL;
    5191          16 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5192          16 :         int *svals, *lvals, y, z;
    5193          16 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5194          16 :         bool nils = false;
    5195          16 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5196          16 :         oid off1, off2, off3;
    5197          16 :         bat *res = getArgReference_bat(stk, pci, 0),
    5198          16 :                 *l = getArgReference_bat(stk, pci, 1),
    5199          16 :                 *r = getArgReference_bat(stk, pci, 2),
    5200          16 :                 *t = getArgReference_bat(stk, pci, 3),
    5201          16 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5202          16 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5203          16 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5204             : 
    5205          16 :         (void) cntxt;
    5206          16 :         (void) mb;
    5207          16 :         if (!buf) {
    5208           0 :                 msg = createException(MAL, "batstr.substring",
    5209             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5210           0 :                 goto bailout;
    5211             :         }
    5212          16 :         if (!(left = BATdescriptor(*l)) || !(start = BATdescriptor(*r))
    5213          16 :                 || !(length = BATdescriptor(*t))) {
    5214           0 :                 msg = createException(MAL, "batstr.substring",
    5215             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5216           0 :                 goto bailout;
    5217             :         }
    5218          16 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5219          16 :                 (sid2 && !is_bat_nil(*sid2) && !(ss = BATdescriptor(*sid2))) ||
    5220           0 :                 (sid3 && !is_bat_nil(*sid3) && !(lens = BATdescriptor(*sid3)))) {
    5221           0 :                 msg = createException(MAL, "batstr.substring",
    5222             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5223           0 :                 goto bailout;
    5224             :         }
    5225          16 :         canditer_init(&ci1, left, ls);
    5226          16 :         canditer_init(&ci2, start, ss);
    5227          16 :         canditer_init(&ci3, length, lens);
    5228          16 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5229          16 :                 || ci2.hseq != ci3.hseq) {
    5230           0 :                 msg = createException(MAL, "batstr.substring",
    5231             :                                                           ILLEGAL_ARGUMENT
    5232             :                                                           " Requires bats of identical size");
    5233           0 :                 goto bailout;
    5234             :         }
    5235          16 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5236           0 :                 msg = createException(MAL, "batstr.substring",
    5237             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5238           0 :                 goto bailout;
    5239             :         }
    5240             : 
    5241          16 :         off1 = left->hseqbase;
    5242          16 :         off2 = start->hseqbase;
    5243          16 :         off3 = length->hseqbase;
    5244          16 :         lefti = bat_iterator(left);
    5245          16 :         starti = bat_iterator(start);
    5246          16 :         lengthi = bat_iterator(length);
    5247          16 :         svals = starti.base;
    5248          16 :         lvals = lengthi.base;
    5249          16 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5250        4237 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5251        4221 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5252        4221 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5253        4221 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5254        4221 :                         const char *x = BUNtvar(lefti, p1);
    5255        4223 :                         y = svals[p2];
    5256        4223 :                         z = lvals[p3];
    5257             : 
    5258        8416 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5259          48 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5260           0 :                                         msg = createException(MAL, "batstr.substring",
    5261             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5262           0 :                                         goto bailout1;
    5263             :                                 }
    5264             :                                 nils = true;
    5265             :                         } else {
    5266        4175 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5267           0 :                                         goto bailout1;
    5268        4187 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5269           0 :                                         msg = createException(MAL, "batstr.substring",
    5270             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5271           0 :                                         goto bailout1;
    5272             :                                 }
    5273             :                         }
    5274             :                 }
    5275             :         } else {
    5276           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5277           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5278           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5279           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5280           0 :                         const char *x = BUNtvar(lefti, p1);
    5281           0 :                         y = svals[p2];
    5282           0 :                         z = lvals[p3];
    5283             : 
    5284           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5285           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5286           0 :                                         msg = createException(MAL, "batstr.substring",
    5287             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5288           0 :                                         goto bailout1;
    5289             :                                 }
    5290             :                                 nils = true;
    5291             :                         } else {
    5292           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5293           0 :                                         goto bailout1;
    5294           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5295           0 :                                         msg = createException(MAL, "batstr.substring",
    5296             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5297           0 :                                         goto bailout1;
    5298             :                                 }
    5299             :                         }
    5300             :                 }
    5301             :         }
    5302           0 :   bailout1:
    5303          16 :         bat_iterator_end(&lefti);
    5304          16 :         bat_iterator_end(&starti);
    5305          16 :         bat_iterator_end(&lengthi);
    5306          16 :   bailout:
    5307          16 :         GDKfree(buf);
    5308          16 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5309          16 :         unfix_inputs(6, left, ls, start, ss, length, lens);
    5310          16 :         return msg;
    5311             : }
    5312             : 
    5313             : static str
    5314           0 : STRbatstrLocatecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5315             : {
    5316           0 :         BATiter bi;
    5317           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5318           0 :         int *restrict vals;
    5319           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5320           0 :         str msg = MAL_SUCCEED;
    5321           0 :         bool nils = false;
    5322           0 :         struct canditer ci1 = { 0 };
    5323           0 :         oid off1;
    5324           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5325           0 :                 *l = getArgReference_bat(stk, pci, 1),
    5326           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5327             : 
    5328           0 :         (void) cntxt;
    5329           0 :         (void) mb;
    5330           0 :         if (!(b = BATdescriptor(*l))) {
    5331           0 :                 msg = createException(MAL, "batstr.locate",
    5332             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5333           0 :                 goto bailout;
    5334             :         }
    5335           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5336           0 :                 msg = createException(MAL, "batstr.locate",
    5337             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5338           0 :                 goto bailout;
    5339             :         }
    5340           0 :         canditer_init(&ci1, b, bs);
    5341           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5342           0 :                 msg = createException(MAL, "batstr.locate",
    5343             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5344           0 :                 goto bailout;
    5345             :         }
    5346             : 
    5347           0 :         off1 = b->hseqbase;
    5348           0 :         bi = bat_iterator(b);
    5349           0 :         vals = Tloc(bn, 0);
    5350           0 :         if (ci1.tpe == cand_dense) {
    5351           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5352           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5353           0 :                         const char *x = BUNtvar(bi, p1);
    5354             : 
    5355           0 :                         if (strNil(x) || strNil(y)) {
    5356           0 :                                 vals[i] = int_nil;
    5357           0 :                                 nils = true;
    5358             :                         } else {
    5359           0 :                                 vals[i] = str_locate2(x, y, 1);
    5360             :                         }
    5361             :                 }
    5362             :         } else {
    5363           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5364           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5365           0 :                         const char *x = BUNtvar(bi, p1);
    5366             : 
    5367           0 :                         if (strNil(x) || strNil(y)) {
    5368           0 :                                 vals[i] = int_nil;
    5369           0 :                                 nils = true;
    5370             :                         } else {
    5371           0 :                                 vals[i] = str_locate2(x, y, 1);
    5372             :                         }
    5373             :                 }
    5374             :         }
    5375           0 :         bat_iterator_end(&bi);
    5376           0 :   bailout:
    5377           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5378           0 :         unfix_inputs(2, b, bs);
    5379           0 :         return msg;
    5380             : }
    5381             : 
    5382             : static str
    5383          28 : STRbatstrLocate_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5384             : {
    5385          28 :         BATiter bi;
    5386          28 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5387          28 :         int *restrict vals;
    5388          28 :         const char *x = *getArgReference_str(stk, pci, 1);
    5389          28 :         str msg = MAL_SUCCEED;
    5390          28 :         bool nils = false;
    5391          28 :         struct canditer ci1 = { 0 };
    5392          28 :         oid off1;
    5393          28 :         bat *res = getArgReference_bat(stk, pci, 0),
    5394          28 :                 *l = getArgReference_bat(stk, pci, 2),
    5395          28 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5396             : 
    5397          28 :         (void) cntxt;
    5398          28 :         (void) mb;
    5399          28 :         if (!(b = BATdescriptor(*l))) {
    5400           0 :                 msg = createException(MAL, "batstr.locate",
    5401             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5402           0 :                 goto bailout;
    5403             :         }
    5404          28 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5405           0 :                 msg = createException(MAL, "batstr.locate",
    5406             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5407           0 :                 goto bailout;
    5408             :         }
    5409          28 :         canditer_init(&ci1, b, bs);
    5410          28 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5411           0 :                 msg = createException(MAL, "batstr.locate",
    5412             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5413           0 :                 goto bailout;
    5414             :         }
    5415             : 
    5416          28 :         off1 = b->hseqbase;
    5417          28 :         bi = bat_iterator(b);
    5418          28 :         vals = Tloc(bn, 0);
    5419          28 :         if (ci1.tpe == cand_dense) {
    5420        4187 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5421        4159 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5422        4159 :                         const char *y = BUNtvar(bi, p1);
    5423             : 
    5424        8314 :                         if (strNil(x) || strNil(y)) {
    5425           0 :                                 vals[i] = int_nil;
    5426           0 :                                 nils = true;
    5427             :                         } else {
    5428        4157 :                                 vals[i] = str_locate2(x, y, 1);
    5429             :                         }
    5430             :                 }
    5431             :         } else {
    5432           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5433           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5434           0 :                         const char *y = BUNtvar(bi, p1);
    5435             : 
    5436           0 :                         if (strNil(x) || strNil(y)) {
    5437           0 :                                 vals[i] = int_nil;
    5438           0 :                                 nils = true;
    5439             :                         } else {
    5440           0 :                                 vals[i] = str_locate2(x, y, 1);
    5441             :                         }
    5442             :                 }
    5443             :         }
    5444          28 :         bat_iterator_end(&bi);
    5445          28 :   bailout:
    5446          28 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5447          28 :         unfix_inputs(2, b, bs);
    5448          28 :         return msg;
    5449             : }
    5450             : 
    5451             : static str
    5452           2 : STRbatstrLocate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5453             : {
    5454           2 :         BATiter lefti, righti;
    5455           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    5456           2 :         int *restrict vals;
    5457           2 :         str msg = MAL_SUCCEED;
    5458           2 :         bool nils = false;
    5459           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5460           2 :         oid off1, off2;
    5461           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    5462           2 :                 *l = getArgReference_bat(stk, pci, 1),
    5463           2 :                 *r = getArgReference_bat(stk, pci, 2),
    5464           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    5465           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5466             : 
    5467           2 :         (void) cntxt;
    5468           2 :         (void) mb;
    5469           2 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
    5470           0 :                 msg = createException(MAL, "batstr.locate",
    5471             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5472           0 :                 goto bailout;
    5473             :         }
    5474           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5475           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    5476           0 :                 msg = createException(MAL, "batstr.locate",
    5477             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5478           0 :                 goto bailout;
    5479             :         }
    5480           2 :         canditer_init(&ci1, left, ls);
    5481           2 :         canditer_init(&ci2, right, rs);
    5482           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5483           0 :                 msg = createException(MAL, "batstr.locate",
    5484             :                                                           ILLEGAL_ARGUMENT
    5485             :                                                           " Requires bats of identical size");
    5486           0 :                 goto bailout;
    5487             :         }
    5488           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5489           0 :                 msg = createException(MAL, "batstr.locate",
    5490             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5491           0 :                 goto bailout;
    5492             :         }
    5493             : 
    5494           2 :         off1 = left->hseqbase;
    5495           2 :         off2 = right->hseqbase;
    5496           2 :         lefti = bat_iterator(left);
    5497           2 :         righti = bat_iterator(right);
    5498           2 :         vals = Tloc(bn, 0);
    5499           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5500          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5501           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5502           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5503           8 :                         const char *x = BUNtvar(lefti, p1);
    5504           8 :                         const char *y = BUNtvar(righti, p2);
    5505             : 
    5506          16 :                         if (strNil(x) || strNil(y)) {
    5507           0 :                                 vals[i] = int_nil;
    5508           0 :                                 nils = true;
    5509             :                         } else {
    5510           8 :                                 vals[i] = str_locate2(x, y, 1);
    5511             :                         }
    5512             :                 }
    5513             :         } else {
    5514           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5515           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5516           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5517           0 :                         const char *x = BUNtvar(lefti, p1);
    5518           0 :                         const char *y = BUNtvar(righti, p2);
    5519             : 
    5520           0 :                         if (strNil(x) || strNil(y)) {
    5521           0 :                                 vals[i] = int_nil;
    5522           0 :                                 nils = true;
    5523             :                         } else {
    5524           0 :                                 vals[i] = str_locate2(x, y, 1);
    5525             :                         }
    5526             :                 }
    5527             :         }
    5528           2 :         bat_iterator_end(&lefti);
    5529           2 :         bat_iterator_end(&righti);
    5530           2 :   bailout:
    5531           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5532           2 :         unfix_inputs(4, left, ls, right, rs);
    5533           2 :         return msg;
    5534             : }
    5535             : 
    5536             : static str
    5537           0 : STRbatstrLocate3cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5538             : {
    5539           0 :         BATiter bi;
    5540           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5541           0 :         int *restrict vals, z = *getArgReference_int(stk, pci, 3);
    5542           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5543           0 :         str msg = MAL_SUCCEED;
    5544           0 :         bool nils = false;
    5545           0 :         struct canditer ci1 = { 0 };
    5546           0 :         oid off1;
    5547           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5548           0 :                 *l = getArgReference_bat(stk, pci, 1),
    5549           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5550             : 
    5551           0 :         (void) cntxt;
    5552           0 :         (void) mb;
    5553           0 :         if (!(b = BATdescriptor(*l))) {
    5554           0 :                 msg = createException(MAL, "batstr.locate2",
    5555             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5556           0 :                 goto bailout;
    5557             :         }
    5558           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5559           0 :                 msg = createException(MAL, "batstr.locate2",
    5560             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5561           0 :                 goto bailout;
    5562             :         }
    5563           0 :         canditer_init(&ci1, b, bs);
    5564           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5565           0 :                 msg = createException(MAL, "batstr.locate2",
    5566             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5567           0 :                 goto bailout;
    5568             :         }
    5569             : 
    5570           0 :         off1 = b->hseqbase;
    5571           0 :         bi = bat_iterator(b);
    5572           0 :         vals = Tloc(bn, 0);
    5573           0 :         if (ci1.tpe == cand_dense) {
    5574           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5575           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5576           0 :                         const char *x = BUNtvar(bi, p1);
    5577             : 
    5578           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5579           0 :                                 vals[i] = int_nil;
    5580           0 :                                 nils = true;
    5581             :                         } else {
    5582           0 :                                 vals[i] = str_locate2(x, y, z);
    5583             :                         }
    5584             :                 }
    5585             :         } else {
    5586           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5587           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5588           0 :                         const char *x = BUNtvar(bi, p1);
    5589             : 
    5590           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5591           0 :                                 vals[i] = int_nil;
    5592           0 :                                 nils = true;
    5593             :                         } else {
    5594           0 :                                 vals[i] = str_locate2(x, y, z);
    5595             :                         }
    5596             :                 }
    5597             :         }
    5598           0 :         bat_iterator_end(&bi);
    5599           0 :   bailout:
    5600           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5601           0 :         unfix_inputs(2, b, bs);
    5602           0 :         return msg;
    5603             : }
    5604             : 
    5605             : static str
    5606           0 : STRbatstrLocate3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5607             : {
    5608           0 :         BATiter lefti, righti, starti;
    5609           0 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL,
    5610           0 :                 *rs = NULL, *start = NULL, *ss = NULL;
    5611           0 :         int *restrict vals, *restrict svals, z;
    5612           0 :         str msg = MAL_SUCCEED;
    5613           0 :         bool nils = false;
    5614           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5615           0 :         oid off1, off2, off3;
    5616           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5617           0 :                 *l = getArgReference_bat(stk, pci, 1),
    5618           0 :                 *r = getArgReference_bat(stk, pci, 2),
    5619           0 :                 *s = getArgReference_bat(stk, pci, 3),
    5620           0 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5621           0 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5622           0 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5623             : 
    5624           0 :         (void) cntxt;
    5625           0 :         (void) mb;
    5626           0 :         if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))
    5627           0 :                 || !(start = BATdescriptor(*s))) {
    5628           0 :                 msg = createException(MAL, "batstr.locate2",
    5629             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5630           0 :                 goto bailout;
    5631             :         }
    5632           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5633           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2))) ||
    5634           0 :                 (sid3 && !is_bat_nil(*sid3) && !(ss = BATdescriptor(*sid3)))) {
    5635           0 :                 msg = createException(MAL, "batstr.locate2",
    5636             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5637           0 :                 goto bailout;
    5638             :         }
    5639           0 :         canditer_init(&ci1, left, ls);
    5640           0 :         canditer_init(&ci2, right, rs);
    5641           0 :         canditer_init(&ci3, start, ss);
    5642           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5643           0 :                 || ci2.hseq != ci3.hseq) {
    5644           0 :                 msg = createException(MAL, "batstr.locate2",
    5645             :                                                           ILLEGAL_ARGUMENT
    5646             :                                                           " Requires bats of identical size");
    5647           0 :                 goto bailout;
    5648             :         }
    5649           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5650           0 :                 msg = createException(MAL, "batstr.locate2",
    5651             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5652           0 :                 goto bailout;
    5653             :         }
    5654             : 
    5655           0 :         off1 = left->hseqbase;
    5656           0 :         off2 = right->hseqbase;
    5657           0 :         off3 = start->hseqbase;
    5658           0 :         lefti = bat_iterator(left);
    5659           0 :         righti = bat_iterator(right);
    5660           0 :         starti = bat_iterator(start);
    5661           0 :         svals = starti.base;
    5662           0 :         vals = Tloc(bn, 0);
    5663           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5664           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5665           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5666           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5667           0 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5668           0 :                         const char *x = BUNtvar(lefti, p1);
    5669           0 :                         const char *y = BUNtvar(righti, p2);
    5670           0 :                         z = svals[p3];
    5671             : 
    5672           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5673           0 :                                 vals[i] = int_nil;
    5674           0 :                                 nils = true;
    5675             :                         } else {
    5676           0 :                                 vals[i] = str_locate2(x, y, z);
    5677             :                         }
    5678             :                 }
    5679             :         } else {
    5680           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5681           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5682           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5683           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5684           0 :                         const char *x = BUNtvar(lefti, p1);
    5685           0 :                         const char *y = BUNtvar(righti, p2);
    5686           0 :                         z = svals[p3];
    5687             : 
    5688           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5689           0 :                                 vals[i] = int_nil;
    5690           0 :                                 nils = true;
    5691             :                         } else {
    5692           0 :                                 vals[i] = str_locate2(x, y, z);
    5693             :                         }
    5694             :                 }
    5695             :         }
    5696           0 :         bat_iterator_end(&starti);
    5697           0 :         bat_iterator_end(&lefti);
    5698           0 :         bat_iterator_end(&righti);
    5699           0 :   bailout:
    5700           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5701           0 :         unfix_inputs(6, left, ls, right, rs, start, ss);
    5702           0 :         return msg;
    5703             : }
    5704             : 
    5705             : static str
    5706          12 : BATSTRasciify(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5707             : {
    5708             : #ifdef HAVE_ICONV
    5709          12 :         (void) cntxt;
    5710          12 :         (void) mb;
    5711          12 :         bat *rid = getArgReference_bat(stk, pci, 0),
    5712          12 :                         *bid = getArgReference_bat(stk, pci, 1),
    5713          12 :                         *sid = pci->argc == 2 ? NULL : getArgReference_bat(stk, pci, 2);
    5714          12 :         BAT *b = NULL, *bs = NULL, *bn = NULL;
    5715          12 :         BATiter bi;
    5716          12 :         struct canditer ci = { 0 };
    5717          12 :         oid off;
    5718          12 :         bool nils = false, dense = false;
    5719          12 :         size_t prev_out_len = 0, in_len = 0, out_len = 0;
    5720          12 :         str s = NULL, out = NULL, in = NULL, msg = MAL_SUCCEED;
    5721          12 :         iconv_t cd;
    5722          12 :         const str f = "UTF-8", t = "ASCII//TRANSLIT";
    5723             : 
    5724             :         /* man iconv; /TRANSLIT */
    5725          12 :         if ((cd = iconv_open(t, f)) == (iconv_t) (-1))
    5726           0 :                 throw(MAL, "batstr.asciify", "ICONV: cannot convert from (%s) to (%s).",
    5727             :                           f, t);
    5728             : 
    5729          12 :         if (!(b = BATdescriptor(*bid))) {
    5730           0 :                 iconv_close(cd);
    5731           0 :                 throw(MAL, "batstr.asciify", RUNTIME_OBJECT_MISSING);
    5732             :         }
    5733             : 
    5734          12 :         if (sid && !is_bat_nil(*sid) && !(bs = BATdescriptor(*sid))) {
    5735           0 :                 iconv_close(cd);
    5736           0 :                 BBPreclaim(b);
    5737           0 :                 throw(MAL, "batstr.asciify", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5738             :         }
    5739             : 
    5740          12 :         canditer_init(&ci, b, bs);
    5741             : 
    5742          12 :         if ((bn = COLnew(ci.hseq, TYPE_str, ci.ncand, TRANSIENT)) == NULL) {
    5743           0 :                 iconv_close(cd);
    5744           0 :                 BBPreclaim(b);
    5745           0 :                 BBPreclaim(bs);
    5746           0 :                 throw(MAL, "batstr.asciify", GDK_EXCEPTION);
    5747             :         }
    5748             : 
    5749          12 :         off = b->hseqbase;
    5750          12 :         bi = bat_iterator(b);
    5751             : 
    5752          12 :         if ((s = out = GDKmalloc(64 * 1024)) == NULL) {
    5753           0 :                 msg = createException(MAL, "batstr.asciify", MAL_MALLOC_FAIL);
    5754           0 :                 goto exit;
    5755             :         }
    5756          12 :         prev_out_len = 64 * 1024;
    5757             : 
    5758          12 :         dense = ci.tpe == cand_dense ? true : false;
    5759        4492 :         for (BUN i = 0; i < ci.ncand; i++) {
    5760        4480 :                 oid p = dense ? (canditer_next_dense(&ci) - off) : (canditer_next(&ci) -
    5761             :                                                                                                                         off);
    5762        4480 :                 in = BUNtvar(bi, p);
    5763        4468 :                 if (strNil(in)) {
    5764           0 :                         if (BUNappend(bn, str_nil, false) != GDK_SUCCEED) {
    5765           0 :                                 msg = createException(MAL, "batstr.asciify",
    5766             :                                                                           "BUNappend failed.");
    5767           0 :                                 goto exit;
    5768             :                         }
    5769           0 :                         nils = true;
    5770           0 :                         continue;
    5771             :                 }
    5772             :                 /* over sized as single utf8 symbols change into multiple ascii characters */
    5773        4468 :                 in_len = strlen(in), out_len = in_len * 4;
    5774        4468 :                 if (out_len > prev_out_len) {
    5775           0 :                         if ((out = GDKrealloc(s, out_len)) == NULL) {
    5776           0 :                                 msg = createException(MAL, "batstr.asciify", MAL_MALLOC_FAIL);
    5777           0 :                                 goto exit;
    5778             :                         }
    5779           0 :                         prev_out_len = out_len;
    5780           0 :                         s = out;
    5781             :                 }
    5782        4468 :                 out = s;
    5783        4468 :                 if (iconv(cd, &in, &in_len, &out, &out_len) == (size_t) -1) {
    5784           0 :                         msg = createException(MAL, "batstr.asciify",
    5785             :                                                                   "ICONV: string conversion failed");
    5786           0 :                         goto exit;
    5787             :                 }
    5788        4782 :                 *out = '\0';
    5789        4782 :                 if (BUNappend(bn, s, false) != GDK_SUCCEED) {
    5790           0 :                         msg = createException(MAL, "batstr.asciify", GDK_EXCEPTION);
    5791           0 :                         goto exit;
    5792             :                 }
    5793             :         }
    5794             : 
    5795          12 :   exit:
    5796          12 :         GDKfree(s);
    5797          12 :         bat_iterator_end(&bi);
    5798          12 :         iconv_close(cd);
    5799          12 :         finalize_output(rid, bn, msg, nils, ci.ncand);
    5800          12 :         unfix_inputs(2, b, bs);
    5801          12 :         return msg;
    5802             : #else
    5803             :         throw(MAL, "batstr.asciify", "ICONV library not available.");
    5804             : #endif
    5805             : }
    5806             : 
    5807             : #include "mel.h"
    5808             : mel_func batstr_init_funcs[] = {
    5809             :         pattern("batstr", "length", STRbatLength, false, "Return the length of a string.", args(1,2, batarg("",int),batarg("s",str))),
    5810             :         pattern("batstr", "length", STRbatLength, false, "Return the length of a string.", args(1,3, batarg("",int),batarg("s",str),batarg("s",oid))),
    5811             :         pattern("batstr", "nbytes", STRbatBytes, false, "Return the string length in bytes.", args(1,2, batarg("",int),batarg("s",str))),
    5812             :         pattern("batstr", "nbytes", STRbatBytes, false, "Return the string length in bytes.", args(1,3, batarg("",int),batarg("s",str),batarg("s",oid))),
    5813             :         pattern("batstr", "toLower", STRbatLower, false, "Convert a string to lower case.", args(1,2, batarg("",str),batarg("s",str))),
    5814             :         pattern("batstr", "toLower", STRbatLower, false, "Convert a string to lower case.", args(1,3, batarg("",str),batarg("s",str),batarg("s",oid))),
    5815             :         pattern("batstr", "toUpper", STRbatUpper, false, "Convert a string to upper case.", args(1,2, batarg("",str),batarg("s",str))),
    5816             :         pattern("batstr", "toUpper", STRbatUpper, false, "Convert a string to upper case.", args(1,3, batarg("",str),batarg("s",str),batarg("s",oid))),
    5817             :         pattern("batstr", "trim", STRbatStrip, false, "Strip whitespaces around a string.", args(1,2, batarg("",str),batarg("s",str))),
    5818             :         pattern("batstr", "trim", STRbatStrip, false, "Strip whitespaces around a string.", args(1,3, batarg("",str),batarg("s",str),batarg("s",oid))),
    5819             :         pattern("batstr", "ltrim", STRbatLtrim, false, "Strip whitespaces from start of a string.", args(1,2, batarg("",str),batarg("s",str))),
    5820             :         pattern("batstr", "ltrim", STRbatLtrim, false, "Strip whitespaces from start of a string.", args(1,3, batarg("",str),batarg("s",str),batarg("s",oid))),
    5821             :         pattern("batstr", "rtrim", STRbatRtrim, false, "Strip whitespaces from end of a string.", args(1,2, batarg("",str),batarg("s",str))),
    5822             :         pattern("batstr", "rtrim", STRbatRtrim, false, "Strip whitespaces from end of a string.", args(1,3, batarg("",str),batarg("s",str),batarg("s",oid))),
    5823             :         pattern("batstr", "trim2", STRbatStrip2_const, false, "Strip characters in the second string around the first strings.", args(1,3, batarg("",str),batarg("s",str),arg("s2",str))),
    5824             :         pattern("batstr", "trim2", STRbatStrip2_const, false, "Strip characters in the second string around the first strings.", args(1,4, batarg("",str),batarg("s",str),arg("s2",str),batarg("s",oid))),
    5825             :         pattern("batstr", "trim2", STRbatStrip2_1st_const, false, "Strip characters in the second string around the first strings.", args(1,3, batarg("",str),arg("s",str),batarg("s2",str))),
    5826             :         pattern("batstr", "trim2", STRbatStrip2_1st_const, false, "Strip characters in the second string around the first strings.", args(1,4, batarg("",str),arg("s",str),batarg("s2",str),batarg("s",oid))),
    5827             :         pattern("batstr", "ltrim2", STRbatLtrim2_const, false, "Strip characters in the second string from start of the first strings.", args(1,3, batarg("",str),batarg("s",str),arg("s2",str))),
    5828             :         pattern("batstr", "ltrim2", STRbatLtrim2_const, false, "Strip characters in the second string from start of the first strings.", args(1,4, batarg("",str),batarg("s",str),arg("s2",str),batarg("s",oid))),
    5829             :         pattern("batstr", "ltrim2", STRbatLtrim2_1st_const, false, "Strip characters in the second string from start of the first strings.", args(1,3, batarg("",str),arg("s",str),batarg("s2",str))),
    5830             :         pattern("batstr", "ltrim2", STRbatLtrim2_1st_const, false, "Strip characters in the second string from start of the first strings.", args(1,4, batarg("",str),arg("s",str),batarg("s2",str),batarg("s",oid))),
    5831             :         pattern("batstr", "rtrim2", STRbatRtrim2_const, false, "Strip characters in the second string from end of the first strings.", args(1,3, batarg("",str),batarg("s",str),arg("s2",str))),
    5832             :         pattern("batstr", "rtrim2", STRbatRtrim2_const, false, "Strip characters in the second string from end of the first strings.", args(1,4, batarg("",str),batarg("s",str),arg("s2",str),batarg("s",oid))),
    5833             :         pattern("batstr", "rtrim2", STRbatRtrim2_1st_const, false, "Strip characters in the second string from end of the first strings.", args(1,3, batarg("",str),arg("s",str),batarg("s2",str))),
    5834             :         pattern("batstr", "rtrim2", STRbatRtrim2_1st_const, false, "Strip characters in the second string from end of the first strings.", args(1,4, batarg("",str),arg("s",str),batarg("s2",str),batarg("s",oid))),
    5835             :         pattern("batstr", "trim2", STRbatStrip2_bat, false, "Strip characters in the second strings around the first strings.", args(1,3, batarg("",str),batarg("s",str),batarg("s2",str))),
    5836             :         pattern("batstr", "trim2", STRbatStrip2_bat, false, "Strip characters in the second strings around the first strings.", args(1,5, batarg("",str),batarg("s",str),batarg("s2",str),batarg("s1",oid),batarg("s2",oid))),
    5837             :         pattern("batstr", "ltrim2", STRbatLtrim2_bat, false, "Strip characters in the second strings from start of the first strings.", args(1,3, batarg("",str),batarg("s",str),batarg("s2",str))),
    5838             :         pattern("batstr", "ltrim2", STRbatLtrim2_bat, false, "Strip characters in the second strings from start of the first strings.", args(1,5, batarg("",str),batarg("s",str),batarg("s2",str),batarg("s1",oid),batarg("s2",oid))),
    5839             :         pattern("batstr", "rtrim2", STRbatRtrim2_bat, false, "Strip characters in the second strings from end of the first strings.", args(1,3, batarg("",str),batarg("s",str),batarg("s2",str))),
    5840             :         pattern("batstr", "rtrim2", STRbatRtrim2_bat, false, "Strip characters in the second strings from end of the first strings.", args(1,5, batarg("",str),batarg("s",str),batarg("s2",str),batarg("s1",oid),batarg("s2",oid))),
    5841             :         pattern("batstr", "lpad", STRbatLpad_const, false, "Prepend whitespaces to the strings to reach the given length. Truncate the strings on the right if their lengths is larger than the given length.", args(1,3, batarg("",str),batarg("s",str),arg("n",int))),
    5842             :         pattern("batstr", "lpad", STRbatLpad_const, false, "Prepend whitespaces to the strings to reach the given length. Truncate the strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),batarg("s",oid))),
    5843             :         pattern("batstr", "rpad", STRbatRpad_const, false, "Append whitespaces to the strings to reach the given length. Truncate the strings on the right if their lengths is larger than the given length.", args(1,3, batarg("",str),batarg("s",str),arg("n",int))),
    5844             :         pattern("batstr", "rpad", STRbatRpad_const, false, "Append whitespaces to the strings to reach the given length. Truncate the strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),batarg("s",oid))),
    5845             :         pattern("batstr", "lpad", STRbatLpad_1st_const, false, "Prepend whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,3, batarg("",str),arg("s",str),batarg("n",int))),
    5846             :         pattern("batstr", "lpad", STRbatLpad_1st_const, false, "Prepend whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),arg("s",str),batarg("n",int),batarg("s",oid))),
    5847             :         pattern("batstr", "rpad", STRbatRpad_1st_const, false, "Append whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,3, batarg("",str),arg("s",str),batarg("n",int))),
    5848             :         pattern("batstr", "rpad", STRbatRpad_1st_const, false, "Append whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),arg("s",str),batarg("n",int),batarg("s",oid))),
    5849             :         pattern("batstr", "lpad", STRbatLpad_bat, false, "Prepend whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,3, batarg("",str),batarg("s",str),batarg("n",int))),
    5850             :         pattern("batstr", "lpad", STRbatLpad_bat, false, "Prepend whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,5, batarg("",str),batarg("s",str),batarg("n",int),batarg("s1",oid),batarg("s2",oid))),
    5851             :         pattern("batstr", "rpad", STRbatRpad_bat, false, "Append whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,3, batarg("",str),batarg("s",str),batarg("n",int))),
    5852             :         pattern("batstr", "rpad", STRbatRpad_bat, false, "Append whitespaces to the strings to reach the given lengths. Truncate the strings on the right if their lengths is larger than the given lengths.", args(1,5, batarg("",str),batarg("s",str),batarg("n",int),batarg("s1",oid),batarg("s2",oid))),
    5853             :         pattern("batstr", "lpad3", STRbatLpad3_const_const, false, "Prepend the second string to the first strings to reach the given length. Truncate the first strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),arg("s2",str))),
    5854             :         pattern("batstr", "rpad3", STRbatRpad3_const_const, false, "Append the second string to the first strings to reach the given length. Truncate the first strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),arg("s2",str))),
    5855             :         pattern("batstr", "lpad3", STRbatLpad3_bat_const, false, "Prepend the second string to the first strings to reach the given lengths. Truncate the first strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),batarg("s",str),batarg("n",int),arg("s2",str))),
    5856             :         pattern("batstr", "rpad3", STRbatRpad3_bat_const, false, "Append the second string to the first strings to reach the given lengths. Truncate the first strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),batarg("s",str),batarg("n",int),arg("s2",str))),
    5857             :         pattern("batstr", "lpad3", STRbatLpad3_const_bat, false, "Prepend the second strings to the first strings to reach the given length. Truncate the first strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),batarg("s2",str))),
    5858             :         pattern("batstr", "rpad3", STRbatRpad3_const_bat, false, "Append the second strings to the first strings to reach the given length. Truncate the first strings on the right if their lengths is larger than the given length.", args(1,4, batarg("",str),batarg("s",str),arg("n",int),batarg("s2",str))),
    5859             :         pattern("batstr", "lpad3", STRbatLpad3_bat_bat, false, "Prepend the second strings to the first strings to reach the given lengths. Truncate the first strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),batarg("s",str),batarg("n",int),batarg("s2",str))),
    5860             :         pattern("batstr", "rpad3", STRbatRpad3_bat_bat, false, "Append the second strings to the first strings to reach the given lengths. Truncate the first strings on the right if their lengths is larger than the given lengths.", args(1,4, batarg("",str),batarg("s",str),batarg("n",int),batarg("s2",str))),
    5861             :         pattern("batstr", "startswith", BATSTRstarts_with, false, "Check if bat string starts with bat substring.", args(1,3, batarg("",bit),batarg("s",str),batarg("prefix",str))),
    5862             :         pattern("batstr", "startswith", BATSTRstarts_with, false, "Check if bat string starts with bat substring, icase flag.", args(1,4, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit))),
    5863             :         pattern("batstr", "startswith", BATSTRstarts_with, false, "Check if bat string starts with bat substring (with CLs).", args(1,5, batarg("",bit),batarg("s",str),batarg("prefix",str),batarg("s1",oid),batarg("s2",oid))),
    5864             :         pattern("batstr", "startswith", BATSTRstarts_with, false, "Check if bat string starts with bat substring (with CLs) + icase flag.", args(1,6, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s1",oid),batarg("s2",oid))),
    5865             :         pattern("batstr", "startswith", BATSTRstarts_with_cst, false, "Check if bat string starts with substring.", args(1,3, batarg("",bit),batarg("s",str),arg("prefix",str))),
    5866             :         pattern("batstr", "startswith", BATSTRstarts_with_cst, false, "Check if bat string starts with substring, icase flag.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit))),
    5867             :         pattern("batstr", "startswith", BATSTRstarts_with_cst, false, "Check if bat string(with CL) starts with substring.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),batarg("s",oid))),
    5868             :         pattern("batstr", "startswith", BATSTRstarts_with_cst, false, "Check if bat string(with CL) starts with substring + icase flag.", args(1,5, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5869             :         pattern("batstr", "startswith", BATSTRstarts_with_strcst, false, "Check if string starts with bat substring.", args(1,3, batarg("",bit),arg("s",str),batarg("prefix",str))),
    5870             :         pattern("batstr", "startswith", BATSTRstarts_with_strcst, false, "Check if string starts with bat substring + icase flag.", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit))),
    5871             :         pattern("batstr", "startswith", BATSTRstarts_with_strcst, false, "Check if string starts with bat substring(with CL).", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),batarg("s",oid))),
    5872             :         pattern("batstr", "startswith", BATSTRstarts_with_strcst, false, "Check if string starts with bat substring(with CL) + icase flag.", args(1,5, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5873             :         pattern("batstr", "endswith", BATSTRends_with, false, "Check if bat string ends with bat substring.", args(1,3, batarg("",bit),batarg("s",str),batarg("prefix",str))),
    5874             :         pattern("batstr", "endswith", BATSTRends_with, false, "Check if bat string ends with bat substring, icase flag.", args(1,4, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit))),
    5875             :         pattern("batstr", "endswith", BATSTRends_with, false, "Check if bat string ends with bat substring (with CLs).", args(1,5, batarg("",bit),batarg("s",str),batarg("prefix",str),batarg("s1",oid),batarg("s2",oid))),
    5876             :         pattern("batstr", "endswith", BATSTRends_with, false, "Check if bat string ends with bat substring (with CLs) + icase flag.", args(1,6, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s1",oid),batarg("s2",oid))),
    5877             :         pattern("batstr", "endswith", BATSTRends_with_cst, false, "Check if bat string ends with substring.", args(1,3, batarg("",bit),batarg("s",str),arg("prefix",str))),
    5878             :         pattern("batstr", "endswith", BATSTRends_with_cst, false, "Check if bat string ends with substring, icase flag.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit))),
    5879             :         pattern("batstr", "endswith", BATSTRends_with_cst, false, "Check if bat string(with CL) ends with substring.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),batarg("s",oid))),
    5880             :         pattern("batstr", "endswith", BATSTRends_with_cst, false, "Check if bat string(with CL) ends with substring + icase flag.", args(1,5, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5881             :         pattern("batstr", "endswith", BATSTRends_with_strcst, false, "Check if string ends with bat substring.", args(1,3, batarg("",bit),arg("s",str),batarg("prefix",str))),
    5882             :         pattern("batstr", "endswith", BATSTRends_with_strcst, false, "Check if string ends with bat substring + icase flag.", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit))),
    5883             :         pattern("batstr", "endswith", BATSTRends_with_strcst, false, "Check if string ends with bat substring(with CL).", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),batarg("s",oid))),
    5884             :         pattern("batstr", "endswith", BATSTRends_with_strcst, false, "Check if string ends with bat substring(with CL) + icase flag.", args(1,5, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5885             :         pattern("batstr", "contains", BATSTRcontains, false, "Check if bat string haystack contains bat string needle.", args(1,3, batarg("",bit),batarg("s",str),batarg("prefix",str))),
    5886             :         pattern("batstr", "contains", BATSTRcontains, false, "Check if bat string haystack contains bat string needle, icase flag.", args(1,4, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit))),
    5887             :         pattern("batstr", "contains", BATSTRcontains, false, "Check if bat string haystack contains bat string needle (with CLs).", args(1,5, batarg("",bit),batarg("s",str),batarg("prefix",str),batarg("s1",oid),batarg("s2",oid))),
    5888             :         pattern("batstr", "contains", BATSTRcontains, false, "Check if bat string haystack contains bat string needle (with CLs) + icase flag.", args(1,6, batarg("",bit),batarg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s1",oid),batarg("s2",oid))),
    5889             :         pattern("batstr", "contains", BATSTRcontains_cst, false, "Check if bat string haystack contains string needle.", args(1,3, batarg("",bit),batarg("s",str),arg("prefix",str))),
    5890             :         pattern("batstr", "contains", BATSTRcontains_cst, false, "Check if bat string haystack contains string needle, icase flag.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit))),
    5891             :         pattern("batstr", "contains", BATSTRcontains_cst, false, "Check if bat string haystack contains string needle (with CL) ends with substring.", args(1,4, batarg("",bit),batarg("s",str),arg("prefix",str),batarg("s",oid))),
    5892             :         pattern("batstr", "contains", BATSTRcontains_cst, false, "Check if bat string haystack contains string needle (with CL) ends with substring + icase flag.", args(1,5, batarg("",bit),batarg("s",str),arg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5893             :         pattern("batstr", "contains", BATSTRcontains_strcst, false, "Check if string haystack contains bat string needle.", args(1,3, batarg("",bit),arg("s",str),batarg("prefix",str))),
    5894             :         pattern("batstr", "contains", BATSTRcontains_strcst, false, "Check if string haystack contains bat string needle + icase flag.", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit))),
    5895             :         pattern("batstr", "contains", BATSTRcontains_strcst, false, "Check if string haystack contains bat string needle (with CL).", args(1,4, batarg("",bit),arg("s",str),batarg("prefix",str),batarg("s",oid))),
    5896             :         pattern("batstr", "contains", BATSTRcontains_strcst, false, "Check if string haystack contains bat string needle (with CL) + icase flag.", args(1,5, batarg("",bit),arg("s",str),batarg("prefix",str),arg("icase",bit),batarg("s",oid))),
    5897             :         pattern("batstr", "splitpart", STRbatsplitpart, false, "Split string on delimiter. Returns\ngiven field (counting from one.)", args(1,4, batarg("",str),batarg("s",str),batarg("needle",str),batarg("field",int))),
    5898             :         pattern("batstr", "splitpart", STRbatsplitpartcst, false, "Split string on delimiter. Returns\ngiven field (counting from one.)", args(1,4, batarg("",str),batarg("s",str),arg("needle",str),arg("field",int))),
    5899             :         pattern("batstr", "splitpart", STRbatsplitpart_needlecst, false, "Split string on delimiter. Returns\ngiven field (counting from one.)", args(1,4, batarg("",str),batarg("s",str),arg("needle",str),batarg("field",int))),
    5900             :         pattern("batstr", "splitpart", STRbatsplitpart_fieldcst, false, "Split string on delimiter. Returns\ngiven field (counting from one.)", args(1,4, batarg("",str),batarg("s",str),batarg("needle",str),arg("field",int))),
    5901             :         pattern("batstr", "search", BATSTRstr_search, false, "Search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),batarg("s",str),batarg("c",str))),
    5902             :         pattern("batstr", "search", BATSTRstr_search, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,4, batarg("",int),batarg("s",str),batarg("c",str),arg("icase",bit))),
    5903             :         pattern("batstr", "search", BATSTRstr_search, false, "Search for a substring. Returns position, -1 if not found.", args(1,5, batarg("",int),batarg("s",str),batarg("c",str),batarg("s1",oid),batarg("s2",oid))),
    5904             :         pattern("batstr", "search", BATSTRstr_search, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,6, batarg("",int),batarg("s",str),batarg("c",str),arg("icase",bit),batarg("s1",oid),batarg("s2",oid))),
    5905             :         pattern("batstr", "search", BATSTRstr_search_cst, false, "Search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),batarg("s",str),arg("c",str))),
    5906             :         pattern("batstr", "search", BATSTRstr_search_cst, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,4, batarg("",int),batarg("s",str),arg("c",str),arg("icase",bit))),
    5907             :         pattern("batstr", "search", BATSTRstr_search_cst, false, "Search for a substring. Returns position, -1 if not found.", args(1,4, batarg("",int),batarg("s",str),arg("c",str),batarg("s",oid))),
    5908             :         pattern("batstr", "search", BATSTRstr_search_cst, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,5, batarg("",int),batarg("s",str),arg("c",str),arg("icase",bit),batarg("s",oid))),
    5909             :         pattern("batstr", "search", BATSTRstr_search_strcst, false, "Search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),arg("s",str),batarg("c",str))),
    5910             :         pattern("batstr", "search", BATSTRstr_search_strcst, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,4, batarg("",int),arg("s",str),batarg("c",str),arg("icase",bit))),
    5911             :         pattern("batstr", "search", BATSTRstr_search_strcst, false, "Search for a substring. Returns position, -1 if not found.", args(1,4, batarg("",int),arg("s",str),batarg("c",str),batarg("s",oid))),
    5912             :         pattern("batstr", "search", BATSTRstr_search_strcst, false, "Search for a substring. Returns position, -1 if not found, icase flag.", args(1,5, batarg("",int),arg("s",str),batarg("c",str),arg("icase",bit),batarg("s",oid))),
    5913             :         pattern("batstr", "r_search", BATSTRrevstr_search, false, "Reverse search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),batarg("s",str),batarg("c",str))),
    5914             :         pattern("batstr", "r_search", BATSTRrevstr_search, false, "Reverse search for a substring + icase flag. Returns position, -1 if not found.", args(1,4, batarg("",int),batarg("s",str),batarg("c",str),arg("icase",bit))),
    5915             :         pattern("batstr", "r_search", BATSTRrevstr_search, false, "Reverse search for a substring (with CLs). Returns position, -1 if not found.", args(1,5, batarg("",int),batarg("s",str),batarg("c",str),batarg("s1",oid),batarg("s2",oid))),
    5916             :         pattern("batstr", "r_search", BATSTRrevstr_search, false, "Reverse search for a substring (with CLs) + icase flag. Returns position, -1 if not found.", args(1,6, batarg("",int),batarg("s",str),batarg("c",str),arg("icase",bit),batarg("s1",oid),batarg("s2",oid))),
    5917             :         pattern("batstr", "r_search", BATSTRrevstr_search_cst, false, "Reverse search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),batarg("s",str),arg("c",str))),
    5918             :         pattern("batstr", "r_search", BATSTRrevstr_search_cst, false, "Reverse search for a substring + icase flag. Returns position, -1 if not found.", args(1,4, batarg("",int),batarg("s",str),arg("c",str),arg("icase",bit))),
    5919             :         pattern("batstr", "r_search", BATSTRrevstr_search_cst, false, "Reverse search for a substring (with CL). Returns position, -1 if not found.", args(1,4, batarg("",int),batarg("s",str),arg("c",str),batarg("s",oid))),
    5920             :         pattern("batstr", "r_search", BATSTRrevstr_search_cst, false, "Reverse search for a substring (with CL) + icase flag. Returns position, -1 if not found.", args(1,5, batarg("",int),batarg("s",str),arg("c",str),arg("icase",bit),batarg("s",oid))),
    5921             :         pattern("batstr", "r_search", BATSTRrevstr_search_strcst, false, "Reverse search for a substring. Returns position, -1 if not found.", args(1,3, batarg("",int),arg("s",str),batarg("c",str))),
    5922             :         pattern("batstr", "r_search", BATSTRrevstr_search_strcst, false, "Reverse search for a substring + icase flag. Returns position, -1 if not found.", args(1,4, batarg("",int),arg("s",str),batarg("c",str),arg("icase",bit))),
    5923             :         pattern("batstr", "r_search", BATSTRrevstr_search_strcst, false, "Reverse search for a substring (with CL). Returns position, -1 if not found.", args(1,4, batarg("",int),arg("s",str),batarg("c",str),batarg("s",oid))),
    5924             :         pattern("batstr", "r_search", BATSTRrevstr_search_strcst, false, "Reverse search for a substring (with CL) + icase flag. Returns position, -1 if not found.", args(1,5, batarg("",int),arg("s",str),batarg("c",str),arg("icase",bit),batarg("s",oid))),
    5925             :         pattern("batstr", "string", STRbatTail, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,3, batarg("",str),batarg("b",str),batarg("offset",int))),
    5926             :         pattern("batstr", "string", STRbatTail, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,5, batarg("",str),batarg("b",str),batarg("offset",int),batarg("s1",oid),batarg("s2",oid))),
    5927             :         pattern("batstr", "string", STRbatTailcst, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,3, batarg("",str),batarg("b",str),arg("offset",int))),
    5928             :         pattern("batstr", "string", STRbatTailcst, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,4, batarg("",str),batarg("b",str),arg("offset",int),batarg("s",oid))),
    5929             :         pattern("batstr", "string", STRbatTail_strcst, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,3, batarg("",str),arg("b",str),batarg("offset",int))),
    5930             :         pattern("batstr", "string", STRbatTail_strcst, false, "Return the tail s[offset..n] of a string s[0..n].", args(1,4, batarg("",str),arg("b",str),batarg("offset",int),batarg("s",oid))),
    5931             :         pattern("batstr", "ascii", STRbatAscii, false, "Return unicode of head of string", args(1,2, batarg("",int),batarg("s",str))),
    5932             :         pattern("batstr", "ascii", STRbatAscii, false, "Return unicode of head of string", args(1,3, batarg("",int),batarg("s",str),batarg("s",oid))),
    5933             :         pattern("batstr", "substring", STRbatsubstringTail, false, "Extract the tail of a string", args(1,3, batarg("",str),batarg("s",str),batarg("start",int))),
    5934             :         pattern("batstr", "substring", STRbatsubstringTail, false, "Extract the tail of a string", args(1,5, batarg("",str),batarg("s",str),batarg("start",int),batarg("s1",oid),batarg("s2",oid))),
    5935             :         pattern("batstr", "substring", STRbatsubstringTailcst, false, "Extract the tail of a string", args(1,3, batarg("",str),batarg("s",str),arg("start",int))),
    5936             :         pattern("batstr", "substring", STRbatsubstringTailcst, false, "Extract the tail of a string", args(1,4, batarg("",str),batarg("s",str),arg("start",int),batarg("s",oid))),
    5937             :         pattern("batstr", "substring", STRbatsubstringTail_strcst, false, "Extract the tail of a string", args(1,3, batarg("",str),arg("s",str),batarg("start",int))),
    5938             :         pattern("batstr", "substring", STRbatsubstringTail_strcst, false, "Extract the tail of a string", args(1,4, batarg("",str),arg("s",str),batarg("start",int),batarg("s",oid))),
    5939             :         pattern("batstr", "substring3", STRbatsubstring, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),batarg("s",str),batarg("start",int),batarg("index",int))),
    5940             :         pattern("batstr", "substring3", STRbatsubstring, false, "Substring extraction using [start,start+length]", args(1,7, batarg("",str),batarg("s",str),batarg("start",int),batarg("index",int),batarg("s1",oid),batarg("s2",oid),batarg("s3",oid))),
    5941             :         pattern("batstr", "substring3", STRbatsubstring_2nd_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),batarg("s",str),arg("start",int),arg("index",int))),
    5942             :         pattern("batstr", "substring3", STRbatsubstring_2nd_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,5, batarg("",str),batarg("s",str),arg("start",int),arg("index",int),batarg("s",oid))),
    5943             :         pattern("batstr", "substring3", STRbatsubstring_2nd_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),batarg("s",str),arg("start",int),batarg("index",int))),
    5944             :         pattern("batstr", "substring3", STRbatsubstring_2nd_cst, false, "Substring extraction using [start,start+length]", args(1,6, batarg("",str),batarg("s",str),arg("start",int),batarg("index",int),batarg("s1",oid),batarg("s2",oid))),
    5945             :         pattern("batstr", "substring3", STRbatsubstring_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),batarg("s",str),batarg("start",int),arg("index",int))),
    5946             :         pattern("batstr", "substring3", STRbatsubstring_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,6, batarg("",str),batarg("s",str),batarg("start",int),arg("index",int),batarg("s1",oid),batarg("s2",oid))),
    5947             :         pattern("batstr", "substring3", STRbatsubstring_1st_2nd_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),arg("s",str),arg("start",int),batarg("index",int))),
    5948             :         pattern("batstr", "substring3", STRbatsubstring_1st_2nd_cst, false, "Substring extraction using [start,start+length]", args(1,5, batarg("",str),arg("s",str),arg("start",int),batarg("index",int),batarg("s",oid))),
    5949             :         pattern("batstr", "substring3", STRbatsubstring_1st_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),arg("s",str),batarg("start",int),arg("index",int))),
    5950             :         pattern("batstr", "substring3", STRbatsubstring_1st_3rd_cst, false, "Substring extraction using [start,start+length]", args(1,5, batarg("",str),arg("s",str),batarg("start",int),arg("index",int),batarg("s",oid))),
    5951             :         pattern("batstr", "substring3", STRbatsubstring_1st_cst, false, "Substring extraction using [start,start+length]", args(1,4, batarg("",str),arg("s",str),batarg("start",int),batarg("index",int))),
    5952             :         pattern("batstr", "substring3", STRbatsubstring_1st_cst, false, "Substring extraction using [start,start+length]", args(1,6, batarg("",str),arg("s",str),batarg("start",int),batarg("index",int),batarg("s1",oid),batarg("s2",oid))),
    5953             :         pattern("batstr", "unicode", STRbatFromWChr, false, "convert a unicode to a character.", args(1,2, batarg("",str),batarg("wchar",int))),
    5954             :         pattern("batstr", "unicode", STRbatFromWChr, false, "convert a unicode to a character.", args(1,3, batarg("",str),batarg("wchar",int),batarg("s",oid))),
    5955             :         pattern("batstr", "unicodeAt", STRbatWChrAt, false, "get a unicode character (as an int) from a string position.", args(1,3, batarg("",int),batarg("s",str),batarg("index",int))),
    5956             :         pattern("batstr", "unicodeAt", STRbatWChrAt, false, "get a unicode character (as an int) from a string position.", args(1,5, batarg("",int),batarg("s",str),batarg("index",int),batarg("s1",oid),batarg("s2",oid))),
    5957             :         pattern("batstr", "unicodeAt", STRbatWChrAtcst, false, "get a unicode character (as an int) from a string position.", args(1,3, batarg("",int),batarg("s",str),arg("index",int))),
    5958             :         pattern("batstr", "unicodeAt", STRbatWChrAtcst, false, "get a unicode character (as an int) from a string position.", args(1,4, batarg("",int),batarg("s",str),arg("index",int),batarg("s",oid))),
    5959             :         pattern("batstr", "unicodeAt", STRbatWChrAt_strcst, false, "get a unicode character (as an int) from a string position.", args(1,3, batarg("",int),arg("s",str),batarg("index",int))),
    5960             :         pattern("batstr", "unicodeAt", STRbatWChrAt_strcst, false, "get a unicode character (as an int) from a string position.", args(1,4, batarg("",int),arg("s",str),batarg("index",int),batarg("s",oid))),
    5961             :         pattern("batstr", "substitute", STRbatSubstitute, false, "Substitute first occurrence of 'src' by\n'dst'. Iff repeated = true this is\nrepeated while 'src' can be found in the\nresult string. In order to prevent\nrecursion and result strings of unlimited\nsize, repeating is only done iff src is\nnot a substring of dst.", args(1,5, batarg("",str),batarg("s",str),batarg("src",str),batarg("dst",str),batarg("rep",bit))),
    5962             :         pattern("batstr", "substitute", STRbatSubstitutecst, false, "Substitute first occurrence of 'src' by\n'dst'. Iff repeated = true this is\nrepeated while 'src' can be found in the\nresult string. In order to prevent\nrecursion and result strings of unlimited\nsize, repeating is only done iff src is\nnot a substring of dst.", args(1,5, batarg("",str),batarg("s",str),arg("src",str),arg("dst",str),arg("rep",bit))),
    5963             :         pattern("batstr", "stringleft", STRbatprefix, false, "", args(1,3, batarg("",str),batarg("s",str),batarg("l",int))),
    5964             :         pattern("batstr", "stringleft", STRbatprefix, false, "", args(1,5, batarg("",str),batarg("s",str),batarg("l",int),batarg("s1",oid),batarg("s2",oid))),
    5965             :         pattern("batstr", "stringleft", STRbatprefixcst, false, "", args(1,3, batarg("",str),batarg("s",str),arg("l",int))),
    5966             :         pattern("batstr", "stringleft", STRbatprefixcst, false, "", args(1,4, batarg("",str),batarg("s",str),arg("l",int),batarg("s",oid))),
    5967             :         pattern("batstr", "stringleft", STRbatprefix_strcst, false, "", args(1,3, batarg("",str),arg("s",str),batarg("l",int))),
    5968             :         pattern("batstr", "stringleft", STRbatprefix_strcst, false, "", args(1,4, batarg("",str),arg("s",str),batarg("l",int),batarg("s",oid))),
    5969             :         pattern("batstr", "stringright", STRbatsuffix, false, "", args(1,3, batarg("",str),batarg("s",str),batarg("l",int))),
    5970             :         pattern("batstr", "stringright", STRbatsuffix, false, "", args(1,5, batarg("",str),batarg("s",str),batarg("l",int),batarg("s1",oid),batarg("s2",oid))),
    5971             :         pattern("batstr", "stringright", STRbatsuffixcst, false, "", args(1,3, batarg("",str),batarg("s",str),arg("l",int))),
    5972             :         pattern("batstr", "stringright", STRbatsuffixcst, false, "", args(1,4, batarg("",str),batarg("s",str),arg("l",int),batarg("s",oid))),
    5973             :         pattern("batstr", "stringright", STRbatsuffix_strcst, false, "", args(1,3, batarg("",str),arg("s",str),batarg("l",int))),
    5974             :         pattern("batstr", "stringright", STRbatsuffix_strcst, false, "", args(1,4, batarg("",str),arg("s",str),batarg("l",int),batarg("s",oid))),
    5975             :         pattern("batstr", "locate", STRbatstrLocate, false, "Locate the start position of a string", args(1,3, batarg("",int),batarg("s1",str),batarg("s2",str))),
    5976             :         pattern("batstr", "locate", STRbatstrLocate, false, "Locate the start position of a string", args(1,5, batarg("",int),batarg("s1",str),batarg("s2",str),batarg("s1",oid),batarg("s2",oid))),
    5977             :         pattern("batstr", "locate", STRbatstrLocatecst, false, "Locate the start position of a string", args(1,3, batarg("",int),batarg("s1",str),arg("s2",str))),
    5978             :         pattern("batstr", "locate", STRbatstrLocatecst, false, "Locate the start position of a string", args(1,4, batarg("",int),batarg("s1",str),arg("s2",str),batarg("s",oid))),
    5979             :         pattern("batstr", "locate", STRbatstrLocate_strcst, false, "Locate the start position of a string", args(1,3, batarg("",int),arg("s1",str),batarg("s2",str))),
    5980             :         pattern("batstr", "locate", STRbatstrLocate_strcst, false, "Locate the start position of a string", args(1,4, batarg("",int),arg("s1",str),batarg("s2",str),batarg("s",oid))),
    5981             :         pattern("batstr", "locate3", STRbatstrLocate3, false, "Locate the start position of a string", args(1,4, batarg("",int),batarg("s1",str),batarg("s2",str),batarg("start",int))),
    5982             :         pattern("batstr", "locate3", STRbatstrLocate3cst, false, "Locate the start position of a string", args(1,4, batarg("",int),batarg("s1",str),arg("s2",str),arg("start",int))),
    5983             :         pattern("batstr", "insert", STRbatInsert, false, "Insert a string into another", args(1,5, batarg("",str),batarg("s",str),batarg("start",int),batarg("l",int),batarg("s2",str))),
    5984             :         pattern("batstr", "insert", STRbatInsertcst, false, "Insert a string into another", args(1,5, batarg("",str),batarg("s",str),arg("start",int),arg("l",int),arg("s2",str))),
    5985             :         pattern("batstr", "replace", STRbatReplace, false, "Insert a string into another", args(1,4, batarg("",str),batarg("s",str),batarg("pat",str),batarg("s2",str))),
    5986             :         pattern("batstr", "replace", STRbatReplacecst, false, "Insert a string into another", args(1,4, batarg("",str),batarg("s",str),arg("pat",str),arg("s2",str))),
    5987             :         pattern("batstr", "repeat", STRbatrepeat, false, "", args(1,3, batarg("",str),batarg("s",str),batarg("c",int))),
    5988             :         pattern("batstr", "repeat", STRbatrepeat, false, "", args(1,5, batarg("",str),batarg("s",str),batarg("c",int),batarg("s1",oid),batarg("s2",oid))),
    5989             :         pattern("batstr", "repeat", STRbatrepeatcst, false, "", args(1,3, batarg("",str),batarg("s",str),arg("c",int))),
    5990             :         pattern("batstr", "repeat", STRbatrepeatcst, false, "", args(1,4, batarg("",str),batarg("s",str),arg("c",int),batarg("s",oid))),
    5991             :         pattern("batstr", "repeat", STRbatrepeat_strcst, false, "", args(1,3, batarg("",str),arg("s",str),batarg("c",int))),
    5992             :         pattern("batstr", "repeat", STRbatrepeat_strcst, false, "", args(1,4, batarg("",str),arg("s",str),batarg("c",int),batarg("s",oid))),
    5993             :         pattern("batstr", "space", STRbatSpace, false, "", args(1,2, batarg("",str),batarg("l",int))),
    5994             :         pattern("batstr", "space", STRbatSpace, false, "", args(1,3, batarg("",str),batarg("l",int),batarg("s",oid))),
    5995             :         pattern("batstr", "asciify", BATSTRasciify, false, "Transform BAT of strings from UTF8 to ASCII", args(1, 2, batarg("",str), batarg("b",str))),
    5996             :         pattern("batstr", "asciify", BATSTRasciify, false, "Transform BAT of strings from UTF8 to ASCII", args(1, 3, batarg("",str), batarg("b",str),batarg("s",oid))),
    5997             :         { .imp=NULL }
    5998             : };
    5999             : #include "mal_import.h"
    6000             : #ifdef _MSC_VER
    6001             : #undef read
    6002             : #pragma section(".CRT$XCU",read)
    6003             : #endif
    6004         329 : LIB_STARTUP_FUNC(init_batstr_mal)
    6005         329 : { mal_module("batstr", NULL, batstr_init_funcs); }

Generated by: LCOV version 1.14