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

Generated by: LCOV version 1.14