LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - batstr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1415 3682 38.4 %
Date: 2024-10-07 21:21:43 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         924 : batstr_func_has_candidates(const char *func)
      33             : {
      34        7378 :         for (size_t i = 0; batstr_funcs_with_no_cands[i]; i++)
      35        6466 :                 if (strcmp(batstr_funcs_with_no_cands[i], func) == 0)
      36             :                         return false;
      37             :         return true;
      38             : }
      39             : 
      40             : static inline void
      41        3093 : finalize_output(bat *res, BAT *bn, const char *msg, bool nils, BUN q)
      42             : {
      43        3093 :         if (bn && !msg) {
      44        3093 :                 BATsetcount(bn, q);
      45        3092 :                 bn->tnil = nils;
      46        3092 :                 bn->tnonil = !nils;
      47        3092 :                 bn->tkey = BATcount(bn) <= 1;
      48        3092 :                 bn->tsorted = BATcount(bn) <= 1;
      49        3092 :                 bn->trevsorted = BATcount(bn) <= 1;
      50        3092 :                 bn->theap->dirty |= BATcount(bn) > 0;
      51        3092 :                 *res = bn->batCacheid;
      52        3092 :                 BBPkeepref(bn);
      53           0 :         } else if (bn)
      54           0 :                 BBPreclaim(bn);
      55        3093 : }
      56             : 
      57             : static void
      58        3228 : unfix_inputs(int nargs, ...)
      59             : {
      60        3228 :         va_list valist;
      61             : 
      62        3228 :         va_start(valist, nargs);
      63       10018 :         for (int i = 0; i < nargs; i++) {
      64        6782 :                 BAT *b = va_arg(valist, BAT *);
      65       10800 :                 BBPreclaim(b);
      66             :         }
      67        3236 :         va_end(valist);
      68        3236 : }
      69             : 
      70             : static inline str
      71        5624 : str_prefix(str *buf, size_t *buflen, const char *s, int l)
      72             : {
      73        5624 :         return str_Sub_String(buf, buflen, s, 0, l);
      74             : }
      75             : 
      76             : static str
      77        2202 : do_batstr_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
      78             :                           const char *name, int (*func)(const char *))
      79             : {
      80        2202 :         BATiter bi;
      81        2202 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
      82        2202 :         int *restrict vals;
      83        2202 :         str msg = MAL_SUCCEED;
      84        2202 :         bool nils = false;
      85        2202 :         struct canditer ci1 = { 0 };
      86        2202 :         oid off1;
      87        2202 :         bat *res = getArgReference_bat(stk, pci, 0),
      88        2202 :                 bid = *getArgReference_bat(stk, pci, 1),
      89        2202 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
      90             : 
      91        2202 :         (void) cntxt;
      92        2202 :         (void) mb;
      93        2202 :         if (!(b = BATdescriptor(bid))) {
      94           0 :                 msg = createException(MAL, name,
      95             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      96           0 :                 goto bailout;
      97             :         }
      98        2204 :         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        2204 :         canditer_init(&ci1, b, bs);
     104        2202 :         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        2204 :         off1 = b->hseqbase;
     110        2204 :         bi = bat_iterator(b);
     111        2204 :         vals = Tloc(bn, 0);
     112        2204 :         if (ci1.tpe == cand_dense) {
     113     1304332 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     114     1302170 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     115     1302170 :                         const char *restrict x = BUNtvar(bi, p1);
     116             : 
     117     1303508 :                         if (strNil(x)) {
     118           3 :                                 vals[i] = int_nil;
     119           3 :                                 nils = true;
     120             :                         } else {
     121     1303505 :                                 vals[i] = func(x);
     122             :                         }
     123             :                 }
     124             :         } else {
     125     1734942 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     126     1734902 :                         oid p1 = (canditer_next(&ci1) - off1);
     127     1734733 :                         const char *restrict x = BUNtvar(bi, p1);
     128             : 
     129     1734744 :                         if (strNil(x)) {
     130           0 :                                 vals[i] = int_nil;
     131           0 :                                 nils = true;
     132             :                         } else {
     133     1734744 :                                 vals[i] = func(x);
     134             :                         }
     135             :                 }
     136             :         }
     137        2202 :         bat_iterator_end(&bi);
     138        2202 :   bailout:
     139        2202 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     140        2203 :         unfix_inputs(2, b, bs);
     141        2204 :         return msg;
     142             : }
     143             : 
     144             : static str
     145        2202 : STRbatLength(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     146             : {
     147        2202 :         bat bid = *getArgReference_bat(stk, pci, 1);
     148        2202 :         BAT *b = BATdescriptor(bid);
     149        2202 :         str err;
     150        2202 :         if (b && b->tascii)
     151        2197 :                 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        2203 :         BBPreclaim(b);
     155        2203 :         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          50 : do_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     426             :                           const char *name, str (*func)(str *, size_t *, const char *))
     427             : {
     428          50 :         BATiter bi;
     429          50 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     430          50 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     431          50 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     432          50 :         bool nils = false;
     433          50 :         struct canditer ci1 = { 0 };
     434          50 :         oid off1;
     435          50 :         bat *res = getArgReference_bat(stk, pci, 0),
     436          50 :                 bid = *getArgReference_bat(stk, pci, 1),
     437          50 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     438             : 
     439          50 :         (void) cntxt;
     440          50 :         (void) mb;
     441          50 :         if (!buf) {
     442           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     443           0 :                 goto bailout;
     444             :         }
     445          50 :         if (!(b = BATdescriptor(bid))) {
     446           0 :                 msg = createException(MAL, name,
     447             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     448           0 :                 goto bailout;
     449             :         }
     450          50 :         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          50 :         canditer_init(&ci1, b, bs);
     456          49 :         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          49 :         off1 = b->hseqbase;
     462          49 :         bi = bat_iterator(b);
     463          50 :         if (ci1.tpe == cand_dense) {
     464         424 :                 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          50 :         bat_iterator_end(&bi);
     510          50 :   bailout:
     511          50 :         GDKfree(buf);
     512          50 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     513          50 :         unfix_inputs(2, b, bs);
     514          50 :         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          11 : 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          11 :         BATiter bi;
     526          11 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     527          11 :         const char *y = *getArgReference_str(stk, pci, 2);
     528          11 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     529          11 :         bool nils = false;
     530          11 :         struct canditer ci1 = { 0 };
     531          11 :         oid off1;
     532          11 :         bat *res = getArgReference_bat(stk, pci, 0),
     533          11 :                 bid = *getArgReference_bat(stk, pci, 1),
     534          11 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     535             : 
     536          11 :         (void) cntxt;
     537          11 :         (void) mb;
     538          11 :         if (!buf) {
     539           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     540           0 :                 goto bailout;
     541             :         }
     542          11 :         if (!(b = BATdescriptor(bid))) {
     543           0 :                 msg = createException(MAL, name,
     544             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     545           0 :                 goto bailout;
     546             :         }
     547          11 :         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          11 :         canditer_init(&ci1, b, bs);
     553          11 :         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          11 :         off1 = b->hseqbase;
     559          11 :         bi = bat_iterator(b);
     560          11 :         if (ci1.tpe == cand_dense) {
     561          29 :                 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          11 :         bat_iterator_end(&bi);
     607          11 :   bailout:
     608          11 :         GDKfree(buf);
     609          11 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     610          11 :         unfix_inputs(2, b, bs);
     611          11 :         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         140 : STRbatConvert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1606             :                           BAT *(*func)(BAT *, BAT *), const char *malfunc)
    1607             : {
    1608         140 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1609         140 :         bat *res = getArgReference_bat(stk, pci, 0),
    1610         140 :                 *bid = getArgReference_bat(stk, pci, 1),
    1611         140 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
    1612             : 
    1613         140 :         (void) cntxt;
    1614         140 :         (void) mb;
    1615         140 :         if (!(b = BATdescriptor(*bid))) {
    1616           0 :                 throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1617             :         }
    1618         140 :         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         140 :         bn = (*func)(b, bs);
    1623         140 :         unfix_inputs(2, b, bs);
    1624         140 :         if (bn == NULL)
    1625           0 :                 throw(MAL, malfunc, GDK_EXCEPTION);
    1626         140 :         *res = bn->batCacheid;
    1627         140 :         BBPkeepref(bn);
    1628         140 :         return MAL_SUCCEED;
    1629             : }
    1630             : 
    1631             : static str
    1632         101 : STRbatLower(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1633             : {
    1634         101 :         return STRbatConvert(cntxt, mb, stk, pci, BATtolower, "batstr.toLower");
    1635             : }
    1636             : 
    1637             : static str
    1638          19 : STRbatUpper(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1639             : {
    1640          19 :         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          38 : STRbatRtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1663             : {
    1664          38 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim", str_rtrim);
    1665             : }
    1666             : 
    1667             : static str
    1668           9 : STRbatStrip2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1669             : {
    1670           9 :         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          94 : 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          94 :         BATiter bi;
    2815          94 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2816          94 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2817          94 :         int y = *getArgReference_int(stk, pci, 2);
    2818          94 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2819          95 :         bool nils = false;
    2820          95 :         struct canditer ci1 = { 0 };
    2821          95 :         oid off1;
    2822          95 :         bat *res = getArgReference_bat(stk, pci, 0),
    2823          95 :                 l = *getArgReference_bat(stk, pci, 1),
    2824          95 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2825             : 
    2826          95 :         (void) cntxt;
    2827          95 :         (void) mb;
    2828          95 :         if (!buf) {
    2829           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2830           0 :                 goto bailout;
    2831             :         }
    2832          95 :         if (!(b = BATdescriptor(l))) {
    2833           0 :                 msg = createException(MAL, name,
    2834             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2835           0 :                 goto bailout;
    2836             :         }
    2837          94 :         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          94 :         canditer_init(&ci1, b, bs);
    2843          95 :         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          95 :         off1 = b->hseqbase;
    2849          95 :         bi = bat_iterator(b);
    2850          95 :         if (ci1.tpe == cand_dense) {
    2851        6172 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2852        6077 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2853        6077 :                         const char *x = BUNtvar(bi, p1);
    2854             : 
    2855       11723 :                         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        5643 :                                 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           1 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2874           1 :                         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          95 :         bat_iterator_end(&bi);
    2897          94 :   bailout:
    2898          94 :         GDKfree(buf);
    2899          95 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2900          94 :         unfix_inputs(2, b, bs);
    2901          95 :         return msg;
    2902             : }
    2903             : 
    2904             : static str
    2905          84 : STRbatprefixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2906             : {
    2907          84 :         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           5 : 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           5 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3032           5 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3033           5 :         int *restrict vals, y;
    3034           5 :         const char *x = *getArgReference_str(stk, pci, 1);
    3035           5 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3036           5 :         bool nils = false;
    3037           5 :         struct canditer ci1 = { 0 };
    3038           5 :         oid off1;
    3039           5 :         bat *res = getArgReference_bat(stk, pci, 0),
    3040           5 :                 l = *getArgReference_bat(stk, pci, 2),
    3041           5 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3042           5 :         BATiter bi;
    3043             : 
    3044           5 :         (void) cntxt;
    3045           5 :         (void) mb;
    3046           5 :         if (!buf) {
    3047           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3048           0 :                 goto bailout;
    3049             :         }
    3050           5 :         if (!(b = BATdescriptor(l))) {
    3051           0 :                 msg = createException(MAL, name,
    3052             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3053           0 :                 goto bailout;
    3054             :         }
    3055           5 :         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           5 :         canditer_init(&ci1, b, bs);
    3061           5 :         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           5 :         off1 = b->hseqbase;
    3067           5 :         bi = bat_iterator(b);
    3068           5 :         vals = bi.base;
    3069           5 :         if (ci1.tpe == cand_dense) {
    3070          10 :                 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           5 :                                 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           5 :         bat_iterator_end(&bi);
    3116           5 :   bailout:
    3117           5 :         GDKfree(buf);
    3118           5 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3119           5 :         unfix_inputs(2, b, bs);
    3120           5 :         return msg;
    3121             : }
    3122             : 
    3123             : static str
    3124           5 : STRbatprefix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3125             : {
    3126           5 :         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       32431 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3303       32398 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3304       32398 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3305       32398 :                         const char *x = BUNtvar(lefti, p1);
    3306       32398 :                         y = righti[p2];
    3307             : 
    3308       36160 :                         if (strNil(x) || is_int_nil(y)) {
    3309       28636 :                                 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        3762 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3317           0 :                                         goto bailout1;
    3318        3759 :                                 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         352 : STRbatSubstitutecst_imp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3501             :                                                 int cand_nargs, const bit *rep)
    3502             : {
    3503         352 :         BATiter bi;
    3504         352 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3505         352 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3506         352 :         const char *y = *getArgReference_str(stk, pci, 2),
    3507         352 :                 *z = *getArgReference_str(stk, pci, 3);
    3508         352 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3509         352 :         bool nils = false;
    3510         352 :         bit w = *rep;
    3511         352 :         struct canditer ci1 = { 0 };
    3512         352 :         oid off1;
    3513         352 :         bat *res = getArgReference_bat(stk, pci, 0),
    3514         352 :                 bid = *getArgReference_bat(stk, pci, 1),
    3515         352 :                 *sid1 = pci->argc == cand_nargs ? getArgReference_bat(stk, pci, cand_nargs - 1) : NULL;
    3516             : 
    3517         352 :         if (!buf) {
    3518           0 :                 msg = createException(MAL, "batstr.substritute",
    3519             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3520           0 :                 goto bailout;
    3521             :         }
    3522         352 :         if (!(b = BATdescriptor(bid))) {
    3523           0 :                 msg = createException(MAL, "batstr.substritute",
    3524             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3525           0 :                 goto bailout;
    3526             :         }
    3527         352 :         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         352 :         canditer_init(&ci1, b, bs);
    3533         352 :         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         352 :         (void) cntxt;
    3540         352 :         (void) mb;
    3541         352 :         off1 = b->hseqbase;
    3542         352 :         bi = bat_iterator(b);
    3543         352 :         if (ci1.tpe == cand_dense) {
    3544      117185 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3545      116833 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3546      116833 :                         const char *x = BUNtvar(bi, p1);
    3547             : 
    3548      464708 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3549         840 :                                 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      115967 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3557           0 :                                         goto bailout1;
    3558      116000 :                                 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         352 :         bat_iterator_end(&bi);
    3590         352 :   bailout:
    3591         352 :         GDKfree(buf);
    3592         352 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3593         351 :         unfix_inputs(2, b, bs);
    3594         352 :         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           2 : STRbatsplitpartcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3747             : {
    3748           2 :         BATiter bi;
    3749           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3750           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3751           2 :         int z = *getArgReference_int(stk, pci, 3);
    3752           2 :         const char *y = *getArgReference_str(stk, pci, 2);
    3753           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3754           2 :         bool nils = false;
    3755           2 :         struct canditer ci1 = { 0 };
    3756           2 :         oid off1;
    3757           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    3758           2 :                 bid = *getArgReference_bat(stk, pci, 1),
    3759           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3760             : 
    3761           2 :         (void) cntxt;
    3762           2 :         (void) mb;
    3763           2 :         if (!buf) {
    3764           0 :                 msg = createException(MAL, "batstr.splitpart",
    3765             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3766           0 :                 goto bailout;
    3767             :         }
    3768           2 :         if (!(b = BATdescriptor(bid))) {
    3769           0 :                 msg = createException(MAL, "batstr.splitpart",
    3770             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3771           0 :                 goto bailout;
    3772             :         }
    3773           2 :         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           2 :         canditer_init(&ci1, b, bs);
    3779           2 :         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           2 :         off1 = b->hseqbase;
    3786           2 :         bi = bat_iterator(b);
    3787           2 :         if (ci1.tpe == cand_dense) {
    3788          16 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3789          14 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3790          14 :                         const char *x = BUNtvar(bi, p1);
    3791             : 
    3792          42 :                         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          14 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3801           0 :                                         goto bailout1;
    3802          14 :                                 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           2 :         bat_iterator_end(&bi);
    3834           2 :   bailout:
    3835           2 :         GDKfree(buf);
    3836           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3837           2 :         unfix_inputs(2, b, bs);
    3838           2 :         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         352 : STRbatReplacecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4200             : {
    4201         352 :         bit rep = TRUE;
    4202             : 
    4203         352 :         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         123 : STRbatsubstring_2nd_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4575             :                                                         InstrPtr pci)
    4576             : {
    4577         123 :         BATiter bi;
    4578         123 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4579         123 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4580         123 :         int y = *getArgReference_int(stk, pci, 2),
    4581         123 :                 z = *getArgReference_int(stk, pci, 3);
    4582         123 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4583         123 :         bool nils = false;
    4584         123 :         struct canditer ci1 = { 0 };
    4585         123 :         oid off1;
    4586         123 :         bat *res = getArgReference_bat(stk, pci, 0),
    4587         123 :                 bid = *getArgReference_bat(stk, pci, 1),
    4588         123 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4589             : 
    4590         123 :         (void) cntxt;
    4591         123 :         (void) mb;
    4592         123 :         if (!buf) {
    4593           0 :                 msg = createException(MAL, "batstr.substring",
    4594             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4595           0 :                 goto bailout;
    4596             :         }
    4597         123 :         if (!(b = BATdescriptor(bid))) {
    4598           0 :                 msg = createException(MAL, "batstr.substring",
    4599             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4600           0 :                 goto bailout;
    4601             :         }
    4602         123 :         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         123 :         canditer_init(&ci1, b, bs);
    4608         123 :         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         123 :         off1 = b->hseqbase;
    4615         123 :         bi = bat_iterator(b);
    4616         123 :         if (ci1.tpe == cand_dense) {
    4617     3706569 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4618     3706448 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4619     3706448 :                         const char *x = BUNtvar(bi, p1);
    4620             : 
    4621     7270809 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4622       99720 :                                 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     3585307 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4630           0 :                                         goto bailout1;
    4631     3687688 :                                 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         121 :         bat_iterator_end(&bi);
    4663         123 :   bailout:
    4664         123 :         GDKfree(buf);
    4665         123 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4666         123 :         unfix_inputs(2, b, bs);
    4667         123 :         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           5 : STRbatsubstring_1st_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4770             :                                                         InstrPtr pci)
    4771             : {
    4772           5 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4773           5 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4774           5 :         int y, z = *getArgReference_int(stk, pci, 3), *restrict input;
    4775           5 :         const char *x = *getArgReference_str(stk, pci, 1);
    4776           5 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4777           5 :         bool nils = false;
    4778           5 :         struct canditer ci1 = { 0 };
    4779           5 :         oid off1;
    4780           5 :         bat *res = getArgReference_bat(stk, pci, 0),
    4781           5 :                 bid = *getArgReference_bat(stk, pci, 2),
    4782           5 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4783           5 :         BATiter bi;
    4784             : 
    4785           5 :         (void) cntxt;
    4786           5 :         (void) mb;
    4787           5 :         if (!buf) {
    4788           0 :                 msg = createException(MAL, "batstr.substring",
    4789             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4790           0 :                 goto bailout;
    4791             :         }
    4792           5 :         if (!(b = BATdescriptor(bid))) {
    4793           0 :                 msg = createException(MAL, "batstr.substring",
    4794             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4795           0 :                 goto bailout;
    4796             :         }
    4797           5 :         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           5 :         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           5 :         off1 = b->hseqbase;
    4810           5 :         bi = bat_iterator(b);
    4811           5 :         input = bi.base;
    4812           5 :         if (ci1.tpe == cand_dense) {
    4813           9 :                 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           5 :         bat_iterator_end(&bi);
    4859           5 :   bailout:
    4860           5 :         GDKfree(buf);
    4861           5 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4862           5 :         unfix_inputs(2, b, bs);
    4863           5 :         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           4 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    4898           4 :                 || (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           4 :         canditer_init(&ci1, b, bs);
    4904           3 :         canditer_init(&ci2, lb, lbs);
    4905           4 :         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           4 :         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           2 :         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           9 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4925           6 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4926           6 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    4927           6 :                         y = vals1[p1];
    4928           6 :                         z = vals2[p2];
    4929             : 
    4930          12 :                         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           6 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4939           0 :                                         goto bailout1;
    4940           5 :                                 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           3 :         bat_iterator_end(&bi);
    4974           2 :         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          32 : STRbatsubstring_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4984             : {
    4985          32 :         BATiter bi;
    4986          32 :         BATiter lbi;
    4987          32 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4988          32 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4989          32 :         int y = *getArgReference_int(stk, pci, 2), *len, z;
    4990          32 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4991          32 :         bool nils = false;
    4992          32 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4993          32 :         oid off1, off2;
    4994          32 :         bat *res = getArgReference_bat(stk, pci, 0),
    4995          32 :                 bid = *getArgReference_bat(stk, pci, 1),
    4996          32 :                 l = *getArgReference_bat(stk, pci, 3),
    4997          32 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4998          32 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4999             : 
    5000          32 :         (void) cntxt;
    5001          32 :         (void) mb;
    5002          32 :         if (!buf) {
    5003           0 :                 msg = createException(MAL, "batstr.substring",
    5004             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5005           0 :                 goto bailout;
    5006             :         }
    5007          32 :         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          32 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5013          32 :                 || (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          32 :         canditer_init(&ci1, b, bs);
    5019          32 :         canditer_init(&ci2, lb, lbs);
    5020          32 :         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          32 :         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          32 :         off1 = b->hseqbase;
    5033          32 :         off2 = lb->hseqbase;
    5034          32 :         bi = bat_iterator(b);
    5035          32 :         lbi = bat_iterator(lb);
    5036          32 :         len = lbi.base;
    5037          32 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5038          36 :                 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          32 :         bat_iterator_end(&lbi);
    5088          32 :         bat_iterator_end(&bi);
    5089          32 :   bailout:
    5090          32 :         GDKfree(buf);
    5091          32 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5092          32 :         unfix_inputs(4, b, bs, lb, lbs);
    5093          32 :         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          28 : STRbatsubstring(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5211             : {
    5212          28 :         BATiter lefti, starti, lengthi;
    5213          28 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *start = NULL,
    5214          28 :                 *ss = NULL, *length = NULL, *lens = NULL;
    5215          28 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5216          28 :         int *svals, *lvals, y, z;
    5217          28 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5218          28 :         bool nils = false;
    5219          28 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5220          28 :         oid off1, off2, off3;
    5221          28 :         bat *res = getArgReference_bat(stk, pci, 0),
    5222          28 :                 l = *getArgReference_bat(stk, pci, 1),
    5223          28 :                 r = *getArgReference_bat(stk, pci, 2),
    5224          28 :                 t = *getArgReference_bat(stk, pci, 3),
    5225          28 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5226          28 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5227          28 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5228             : 
    5229          28 :         (void) cntxt;
    5230          28 :         (void) mb;
    5231          28 :         if (!buf) {
    5232           0 :                 msg = createException(MAL, "batstr.substring",
    5233             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5234           0 :                 goto bailout;
    5235             :         }
    5236          28 :         if (!(left = BATdescriptor(l)) || !(start = BATdescriptor(r))
    5237          28 :                 || !(length = BATdescriptor(t))) {
    5238           0 :                 msg = createException(MAL, "batstr.substring",
    5239             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5240           0 :                 goto bailout;
    5241             :         }
    5242          28 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5243          28 :                 (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          28 :         canditer_init(&ci1, left, ls);
    5250          28 :         canditer_init(&ci2, start, ss);
    5251          28 :         canditer_init(&ci3, length, lens);
    5252          28 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5253          28 :                 || 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          28 :         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          28 :         off1 = left->hseqbase;
    5266          28 :         off2 = start->hseqbase;
    5267          28 :         off3 = length->hseqbase;
    5268          28 :         lefti = bat_iterator(left);
    5269          28 :         starti = bat_iterator(start);
    5270          28 :         lengthi = bat_iterator(length);
    5271          28 :         svals = starti.base;
    5272          28 :         lvals = lengthi.base;
    5273          28 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5274        3823 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5275        3795 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5276        3795 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5277        3795 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5278        3795 :                         const char *x = BUNtvar(lefti, p1);
    5279        3795 :                         y = svals[p2];
    5280        3795 :                         z = lvals[p3];
    5281             : 
    5282        7560 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5283          47 :                                 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        3748 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5291           0 :                                         goto bailout1;
    5292        3689 :                                 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          28 :         bat_iterator_end(&lefti);
    5328          28 :         bat_iterator_end(&starti);
    5329          28 :         bat_iterator_end(&lengthi);
    5330          28 :   bailout:
    5331          28 :         GDKfree(buf);
    5332          28 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5333          28 :         unfix_inputs(6, left, ls, start, ss, length, lens);
    5334          28 :         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          52 : STRbatstrLocate_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5408             : {
    5409          52 :         BATiter bi;
    5410          52 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5411          52 :         int *restrict vals;
    5412          52 :         const char *x = *getArgReference_str(stk, pci, 1);
    5413          52 :         str msg = MAL_SUCCEED;
    5414          52 :         bool nils = false;
    5415          52 :         struct canditer ci1 = { 0 };
    5416          52 :         oid off1;
    5417          52 :         bat *res = getArgReference_bat(stk, pci, 0),
    5418          52 :                 l = *getArgReference_bat(stk, pci, 2),
    5419          52 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5420             : 
    5421          52 :         (void) cntxt;
    5422          52 :         (void) mb;
    5423          52 :         if (!(b = BATdescriptor(l))) {
    5424           0 :                 msg = createException(MAL, "batstr.locate",
    5425             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5426           0 :                 goto bailout;
    5427             :         }
    5428          52 :         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          52 :         canditer_init(&ci1, b, bs);
    5434          52 :         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          52 :         off1 = b->hseqbase;
    5441          52 :         bi = bat_iterator(b);
    5442          52 :         vals = Tloc(bn, 0);
    5443          52 :         if (ci1.tpe == cand_dense) {
    5444        3381 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5445        3329 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5446        3329 :                         const char *y = BUNtvar(bi, p1);
    5447             : 
    5448        6638 :                         if (strNil(x) || strNil(y)) {
    5449           0 :                                 vals[i] = int_nil;
    5450           0 :                                 nils = true;
    5451             :                         } else {
    5452        3319 :                                 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          52 :         bat_iterator_end(&bi);
    5469          52 :   bailout:
    5470          52 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5471          52 :         unfix_inputs(2, b, bs);
    5472          52 :         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          20 : BATSTRasciify(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5731             : {
    5732          20 :         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         323 : LIB_STARTUP_FUNC(init_batstr_mal)
    5935         323 : { mal_module("batstr", NULL, batstr_init_funcs); }

Generated by: LCOV version 1.14