LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - batstr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1413 3682 38.4 %
Date: 2024-10-04 20:04:04 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        2773 : finalize_output(bat *res, BAT *bn, const char *msg, bool nils, BUN q)
      42             : {
      43        2773 :         if (bn && !msg) {
      44        2773 :                 BATsetcount(bn, q);
      45        2773 :                 bn->tnil = nils;
      46        2773 :                 bn->tnonil = !nils;
      47        2773 :                 bn->tkey = BATcount(bn) <= 1;
      48        2773 :                 bn->tsorted = BATcount(bn) <= 1;
      49        2773 :                 bn->trevsorted = BATcount(bn) <= 1;
      50        2773 :                 bn->theap->dirty |= BATcount(bn) > 0;
      51        2773 :                 *res = bn->batCacheid;
      52        2773 :                 BBPkeepref(bn);
      53           0 :         } else if (bn)
      54           0 :                 BBPreclaim(bn);
      55        2774 : }
      56             : 
      57             : static void
      58        2891 : unfix_inputs(int nargs, ...)
      59             : {
      60        2891 :         va_list valist;
      61             : 
      62        2891 :         va_start(valist, nargs);
      63        8913 :         for (int i = 0; i < nargs; i++) {
      64        6022 :                 BAT *b = va_arg(valist, BAT *);
      65        9554 :                 BBPreclaim(b);
      66             :         }
      67        2891 :         va_end(valist);
      68        2891 : }
      69             : 
      70             : static inline str
      71        5626 : str_prefix(str *buf, size_t *buflen, const char *s, int l)
      72             : {
      73        5626 :         return str_Sub_String(buf, buflen, s, 0, l);
      74             : }
      75             : 
      76             : static str
      77        2000 : do_batstr_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
      78             :                           const char *name, int (*func)(const char *))
      79             : {
      80        2000 :         BATiter bi;
      81        2000 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
      82        2000 :         int *restrict vals;
      83        2000 :         str msg = MAL_SUCCEED;
      84        2000 :         bool nils = false;
      85        2000 :         struct canditer ci1 = { 0 };
      86        2000 :         oid off1;
      87        2000 :         bat *res = getArgReference_bat(stk, pci, 0),
      88        2000 :                 bid = *getArgReference_bat(stk, pci, 1),
      89        2000 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
      90             : 
      91        2000 :         (void) cntxt;
      92        2000 :         (void) mb;
      93        2000 :         if (!(b = BATdescriptor(bid))) {
      94           0 :                 msg = createException(MAL, name,
      95             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      96           0 :                 goto bailout;
      97             :         }
      98        1999 :         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        1999 :         canditer_init(&ci1, b, bs);
     104        2000 :         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        2000 :         off1 = b->hseqbase;
     110        2000 :         bi = bat_iterator(b);
     111        2000 :         vals = Tloc(bn, 0);
     112        2000 :         if (ci1.tpe == cand_dense) {
     113     1812743 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     114     1810784 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     115     1810784 :                         const char *restrict x = BUNtvar(bi, p1);
     116             : 
     117     1810343 :                         if (strNil(x)) {
     118           3 :                                 vals[i] = int_nil;
     119           3 :                                 nils = true;
     120             :                         } else {
     121     1810340 :                                 vals[i] = func(x);
     122             :                         }
     123             :                 }
     124             :         } else {
     125     1999073 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     126     1999033 :                         oid p1 = (canditer_next(&ci1) - off1);
     127     1999029 :                         const char *restrict x = BUNtvar(bi, p1);
     128             : 
     129     1999030 :                         if (strNil(x)) {
     130           0 :                                 vals[i] = int_nil;
     131           0 :                                 nils = true;
     132             :                         } else {
     133     1999030 :                                 vals[i] = func(x);
     134             :                         }
     135             :                 }
     136             :         }
     137        1999 :         bat_iterator_end(&bi);
     138        2000 :   bailout:
     139        2000 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     140        2000 :         unfix_inputs(2, b, bs);
     141        2000 :         return msg;
     142             : }
     143             : 
     144             : static str
     145        1998 : STRbatLength(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     146             : {
     147        1998 :         bat bid = *getArgReference_bat(stk, pci, 1);
     148        1998 :         BAT *b = BATdescriptor(bid);
     149        1999 :         str err;
     150        1999 :         if (b && b->tascii)
     151        1995 :                 err = do_batstr_int(cntxt, mb, stk, pci, "batstr.bytes", str_strlen);
     152             :         else
     153           4 :                 err = do_batstr_int(cntxt, mb, stk, pci, "batstr.length", UTF8_strlen);
     154        1999 :         BBPreclaim(b);
     155        1999 :         return err;
     156             : }
     157             : 
     158             : static str
     159           1 : STRbatBytes(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     160             : {
     161           1 :         return do_batstr_int(cntxt, mb, stk, pci, "batstr.bytes", str_strlen);
     162             : }
     163             : 
     164             : static str
     165           3 : STRbatAscii(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     166             : {
     167           3 :         BATiter bi;
     168           3 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     169           3 :         int *restrict vals, next;
     170           3 :         str msg = MAL_SUCCEED;
     171           3 :         bool nils = false;
     172           3 :         struct canditer ci1 = { 0 };
     173           3 :         oid off1;
     174           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     175           3 :                 bid = *getArgReference_bat(stk, pci, 1),
     176           3 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     177             : 
     178           3 :         (void) cntxt;
     179           3 :         (void) mb;
     180           3 :         if (!(b = BATdescriptor(bid))) {
     181           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     182             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     183           0 :                 goto bailout;
     184             :         }
     185           3 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     186           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     187             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     188           0 :                 goto bailout;
     189             :         }
     190           3 :         canditer_init(&ci1, b, bs);
     191           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
     192           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     193             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     194           0 :                 goto bailout;
     195             :         }
     196             : 
     197           3 :         off1 = b->hseqbase;
     198           3 :         bi = bat_iterator(b);
     199           3 :         vals = Tloc(bn, 0);
     200           3 :         if (ci1.tpe == cand_dense) {
     201          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     202           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     203           8 :                         const char *restrict x = BUNtvar(bi, p1);
     204             : 
     205           8 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     206           0 :                                 goto bailout1;
     207           8 :                         vals[i] = next;
     208           8 :                         nils |= is_int_nil(next);
     209             :                 }
     210             :         } else {
     211          15 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     212          14 :                         oid p1 = (canditer_next(&ci1) - off1);
     213          14 :                         const char *restrict x = BUNtvar(bi, p1);
     214             : 
     215          14 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     216           0 :                                 goto bailout1;
     217          14 :                         vals[i] = next;
     218          14 :                         nils |= is_int_nil(next);
     219             :                 }
     220             :         }
     221           1 :   bailout1:
     222           3 :         bat_iterator_end(&bi);
     223           3 :   bailout:
     224           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     225           3 :         unfix_inputs(2, b, bs);
     226           3 :         return msg;
     227             : }
     228             : 
     229             : static str
     230           1 : STRbatFromWChr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     231             : {
     232           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     233           1 :         size_t buflen = MAX(strlen(str_nil) + 1, 8);
     234           1 :         int *restrict vals, x;
     235           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     236           1 :         bool nils = false;
     237           1 :         struct canditer ci1 = { 0 };
     238           1 :         oid off1;
     239           1 :         bat *res = getArgReference_bat(stk, pci, 0),
     240           1 :                 bid = *getArgReference_bat(stk, pci, 1),
     241           1 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     242           1 :         BATiter bi;
     243             : 
     244           1 :         (void) cntxt;
     245           1 :         (void) mb;
     246           1 :         if (!buf) {
     247           0 :                 msg = createException(MAL, "batstr.unicode",
     248             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     249           0 :                 goto bailout;
     250             :         }
     251           1 :         if (!(b = BATdescriptor(bid))) {
     252           0 :                 msg = createException(MAL, "batstr.unicode",
     253             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     254           0 :                 goto bailout;
     255             :         }
     256           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     257           0 :                 msg = createException(MAL, "batstr.unicode",
     258             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     259           0 :                 goto bailout;
     260             :         }
     261           1 :         canditer_init(&ci1, b, bs);
     262           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     263           0 :                 msg = createException(MAL, "batstr.unicode",
     264             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     265           0 :                 goto bailout;
     266             :         }
     267             : 
     268           1 :         bi = bat_iterator(b);
     269           1 :         off1 = b->hseqbase;
     270           1 :         vals = bi.base;
     271           1 :         if (ci1.tpe == cand_dense) {
     272           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     273           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     274           4 :                         x = vals[p1];
     275             : 
     276           4 :                         if (is_int_nil(x)) {
     277           2 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     278           0 :                                         msg = createException(MAL, "batstr.unicode",
     279             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     280           0 :                                         goto bailout1;
     281             :                                 }
     282             :                                 nils = true;
     283             :                         } else {
     284           2 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     285           0 :                                         goto bailout1;
     286             :                                 }
     287           2 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     288           0 :                                         msg = createException(MAL, "batstr.unicode",
     289             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     290           0 :                                         goto bailout1;
     291             :                                 }
     292             :                         }
     293             :                 }
     294             :         } else {
     295           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     296           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     297           0 :                         x = vals[p1];
     298             : 
     299           0 :                         if (is_int_nil(x)) {
     300           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     301           0 :                                         msg = createException(MAL, "batstr.unicode",
     302             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     303           0 :                                         goto bailout1;
     304             :                                 }
     305             :                                 nils = true;
     306             :                         } else {
     307           0 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     308           0 :                                         goto bailout1;
     309             :                                 }
     310           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     311           0 :                                         msg = createException(MAL, "batstr.unicode",
     312             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     313           0 :                                         goto bailout1;
     314             :                                 }
     315             :                         }
     316             :                 }
     317             :         }
     318           0 :   bailout1:
     319           1 :         bat_iterator_end(&bi);
     320           1 :   bailout:
     321           1 :         GDKfree(buf);
     322           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     323           1 :         unfix_inputs(2, b, bs);
     324           1 :         return msg;
     325             : }
     326             : 
     327             : static str
     328           0 : STRbatSpace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     329             : {
     330           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     331           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     332           0 :         int *restrict vals, x;
     333           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     334           0 :         bool nils = false;
     335           0 :         const char space[] = " ", *s = space;
     336           0 :         struct canditer ci1 = { 0 };
     337           0 :         oid off1;
     338           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     339           0 :                 bid = *getArgReference_bat(stk, pci, 1),
     340           0 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     341           0 :         BATiter bi;
     342             : 
     343           0 :         (void) cntxt;
     344           0 :         (void) mb;
     345           0 :         if (!buf) {
     346           0 :                 msg = createException(MAL, "batstr.space",
     347             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     348           0 :                 goto bailout;
     349             :         }
     350           0 :         if (!(b = BATdescriptor(bid))) {
     351           0 :                 msg = createException(MAL, "batstr.space",
     352             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     353           0 :                 goto bailout;
     354             :         }
     355           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     356           0 :                 msg = createException(MAL, "batstr.search",
     357             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     358           0 :                 goto bailout;
     359             :         }
     360           0 :         canditer_init(&ci1, b, bs);
     361           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     362           0 :                 msg = createException(MAL, "batstr.space",
     363             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     364           0 :                 goto bailout;
     365             :         }
     366             : 
     367           0 :         off1 = b->hseqbase;
     368           0 :         bi = bat_iterator(b);
     369           0 :         vals = bi.base;
     370           0 :         if (ci1.tpe == cand_dense) {
     371           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     372           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     373           0 :                         x = vals[p1];
     374             : 
     375           0 :                         if (is_int_nil(x) || x < 0) {
     376           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     377           0 :                                         msg = createException(MAL, "batstr.space",
     378             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     379           0 :                                         goto bailout1;
     380             :                                 }
     381             :                                 nils = true;
     382             :                         } else {
     383           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     384           0 :                                         goto bailout1;
     385           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     386           0 :                                         msg = createException(MAL, "batstr.space",
     387             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     388           0 :                                         goto bailout1;
     389             :                                 }
     390             :                         }
     391             :                 }
     392             :         } else {
     393           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     394           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     395           0 :                         x = vals[p1];
     396             : 
     397           0 :                         if (is_int_nil(x) || x < 0) {
     398           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     399           0 :                                         msg = createException(MAL, "batstr.space",
     400             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     401           0 :                                         goto bailout1;
     402             :                                 }
     403             :                                 nils = true;
     404             :                         } else {
     405           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     406           0 :                                         goto bailout1;
     407           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     408           0 :                                         msg = createException(MAL, "batstr.space",
     409             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     410           0 :                                         goto bailout1;
     411             :                                 }
     412             :                         }
     413             :                 }
     414             :         }
     415           0 :   bailout1:
     416           0 :         bat_iterator_end(&bi);
     417           0 :   bailout:
     418           0 :         GDKfree(buf);
     419           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     420           0 :         unfix_inputs(2, b, bs);
     421           0 :         return msg;
     422             : }
     423             : 
     424             : static str
     425          38 : do_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     426             :                           const char *name, str (*func)(str *, size_t *, const char *))
     427             : {
     428          38 :         BATiter bi;
     429          38 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     430          38 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     431          38 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     432          38 :         bool nils = false;
     433          38 :         struct canditer ci1 = { 0 };
     434          38 :         oid off1;
     435          38 :         bat *res = getArgReference_bat(stk, pci, 0),
     436          38 :                 bid = *getArgReference_bat(stk, pci, 1),
     437          38 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     438             : 
     439          38 :         (void) cntxt;
     440          38 :         (void) mb;
     441          38 :         if (!buf) {
     442           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     443           0 :                 goto bailout;
     444             :         }
     445          38 :         if (!(b = BATdescriptor(bid))) {
     446           0 :                 msg = createException(MAL, name,
     447             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     448           0 :                 goto bailout;
     449             :         }
     450          38 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     451           0 :                 msg = createException(MAL, name,
     452             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     453           0 :                 goto bailout;
     454             :         }
     455          38 :         canditer_init(&ci1, b, bs);
     456          38 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     457           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     458           0 :                 goto bailout;
     459             :         }
     460             : 
     461          38 :         off1 = b->hseqbase;
     462          38 :         bi = bat_iterator(b);
     463          38 :         if (ci1.tpe == cand_dense) {
     464         412 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     465         374 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     466         374 :                         const char *restrict x = BUNtvar(bi, p1);
     467             : 
     468         374 :                         if (strNil(x)) {
     469           5 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     470           0 :                                         msg = createException(MAL, name,
     471             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     472           0 :                                         goto bailout1;
     473             :                                 }
     474             :                                 nils = true;
     475             :                         } else {
     476         369 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     477           0 :                                         goto bailout1;
     478         369 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     479           0 :                                         msg = createException(MAL, name,
     480             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     481           0 :                                         goto bailout1;
     482             :                                 }
     483             :                         }
     484             :                 }
     485             :         } else {
     486           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     487           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     488           0 :                         const char *restrict x = BUNtvar(bi, p1);
     489             : 
     490           0 :                         if (strNil(x)) {
     491           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     492           0 :                                         msg = createException(MAL, name,
     493             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     494           0 :                                         goto bailout1;
     495             :                                 }
     496             :                                 nils = true;
     497             :                         } else {
     498           0 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     499           0 :                                         goto bailout1;
     500           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     501           0 :                                         msg = createException(MAL, name,
     502             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     503           0 :                                         goto bailout1;
     504             :                                 }
     505             :                         }
     506             :                 }
     507             :         }
     508           0 :   bailout1:
     509          38 :         bat_iterator_end(&bi);
     510          38 :   bailout:
     511          38 :         GDKfree(buf);
     512          38 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     513          38 :         unfix_inputs(2, b, bs);
     514          38 :         return msg;
     515             : }
     516             : 
     517             : /* Input: a BAT of strings 'b' and a constant string 'y'
     518             :  * Output type: str (a BAT of strings)
     519             :  */
     520             : static str
     521           7 : do_batstr_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     522             :                                            const char *name, size_t buflen,
     523             :                                            str (*func)(str *, size_t *, const char *, const char *))
     524             : {
     525           7 :         BATiter bi;
     526           7 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     527           7 :         const char *y = *getArgReference_str(stk, pci, 2);
     528           7 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     529           7 :         bool nils = false;
     530           7 :         struct canditer ci1 = { 0 };
     531           7 :         oid off1;
     532           7 :         bat *res = getArgReference_bat(stk, pci, 0),
     533           7 :                 bid = *getArgReference_bat(stk, pci, 1),
     534           7 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     535             : 
     536           7 :         (void) cntxt;
     537           7 :         (void) mb;
     538           7 :         if (!buf) {
     539           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     540           0 :                 goto bailout;
     541             :         }
     542           7 :         if (!(b = BATdescriptor(bid))) {
     543           0 :                 msg = createException(MAL, name,
     544             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     545           0 :                 goto bailout;
     546             :         }
     547           7 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     548           0 :                 msg = createException(MAL, name,
     549             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     550           0 :                 goto bailout;
     551             :         }
     552           7 :         canditer_init(&ci1, b, bs);
     553           7 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     554           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     555           0 :                 goto bailout;
     556             :         }
     557             : 
     558           7 :         off1 = b->hseqbase;
     559           7 :         bi = bat_iterator(b);
     560           7 :         if (ci1.tpe == cand_dense) {
     561          25 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     562          18 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     563          18 :                         const char *x = BUNtvar(bi, p1);
     564             : 
     565          36 :                         if (strNil(x) || strNil(y)) {
     566           9 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     567           0 :                                         msg = createException(MAL, name,
     568             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     569           0 :                                         goto bailout1;
     570             :                                 }
     571             :                                 nils = true;
     572             :                         } else {
     573           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     574           0 :                                         goto bailout1;
     575           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     576           0 :                                         msg = createException(MAL, name,
     577             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     578           0 :                                         goto bailout1;
     579             :                                 }
     580             :                         }
     581             :                 }
     582             :         } else {
     583           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     584           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     585           0 :                         const char *x = BUNtvar(bi, p1);
     586             : 
     587           0 :                         if (strNil(x) || strNil(y)) {
     588           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     589           0 :                                         msg = createException(MAL, name,
     590             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     591           0 :                                         goto bailout1;
     592             :                                 }
     593             :                                 nils = true;
     594             :                         } else {
     595           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     596           0 :                                         goto bailout1;
     597           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     598           0 :                                         msg = createException(MAL, name,
     599             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     600           0 :                                         goto bailout1;
     601             :                                 }
     602             :                         }
     603             :                 }
     604             :         }
     605           0 :   bailout1:
     606           7 :         bat_iterator_end(&bi);
     607           7 :   bailout:
     608           7 :         GDKfree(buf);
     609           7 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     610           7 :         unfix_inputs(2, b, bs);
     611           7 :         return msg;
     612             : }
     613             : 
     614             : /* Input: a const string 'x' and a BAT of strings 'y'
     615             :  * Output type: str (a BAT of strings)
     616             :  */
     617             : static str
     618           0 : do_batstr_str_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     619             :                                            const char *name, size_t buflen,
     620             :                                            str (*func)(str *, size_t *, const char *, const char *))
     621             : {
     622           0 :         BATiter bi;
     623           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     624           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     625           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     626           0 :         bool nils = false;
     627           0 :         struct canditer ci1 = { 0 };
     628           0 :         oid off1;
     629           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     630           0 :                 bid = *getArgReference_bat(stk, pci, 2),
     631           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     632             : 
     633           0 :         (void) cntxt;
     634           0 :         (void) mb;
     635           0 :         if (!buf) {
     636           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     637           0 :                 goto bailout;
     638             :         }
     639           0 :         if (!(b = BATdescriptor(bid))) {
     640           0 :                 msg = createException(MAL, name,
     641             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     642           0 :                 goto bailout;
     643             :         }
     644           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     645           0 :                 msg = createException(MAL, name,
     646             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     647           0 :                 goto bailout;
     648             :         }
     649           0 :         canditer_init(&ci1, b, bs);
     650           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     651           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     652           0 :                 goto bailout;
     653             :         }
     654             : 
     655           0 :         off1 = b->hseqbase;
     656           0 :         bi = bat_iterator(b);
     657           0 :         if (ci1.tpe == cand_dense) {
     658           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     659           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     660           0 :                         const char *y = BUNtvar(bi, p1);
     661             : 
     662           0 :                         if (strNil(x) || strNil(y)) {
     663           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     664           0 :                                         msg = createException(MAL, name,
     665             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     666           0 :                                         goto bailout1;
     667             :                                 }
     668             :                                 nils = true;
     669             :                         } else {
     670           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     671           0 :                                         goto bailout1;
     672           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     673           0 :                                         msg = createException(MAL, name,
     674             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     675           0 :                                         goto bailout1;
     676             :                                 }
     677             :                         }
     678             :                 }
     679             :         } else {
     680           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     681           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     682           0 :                         const char *y = BUNtvar(bi, p1);
     683             : 
     684           0 :                         if (strNil(x) || strNil(y)) {
     685           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     686           0 :                                         msg = createException(MAL, name,
     687             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     688           0 :                                         goto bailout1;
     689             :                                 }
     690             :                                 nils = true;
     691             :                         } else {
     692           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     693           0 :                                         goto bailout1;
     694           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     695           0 :                                         msg = createException(MAL, name,
     696             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     697           0 :                                         goto bailout1;
     698             :                                 }
     699             :                         }
     700             :                 }
     701             :         }
     702           0 :   bailout1:
     703           0 :         bat_iterator_end(&bi);
     704           0 :   bailout:
     705           0 :         GDKfree(buf);
     706           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     707           0 :         unfix_inputs(2, b, bs);
     708           0 :         return msg;
     709             : }
     710             : 
     711             : /* Input: two BATs of strings 'l' and 'l2'
     712             :  * Output type: str (a BAT of strings)
     713             :  */
     714             : static str
     715           3 : do_batstr_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     716             :                                          const char *name, size_t buflen,
     717             :                                          str (*func)(str *, size_t *, const char *, const char *))
     718             : {
     719           3 :         BATiter lefti, righti;
     720           3 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
     721           3 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     722           3 :         bool nils = false;
     723           3 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
     724           3 :         oid off1, off2;
     725           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     726           3 :                 l = *getArgReference_bat(stk, pci, 1),
     727           3 :                 l2 = *getArgReference_bat(stk, pci, 2),
     728           3 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
     729           3 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
     730             : 
     731           3 :         (void) cntxt;
     732           3 :         (void) mb;
     733           3 :         if (!buf) {
     734           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     735           0 :                 goto bailout;
     736             :         }
     737           3 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(l2))) {
     738           0 :                 msg = createException(MAL, name,
     739             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     740           0 :                 goto bailout;
     741             :         }
     742           3 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
     743           3 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
     744           0 :                 msg = createException(MAL, name,
     745             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     746           0 :                 goto bailout;
     747             :         }
     748           3 :         canditer_init(&ci1, left, lefts);
     749           3 :         canditer_init(&ci2, right, rights);
     750           3 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
     751           0 :                 msg = createException(MAL, name,
     752             :                                                           ILLEGAL_ARGUMENT
     753             :                                                           " Requires bats of identical size");
     754           0 :                 goto bailout;
     755             :         }
     756           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     757           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     758           0 :                 goto bailout;
     759             :         }
     760             : 
     761           3 :         off1 = left->hseqbase;
     762           3 :         off2 = right->hseqbase;
     763           3 :         lefti = bat_iterator(left);
     764           3 :         righti = bat_iterator(right);
     765           3 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
     766          12 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     767           9 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
     768           9 :                                 p2 = (canditer_next_dense(&ci2) - off2);
     769           9 :                         const char *x = BUNtvar(lefti, p1);
     770           9 :                         const char *y = BUNtvar(righti, p2);
     771             : 
     772          18 :                         if (strNil(x) || strNil(y)) {
     773           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     774           0 :                                         msg = createException(MAL, name,
     775             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     776           0 :                                         goto bailout1;
     777             :                                 }
     778             :                                 nils = true;
     779             :                         } else {
     780           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     781           0 :                                         goto bailout1;
     782           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     783           0 :                                         msg = createException(MAL, name,
     784             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     785           0 :                                         goto bailout1;
     786             :                                 }
     787             :                         }
     788             :                 }
     789             :         } else {
     790           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     791           0 :                         oid p1 = (canditer_next(&ci1) - off1),
     792           0 :                                 p2 = (canditer_next(&ci2) - off2);
     793           0 :                         const char *x = BUNtvar(lefti, p1);
     794           0 :                         const char *y = BUNtvar(righti, p2);
     795             : 
     796           0 :                         if (strNil(x) || strNil(y)) {
     797           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     798           0 :                                         msg = createException(MAL, name,
     799             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     800           0 :                                         goto bailout1;
     801             :                                 }
     802             :                                 nils = true;
     803             :                         } else {
     804           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     805           0 :                                         goto bailout1;
     806           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     807           0 :                                         msg = createException(MAL, name,
     808             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     809           0 :                                         goto bailout1;
     810             :                                 }
     811             :                         }
     812             :                 }
     813             :         }
     814           0 :   bailout1:
     815           3 :         bat_iterator_end(&lefti);
     816           3 :         bat_iterator_end(&righti);
     817           3 :   bailout:
     818           3 :         GDKfree(buf);
     819           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     820           3 :         unfix_inputs(4, left, lefts, right, rights);
     821           3 :         return msg;
     822             : }
     823             : 
     824             : /* Input: a BAT of strings 'l' and a constant int 'y'
     825             :  * Output type: str (a BAT of strings)
     826             :  */
     827             : static str
     828           2 : do_batstr_constint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     829             :                                            const char *name,
     830             :                                            str (*func)(str *, size_t *, const char *, int))
     831             : {
     832           2 :         BATiter bi;
     833           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     834           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     835           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     836           2 :         int y = *getArgReference_int(stk, pci, 2);
     837           2 :         bool nils = false;
     838           2 :         struct canditer ci1 = { 0 };
     839           2 :         oid off1;
     840           2 :         bat *res = getArgReference_bat(stk, pci, 0),
     841           2 :                 bid = *getArgReference_bat(stk, pci, 1),
     842           2 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     843             : 
     844           2 :         (void) cntxt;
     845           2 :         (void) mb;
     846           2 :         if (!buf) {
     847           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     848           0 :                 goto bailout;
     849             :         }
     850           2 :         if (!(b = BATdescriptor(bid))) {
     851           0 :                 msg = createException(MAL, name,
     852             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     853           0 :                 goto bailout;
     854             :         }
     855           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     856           0 :                 msg = createException(MAL, name,
     857             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     858           0 :                 goto bailout;
     859             :         }
     860           2 :         canditer_init(&ci1, b, bs);
     861           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     862           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     863           0 :                 goto bailout;
     864             :         }
     865             : 
     866           2 :         off1 = b->hseqbase;
     867           2 :         bi = bat_iterator(b);
     868           2 :         if (ci1.tpe == cand_dense) {
     869           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     870           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     871           4 :                         const char *x = BUNtvar(bi, p1);
     872             : 
     873           8 :                         if (strNil(x) || is_int_nil(y)) {
     874           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     875           0 :                                         msg = createException(MAL, name,
     876             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     877           0 :                                         goto bailout1;
     878             :                                 }
     879             :                                 nils = true;
     880             :                         } else {
     881           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     882           0 :                                         goto bailout1;
     883           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     884           0 :                                         msg = createException(MAL, name,
     885             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     886           0 :                                         goto bailout1;
     887             :                                 }
     888             :                         }
     889             :                 }
     890             :         } else {
     891           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     892           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     893           0 :                         const char *x = BUNtvar(bi, p1);
     894             : 
     895           0 :                         if (strNil(x) || is_int_nil(y)) {
     896           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     897           0 :                                         msg = createException(MAL, name,
     898             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     899           0 :                                         goto bailout1;
     900             :                                 }
     901             :                                 nils = true;
     902             :                         } else {
     903           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     904           0 :                                         goto bailout1;
     905           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     906           0 :                                         msg = createException(MAL, name,
     907             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     908           0 :                                         goto bailout1;
     909             :                                 }
     910             :                         }
     911             :                 }
     912             :         }
     913           0 :   bailout1:
     914           2 :         bat_iterator_end(&bi);
     915           2 :   bailout:
     916           2 :         GDKfree(buf);
     917           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     918           2 :         unfix_inputs(2, b, bs);
     919           2 :         return msg;
     920             : }
     921             : 
     922             : /* Input: a constant string 'x' and a BAT of integers 'y'
     923             :  * Output type: str (a BAT of strings)
     924             :  */
     925             : static str
     926           0 : do_batstr_int_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     927             :                                            const char *name,
     928             :                                            str (*func)(str *, size_t *, const char *, int))
     929             : {
     930           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     931           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     932           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     933           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     934           0 :         int y, *restrict inputs;
     935           0 :         bool nils = false;
     936           0 :         struct canditer ci1 = { 0 };
     937           0 :         oid off1;
     938           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     939           0 :                 bid = *getArgReference_bat(stk, pci, 2),
     940           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     941           0 :         BATiter bi;
     942             : 
     943           0 :         (void) cntxt;
     944           0 :         (void) mb;
     945           0 :         if (!buf) {
     946           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     947           0 :                 goto bailout;
     948             :         }
     949           0 :         if (!(b = BATdescriptor(bid))) {
     950           0 :                 msg = createException(MAL, name,
     951             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     952           0 :                 goto bailout;
     953             :         }
     954           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     955           0 :                 msg = createException(MAL, name,
     956             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     957           0 :                 goto bailout;
     958             :         }
     959           0 :         canditer_init(&ci1, b, bs);
     960           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     961           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     962           0 :                 goto bailout;
     963             :         }
     964             : 
     965           0 :         off1 = b->hseqbase;
     966           0 :         bi = bat_iterator(b);
     967           0 :         inputs = bi.base;
     968           0 :         if (ci1.tpe == cand_dense) {
     969           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     970           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     971           0 :                         y = inputs[p1];
     972             : 
     973           0 :                         if (strNil(x) || is_int_nil(y)) {
     974           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     975           0 :                                         msg = createException(MAL, name,
     976             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     977           0 :                                         goto bailout1;
     978             :                                 }
     979             :                                 nils = true;
     980             :                         } else {
     981           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     982           0 :                                         goto bailout1;
     983           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     984           0 :                                         msg = createException(MAL, name,
     985             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     986           0 :                                         goto bailout1;
     987             :                                 }
     988             :                         }
     989             :                 }
     990             :         } else {
     991           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     992           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     993           0 :                         y = inputs[p1];
     994             : 
     995           0 :                         if (strNil(x) || is_int_nil(y)) {
     996           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     997           0 :                                         msg = createException(MAL, name,
     998             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     999           0 :                                         goto bailout1;
    1000             :                                 }
    1001             :                                 nils = true;
    1002             :                         } else {
    1003           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1004           0 :                                         goto bailout1;
    1005           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1006           0 :                                         msg = createException(MAL, name,
    1007             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1008           0 :                                         goto bailout1;
    1009             :                                 }
    1010             :                         }
    1011             :                 }
    1012             :         }
    1013           0 :   bailout1:
    1014           0 :         bat_iterator_end(&bi);
    1015           0 :   bailout:
    1016           0 :         GDKfree(buf);
    1017           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1018           0 :         unfix_inputs(2, b, bs);
    1019           0 :         return msg;
    1020             : }
    1021             : 
    1022             : /* Input: a BAT of strings 'l' and a BAT of integers 'n'
    1023             :  * Output type: str (a BAT of strings)
    1024             :  */
    1025             : static str
    1026           2 : do_batstr_batint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1027             :                                          const char *name,
    1028             :                                          str (*func)(str *, size_t *, const char *, int))
    1029             : {
    1030           2 :         BATiter lefti;
    1031           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1032           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1033           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1034           2 :         bool nils = false;
    1035           2 :         int *restrict righti, y;
    1036           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1037           2 :         oid off1, off2;
    1038           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1039           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1040           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1041           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    1042           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1043           2 :         BATiter bi;
    1044             : 
    1045           2 :         (void) cntxt;
    1046           2 :         (void) mb;
    1047           2 :         if (!buf) {
    1048           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1049           0 :                 goto bailout;
    1050             :         }
    1051           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(n))) {
    1052           0 :                 msg = createException(MAL, name,
    1053             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1054           0 :                 goto bailout;
    1055             :         }
    1056           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1057           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1058           0 :                 msg = createException(MAL, name,
    1059             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1060           0 :                 goto bailout;
    1061             :         }
    1062           2 :         canditer_init(&ci1, left, ls);
    1063           2 :         canditer_init(&ci2, right, rs);
    1064           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1065           0 :                 msg = createException(MAL, name,
    1066             :                                                           ILLEGAL_ARGUMENT
    1067             :                                                           " Requires bats of identical size");
    1068           0 :                 goto bailout;
    1069             :         }
    1070           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1071           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1072           0 :                 goto bailout;
    1073             :         }
    1074             : 
    1075           2 :         off1 = left->hseqbase;
    1076           2 :         off2 = right->hseqbase;
    1077           2 :         lefti = bat_iterator(left);
    1078           2 :         bi = bat_iterator(right);
    1079           2 :         righti = bi.base;
    1080           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1081           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1082           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1083           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1084           4 :                         const char *x = BUNtvar(lefti, p1);
    1085           4 :                         y = righti[p2];
    1086             : 
    1087           8 :                         if (strNil(x) || is_int_nil(y)) {
    1088           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1089           0 :                                         msg = createException(MAL, name,
    1090             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1091           0 :                                         goto bailout1;
    1092             :                                 }
    1093             :                                 nils = true;
    1094             :                         } else {
    1095           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1096           0 :                                         goto bailout1;
    1097           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1098           0 :                                         msg = createException(MAL, name,
    1099             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1100           0 :                                         goto bailout1;
    1101             :                                 }
    1102             :                         }
    1103             :                 }
    1104             :         } else {
    1105           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1106           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1107           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1108           0 :                         const char *x = BUNtvar(lefti, p1);
    1109           0 :                         y = righti[p2];
    1110             : 
    1111           0 :                         if (strNil(x) || is_int_nil(y)) {
    1112           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1113           0 :                                         msg = createException(MAL, name,
    1114             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1115           0 :                                         goto bailout1;
    1116             :                                 }
    1117             :                                 nils = true;
    1118             :                         } else {
    1119           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1120           0 :                                         goto bailout1;
    1121           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1122           0 :                                         msg = createException(MAL, name,
    1123             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1124           0 :                                         goto bailout1;
    1125             :                                 }
    1126             :                         }
    1127             :                 }
    1128             :         }
    1129           0 :   bailout1:
    1130           2 :         bat_iterator_end(&bi);
    1131           2 :         bat_iterator_end(&lefti);
    1132           2 :   bailout:
    1133           2 :         GDKfree(buf);
    1134           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1135           2 :         unfix_inputs(4, left, ls, right, rs);
    1136           2 :         return msg;
    1137             : }
    1138             : 
    1139             : /* Input: a BAT of strings 'l', a constant int 'y' and a constant str 'z'
    1140             :  * Output type: str (a BAT of strings)
    1141             :  */
    1142             : static str
    1143           2 : do_batstr_constint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1144             :                                                                 InstrPtr pci, const char *name,
    1145             :                                                                 str (*func)(str *, size_t *, const char *, int, const char *))
    1146             : {
    1147           2 :         BATiter bi;
    1148           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1149           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1150           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1151           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1152           2 :         int y = *getArgReference_int(stk, pci, 2);
    1153           2 :         bool nils = false;
    1154           2 :         struct canditer ci1 = { 0 };
    1155           2 :         oid off1;
    1156           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1157           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1158           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1159             : 
    1160           2 :         (void) cntxt;
    1161           2 :         (void) mb;
    1162           2 :         if (!buf) {
    1163           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1164           0 :                 goto bailout;
    1165             :         }
    1166           2 :         if (!(b = BATdescriptor(l))) {
    1167           0 :                 msg = createException(MAL, name,
    1168             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1169           0 :                 goto bailout;
    1170             :         }
    1171           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    1172           0 :                 msg = createException(MAL, name,
    1173             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1174           0 :                 goto bailout;
    1175             :         }
    1176           2 :         canditer_init(&ci1, b, bs);
    1177           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1178           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1179           0 :                 goto bailout;
    1180             :         }
    1181             : 
    1182           2 :         off1 = b->hseqbase;
    1183           2 :         bi = bat_iterator(b);
    1184           2 :         if (ci1.tpe == cand_dense) {
    1185          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1186           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    1187           8 :                         const char *x = BUNtvar(bi, p1);
    1188             : 
    1189          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1190           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1191           0 :                                         msg = createException(MAL, name,
    1192             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1193           0 :                                         goto bailout1;
    1194             :                                 }
    1195             :                                 nils = true;
    1196             :                         } else {
    1197           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1198           0 :                                         goto bailout1;
    1199           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1200           0 :                                         msg = createException(MAL, name,
    1201             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1202           0 :                                         goto bailout1;
    1203             :                                 }
    1204             :                         }
    1205             :                 }
    1206             :         } else {
    1207           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1208           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    1209           0 :                         const char *x = BUNtvar(bi, p1);
    1210             : 
    1211           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1212           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1213           0 :                                         msg = createException(MAL, name,
    1214             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1215           0 :                                         goto bailout1;
    1216             :                                 }
    1217             :                                 nils = true;
    1218             :                         } else {
    1219           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1220           0 :                                         goto bailout1;
    1221           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1222           0 :                                         msg = createException(MAL, name,
    1223             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1224           0 :                                         goto bailout1;
    1225             :                                 }
    1226             :                         }
    1227             :                 }
    1228             :         }
    1229           0 :   bailout1:
    1230           2 :         bat_iterator_end(&bi);
    1231           2 :   bailout:
    1232           2 :         GDKfree(buf);
    1233           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1234           2 :         unfix_inputs(2, b, bs);
    1235           2 :         return msg;
    1236             : }
    1237             : 
    1238             : /* Input: a BAT of strings 'l', a BAT of integers 'n' and a constant str 'z'
    1239             :  * Output type: str (a BAT of strings)
    1240             :  */
    1241             : static str
    1242           2 : do_batstr_batint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1243             :                                                           InstrPtr pci, const char *name,
    1244             :                                                           str (*func)(str *, size_t *, const char *,
    1245             :                                                                                   int, const char *))
    1246             : {
    1247           2 :         BATiter lefti;
    1248           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1249           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1250           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1251           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1252           2 :         bool nils = false;
    1253           2 :         int *restrict righti, y;
    1254           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1255           2 :         oid off1, off2;
    1256           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1257           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1258           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1259           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1260           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1261           2 :         BATiter bi;
    1262             : 
    1263           2 :         (void) cntxt;
    1264           2 :         (void) mb;
    1265           2 :         if (!buf) {
    1266           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1267           0 :                 goto bailout;
    1268             :         }
    1269           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(n))) {
    1270           0 :                 msg = createException(MAL, name,
    1271             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1272           0 :                 goto bailout;
    1273             :         }
    1274           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1275           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1276           0 :                 msg = createException(MAL, name,
    1277             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1278           0 :                 goto bailout;
    1279             :         }
    1280           2 :         canditer_init(&ci1, left, ls);
    1281           2 :         canditer_init(&ci2, right, rs);
    1282           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1283           0 :                 msg = createException(MAL, name,
    1284             :                                                           ILLEGAL_ARGUMENT
    1285             :                                                           " Requires bats of identical size");
    1286           0 :                 goto bailout;
    1287             :         }
    1288           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1289           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1290           0 :                 goto bailout;
    1291             :         }
    1292             : 
    1293           2 :         off1 = left->hseqbase;
    1294           2 :         off2 = right->hseqbase;
    1295           2 :         lefti = bat_iterator(left);
    1296           2 :         bi = bat_iterator(right);
    1297           2 :         righti = bi.base;
    1298           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1299          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1300           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1301           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1302           8 :                         const char *x = BUNtvar(lefti, p1);
    1303           8 :                         y = righti[p2];
    1304             : 
    1305          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1306           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1307           0 :                                         msg = createException(MAL, name,
    1308             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1309           0 :                                         goto bailout1;
    1310             :                                 }
    1311             :                                 nils = true;
    1312             :                         } else {
    1313           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1314           0 :                                         goto bailout1;
    1315           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1316           0 :                                         msg = createException(MAL, name,
    1317             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1318           0 :                                         goto bailout1;
    1319             :                                 }
    1320             :                         }
    1321             :                 }
    1322             :         } else {
    1323           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1324           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1325           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1326           0 :                         const char *x = BUNtvar(lefti, p1);
    1327           0 :                         y = righti[p2];
    1328             : 
    1329           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1330           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1331           0 :                                         msg = createException(MAL, name,
    1332             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1333           0 :                                         goto bailout1;
    1334             :                                 }
    1335             :                                 nils = true;
    1336             :                         } else {
    1337           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1338           0 :                                         goto bailout1;
    1339           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1340           0 :                                         msg = createException(MAL, name,
    1341             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1342           0 :                                         goto bailout1;
    1343             :                                 }
    1344             :                         }
    1345             :                 }
    1346             :         }
    1347           0 :   bailout1:
    1348           2 :         bat_iterator_end(&bi);
    1349           2 :         bat_iterator_end(&lefti);
    1350           2 :   bailout:
    1351           2 :         GDKfree(buf);
    1352           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1353           2 :         unfix_inputs(4, left, ls, right, rs);
    1354           2 :         return msg;
    1355             : }
    1356             : 
    1357             : /* Input: a BAT of strings 'l', a constant int 'y' and a BAT of strings 'l2'
    1358             :  * Output type: str (a BAT of strings)
    1359             :  */
    1360             : static str
    1361           2 : do_batstr_constint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1362             :                                                           InstrPtr pci, const char *name,
    1363             :                                                           str (*func)(str *, size_t *, const char *,
    1364             :                                                                                   int, const char *))
    1365             : {
    1366           2 :         BATiter lefti, righti;
    1367           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1368           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1369           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1370           2 :         bool nils = false;
    1371           2 :         int y = *getArgReference_int(stk, pci, 2);
    1372           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1373           2 :         oid off1, off2;
    1374           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1375           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1376           2 :                 l2 = *getArgReference_bat(stk, pci, 3),
    1377           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1378           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1379             : 
    1380           2 :         (void) cntxt;
    1381           2 :         (void) mb;
    1382           2 :         if (!buf) {
    1383           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1384           0 :                 goto bailout;
    1385             :         }
    1386           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(l2))) {
    1387           0 :                 msg = createException(MAL, name,
    1388             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1389           0 :                 goto bailout;
    1390             :         }
    1391           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1392           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1393           0 :                 msg = createException(MAL, name,
    1394             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1395           0 :                 goto bailout;
    1396             :         }
    1397           2 :         canditer_init(&ci1, left, ls);
    1398           2 :         canditer_init(&ci2, right, rs);
    1399           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1400           0 :                 msg = createException(MAL, name,
    1401             :                                                           ILLEGAL_ARGUMENT
    1402             :                                                           " Requires bats of identical size");
    1403           0 :                 goto bailout;
    1404             :         }
    1405           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1406           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1407           0 :                 goto bailout;
    1408             :         }
    1409             : 
    1410           2 :         off1 = left->hseqbase;
    1411           2 :         off2 = right->hseqbase;
    1412           2 :         lefti = bat_iterator(left);
    1413           2 :         righti = bat_iterator(right);
    1414           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1415          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1416           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1417           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1418           8 :                         const char *x = BUNtvar(lefti, p1);
    1419           8 :                         const char *z = BUNtvar(righti, p2);
    1420             : 
    1421          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1422           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1423           0 :                                         msg = createException(MAL, name,
    1424             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1425           0 :                                         goto bailout1;
    1426             :                                 }
    1427             :                                 nils = true;
    1428             :                         } else {
    1429           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1430           0 :                                         goto bailout1;
    1431           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1432           0 :                                         msg = createException(MAL, name,
    1433             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1434           0 :                                         goto bailout1;
    1435             :                                 }
    1436             :                         }
    1437             :                 }
    1438             :         } else {
    1439           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1440           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1441           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1442           0 :                         const char *x = BUNtvar(lefti, p1);
    1443           0 :                         const char *z = BUNtvar(righti, p2);
    1444             : 
    1445           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1446           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1447           0 :                                         msg = createException(MAL, name,
    1448             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1449           0 :                                         goto bailout1;
    1450             :                                 }
    1451             :                                 nils = true;
    1452             :                         } else {
    1453           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1454           0 :                                         goto bailout1;
    1455           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1456           0 :                                         msg = createException(MAL, name,
    1457             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1458           0 :                                         goto bailout1;
    1459             :                                 }
    1460             :                         }
    1461             :                 }
    1462             :         }
    1463           0 :   bailout1:
    1464           2 :         bat_iterator_end(&lefti);
    1465           2 :         bat_iterator_end(&righti);
    1466           2 :   bailout:
    1467           2 :         GDKfree(buf);
    1468           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1469           2 :         unfix_inputs(4, left, ls, right, rs);
    1470           2 :         return msg;
    1471             : }
    1472             : 
    1473             : /* Input: a BAT of strings 'l', a BAT of int 'n' and a BAT of strings 'l2'
    1474             :  * Output type: str (a BAT of strings)
    1475             :  */
    1476             : static str
    1477           2 : do_batstr_batint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1478             :                                                         InstrPtr pci, const char *name,
    1479             :                                                         str (*func)(str *, size_t *, const char *,
    1480             :                                                                                 int, const char *))
    1481             : {
    1482           2 :         BATiter arg1i, arg3i, bi;
    1483           2 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL, *arg2s = NULL,
    1484           2 :                 *arg3 = NULL, *arg3s = NULL;
    1485           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1486           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1487           2 :         bool nils = false;
    1488           2 :         int *restrict arg2i, y;
    1489           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    1490           2 :         oid off1, off2, off3;
    1491           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1492           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1493           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1494           2 :                 l2 = *getArgReference_bat(stk, pci, 3),
    1495           2 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    1496           2 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    1497           2 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    1498             : 
    1499           2 :         (void) cntxt;
    1500           2 :         (void) mb;
    1501           2 :         if (!buf) {
    1502           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1503           0 :                 goto bailout;
    1504             :         }
    1505           2 :         if (!(arg1 = BATdescriptor(l)) || !(arg2 = BATdescriptor(n))
    1506           2 :                 || !(arg3 = BATdescriptor(l2))) {
    1507           0 :                 msg = createException(MAL, name,
    1508             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1509           0 :                 goto bailout;
    1510             :         }
    1511           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1)))
    1512           2 :                 || (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2)))
    1513           2 :                 || (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3)))) {
    1514           0 :                 msg = createException(MAL, name,
    1515             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1516           0 :                 goto bailout;
    1517             :         }
    1518           2 :         canditer_init(&ci1, arg1, arg1s);
    1519           2 :         canditer_init(&ci2, arg2, arg2s);
    1520           2 :         canditer_init(&ci3, arg3, arg3s);
    1521           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    1522           2 :                 || ci2.hseq != ci3.hseq) {
    1523           0 :                 msg = createException(MAL, name,
    1524             :                                                           ILLEGAL_ARGUMENT
    1525             :                                                           " Requires bats of identical size");
    1526           0 :                 goto bailout;
    1527             :         }
    1528           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1529           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1530           0 :                 goto bailout;
    1531             :         }
    1532             : 
    1533           2 :         off1 = arg1->hseqbase;
    1534           2 :         off2 = arg2->hseqbase;
    1535           2 :         off3 = arg3->hseqbase;
    1536           2 :         arg1i = bat_iterator(arg1);
    1537           2 :         bi = bat_iterator(arg2);
    1538           2 :         arg2i = bi.base;
    1539           2 :         arg3i = bat_iterator(arg3);
    1540           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    1541          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1542           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1543           8 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    1544           8 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    1545           8 :                         const char *x = BUNtvar(arg1i, p1);
    1546           8 :                         y = arg2i[p2];
    1547           8 :                         const char *z = BUNtvar(arg3i, p3);
    1548             : 
    1549          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1550           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1551           0 :                                         msg = createException(MAL, name,
    1552             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1553           0 :                                         goto bailout1;
    1554             :                                 }
    1555             :                                 nils = true;
    1556             :                         } else {
    1557           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1558           0 :                                         goto bailout1;
    1559           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1560           0 :                                         msg = createException(MAL, name,
    1561             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1562           0 :                                         goto bailout1;
    1563             :                                 }
    1564             :                         }
    1565             :                 }
    1566             :         } else {
    1567           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1568           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1569           0 :                                 p2 = (canditer_next(&ci2) - off2),
    1570           0 :                                 p3 = (canditer_next(&ci3) - off3);
    1571           0 :                         const char *x = BUNtvar(arg1i, p1);
    1572           0 :                         y = arg2i[p2];
    1573           0 :                         const char *z = BUNtvar(arg3i, p3);
    1574             : 
    1575           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1576           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1577           0 :                                         msg = createException(MAL, name,
    1578             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1579           0 :                                         goto bailout1;
    1580             :                                 }
    1581             :                                 nils = true;
    1582             :                         } else {
    1583           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1584           0 :                                         goto bailout1;
    1585           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1586           0 :                                         msg = createException(MAL, name,
    1587             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1588           0 :                                         goto bailout1;
    1589             :                                 }
    1590             :                         }
    1591             :                 }
    1592             :         }
    1593           0 :   bailout1:
    1594           2 :         bat_iterator_end(&arg1i);
    1595           2 :         bat_iterator_end(&arg3i);
    1596           2 :         bat_iterator_end(&bi);
    1597           2 :   bailout:
    1598           2 :         GDKfree(buf);
    1599           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1600           2 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    1601           2 :         return msg;
    1602             : }
    1603             : 
    1604             : static str
    1605         117 : STRbatConvert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1606             :                           BAT *(*func)(BAT *, BAT *), const char *malfunc)
    1607             : {
    1608         117 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1609         117 :         bat *res = getArgReference_bat(stk, pci, 0),
    1610         117 :                 *bid = getArgReference_bat(stk, pci, 1),
    1611         117 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
    1612             : 
    1613         117 :         (void) cntxt;
    1614         117 :         (void) mb;
    1615         117 :         if (!(b = BATdescriptor(*bid))) {
    1616           0 :                 throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1617             :         }
    1618         117 :         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         117 :         bn = (*func)(b, bs);
    1623         117 :         unfix_inputs(2, b, bs);
    1624         117 :         if (bn == NULL)
    1625           0 :                 throw(MAL, malfunc, GDK_EXCEPTION);
    1626         117 :         *res = bn->batCacheid;
    1627         117 :         BBPkeepref(bn);
    1628         117 :         return MAL_SUCCEED;
    1629             : }
    1630             : 
    1631             : static str
    1632          87 : STRbatLower(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1633             : {
    1634          87 :         return STRbatConvert(cntxt, mb, stk, pci, BATtolower, "batstr.toLower");
    1635             : }
    1636             : 
    1637             : static str
    1638          18 : STRbatUpper(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1639             : {
    1640          18 :         return STRbatConvert(cntxt, mb, stk, pci, BATtoupper, "batstr.toUpper");
    1641             : }
    1642             : 
    1643             : static str
    1644           0 : STRbatCaseFold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1645             : {
    1646           0 :         return STRbatConvert(cntxt, mb, stk, pci, BATcasefold, "batstr.caseFold");
    1647             : }
    1648             : 
    1649             : static str
    1650          10 : STRbatStrip(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1651             : {
    1652          10 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.strip", str_strip);
    1653             : }
    1654             : 
    1655             : static str
    1656           2 : STRbatLtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1657             : {
    1658           2 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim", str_ltrim);
    1659             : }
    1660             : 
    1661             : static str
    1662          26 : STRbatRtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1663             : {
    1664          26 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim", str_rtrim);
    1665             : }
    1666             : 
    1667             : static str
    1668           5 : STRbatStrip2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1669             : {
    1670           5 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.strip",
    1671             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1672             :                                                                   str_strip2);
    1673             : }
    1674             : 
    1675             : static str
    1676           1 : STRbatLtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1677             : {
    1678           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1679             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1680             :                                                                   str_ltrim2);
    1681             : }
    1682             : 
    1683             : static str
    1684           1 : STRbatRtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1685             : {
    1686           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1687             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1688             :                                                                   str_rtrim2);
    1689             : }
    1690             : 
    1691             : static str
    1692           0 : STRbatStrip2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1693             : {
    1694           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.strip",
    1695             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1696             :                                                                   str_strip2);
    1697             : }
    1698             : 
    1699             : static str
    1700           0 : STRbatLtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1701             : {
    1702           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.ltrim",
    1703             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1704             :                                                                   str_ltrim2);
    1705             : }
    1706             : 
    1707             : static str
    1708           0 : STRbatRtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1709             : {
    1710           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.rtrim",
    1711             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1712             :                                                                   str_rtrim2);
    1713             : }
    1714             : 
    1715             : static str
    1716           1 : STRbatStrip2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1717             : {
    1718           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.strip",
    1719             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1720             :                                                                 str_strip2);
    1721             : }
    1722             : 
    1723             : static str
    1724           1 : STRbatLtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1725             : {
    1726           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1727             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1728             :                                                                 str_ltrim2);
    1729             : }
    1730             : 
    1731             : static str
    1732           1 : STRbatRtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1733             : {
    1734           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1735             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1736             :                                                                 str_rtrim2);
    1737             : }
    1738             : 
    1739             : static str
    1740           1 : STRbatLpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1741             : {
    1742           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1743             : }
    1744             : 
    1745             : static str
    1746           1 : STRbatRpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1747             : {
    1748           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1749             : }
    1750             : 
    1751             : static str
    1752           0 : STRbatLpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1753             : {
    1754           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1755             : }
    1756             : 
    1757             : static str
    1758           0 : STRbatRpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1759             : {
    1760           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1761             : }
    1762             : 
    1763             : static str
    1764           1 : STRbatLpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1765             : {
    1766           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1767             : }
    1768             : 
    1769             : static str
    1770           1 : STRbatRpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1771             : {
    1772           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1773             : }
    1774             : 
    1775             : static str
    1776           1 : STRbatLpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1777             : {
    1778           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1779             :                                                                                    str_lpad3);
    1780             : }
    1781             : 
    1782             : static str
    1783           1 : STRbatRpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1784             : {
    1785           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1786             :                                                                                    str_rpad3);
    1787             : }
    1788             : 
    1789             : static str
    1790           1 : STRbatLpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1791             : {
    1792           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1793             :                                                                                  str_lpad3);
    1794             : }
    1795             : 
    1796             : static str
    1797           1 : STRbatRpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1798             : {
    1799           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1800             :                                                                                  str_rpad3);
    1801             : }
    1802             : 
    1803             : static str
    1804           1 : STRbatLpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1805             : {
    1806           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1807             :                                                                                  str_lpad3);
    1808             : }
    1809             : 
    1810             : static str
    1811           1 : STRbatRpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1812             : {
    1813           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1814             :                                                                                  str_rpad3);
    1815             : }
    1816             : 
    1817             : static str
    1818           1 : STRbatLpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1819             : {
    1820           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1821             :                                                                            str_lpad3);
    1822             : }
    1823             : 
    1824             : static str
    1825           1 : STRbatRpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1826             : {
    1827           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1828             :                                                                            str_rpad3);
    1829             : }
    1830             : 
    1831             : /*
    1832             :  * A general assumption in all cases is the bats are synchronized on their
    1833             :  * head column. This is not checked and may be mis-used to deploy the
    1834             :  * implementation for shifted window arithmetic as well.
    1835             :  */
    1836             : static str
    1837          15 : prefix_or_suffix(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1838             :                                  const char *name, int (*func)(const char *, const char *, int),
    1839             :                                  bit *icase)
    1840             : {
    1841          15 :          (void) cntxt;
    1842          15 :         (void) mb;
    1843             : 
    1844          15 :         BATiter lefti, righti;
    1845          15 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    1846          15 :         bit *restrict vals;
    1847          15 :         str msg = MAL_SUCCEED;
    1848          15 :         bool nils = false;
    1849          15 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1850          15 :         oid off1, off2;
    1851          15 :         bat *res = getArgReference_bat(stk, pci, 0),
    1852          15 :                 l = *getArgReference_bat(stk, pci, 1),
    1853          15 :                 r = *getArgReference_bat(stk, pci, 2),
    1854          28 :                 *sid1 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 4 : 3) : NULL,
    1855          28 :                 *sid2 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 5 : 4) : NULL;
    1856             : 
    1857          15 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    1858           0 :                 msg = createException(MAL, name,
    1859             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1860           0 :                 goto exit2;
    1861             :         }
    1862          15 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) ||
    1863          13 :                 (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    1864           0 :                 msg = createException(MAL, name,
    1865             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1866           0 :                 goto exit2;
    1867             :         }
    1868          15 :         canditer_init(&ci1, left, lefts);
    1869          15 :         canditer_init(&ci2, right, rights);
    1870          15 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1871           0 :                 msg = createException(MAL, name,
    1872             :                                                           ILLEGAL_ARGUMENT
    1873             :                                                           " Requires bats of identical size");
    1874           0 :                 goto exit2;
    1875             :         }
    1876          15 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    1877           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1878           0 :                 goto exit2;
    1879             :         }
    1880             : 
    1881          15 :         off1 = left->hseqbase;
    1882          15 :         off2 = right->hseqbase;
    1883          15 :         lefti = bat_iterator(left);
    1884          15 :         righti = bat_iterator(right);
    1885          15 :         vals = Tloc(bn, 0);
    1886          15 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1887          48 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1888          33 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1889          33 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1890          33 :                         char *x = BUNtvar(lefti, p1);
    1891          33 :                         char *y = BUNtvar(righti, p2);
    1892             : 
    1893          66 :                         if (strNil(x) || strNil(y)) {
    1894           0 :                                 vals[i] = bit_nil;
    1895           0 :                                 nils = true;
    1896             :                         } else {
    1897          33 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    1898             :                         }
    1899             :                 }
    1900             :         } else {
    1901           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1902           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1903           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1904           0 :                         char *x = BUNtvar(lefti, p1);
    1905           0 :                         char *y = BUNtvar(righti, p2);
    1906             : 
    1907           0 :                         if (strNil(x) || strNil(y)) {
    1908           0 :                                 vals[i] = bit_nil;
    1909           0 :                                 nils = true;
    1910             :                         } else {
    1911           0 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    1912             :                         }
    1913             :                 }
    1914             :         }
    1915          15 :         bat_iterator_end(&lefti);
    1916          15 :         bat_iterator_end(&righti);
    1917          15 :   exit2:
    1918          15 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1919          15 :         unfix_inputs(4, left, lefts, right, rights);
    1920          15 :         return msg;
    1921             : }
    1922             : 
    1923             : static str
    1924           2 : BATSTRstarts_with(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1925             : {
    1926           2 :         bit *icase = NULL;
    1927           2 :         if (pci->argc == 4 || pci->argc == 6) {
    1928           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1929           0 :                 icase = getArgReference_bit(stk, pci, 3);
    1930             :         }
    1931           2 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.startswith",
    1932             :                                                         (icase
    1933           0 :                                                          && *icase) ? str_is_iprefix : str_is_prefix,
    1934             :                                                         icase);
    1935             : }
    1936             : 
    1937             : static str
    1938           1 : BATSTRends_with(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1939             : {
    1940           1 :         bit *icase = NULL;
    1941           1 :         if (pci->argc == 4 || pci->argc == 6) {
    1942           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1943           0 :                 icase = getArgReference_bit(stk, pci, 3);
    1944             :         }
    1945           1 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.endswith",
    1946             :                                                         (icase
    1947           0 :                                                          && *icase) ? str_is_isuffix : str_is_suffix,
    1948             :                                                         icase);
    1949             : }
    1950             : 
    1951             : static str
    1952          12 : BATSTRcontains(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1953             : {
    1954          12 :         bit *icase = NULL;
    1955          12 :         if (pci->argc == 4 || pci->argc == 6) {
    1956           2 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    1957           2 :                 icase = getArgReference_bit(stk, pci, 3);
    1958             :         }
    1959          12 :         return prefix_or_suffix(cntxt, mb, stk, pci, "batstr.contains",
    1960             :                                                         (icase
    1961           2 :                                                          && *icase) ? str_icontains : str_contains, icase);
    1962             : }
    1963             : 
    1964             : static str
    1965          58 : prefix_or_suffix_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1966             :                                          const char *name, int (*func)(const char *, const char *,
    1967             :                                                                                                    int), bit *icase)
    1968             : {
    1969          58 :          (void) cntxt;
    1970          58 :         (void) mb;
    1971             : 
    1972          58 :         BATiter bi;
    1973          58 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1974          58 :         bit *restrict vals;
    1975          58 :         const char *y = *getArgReference_str(stk, pci, 2);
    1976          58 :         char *msg = MAL_SUCCEED;
    1977          58 :         bool nils = false;
    1978          58 :         struct canditer ci1 = { 0 };
    1979          58 :         oid off1;
    1980          58 :         bat *res = getArgReference_bat(stk, pci, 0),
    1981          58 :                         bid = *getArgReference_bat(stk, pci, 1), *sid1 = NULL;
    1982          58 :         int ynil, ylen;
    1983             : 
    1984          58 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    1985          68 :                 assert(isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    1986          34 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    1987             :         }
    1988             : 
    1989          58 :         if (!(b = BATdescriptor(bid))) {
    1990           0 :                 msg = createException(MAL, name,
    1991             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1992           0 :                 goto exit2;
    1993             :         }
    1994          58 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    1995           0 :                 msg = createException(MAL, name,
    1996             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1997           0 :                 goto exit2;
    1998             :         }
    1999          58 :         canditer_init(&ci1, b, bs);
    2000          58 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    2001           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2002           0 :                 goto exit2;
    2003             :         }
    2004             : 
    2005          58 :         off1 = b->hseqbase;
    2006          58 :         bi = bat_iterator(b);
    2007          58 :         vals = Tloc(bn, 0);
    2008          58 :         ynil = strNil(y);
    2009          55 :         ylen = ynil ? 0 : str_strlen(y); /* not used if nil */
    2010          58 :         if (ci1.tpe == cand_dense) {
    2011        2024 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2012        1966 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2013        1966 :                         char *x = BUNtvar(bi, p1);
    2014             : 
    2015        1966 :                         if (ynil || strNil(x)) {
    2016           6 :                                 vals[i] = bit_nil;
    2017           6 :                                 nils = true;
    2018             :                         } else {
    2019        1960 :                                 vals[i] = func(x, y, ylen) == 0;
    2020             :                         }
    2021             :                 }
    2022             :         } else {
    2023           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2024           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2025           0 :                         char *x = BUNtvar(bi, p1);
    2026             : 
    2027           0 :                         if (ynil || strNil(x)) {
    2028           0 :                                 vals[i] = bit_nil;
    2029           0 :                                 nils = true;
    2030             :                         } else {
    2031           0 :                                 vals[i] = func(x, y, ylen) == 0;
    2032             :                         }
    2033             :                 }
    2034             :         }
    2035          58 :         bat_iterator_end(&bi);
    2036          58 :   exit2:
    2037          58 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2038          58 :         unfix_inputs(2, b, bs);
    2039          58 :         return msg;
    2040             : }
    2041             : 
    2042             : static str
    2043          16 : BATSTRstarts_with_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2044             : {
    2045          16 :         bit *icase = NULL;
    2046          16 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2047          10 :                 || pci->argc == 5) {
    2048           6 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2049           6 :                 icase = getArgReference_bit(stk, pci, 3);
    2050             :         }
    2051          16 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.startswith",
    2052             :                                                                 (icase
    2053           6 :                                                                  && *icase) ? str_is_iprefix : str_is_prefix,
    2054             :                                                                 icase);
    2055             : }
    2056             : 
    2057             : static str
    2058          21 : BATSTRends_with_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2059             : {
    2060          21 :         bit *icase = NULL;
    2061          21 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2062          12 :                 || pci->argc == 5) {
    2063           9 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2064           9 :                 icase = getArgReference_bit(stk, pci, 3);
    2065             :         }
    2066          21 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.endswith",
    2067             :                                                                 (icase
    2068           9 :                                                                  && *icase) ? str_is_isuffix : str_is_suffix,
    2069             :                                                                 icase);
    2070             : }
    2071             : 
    2072             : static str
    2073          21 : BATSTRcontains_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2074             : {
    2075          21 :         bit *icase = NULL;
    2076          21 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2077          12 :                 || pci->argc == 5) {
    2078           9 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2079           9 :                 icase = getArgReference_bit(stk, pci, 3);
    2080             :         }
    2081          21 :         return prefix_or_suffix_cst(cntxt, mb, stk, pci, "batstr.contains",
    2082             :                                                                 (icase
    2083           9 :                                                                  && *icase) ? str_icontains : str_contains,
    2084             :                                                                 icase);
    2085             : }
    2086             : 
    2087             : static str
    2088           0 : prefix_or_suffix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2089             :                                                 const char *name, int (*func)(const char *,
    2090             :                                                                                                           const char *, int),
    2091             :                                                 bit *icase)
    2092             : {
    2093           0 :          (void) cntxt;
    2094           0 :         (void) mb;
    2095             : 
    2096           0 :         BATiter bi;
    2097           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2098           0 :         bit *restrict vals;
    2099           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    2100           0 :         str msg = MAL_SUCCEED;
    2101           0 :         bool nils = false;
    2102           0 :         struct canditer ci1 = { 0 };
    2103           0 :         oid off1;
    2104           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2105           0 :                         bid = *getArgReference_bat(stk, pci, 2), *sid1 = NULL;
    2106           0 :         int xnil;
    2107             : 
    2108           0 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2109           0 :                 assert(isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2110           0 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2111             :         }
    2112             : 
    2113           0 :         if (!(b = BATdescriptor(bid))) {
    2114           0 :                 msg = createException(MAL, name,
    2115             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2116           0 :                 goto exit2;
    2117             :         }
    2118           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2119           0 :                 msg = createException(MAL, name,
    2120             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2121           0 :                 goto exit2;
    2122             :         }
    2123           0 :         canditer_init(&ci1, b, bs);
    2124           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    2125           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2126           0 :                 goto exit2;
    2127             :         }
    2128             : 
    2129           0 :         off1 = b->hseqbase;
    2130           0 :         bi = bat_iterator(b);
    2131           0 :         vals = Tloc(bn, 0);
    2132           0 :         xnil = strNil(x);
    2133           0 :         if (ci1.tpe == cand_dense) {
    2134           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2135           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2136           0 :                         char *y = BUNtvar(bi, p1);
    2137             : 
    2138           0 :                         if (xnil || strNil(y)) {
    2139           0 :                                 vals[i] = bit_nil;
    2140           0 :                                 nils = true;
    2141             :                         } else {
    2142           0 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    2143             :                         }
    2144             :                 }
    2145             :         } else {
    2146           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2147           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2148           0 :                         char *y = BUNtvar(bi, p1);
    2149             : 
    2150           0 :                         if (xnil || strNil(y)) {
    2151           0 :                                 vals[i] = bit_nil;
    2152           0 :                                 nils = true;
    2153             :                         } else {
    2154           0 :                                 vals[i] = func(x, y, str_strlen(y)) == 0;
    2155             :                         }
    2156             :                 }
    2157             :         }
    2158           0 :         bat_iterator_end(&bi);
    2159           0 :   exit2:
    2160           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2161           0 :         unfix_inputs(2, b, bs);
    2162           0 :         return msg;
    2163             : }
    2164             : 
    2165             : static str
    2166           0 : BATSTRstarts_with_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2167             :                                                  InstrPtr pci)
    2168             : {
    2169           0 :         bit *icase = NULL;
    2170           0 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2171           0 :                 || pci->argc == 5) {
    2172           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2173           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2174             :         }
    2175           0 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.startsWith",
    2176             :                                                                    (icase
    2177           0 :                                                                         && *icase) ? str_is_iprefix : str_is_prefix,
    2178             :                                                                    icase);
    2179             : }
    2180             : 
    2181             : static str
    2182           0 : BATSTRends_with_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2183             : {
    2184           0 :         bit *icase = NULL;
    2185           0 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2186           0 :                 || pci->argc == 5) {
    2187           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2188           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2189             :         }
    2190           0 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.endsWith",
    2191             :                                                                    (icase
    2192           0 :                                                                         && *icase) ? str_is_isuffix : str_is_suffix,
    2193             :                                                                    icase);
    2194             : }
    2195             : 
    2196             : static str
    2197           0 : BATSTRcontains_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2198             : {
    2199           0 :         bit *icase = NULL;
    2200           0 :         if ((pci->argc == 4 && getArgType(mb, pci, 3) == TYPE_bit)
    2201           0 :                 || pci->argc == 5) {
    2202           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2203           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2204             :         }
    2205           0 :         return prefix_or_suffix_strcst(cntxt, mb, stk, pci, "batstr.contains",
    2206             :                                                                    (icase
    2207           0 :                                                                         && *icase) ? str_icontains : str_contains,
    2208             :                                                                    icase);
    2209             : }
    2210             : 
    2211             : static str
    2212           1 : search_string_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2213             :                                   const char *name, int (*func)(const char *, const char *),
    2214             :                                   bit *icase)
    2215             : {
    2216           1 :          (void) cntxt;
    2217           1 :         (void) mb;
    2218             : 
    2219           1 :         BATiter lefti, righti;
    2220           1 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    2221           1 :         int *restrict vals;
    2222           1 :         str msg = MAL_SUCCEED;
    2223           1 :         bool nils = false;
    2224           1 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    2225           1 :         oid off1, off2;
    2226           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2227           1 :                 l = *getArgReference_bat(stk, pci, 1),
    2228           1 :                 r = *getArgReference_bat(stk, pci, 2),
    2229           1 :                 *sid1 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 4 : 3) : NULL,
    2230           1 :                 *sid2 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 5 : 4) : NULL;
    2231             : 
    2232           1 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    2233           0 :                 msg = createException(MAL, name,
    2234             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2235           0 :                 goto exit2;
    2236             :         }
    2237           1 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) ||
    2238           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    2239           0 :                 msg = createException(MAL, name,
    2240             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2241           0 :                 goto exit2;
    2242             :         }
    2243           1 :         canditer_init(&ci1, left, lefts);
    2244           1 :         canditer_init(&ci2, right, rights);
    2245           1 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    2246           0 :                 msg = createException(MAL, name,
    2247             :                                                           ILLEGAL_ARGUMENT
    2248             :                                                           " Requires bats of identical size");
    2249           0 :                 goto exit2;
    2250             :         }
    2251           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2252           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2253           0 :                 goto exit2;
    2254             :         }
    2255             : 
    2256           1 :         off1 = left->hseqbase;
    2257           1 :         off2 = right->hseqbase;
    2258           1 :         lefti = bat_iterator(left);
    2259           1 :         righti = bat_iterator(right);
    2260           1 :         vals = Tloc(bn, 0);
    2261           1 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    2262           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2263           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    2264           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    2265           4 :                         char *x = BUNtvar(lefti, p1);
    2266           4 :                         char *y = BUNtvar(righti, p2);
    2267             : 
    2268           8 :                         if (strNil(x) || strNil(y)) {
    2269           0 :                                 vals[i] = int_nil;
    2270           0 :                                 nils = true;
    2271             :                         } else {
    2272           4 :                                 vals[i] = func(x, y);
    2273             :                         }
    2274             :                 }
    2275             :         } else {
    2276           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2277           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    2278           0 :                                 p2 = (canditer_next(&ci2) - off2);
    2279           0 :                         char *x = BUNtvar(lefti, p1);
    2280           0 :                         char *y = BUNtvar(righti, p2);
    2281             : 
    2282           0 :                         if (strNil(x) || strNil(y)) {
    2283           0 :                                 vals[i] = int_nil;
    2284           0 :                                 nils = true;
    2285             :                         } else {
    2286           0 :                                 vals[i] = func(x, y);
    2287             :                         }
    2288             :                 }
    2289             :         }
    2290           1 :         bat_iterator_end(&lefti);
    2291           1 :         bat_iterator_end(&righti);
    2292           1 :   exit2:
    2293           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2294           1 :         unfix_inputs(4, left, lefts, right, rights);
    2295           1 :         return msg;
    2296             : }
    2297             : 
    2298             : static str
    2299           1 : BATSTRstr_search(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2300             : {
    2301           1 :         bit *icase = NULL;
    2302           1 :         switch (pci->argc) {
    2303           0 :         case 4:
    2304           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2305           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2306             :                 break;
    2307           0 :         case 6:
    2308           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2309           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2310           0 :                 break;
    2311             :         }
    2312           1 :         return search_string_bat(cntxt, mb, stk, pci, "batstr.search",
    2313             :                                                          (icase
    2314           0 :                                                           && *icase) ? str_isearch : str_search, icase);
    2315             : }
    2316             : 
    2317             : static str
    2318           0 : BATSTRrevstr_search(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2319             : {
    2320           0 :         bit *icase = NULL;
    2321           0 :         switch (pci->argc) {
    2322           0 :         case 4:
    2323           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2324           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2325             :                 break;
    2326           0 :         case 6:
    2327           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2328           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2329           0 :                 break;
    2330             :         }
    2331           0 :         return search_string_bat(cntxt, mb, stk, pci, "batstr.r_search",
    2332           0 :                                                          (icase && *icase) ?
    2333             :                                                          str_reverse_str_isearch :
    2334             :                                                          str_reverse_str_search, icase);
    2335             : }
    2336             : 
    2337             : static str
    2338           1 : search_string_bat_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2339             :                                           const char *name, int (*func)(const char *, const char *),
    2340             :                                           bit *icase)
    2341             : {
    2342           1 :          (void) cntxt;
    2343           1 :         (void) mb;
    2344             : 
    2345           1 :         BATiter bi;
    2346           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2347           1 :         int *restrict vals;
    2348           1 :         const char *y = *getArgReference_str(stk, pci, 2);
    2349           1 :         str msg = MAL_SUCCEED;
    2350           1 :         bool nils = false;
    2351           1 :         struct canditer ci1 = { 0 };
    2352           1 :         oid off1;
    2353           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2354           1 :                 bid = *getArgReference_bat(stk, pci, 1),
    2355           1 :                 *sid1 = NULL;
    2356           1 :         int ynil;
    2357             : 
    2358           1 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2359           0 :                 assert(isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2360           0 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2361             :         }
    2362             : 
    2363           1 :         if (!(b = BATdescriptor(bid))) {
    2364           0 :                 msg = createException(MAL, name,
    2365             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2366           0 :                 goto exit2;
    2367             :         }
    2368           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2369           0 :                 msg = createException(MAL, name,
    2370             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2371           0 :                 goto exit2;
    2372             :         }
    2373           1 :         canditer_init(&ci1, b, bs);
    2374           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2375           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2376           0 :                 goto exit2;
    2377             :         }
    2378             : 
    2379           1 :         off1 = b->hseqbase;
    2380           1 :         bi = bat_iterator(b);
    2381           1 :         vals = Tloc(bn, 0);
    2382           1 :         ynil = strNil(y);
    2383           1 :         if (ci1.tpe == cand_dense) {
    2384           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2385           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2386           4 :                         char *x = BUNtvar(bi, p1);
    2387             : 
    2388           4 :                         if (ynil || strNil(x)) {
    2389           0 :                                 vals[i] = int_nil;
    2390           0 :                                 nils = true;
    2391             :                         } else {
    2392           4 :                                 vals[i] = func(x, y);
    2393             :                         }
    2394             :                 }
    2395             :         } else {
    2396           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2397           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2398           0 :                         char *x = BUNtvar(bi, p1);
    2399             : 
    2400           0 :                         if (ynil || strNil(x)) {
    2401           0 :                                 vals[i] = int_nil;
    2402           0 :                                 nils = true;
    2403             :                         } else {
    2404           0 :                                 vals[i] = func(x, y);
    2405             :                         }
    2406             :                 }
    2407             :         }
    2408           1 :         bat_iterator_end(&bi);
    2409           1 :   exit2:
    2410           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2411           1 :         unfix_inputs(2, b, bs);
    2412           1 :         return msg;
    2413             : }
    2414             : 
    2415             : static str
    2416           1 : BATSTRstr_search_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2417             : {
    2418           1 :         bit *icase = NULL;
    2419           1 :         switch (pci->argc) {
    2420           0 :         case 4:
    2421           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2422           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2423             :                 break;
    2424           0 :         case 5:
    2425           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2426           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2427           0 :                 break;
    2428             :         }
    2429           1 :         return search_string_bat_cst(cntxt, mb, stk, pci, "batstr.search",
    2430             :                                                                  (icase
    2431           0 :                                                                   && *icase) ? str_isearch : str_search, icase);
    2432             : }
    2433             : 
    2434             : static str
    2435           0 : BATSTRrevstr_search_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2436             : {
    2437           0 :         bit *icase = NULL;
    2438           0 :         switch (pci->argc) {
    2439           0 :         case 4:
    2440           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2441           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2442             :                 break;
    2443           0 :         case 5:
    2444           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2445           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2446           0 :                 break;
    2447             :         }
    2448           0 :         return search_string_bat_cst(cntxt, mb, stk, pci, "batstr.r_search",
    2449             :                                                                  (icase
    2450           0 :                                                                   && *icase) ? str_reverse_str_isearch :
    2451             :                                                                  str_reverse_str_search, icase);
    2452             : }
    2453             : 
    2454             : static str
    2455           0 : search_string_bat_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2456             :                                                  InstrPtr pci, const char *name,
    2457             :                                                  int (*func)(const char *, const char *),
    2458             :                                                  bit *icase)
    2459             : {
    2460           0 :         (void) cntxt;
    2461           0 :         (void) mb;
    2462             : 
    2463           0 :         BATiter bi;
    2464           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2465           0 :         int *restrict vals;
    2466           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    2467           0 :         str msg = MAL_SUCCEED;
    2468           0 :         bool nils = false;
    2469           0 :         struct canditer ci1 = { 0 };
    2470           0 :         oid off1;
    2471           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2472           0 :                         bid = *getArgReference_bat(stk, pci, 2), *sid1 = NULL;
    2473           0 :         int xnil;
    2474             : 
    2475           0 :         if ((!icase && (pci->argc == 4)) || pci->argc == 5) {
    2476           0 :                 assert(isaBatType(getArgType(mb, pci, icase ? 4 : 3)));
    2477           0 :                 sid1 = getArgReference_bat(stk, pci, icase ? 4 : 3);
    2478             :         }
    2479             : 
    2480           0 :         if (!(b = BATdescriptor(bid))) {
    2481           0 :                 msg = createException(MAL, name,
    2482             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2483           0 :                 goto exit2;
    2484             :         }
    2485           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2486           0 :                 msg = createException(MAL, name,
    2487             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2488           0 :                 goto exit2;
    2489             :         }
    2490           0 :         canditer_init(&ci1, b, bs);
    2491           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2492           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2493           0 :                 goto exit2;
    2494             :         }
    2495             : 
    2496           0 :         off1 = b->hseqbase;
    2497           0 :         bi = bat_iterator(b);
    2498           0 :         vals = Tloc(bn, 0);
    2499           0 :         xnil = strNil(x);
    2500           0 :         if (ci1.tpe == cand_dense) {
    2501           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2502           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2503           0 :                         char *y = BUNtvar(bi, p1);
    2504             : 
    2505           0 :                         if (xnil || strNil(y)) {
    2506           0 :                                 vals[i] = int_nil;
    2507           0 :                                 nils = true;
    2508             :                         } else {
    2509           0 :                                 vals[i] = func(x, y);
    2510             :                         }
    2511             :                 }
    2512             :         } else {
    2513           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2514           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2515           0 :                         char *y = BUNtvar(bi, p1);
    2516             : 
    2517           0 :                         if (xnil || strNil(y)) {
    2518           0 :                                 vals[i] = int_nil;
    2519           0 :                                 nils = true;
    2520             :                         } else {
    2521           0 :                                 vals[i] = func(x, y);
    2522             :                         }
    2523             :                 }
    2524             :         }
    2525           0 :         bat_iterator_end(&bi);
    2526           0 :   exit2:
    2527           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2528           0 :         unfix_inputs(2, b, bs);
    2529           0 :         return msg;
    2530             : }
    2531             : 
    2532             : static str
    2533           0 : BATSTRstr_search_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2534             : {
    2535           0 :         bit *icase = NULL;
    2536           0 :         switch (pci->argc) {
    2537           0 :         case 4:
    2538           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2539           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2540             :                 break;
    2541           0 :         case 5:
    2542           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2543           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2544           0 :                 break;
    2545             :         }
    2546           0 :         return search_string_bat_strcst(cntxt, mb, stk, pci, "batstr.search",
    2547             :                                                                         (icase
    2548           0 :                                                                          && *icase) ? str_isearch : str_search,
    2549             :                                                                         icase);
    2550             : }
    2551             : 
    2552             : static str
    2553           0 : BATSTRrevstr_search_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2554             :                                                    InstrPtr pci)
    2555             : {
    2556           0 :         bit *icase = NULL;
    2557           0 :         switch (pci->argc) {
    2558           0 :         case 4:
    2559           0 :                 if (getArgType(mb, pci, 3) == TYPE_bit)
    2560           0 :                         icase = getArgReference_bit(stk, pci, 3);
    2561             :                 break;
    2562           0 :         case 5:
    2563           0 :                 assert(getArgType(mb, pci, 3) == TYPE_bit);
    2564           0 :                 icase = getArgReference_bit(stk, pci, 3);
    2565           0 :                 break;
    2566             :         }
    2567           0 :         return search_string_bat_strcst(cntxt, mb, stk, pci, "batstr.r_search",
    2568             :                                                                         (icase
    2569           0 :                                                                          && *icase) ? str_reverse_str_isearch :
    2570             :                                                                         str_reverse_str_search, icase);
    2571             : }
    2572             : 
    2573             : static str
    2574           0 : STRbatWChrAt(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2575             : {
    2576           0 :         BATiter lefti, bi;
    2577           0 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    2578           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2579           0 :         int *restrict righti, *restrict vals, next, y;
    2580           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2581           0 :         bool nils = false;
    2582           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    2583           0 :         oid off1, off2;
    2584           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2585           0 :                 l = *getArgReference_bat(stk, pci, 1),
    2586           0 :                 r = *getArgReference_bat(stk, pci, 2),
    2587           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    2588           0 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    2589             : 
    2590           0 :         (void) cntxt;
    2591           0 :         (void) mb;
    2592           0 :         if (!buf) {
    2593           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2594             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2595           0 :                 goto bailout;
    2596             :         }
    2597           0 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    2598           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2599             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2600           0 :                 goto bailout;
    2601             :         }
    2602           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    2603           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    2604           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2605             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2606           0 :                 goto bailout;
    2607             :         }
    2608           0 :         canditer_init(&ci1, left, lefts);
    2609           0 :         canditer_init(&ci2, right, rights);
    2610           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    2611           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2612             :                                                           ILLEGAL_ARGUMENT
    2613             :                                                           " Requires bats of identical size");
    2614           0 :                 goto bailout;
    2615             :         }
    2616           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2617           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2618             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2619           0 :                 goto bailout;
    2620             :         }
    2621             : 
    2622           0 :         off1 = left->hseqbase;
    2623           0 :         off2 = right->hseqbase;
    2624           0 :         lefti = bat_iterator(left);
    2625           0 :         bi = bat_iterator(right);
    2626           0 :         righti = bi.base;
    2627           0 :         vals = Tloc(bn, 0);
    2628           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    2629           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2630           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    2631           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    2632           0 :                         const char *x = BUNtvar(lefti, p1);
    2633           0 :                         y = righti[p2];
    2634             : 
    2635           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2636           0 :                                 goto bailout1;
    2637           0 :                         vals[i] = next;
    2638           0 :                         nils |= is_int_nil(next);
    2639             :                 }
    2640             :         } else {
    2641           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2642           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    2643           0 :                                 p2 = (canditer_next(&ci2) - off2);
    2644           0 :                         const char *x = BUNtvar(lefti, p1);
    2645           0 :                         y = righti[p2];
    2646             : 
    2647           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2648           0 :                                 goto bailout1;
    2649           0 :                         vals[i] = next;
    2650           0 :                         nils |= is_int_nil(next);
    2651             :                 }
    2652             :         }
    2653           0 :   bailout1:
    2654           0 :         bat_iterator_end(&bi);
    2655           0 :         bat_iterator_end(&lefti);
    2656           0 :   bailout:
    2657           0 :         GDKfree(buf);
    2658           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2659           0 :         unfix_inputs(4, left, lefts, right, rights);
    2660           0 :         return msg;
    2661             : }
    2662             : 
    2663             : static str
    2664           0 : STRbatWChrAtcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2665             : {
    2666           0 :         BATiter bi;
    2667           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2668           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2669           0 :         int y = *getArgReference_int(stk, pci, 2), *restrict vals, next;
    2670           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2671           0 :         bool nils = false;
    2672           0 :         struct canditer ci1 = { 0 };
    2673           0 :         oid off1;
    2674           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2675           0 :                 l = *getArgReference_bat(stk, pci, 1),
    2676           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2677             : 
    2678           0 :         (void) cntxt;
    2679           0 :         (void) mb;
    2680           0 :         if (!buf) {
    2681           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2682             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2683           0 :                 goto bailout;
    2684             :         }
    2685           0 :         if (!(b = BATdescriptor(l))) {
    2686           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2687             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2688           0 :                 goto bailout;
    2689             :         }
    2690           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2691           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2692             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2693           0 :                 goto bailout;
    2694             :         }
    2695           0 :         canditer_init(&ci1, b, bs);
    2696           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2697           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2698             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2699           0 :                 goto bailout;
    2700             :         }
    2701             : 
    2702           0 :         off1 = b->hseqbase;
    2703           0 :         bi = bat_iterator(b);
    2704           0 :         vals = Tloc(bn, 0);
    2705           0 :         if (ci1.tpe == cand_dense) {
    2706           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2707           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2708           0 :                         const char *x = BUNtvar(bi, p1);
    2709             : 
    2710           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2711           0 :                                 goto bailout1;
    2712           0 :                         vals[i] = next;
    2713           0 :                         nils |= is_int_nil(next);
    2714             :                 }
    2715             :         } else {
    2716           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2717           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2718           0 :                         const char *x = BUNtvar(bi, p1);
    2719             : 
    2720           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2721           0 :                                 goto bailout1;
    2722           0 :                         vals[i] = next;
    2723           0 :                         nils |= is_int_nil(next);
    2724             :                 }
    2725             :         }
    2726           0 :   bailout1:
    2727           0 :         bat_iterator_end(&bi);
    2728           0 :   bailout:
    2729           0 :         GDKfree(buf);
    2730           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2731           0 :         unfix_inputs(2, b, bs);
    2732           0 :         return msg;
    2733             : }
    2734             : 
    2735             : static str
    2736           0 : STRbatWChrAt_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2737             : {
    2738           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2739           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2740           0 :         int y, *restrict vals, *restrict input, next;
    2741           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    2742           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2743           0 :         bool nils = false;
    2744           0 :         struct canditer ci1 = { 0 };
    2745           0 :         oid off1;
    2746           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    2747           0 :                 l = *getArgReference_bat(stk, pci, 2),
    2748           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2749           0 :         BATiter bi;
    2750             : 
    2751           0 :         (void) cntxt;
    2752           0 :         (void) mb;
    2753           0 :         if (!buf) {
    2754           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2755             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2756           0 :                 goto bailout;
    2757             :         }
    2758           0 :         if (!(b = BATdescriptor(l))) {
    2759           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2760             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2761           0 :                 goto bailout;
    2762             :         }
    2763           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2764           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2765             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2766           0 :                 goto bailout;
    2767             :         }
    2768           0 :         canditer_init(&ci1, b, bs);
    2769           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    2770           0 :                 msg = createException(MAL, "batstr.unicodeAt",
    2771             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2772           0 :                 goto bailout;
    2773             :         }
    2774             : 
    2775           0 :         off1 = b->hseqbase;
    2776           0 :         bi = bat_iterator(b);
    2777           0 :         input = bi.base;
    2778           0 :         vals = Tloc(bn, 0);
    2779           0 :         if (ci1.tpe == cand_dense) {
    2780           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2781           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2782           0 :                         y = input[p1];
    2783             : 
    2784           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2785           0 :                                 goto bailout1;
    2786           0 :                         vals[i] = next;
    2787           0 :                         nils |= is_int_nil(next);
    2788             :                 }
    2789             :         } else {
    2790           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2791           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2792           0 :                         y = input[p1];
    2793             : 
    2794           0 :                         if ((msg = str_wchr_at(&next, x, y)) != MAL_SUCCEED)
    2795           0 :                                 goto bailout1;
    2796           0 :                         vals[i] = next;
    2797           0 :                         nils |= is_int_nil(next);
    2798             :                 }
    2799             :         }
    2800           0 :   bailout1:
    2801           0 :         bat_iterator_end(&bi);
    2802           0 :   bailout:
    2803           0 :         GDKfree(buf);
    2804           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2805           0 :         unfix_inputs(2, b, bs);
    2806           0 :         return msg;
    2807             : }
    2808             : 
    2809             : static str
    2810          84 : do_batstr_str_int_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    2811             :                                           const char *name, str (*func)(str *, size_t *,
    2812             :                                                                                                         const char *, int))
    2813             : {
    2814          84 :         BATiter bi;
    2815          84 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2816          84 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2817          84 :         int y = *getArgReference_int(stk, pci, 2);
    2818          84 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2819          84 :         bool nils = false;
    2820          84 :         struct canditer ci1 = { 0 };
    2821          84 :         oid off1;
    2822          84 :         bat *res = getArgReference_bat(stk, pci, 0),
    2823          84 :                 l = *getArgReference_bat(stk, pci, 1),
    2824          84 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2825             : 
    2826          84 :         (void) cntxt;
    2827          84 :         (void) mb;
    2828          84 :         if (!buf) {
    2829           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2830           0 :                 goto bailout;
    2831             :         }
    2832          84 :         if (!(b = BATdescriptor(l))) {
    2833           0 :                 msg = createException(MAL, name,
    2834             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2835           0 :                 goto bailout;
    2836             :         }
    2837          84 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2838           0 :                 msg = createException(MAL, name,
    2839             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2840           0 :                 goto bailout;
    2841             :         }
    2842          84 :         canditer_init(&ci1, b, bs);
    2843          84 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2844           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2845           0 :                 goto bailout;
    2846             :         }
    2847             : 
    2848          84 :         off1 = b->hseqbase;
    2849          84 :         bi = bat_iterator(b);
    2850          84 :         if (ci1.tpe == cand_dense) {
    2851        6162 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2852        6078 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2853        6078 :                         const char *x = BUNtvar(bi, p1);
    2854             : 
    2855       11725 :                         if (strNil(x) || is_int_nil(y)) {
    2856         434 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2857           0 :                                         msg = createException(MAL, name,
    2858             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2859           0 :                                         goto bailout1;
    2860             :                                 }
    2861             :                                 nils = true;
    2862             :                         } else {
    2863        5644 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    2864           0 :                                         goto bailout1;
    2865        5644 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2866           0 :                                         msg = createException(MAL, name,
    2867             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2868           0 :                                         goto bailout1;
    2869             :                                 }
    2870             :                         }
    2871             :                 }
    2872             :         } else {
    2873           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2874           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2875           0 :                         const char *x = BUNtvar(bi, p1);
    2876             : 
    2877           0 :                         if (strNil(x) || is_int_nil(y)) {
    2878           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2879           0 :                                         msg = createException(MAL, name,
    2880             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2881           0 :                                         goto bailout1;
    2882             :                                 }
    2883             :                                 nils = true;
    2884             :                         } else {
    2885           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    2886           0 :                                         goto bailout1;
    2887           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2888           0 :                                         msg = createException(MAL, name,
    2889             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2890           0 :                                         goto bailout1;
    2891             :                                 }
    2892             :                         }
    2893             :                 }
    2894             :         }
    2895           0 :   bailout1:
    2896          84 :         bat_iterator_end(&bi);
    2897          84 :   bailout:
    2898          84 :         GDKfree(buf);
    2899          84 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2900          84 :         unfix_inputs(2, b, bs);
    2901          84 :         return msg;
    2902             : }
    2903             : 
    2904             : static str
    2905          74 : STRbatprefixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2906             : {
    2907          74 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.prefix",
    2908             :                                                                  str_prefix);
    2909             : }
    2910             : 
    2911             : static str
    2912           1 : STRbatsuffixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2913             : {
    2914           1 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.suffix",
    2915             :                                                                  str_suffix);
    2916             : }
    2917             : 
    2918             : static str
    2919           5 : STRbatTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2920             : {
    2921           5 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    2922             : }
    2923             : 
    2924             : static str
    2925           4 : STRbatsubstringTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2926             : {
    2927           4 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.substring",
    2928             :                                                                  str_substring_tail);
    2929             : }
    2930             : 
    2931             : static str
    2932           1 : STRbatrepeatcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2933             : {
    2934           1 :         BATiter bi;
    2935           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2936           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2937           1 :         int y = *getArgReference_int(stk, pci, 2);
    2938           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2939           1 :         bool nils = false;
    2940           1 :         struct canditer ci1 = { 0 };
    2941           1 :         oid off1;
    2942           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2943           1 :                 l = *getArgReference_bat(stk, pci, 1),
    2944           1 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2945             : 
    2946           1 :         (void) cntxt;
    2947           1 :         (void) mb;
    2948           1 :         if (!buf) {
    2949           0 :                 msg = createException(MAL, "batstr.repeat",
    2950             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2951           0 :                 goto bailout;
    2952             :         }
    2953           1 :         if (!(b = BATdescriptor(l))) {
    2954           0 :                 msg = createException(MAL, "batstr.repeat",
    2955             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2956           0 :                 goto bailout;
    2957             :         }
    2958           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2959           0 :                 msg = createException(MAL, "batstr.repeat",
    2960             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2961           0 :                 goto bailout;
    2962             :         }
    2963           1 :         canditer_init(&ci1, b, bs);
    2964           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2965           0 :                 msg = createException(MAL, "batstr.repeat",
    2966             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2967           0 :                 goto bailout;
    2968             :         }
    2969             : 
    2970           1 :         off1 = b->hseqbase;
    2971           1 :         bi = bat_iterator(b);
    2972           1 :         if (ci1.tpe == cand_dense) {
    2973           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2974           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2975           4 :                         const char *x = BUNtvar(bi, p1);
    2976             : 
    2977           8 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    2978           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2979           0 :                                         msg = createException(MAL, "batstr.repeat",
    2980             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2981           0 :                                         goto bailout1;
    2982             :                                 }
    2983             :                                 nils = true;
    2984             :                         } else {
    2985           4 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    2986           0 :                                         goto bailout1;
    2987           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2988           0 :                                         msg = createException(MAL, "batstr.repeat",
    2989             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2990           0 :                                         goto bailout1;
    2991             :                                 }
    2992             :                         }
    2993             :                 }
    2994             :         } else {
    2995           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2996           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2997           0 :                         const char *x = BUNtvar(bi, p1);
    2998             : 
    2999           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3000           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3001           0 :                                         msg = createException(MAL, "batstr.repeat",
    3002             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3003           0 :                                         goto bailout1;
    3004             :                                 }
    3005             :                                 nils = true;
    3006             :                         } else {
    3007           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3008           0 :                                         goto bailout1;
    3009           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3010           0 :                                         msg = createException(MAL, "batstr.repeat",
    3011             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3012           0 :                                         goto bailout1;
    3013             :                                 }
    3014             :                         }
    3015             :                 }
    3016             :         }
    3017           0 :   bailout1:
    3018           1 :         bat_iterator_end(&bi);
    3019           1 :   bailout:
    3020           1 :         GDKfree(buf);
    3021           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3022           1 :         unfix_inputs(2, b, bs);
    3023           1 :         return msg;
    3024             : }
    3025             : 
    3026             : static str
    3027           4 : do_batstr_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3028             :                                  const char *name,
    3029             :                                  str (*func)(str *, size_t *, const char *, int))
    3030             : {
    3031           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3032           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3033           4 :         int *restrict vals, y;
    3034           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    3035           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3036           4 :         bool nils = false;
    3037           4 :         struct canditer ci1 = { 0 };
    3038           4 :         oid off1;
    3039           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    3040           4 :                 l = *getArgReference_bat(stk, pci, 2),
    3041           4 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3042           4 :         BATiter bi;
    3043             : 
    3044           4 :         (void) cntxt;
    3045           4 :         (void) mb;
    3046           4 :         if (!buf) {
    3047           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3048           0 :                 goto bailout;
    3049             :         }
    3050           4 :         if (!(b = BATdescriptor(l))) {
    3051           0 :                 msg = createException(MAL, name,
    3052             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3053           0 :                 goto bailout;
    3054             :         }
    3055           4 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3056           0 :                 msg = createException(MAL, name,
    3057             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3058           0 :                 goto bailout;
    3059             :         }
    3060           4 :         canditer_init(&ci1, b, bs);
    3061           4 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3062           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3063           0 :                 goto bailout;
    3064             :         }
    3065             : 
    3066           4 :         off1 = b->hseqbase;
    3067           4 :         bi = bat_iterator(b);
    3068           4 :         vals = bi.base;
    3069           4 :         if (ci1.tpe == cand_dense) {
    3070           9 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3071           5 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3072           5 :                         y = vals[p1];
    3073             : 
    3074          10 :                         if (strNil(x) || is_int_nil(y)) {
    3075           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3076           0 :                                         msg = createException(MAL, name,
    3077             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3078           0 :                                         goto bailout1;
    3079             :                                 }
    3080             :                                 nils = true;
    3081             :                         } else {
    3082           5 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3083           0 :                                         goto bailout1;
    3084           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           4 :         bat_iterator_end(&bi);
    3116           4 :   bailout:
    3117           4 :         GDKfree(buf);
    3118           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3119           4 :         unfix_inputs(2, b, bs);
    3120           4 :         return msg;
    3121             : }
    3122             : 
    3123             : static str
    3124           4 : STRbatprefix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3125             : {
    3126           4 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.prefix", str_prefix);
    3127             : }
    3128             : 
    3129             : static str
    3130           0 : STRbatsuffix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3131             : {
    3132           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.suffix", str_suffix);
    3133             : }
    3134             : 
    3135             : static str
    3136           0 : STRbatTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3137             : {
    3138           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    3139             : }
    3140             : 
    3141             : static str
    3142           0 : STRbatsubstringTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3143             :                                                    InstrPtr pci)
    3144             : {
    3145           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.substring",
    3146             :                                                         str_substring_tail);
    3147             : }
    3148             : 
    3149             : static str
    3150           0 : STRbatrepeat_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3151             : {
    3152           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3153           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3154           0 :         int *restrict vals, y;
    3155           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    3156           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3157           0 :         bool nils = false;
    3158           0 :         struct canditer ci1 = { 0 };
    3159           0 :         oid off1;
    3160           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3161           0 :                 l = *getArgReference_bat(stk, pci, 2),
    3162           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3163           0 :         BATiter bi;
    3164             : 
    3165           0 :         (void) cntxt;
    3166           0 :         (void) mb;
    3167           0 :         if (!buf) {
    3168           0 :                 msg = createException(MAL, "batstr.repeat",
    3169             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3170           0 :                 goto bailout;
    3171             :         }
    3172           0 :         if (!(b = BATdescriptor(l))) {
    3173           0 :                 msg = createException(MAL, "batstr.repeat",
    3174             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3175           0 :                 goto bailout;
    3176             :         }
    3177           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3178           0 :                 msg = createException(MAL, "batstr.repeat",
    3179             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3180           0 :                 goto bailout;
    3181             :         }
    3182           0 :         canditer_init(&ci1, b, bs);
    3183           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3184           0 :                 msg = createException(MAL, "batstr.repeat",
    3185             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3186           0 :                 goto bailout;
    3187             :         }
    3188             : 
    3189           0 :         off1 = b->hseqbase;
    3190           0 :         bi = bat_iterator(b);
    3191           0 :         vals = bi.base;
    3192           0 :         if (ci1.tpe == cand_dense) {
    3193           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3194           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3195           0 :                         y = vals[p1];
    3196             : 
    3197           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3198           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3199           0 :                                         msg = createException(MAL, "batstr.repeat",
    3200             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3201           0 :                                         goto bailout1;
    3202             :                                 }
    3203             :                                 nils = true;
    3204             :                         } else {
    3205           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3206           0 :                                         goto bailout1;
    3207           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3208           0 :                                         msg = createException(MAL, "batstr.repeat",
    3209             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3210           0 :                                         goto bailout1;
    3211             :                                 }
    3212             :                         }
    3213             :                 }
    3214             :         } else {
    3215           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3216           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3217           0 :                         y = vals[p1];
    3218             : 
    3219           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3220           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3221           0 :                                         msg = createException(MAL, "batstr.repeat",
    3222             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3223           0 :                                         goto bailout1;
    3224             :                                 }
    3225             :                                 nils = true;
    3226             :                         } else {
    3227           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3228           0 :                                         goto bailout1;
    3229           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3230           0 :                                         msg = createException(MAL, "batstr.repeat",
    3231             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3232           0 :                                         goto bailout1;
    3233             :                                 }
    3234             :                         }
    3235             :                 }
    3236             :         }
    3237           0 :   bailout1:
    3238           0 :         bat_iterator_end(&bi);
    3239           0 :   bailout:
    3240           0 :         GDKfree(buf);
    3241           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3242           0 :         unfix_inputs(2, b, bs);
    3243           0 :         return msg;
    3244             : }
    3245             : 
    3246             : static str
    3247          33 : do_batstr_str_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3248             :                                   const char *name, str (*func)(str *, size_t *, const char *,
    3249             :                                                                                                 int))
    3250             : {
    3251          33 :         BATiter lefti;
    3252          33 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    3253          33 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3254          33 :         int *restrict righti, y;
    3255          33 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3256          33 :         bool nils = false;
    3257          33 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3258          33 :         oid off1, off2;
    3259          33 :         bat *res = getArgReference_bat(stk, pci, 0),
    3260          33 :                 l = *getArgReference_bat(stk, pci, 1),
    3261          33 :                 r = *getArgReference_bat(stk, pci, 2),
    3262          33 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    3263          33 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3264          33 :         BATiter bi;
    3265             : 
    3266          33 :         (void) cntxt;
    3267          33 :         (void) mb;
    3268          33 :         if (!buf) {
    3269           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3270           0 :                 goto bailout;
    3271             :         }
    3272          33 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    3273           0 :                 msg = createException(MAL, name,
    3274             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3275           0 :                 goto bailout;
    3276             :         }
    3277          33 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    3278          33 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    3279           0 :                 msg = createException(MAL, name,
    3280             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3281           0 :                 goto bailout;
    3282             :         }
    3283          33 :         canditer_init(&ci1, left, lefts);
    3284          33 :         canditer_init(&ci2, right, rights);
    3285          33 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3286           0 :                 msg = createException(MAL, name,
    3287             :                                                           ILLEGAL_ARGUMENT
    3288             :                                                           " Requires bats of identical size");
    3289           0 :                 goto bailout;
    3290             :         }
    3291          33 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3292           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3293           0 :                 goto bailout;
    3294             :         }
    3295             : 
    3296          33 :         off1 = left->hseqbase;
    3297          33 :         off2 = right->hseqbase;
    3298          33 :         lefti = bat_iterator(left);
    3299          33 :         bi = bat_iterator(right);
    3300          33 :         righti = bi.base;
    3301          33 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3302       32484 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3303       32451 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3304       32451 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3305       32451 :                         const char *x = BUNtvar(lefti, p1);
    3306       32449 :                         y = righti[p2];
    3307             : 
    3308       36262 :                         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        3813 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3317           0 :                                         goto bailout1;
    3318        3807 :                                 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      117399 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3545      117047 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3546      117047 :                         const char *x = BUNtvar(bi, p1);
    3547             : 
    3548      465572 :                         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      116183 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3557           0 :                                         goto bailout1;
    3558      116147 :                                 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         352 :         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          86 : STRbatsubstring_2nd_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4575             :                                                         InstrPtr pci)
    4576             : {
    4577          86 :         BATiter bi;
    4578          86 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4579          86 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4580          86 :         int y = *getArgReference_int(stk, pci, 2),
    4581          86 :                 z = *getArgReference_int(stk, pci, 3);
    4582          86 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4583          86 :         bool nils = false;
    4584          86 :         struct canditer ci1 = { 0 };
    4585          86 :         oid off1;
    4586          86 :         bat *res = getArgReference_bat(stk, pci, 0),
    4587          86 :                 bid = *getArgReference_bat(stk, pci, 1),
    4588          86 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4589             : 
    4590          86 :         (void) cntxt;
    4591          86 :         (void) mb;
    4592          86 :         if (!buf) {
    4593           0 :                 msg = createException(MAL, "batstr.substring",
    4594             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4595           0 :                 goto bailout;
    4596             :         }
    4597          86 :         if (!(b = BATdescriptor(bid))) {
    4598           0 :                 msg = createException(MAL, "batstr.substring",
    4599             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4600           0 :                 goto bailout;
    4601             :         }
    4602          86 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4603           0 :                 msg = createException(MAL, "batstr.substring",
    4604             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4605           0 :                 goto bailout;
    4606             :         }
    4607          86 :         canditer_init(&ci1, b, bs);
    4608          86 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4609           0 :                 msg = createException(MAL, "batstr.substring",
    4610             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4611           0 :                 goto bailout;
    4612             :         }
    4613             : 
    4614          86 :         off1 = b->hseqbase;
    4615          86 :         bi = bat_iterator(b);
    4616          86 :         if (ci1.tpe == cand_dense) {
    4617     3941198 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4618     3941112 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4619     3941112 :                         const char *x = BUNtvar(bi, p1);
    4620             : 
    4621     7753085 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4622      106798 :                                 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     3819443 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4630           0 :                                         goto bailout1;
    4631     3821053 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4632           0 :                                         msg = createException(MAL, "batstr.substring",
    4633             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4634           0 :                                         goto bailout1;
    4635             :                                 }
    4636             :                         }
    4637             :                 }
    4638             :         } else {
    4639           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4640           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4641           0 :                         const char *x = BUNtvar(bi, p1);
    4642             : 
    4643           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4644           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4645           0 :                                         msg = createException(MAL, "batstr.substring",
    4646             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4647           0 :                                         goto bailout1;
    4648             :                                 }
    4649             :                                 nils = true;
    4650             :                         } else {
    4651           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4652           0 :                                         goto bailout1;
    4653           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4654           0 :                                         msg = createException(MAL, "batstr.substring",
    4655             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4656           0 :                                         goto bailout1;
    4657             :                                 }
    4658             :                         }
    4659             :                 }
    4660             :         }
    4661           0 :   bailout1:
    4662          86 :         bat_iterator_end(&bi);
    4663          86 :   bailout:
    4664          86 :         GDKfree(buf);
    4665          86 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4666          86 :         unfix_inputs(2, b, bs);
    4667          86 :         return msg;
    4668             : }
    4669             : 
    4670             : static str
    4671           1 : STRbatsubstring_1st_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4672             :                                                         InstrPtr pci)
    4673             : {
    4674           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4675           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4676           1 :         int y = *getArgReference_int(stk, pci, 2), z, *restrict input;
    4677           1 :         const char *x = *getArgReference_str(stk, pci, 1);
    4678           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4679           1 :         bool nils = false;
    4680           1 :         struct canditer ci1 = { 0 };
    4681           1 :         oid off1;
    4682           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    4683           1 :                 bid = *getArgReference_bat(stk, pci, 3),
    4684           1 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4685           1 :         BATiter bi;
    4686             : 
    4687           1 :         (void) cntxt;
    4688           1 :         (void) mb;
    4689           1 :         if (!buf) {
    4690           0 :                 msg = createException(MAL, "batstr.substring",
    4691             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4692           0 :                 goto bailout;
    4693             :         }
    4694           1 :         if (!(b = BATdescriptor(bid))) {
    4695           0 :                 msg = createException(MAL, "batstr.substring",
    4696             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4697           0 :                 goto bailout;
    4698             :         }
    4699           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4700           0 :                 msg = createException(MAL, "batstr.substring",
    4701             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4702           0 :                 goto bailout;
    4703             :         }
    4704           1 :         canditer_init(&ci1, b, bs);
    4705           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4706           0 :                 msg = createException(MAL, "batstr.substring",
    4707             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4708           0 :                 goto bailout;
    4709             :         }
    4710             : 
    4711           1 :         off1 = b->hseqbase;
    4712           1 :         bi = bat_iterator(b);
    4713           1 :         input = bi.base;
    4714           1 :         if (ci1.tpe == cand_dense) {
    4715           2 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4716           1 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4717           1 :                         z = input[p1];
    4718             : 
    4719           2 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4720           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4721           0 :                                         msg = createException(MAL, "batstr.substring",
    4722             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4723           0 :                                         goto bailout1;
    4724             :                                 }
    4725             :                                 nils = true;
    4726             :                         } else {
    4727           1 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4728           0 :                                         goto bailout1;
    4729           1 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4730           0 :                                         msg = createException(MAL, "batstr.substring",
    4731             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4732           0 :                                         goto bailout1;
    4733             :                                 }
    4734             :                         }
    4735             :                 }
    4736             :         } else {
    4737           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4738           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4739           0 :                         z = input[p1];
    4740             : 
    4741           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4742           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4743           0 :                                         msg = createException(MAL, "batstr.substring",
    4744             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4745           0 :                                         goto bailout1;
    4746             :                                 }
    4747             :                                 nils = true;
    4748             :                         } else {
    4749           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4750           0 :                                         goto bailout1;
    4751           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4752           0 :                                         msg = createException(MAL, "batstr.substring",
    4753             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4754           0 :                                         goto bailout1;
    4755             :                                 }
    4756             :                         }
    4757             :                 }
    4758             :         }
    4759           0 :   bailout1:
    4760           1 :         bat_iterator_end(&bi);
    4761           1 :   bailout:
    4762           1 :         GDKfree(buf);
    4763           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4764           1 :         unfix_inputs(2, b, bs);
    4765           1 :         return msg;
    4766             : }
    4767             : 
    4768             : static str
    4769           4 : STRbatsubstring_1st_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4770             :                                                         InstrPtr pci)
    4771             : {
    4772           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4773           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4774           4 :         int y, z = *getArgReference_int(stk, pci, 3), *restrict input;
    4775           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    4776           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4777           4 :         bool nils = false;
    4778           4 :         struct canditer ci1 = { 0 };
    4779           4 :         oid off1;
    4780           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    4781           4 :                 bid = *getArgReference_bat(stk, pci, 2),
    4782           4 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4783           4 :         BATiter bi;
    4784             : 
    4785           4 :         (void) cntxt;
    4786           4 :         (void) mb;
    4787           4 :         if (!buf) {
    4788           0 :                 msg = createException(MAL, "batstr.substring",
    4789             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4790           0 :                 goto bailout;
    4791             :         }
    4792           4 :         if (!(b = BATdescriptor(bid))) {
    4793           0 :                 msg = createException(MAL, "batstr.substring",
    4794             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4795           0 :                 goto bailout;
    4796             :         }
    4797           4 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4798           0 :                 msg = createException(MAL, "batstr.substring",
    4799             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4800           0 :                 goto bailout;
    4801             :         }
    4802           4 :         canditer_init(&ci1, b, bs);
    4803           4 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4804           0 :                 msg = createException(MAL, "batstr.substring",
    4805             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4806           0 :                 goto bailout;
    4807             :         }
    4808             : 
    4809           4 :         off1 = b->hseqbase;
    4810           4 :         bi = bat_iterator(b);
    4811           4 :         input = bi.base;
    4812           4 :         if (ci1.tpe == cand_dense) {
    4813           8 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4814           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4815           4 :                         y = input[p1];
    4816             : 
    4817           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4818           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4819           0 :                                         msg = createException(MAL, "batstr.substring",
    4820             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4821           0 :                                         goto bailout1;
    4822             :                                 }
    4823             :                                 nils = true;
    4824             :                         } else {
    4825           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4826           0 :                                         goto bailout1;
    4827           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4828           0 :                                         msg = createException(MAL, "batstr.substring",
    4829             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4830           0 :                                         goto bailout1;
    4831             :                                 }
    4832             :                         }
    4833             :                 }
    4834             :         } else {
    4835           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4836           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4837           0 :                         y = input[p1];
    4838             : 
    4839           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4840           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4841           0 :                                         msg = createException(MAL, "batstr.substring",
    4842             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4843           0 :                                         goto bailout1;
    4844             :                                 }
    4845             :                                 nils = true;
    4846             :                         } else {
    4847           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4848           0 :                                         goto bailout1;
    4849           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4850           0 :                                         msg = createException(MAL, "batstr.substring",
    4851             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4852           0 :                                         goto bailout1;
    4853             :                                 }
    4854             :                         }
    4855             :                 }
    4856             :         }
    4857           0 :   bailout1:
    4858           4 :         bat_iterator_end(&bi);
    4859           4 :   bailout:
    4860           4 :         GDKfree(buf);
    4861           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4862           4 :         unfix_inputs(2, b, bs);
    4863           4 :         return msg;
    4864             : }
    4865             : 
    4866             : static str
    4867           4 : STRbatsubstring_1st_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4868             : {
    4869           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4870           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4871           4 :         int y, z, *vals1, *vals2;
    4872           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    4873           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4874           4 :         bool nils = false;
    4875           4 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4876           4 :         oid off1, off2;
    4877           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    4878           4 :                 bid = *getArgReference_bat(stk, pci, 2),
    4879           4 :                 l = *getArgReference_bat(stk, pci, 3),
    4880           4 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4881           4 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4882           4 :         BATiter bi;
    4883           4 :         BATiter lbi;
    4884             : 
    4885           4 :         (void) cntxt;
    4886           4 :         (void) mb;
    4887           4 :         if (!buf) {
    4888           0 :                 msg = createException(MAL, "batstr.substring",
    4889             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4890           0 :                 goto bailout;
    4891             :         }
    4892           4 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    4893           0 :                 msg = createException(MAL, "batstr.substring",
    4894             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4895           0 :                 goto bailout;
    4896             :         }
    4897           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           4 :         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           4 :         lbi = bat_iterator(lb);
    4921           4 :         vals1 = bi.base;
    4922           4 :         vals2 = lbi.base;
    4923           4 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    4924          12 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4925           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4926           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    4927           8 :                         y = vals1[p1];
    4928           8 :                         z = vals2[p2];
    4929             : 
    4930          16 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4931           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4932           0 :                                         msg = createException(MAL, "batstr.substring",
    4933             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4934           0 :                                         goto bailout1;
    4935             :                                 }
    4936             :                                 nils = true;
    4937             :                         } else {
    4938           8 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4939           0 :                                         goto bailout1;
    4940           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4941           0 :                                         msg = createException(MAL, "batstr.substring",
    4942             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4943           0 :                                         goto bailout1;
    4944             :                                 }
    4945             :                         }
    4946             :                 }
    4947             :         } else {
    4948           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4949           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4950           0 :                                 p2 = (canditer_next(&ci2) - off2);
    4951           0 :                         y = vals1[p1];
    4952           0 :                         z = vals2[p2];
    4953             : 
    4954           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4955           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4956           0 :                                         msg = createException(MAL, "batstr.substring",
    4957             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4958           0 :                                         goto bailout1;
    4959             :                                 }
    4960             :                                 nils = true;
    4961             :                         } else {
    4962           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4963           0 :                                         goto bailout1;
    4964           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4965           0 :                                         msg = createException(MAL, "batstr.substring",
    4966             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4967           0 :                                         goto bailout1;
    4968             :                                 }
    4969             :                         }
    4970             :                 }
    4971             :         }
    4972           0 :   bailout1:
    4973           4 :         bat_iterator_end(&bi);
    4974           4 :         bat_iterator_end(&lbi);
    4975           4 :   bailout:
    4976           4 :         GDKfree(buf);
    4977           4 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4978           4 :         unfix_inputs(4, b, bs, lb, lbs);
    4979           4 :         return msg;
    4980             : }
    4981             : 
    4982             : static str
    4983          16 : STRbatsubstring_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4984             : {
    4985          16 :         BATiter bi;
    4986          16 :         BATiter lbi;
    4987          16 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4988          16 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4989          16 :         int y = *getArgReference_int(stk, pci, 2), *len, z;
    4990          16 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4991          16 :         bool nils = false;
    4992          16 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4993          16 :         oid off1, off2;
    4994          16 :         bat *res = getArgReference_bat(stk, pci, 0),
    4995          16 :                 bid = *getArgReference_bat(stk, pci, 1),
    4996          16 :                 l = *getArgReference_bat(stk, pci, 3),
    4997          16 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4998          16 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4999             : 
    5000          16 :         (void) cntxt;
    5001          16 :         (void) mb;
    5002          16 :         if (!buf) {
    5003           0 :                 msg = createException(MAL, "batstr.substring",
    5004             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5005           0 :                 goto bailout;
    5006             :         }
    5007          16 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    5008           0 :                 msg = createException(MAL, "batstr.substring",
    5009             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5010           0 :                 goto bailout;
    5011             :         }
    5012          16 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5013          16 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    5014           0 :                 msg = createException(MAL, "batstr.substring",
    5015             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5016           0 :                 goto bailout;
    5017             :         }
    5018          16 :         canditer_init(&ci1, b, bs);
    5019          16 :         canditer_init(&ci2, lb, lbs);
    5020          16 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5021           0 :                 msg = createException(MAL, "batstr.substring",
    5022             :                                                           ILLEGAL_ARGUMENT
    5023             :                                                           " Requires bats of identical size");
    5024           0 :                 goto bailout;
    5025             :         }
    5026          16 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5027           0 :                 msg = createException(MAL, "batstr.substring",
    5028             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5029           0 :                 goto bailout;
    5030             :         }
    5031             : 
    5032          16 :         off1 = b->hseqbase;
    5033          16 :         off2 = lb->hseqbase;
    5034          16 :         bi = bat_iterator(b);
    5035          16 :         lbi = bat_iterator(lb);
    5036          16 :         len = lbi.base;
    5037          16 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5038          20 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5039           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5040           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5041           4 :                         const char *x = BUNtvar(bi, p1);
    5042           4 :                         z = len[p2];
    5043             : 
    5044           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5045           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5046           0 :                                         msg = createException(MAL, "batstr.substring",
    5047             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5048           0 :                                         goto bailout1;
    5049             :                                 }
    5050             :                                 nils = true;
    5051             :                         } else {
    5052           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5053           0 :                                         goto bailout1;
    5054           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5055           0 :                                         msg = createException(MAL, "batstr.substring",
    5056             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5057           0 :                                         goto bailout1;
    5058             :                                 }
    5059             :                         }
    5060             :                 }
    5061             :         } else {
    5062           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5063           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5064           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5065           0 :                         const char *x = BUNtvar(bi, p1);
    5066           0 :                         z = len[p2];
    5067             : 
    5068           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5069           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5070           0 :                                         msg = createException(MAL, "batstr.substring",
    5071             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5072           0 :                                         goto bailout1;
    5073             :                                 }
    5074             :                                 nils = true;
    5075             :                         } else {
    5076           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5077           0 :                                         goto bailout1;
    5078           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5079           0 :                                         msg = createException(MAL, "batstr.substring",
    5080             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5081           0 :                                         goto bailout1;
    5082             :                                 }
    5083             :                         }
    5084             :                 }
    5085             :         }
    5086           0 :   bailout1:
    5087          16 :         bat_iterator_end(&lbi);
    5088          16 :         bat_iterator_end(&bi);
    5089          16 :   bailout:
    5090          16 :         GDKfree(buf);
    5091          16 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5092          16 :         unfix_inputs(4, b, bs, lb, lbs);
    5093          16 :         return msg;
    5094             : }
    5095             : 
    5096             : static str
    5097           0 : STRbatsubstring_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5098             : {
    5099           0 :         BATiter bi, lbi;
    5100           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    5101           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5102           0 :         int *start, y, z = *getArgReference_int(stk, pci, 3);
    5103           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5104           0 :         bool nils = false;
    5105           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5106           0 :         oid off1, off2;
    5107           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5108           0 :                 bid = *getArgReference_bat(stk, pci, 1),
    5109           0 :                 l = *getArgReference_bat(stk, pci, 2),
    5110           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    5111           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    5112             : 
    5113           0 :         (void) cntxt;
    5114           0 :         (void) mb;
    5115           0 :         if (!buf) {
    5116           0 :                 msg = createException(MAL, "batstr.substring",
    5117             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5118           0 :                 goto bailout;
    5119             :         }
    5120           0 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    5121           0 :                 msg = createException(MAL, "batstr.substring",
    5122             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5123           0 :                 goto bailout;
    5124             :         }
    5125           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5126           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    5127           0 :                 msg = createException(MAL, "batstr.substring",
    5128             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5129           0 :                 goto bailout;
    5130             :         }
    5131           0 :         canditer_init(&ci1, b, bs);
    5132           0 :         canditer_init(&ci2, lb, lbs);
    5133           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5134           0 :                 msg = createException(MAL, "batstr.substring",
    5135             :                                                           ILLEGAL_ARGUMENT
    5136             :                                                           " Requires bats of identical size");
    5137           0 :                 goto bailout;
    5138             :         }
    5139           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5140           0 :                 msg = createException(MAL, "batstr.substring",
    5141             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5142           0 :                 goto bailout;
    5143             :         }
    5144             : 
    5145           0 :         off1 = b->hseqbase;
    5146           0 :         off2 = lb->hseqbase;
    5147           0 :         bi = bat_iterator(b);
    5148           0 :         lbi = bat_iterator(lb);
    5149           0 :         start = lbi.base;
    5150           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5151           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5152           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5153           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5154           0 :                         const char *x = BUNtvar(bi, p1);
    5155           0 :                         y = start[p2];
    5156             : 
    5157           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5158           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5159           0 :                                         msg = createException(MAL, "batstr.substring",
    5160             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5161           0 :                                         goto bailout1;
    5162             :                                 }
    5163             :                                 nils = true;
    5164             :                         } else {
    5165           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5166           0 :                                         goto bailout1;
    5167           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5168           0 :                                         msg = createException(MAL, "batstr.substring",
    5169             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5170           0 :                                         goto bailout1;
    5171             :                                 }
    5172             :                         }
    5173             :                 }
    5174             :         } else {
    5175           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5176           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5177           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5178           0 :                         const char *x = BUNtvar(bi, p1);
    5179           0 :                         y = start[p2];
    5180             : 
    5181           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5182           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5183           0 :                                         msg = createException(MAL, "batstr.substring",
    5184             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5185           0 :                                         goto bailout1;
    5186             :                                 }
    5187             :                                 nils = true;
    5188             :                         } else {
    5189           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5190           0 :                                         goto bailout1;
    5191           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5192           0 :                                         msg = createException(MAL, "batstr.substring",
    5193             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5194           0 :                                         goto bailout1;
    5195             :                                 }
    5196             :                         }
    5197             :                 }
    5198             :         }
    5199           0 :   bailout1:
    5200           0 :         bat_iterator_end(&lbi);
    5201           0 :         bat_iterator_end(&bi);
    5202           0 :   bailout:
    5203           0 :         GDKfree(buf);
    5204           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5205           0 :         unfix_inputs(4, b, bs, lb, lbs);
    5206           0 :         return msg;
    5207             : }
    5208             : 
    5209             : static str
    5210          15 : STRbatsubstring(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5211             : {
    5212          15 :         BATiter lefti, starti, lengthi;
    5213          15 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *start = NULL,
    5214          15 :                 *ss = NULL, *length = NULL, *lens = NULL;
    5215          15 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5216          15 :         int *svals, *lvals, y, z;
    5217          15 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5218          16 :         bool nils = false;
    5219          16 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5220          16 :         oid off1, off2, off3;
    5221          16 :         bat *res = getArgReference_bat(stk, pci, 0),
    5222          16 :                 l = *getArgReference_bat(stk, pci, 1),
    5223          16 :                 r = *getArgReference_bat(stk, pci, 2),
    5224          16 :                 t = *getArgReference_bat(stk, pci, 3),
    5225          16 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5226          16 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5227          16 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5228             : 
    5229          16 :         (void) cntxt;
    5230          16 :         (void) mb;
    5231          16 :         if (!buf) {
    5232           0 :                 msg = createException(MAL, "batstr.substring",
    5233             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5234           0 :                 goto bailout;
    5235             :         }
    5236          16 :         if (!(left = BATdescriptor(l)) || !(start = BATdescriptor(r))
    5237          16 :                 || !(length = BATdescriptor(t))) {
    5238           0 :                 msg = createException(MAL, "batstr.substring",
    5239             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5240           0 :                 goto bailout;
    5241             :         }
    5242          16 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5243          16 :                 (sid2 && !is_bat_nil(*sid2) && !(ss = BATdescriptor(*sid2))) ||
    5244           0 :                 (sid3 && !is_bat_nil(*sid3) && !(lens = BATdescriptor(*sid3)))) {
    5245           0 :                 msg = createException(MAL, "batstr.substring",
    5246             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5247           0 :                 goto bailout;
    5248             :         }
    5249          16 :         canditer_init(&ci1, left, ls);
    5250          16 :         canditer_init(&ci2, start, ss);
    5251          16 :         canditer_init(&ci3, length, lens);
    5252          16 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5253          16 :                 || ci2.hseq != ci3.hseq) {
    5254           0 :                 msg = createException(MAL, "batstr.substring",
    5255             :                                                           ILLEGAL_ARGUMENT
    5256             :                                                           " Requires bats of identical size");
    5257           0 :                 goto bailout;
    5258             :         }
    5259          16 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5260           0 :                 msg = createException(MAL, "batstr.substring",
    5261             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5262           0 :                 goto bailout;
    5263             :         }
    5264             : 
    5265          16 :         off1 = left->hseqbase;
    5266          16 :         off2 = start->hseqbase;
    5267          16 :         off3 = length->hseqbase;
    5268          16 :         lefti = bat_iterator(left);
    5269          16 :         starti = bat_iterator(start);
    5270          16 :         lengthi = bat_iterator(length);
    5271          16 :         svals = starti.base;
    5272          16 :         lvals = lengthi.base;
    5273          16 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5274        3830 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5275        3814 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5276        3814 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5277        3814 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5278        3814 :                         const char *x = BUNtvar(lefti, p1);
    5279        3812 :                         y = svals[p2];
    5280        3812 :                         z = lvals[p3];
    5281             : 
    5282        7594 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5283          48 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5284           0 :                                         msg = createException(MAL, "batstr.substring",
    5285             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5286           0 :                                         goto bailout1;
    5287             :                                 }
    5288             :                                 nils = true;
    5289             :                         } else {
    5290        3764 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5291           0 :                                         goto bailout1;
    5292        3760 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5293           0 :                                         msg = createException(MAL, "batstr.substring",
    5294             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5295           0 :                                         goto bailout1;
    5296             :                                 }
    5297             :                         }
    5298             :                 }
    5299             :         } else {
    5300           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5301           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5302           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5303           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5304           0 :                         const char *x = BUNtvar(lefti, p1);
    5305           0 :                         y = svals[p2];
    5306           0 :                         z = lvals[p3];
    5307             : 
    5308           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5309           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5310           0 :                                         msg = createException(MAL, "batstr.substring",
    5311             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5312           0 :                                         goto bailout1;
    5313             :                                 }
    5314             :                                 nils = true;
    5315             :                         } else {
    5316           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5317           0 :                                         goto bailout1;
    5318           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5319           0 :                                         msg = createException(MAL, "batstr.substring",
    5320             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5321           0 :                                         goto bailout1;
    5322             :                                 }
    5323             :                         }
    5324             :                 }
    5325             :         }
    5326           0 :   bailout1:
    5327          16 :         bat_iterator_end(&lefti);
    5328          16 :         bat_iterator_end(&starti);
    5329          16 :         bat_iterator_end(&lengthi);
    5330          16 :   bailout:
    5331          16 :         GDKfree(buf);
    5332          16 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5333          16 :         unfix_inputs(6, left, ls, start, ss, length, lens);
    5334          16 :         return msg;
    5335             : }
    5336             : 
    5337             : static str
    5338           0 : STRbatstrLocatecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5339             : {
    5340           0 :         BATiter bi;
    5341           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5342           0 :         int *restrict vals;
    5343           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5344           0 :         str msg = MAL_SUCCEED;
    5345           0 :         bool nils = false;
    5346           0 :         struct canditer ci1 = { 0 };
    5347           0 :         oid off1;
    5348           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5349           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5350           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5351             : 
    5352           0 :         (void) cntxt;
    5353           0 :         (void) mb;
    5354           0 :         if (!(b = BATdescriptor(l))) {
    5355           0 :                 msg = createException(MAL, "batstr.locate",
    5356             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5357           0 :                 goto bailout;
    5358             :         }
    5359           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5360           0 :                 msg = createException(MAL, "batstr.locate",
    5361             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5362           0 :                 goto bailout;
    5363             :         }
    5364           0 :         canditer_init(&ci1, b, bs);
    5365           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5366           0 :                 msg = createException(MAL, "batstr.locate",
    5367             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5368           0 :                 goto bailout;
    5369             :         }
    5370             : 
    5371           0 :         off1 = b->hseqbase;
    5372           0 :         bi = bat_iterator(b);
    5373           0 :         vals = Tloc(bn, 0);
    5374           0 :         if (ci1.tpe == cand_dense) {
    5375           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5376           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5377           0 :                         const char *x = BUNtvar(bi, p1);
    5378             : 
    5379           0 :                         if (strNil(x) || strNil(y)) {
    5380           0 :                                 vals[i] = int_nil;
    5381           0 :                                 nils = true;
    5382             :                         } else {
    5383           0 :                                 vals[i] = str_locate2(x, y, 1);
    5384             :                         }
    5385             :                 }
    5386             :         } else {
    5387           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5388           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5389           0 :                         const char *x = BUNtvar(bi, p1);
    5390             : 
    5391           0 :                         if (strNil(x) || strNil(y)) {
    5392           0 :                                 vals[i] = int_nil;
    5393           0 :                                 nils = true;
    5394             :                         } else {
    5395           0 :                                 vals[i] = str_locate2(x, y, 1);
    5396             :                         }
    5397             :                 }
    5398             :         }
    5399           0 :         bat_iterator_end(&bi);
    5400           0 :   bailout:
    5401           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5402           0 :         unfix_inputs(2, b, bs);
    5403           0 :         return msg;
    5404             : }
    5405             : 
    5406             : static str
    5407          28 : STRbatstrLocate_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5408             : {
    5409          28 :         BATiter bi;
    5410          28 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5411          28 :         int *restrict vals;
    5412          28 :         const char *x = *getArgReference_str(stk, pci, 1);
    5413          28 :         str msg = MAL_SUCCEED;
    5414          28 :         bool nils = false;
    5415          28 :         struct canditer ci1 = { 0 };
    5416          28 :         oid off1;
    5417          28 :         bat *res = getArgReference_bat(stk, pci, 0),
    5418          28 :                 l = *getArgReference_bat(stk, pci, 2),
    5419          28 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5420             : 
    5421          28 :         (void) cntxt;
    5422          28 :         (void) mb;
    5423          28 :         if (!(b = BATdescriptor(l))) {
    5424           0 :                 msg = createException(MAL, "batstr.locate",
    5425             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5426           0 :                 goto bailout;
    5427             :         }
    5428          28 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5429           0 :                 msg = createException(MAL, "batstr.locate",
    5430             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5431           0 :                 goto bailout;
    5432             :         }
    5433          28 :         canditer_init(&ci1, b, bs);
    5434          28 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5435           0 :                 msg = createException(MAL, "batstr.locate",
    5436             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5437           0 :                 goto bailout;
    5438             :         }
    5439             : 
    5440          28 :         off1 = b->hseqbase;
    5441          28 :         bi = bat_iterator(b);
    5442          28 :         vals = Tloc(bn, 0);
    5443          28 :         if (ci1.tpe == cand_dense) {
    5444        3534 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5445        3506 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5446        3506 :                         const char *y = BUNtvar(bi, p1);
    5447             : 
    5448        7002 :                         if (strNil(x) || strNil(y)) {
    5449           0 :                                 vals[i] = int_nil;
    5450           0 :                                 nils = true;
    5451             :                         } else {
    5452        3501 :                                 vals[i] = str_locate2(x, y, 1);
    5453             :                         }
    5454             :                 }
    5455             :         } else {
    5456           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5457           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5458           0 :                         const char *y = BUNtvar(bi, p1);
    5459             : 
    5460           0 :                         if (strNil(x) || strNil(y)) {
    5461           0 :                                 vals[i] = int_nil;
    5462           0 :                                 nils = true;
    5463             :                         } else {
    5464           0 :                                 vals[i] = str_locate2(x, y, 1);
    5465             :                         }
    5466             :                 }
    5467             :         }
    5468          28 :         bat_iterator_end(&bi);
    5469          27 :   bailout:
    5470          27 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5471          28 :         unfix_inputs(2, b, bs);
    5472          28 :         return msg;
    5473             : }
    5474             : 
    5475             : static str
    5476           2 : STRbatstrLocate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5477             : {
    5478           2 :         BATiter lefti, righti;
    5479           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    5480           2 :         int *restrict vals;
    5481           2 :         str msg = MAL_SUCCEED;
    5482           2 :         bool nils = false;
    5483           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5484           2 :         oid off1, off2;
    5485           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    5486           2 :                 l = *getArgReference_bat(stk, pci, 1),
    5487           2 :                 r = *getArgReference_bat(stk, pci, 2),
    5488           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    5489           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5490             : 
    5491           2 :         (void) cntxt;
    5492           2 :         (void) mb;
    5493           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    5494           0 :                 msg = createException(MAL, "batstr.locate",
    5495             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5496           0 :                 goto bailout;
    5497             :         }
    5498           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5499           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    5500           0 :                 msg = createException(MAL, "batstr.locate",
    5501             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5502           0 :                 goto bailout;
    5503             :         }
    5504           2 :         canditer_init(&ci1, left, ls);
    5505           2 :         canditer_init(&ci2, right, rs);
    5506           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5507           0 :                 msg = createException(MAL, "batstr.locate",
    5508             :                                                           ILLEGAL_ARGUMENT
    5509             :                                                           " Requires bats of identical size");
    5510           0 :                 goto bailout;
    5511             :         }
    5512           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5513           0 :                 msg = createException(MAL, "batstr.locate",
    5514             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5515           0 :                 goto bailout;
    5516             :         }
    5517             : 
    5518           2 :         off1 = left->hseqbase;
    5519           2 :         off2 = right->hseqbase;
    5520           2 :         lefti = bat_iterator(left);
    5521           2 :         righti = bat_iterator(right);
    5522           2 :         vals = Tloc(bn, 0);
    5523           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5524          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5525           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5526           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5527           8 :                         const char *x = BUNtvar(lefti, p1);
    5528           8 :                         const char *y = BUNtvar(righti, p2);
    5529             : 
    5530          16 :                         if (strNil(x) || strNil(y)) {
    5531           0 :                                 vals[i] = int_nil;
    5532           0 :                                 nils = true;
    5533             :                         } else {
    5534           8 :                                 vals[i] = str_locate2(x, y, 1);
    5535             :                         }
    5536             :                 }
    5537             :         } else {
    5538           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5539           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5540           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5541           0 :                         const char *x = BUNtvar(lefti, p1);
    5542           0 :                         const char *y = BUNtvar(righti, p2);
    5543             : 
    5544           0 :                         if (strNil(x) || strNil(y)) {
    5545           0 :                                 vals[i] = int_nil;
    5546           0 :                                 nils = true;
    5547             :                         } else {
    5548           0 :                                 vals[i] = str_locate2(x, y, 1);
    5549             :                         }
    5550             :                 }
    5551             :         }
    5552           2 :         bat_iterator_end(&lefti);
    5553           2 :         bat_iterator_end(&righti);
    5554           2 :   bailout:
    5555           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5556           2 :         unfix_inputs(4, left, ls, right, rs);
    5557           2 :         return msg;
    5558             : }
    5559             : 
    5560             : static str
    5561           0 : STRbatstrLocate3cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5562             : {
    5563           0 :         BATiter bi;
    5564           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5565           0 :         int *restrict vals, z = *getArgReference_int(stk, pci, 3);
    5566           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5567           0 :         str msg = MAL_SUCCEED;
    5568           0 :         bool nils = false;
    5569           0 :         struct canditer ci1 = { 0 };
    5570           0 :         oid off1;
    5571           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5572           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5573           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5574             : 
    5575           0 :         (void) cntxt;
    5576           0 :         (void) mb;
    5577           0 :         if (!(b = BATdescriptor(l))) {
    5578           0 :                 msg = createException(MAL, "batstr.locate2",
    5579             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5580           0 :                 goto bailout;
    5581             :         }
    5582           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5583           0 :                 msg = createException(MAL, "batstr.locate2",
    5584             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5585           0 :                 goto bailout;
    5586             :         }
    5587           0 :         canditer_init(&ci1, b, bs);
    5588           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5589           0 :                 msg = createException(MAL, "batstr.locate2",
    5590             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5591           0 :                 goto bailout;
    5592             :         }
    5593             : 
    5594           0 :         off1 = b->hseqbase;
    5595           0 :         bi = bat_iterator(b);
    5596           0 :         vals = Tloc(bn, 0);
    5597           0 :         if (ci1.tpe == cand_dense) {
    5598           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5599           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5600           0 :                         const char *x = BUNtvar(bi, p1);
    5601             : 
    5602           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5603           0 :                                 vals[i] = int_nil;
    5604           0 :                                 nils = true;
    5605             :                         } else {
    5606           0 :                                 vals[i] = str_locate2(x, y, z);
    5607             :                         }
    5608             :                 }
    5609             :         } else {
    5610           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5611           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5612           0 :                         const char *x = BUNtvar(bi, p1);
    5613             : 
    5614           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5615           0 :                                 vals[i] = int_nil;
    5616           0 :                                 nils = true;
    5617             :                         } else {
    5618           0 :                                 vals[i] = str_locate2(x, y, z);
    5619             :                         }
    5620             :                 }
    5621             :         }
    5622           0 :         bat_iterator_end(&bi);
    5623           0 :   bailout:
    5624           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5625           0 :         unfix_inputs(2, b, bs);
    5626           0 :         return msg;
    5627             : }
    5628             : 
    5629             : static str
    5630           0 : STRbatstrLocate3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5631             : {
    5632           0 :         BATiter lefti, righti, starti;
    5633           0 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL,
    5634           0 :                 *rs = NULL, *start = NULL, *ss = NULL;
    5635           0 :         int *restrict vals, *restrict svals, z;
    5636           0 :         str msg = MAL_SUCCEED;
    5637           0 :         bool nils = false;
    5638           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5639           0 :         oid off1, off2, off3;
    5640           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5641           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5642           0 :                 r = *getArgReference_bat(stk, pci, 2),
    5643           0 :                 s = *getArgReference_bat(stk, pci, 3),
    5644           0 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5645           0 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5646           0 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5647             : 
    5648           0 :         (void) cntxt;
    5649           0 :         (void) mb;
    5650           0 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))
    5651           0 :                 || !(start = BATdescriptor(s))) {
    5652           0 :                 msg = createException(MAL, "batstr.locate2",
    5653             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5654           0 :                 goto bailout;
    5655             :         }
    5656           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5657           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2))) ||
    5658           0 :                 (sid3 && !is_bat_nil(*sid3) && !(ss = BATdescriptor(*sid3)))) {
    5659           0 :                 msg = createException(MAL, "batstr.locate2",
    5660             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5661           0 :                 goto bailout;
    5662             :         }
    5663           0 :         canditer_init(&ci1, left, ls);
    5664           0 :         canditer_init(&ci2, right, rs);
    5665           0 :         canditer_init(&ci3, start, ss);
    5666           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5667           0 :                 || ci2.hseq != ci3.hseq) {
    5668           0 :                 msg = createException(MAL, "batstr.locate2",
    5669             :                                                           ILLEGAL_ARGUMENT
    5670             :                                                           " Requires bats of identical size");
    5671           0 :                 goto bailout;
    5672             :         }
    5673           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5674           0 :                 msg = createException(MAL, "batstr.locate2",
    5675             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5676           0 :                 goto bailout;
    5677             :         }
    5678             : 
    5679           0 :         off1 = left->hseqbase;
    5680           0 :         off2 = right->hseqbase;
    5681           0 :         off3 = start->hseqbase;
    5682           0 :         lefti = bat_iterator(left);
    5683           0 :         righti = bat_iterator(right);
    5684           0 :         starti = bat_iterator(start);
    5685           0 :         svals = starti.base;
    5686           0 :         vals = Tloc(bn, 0);
    5687           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5688           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5689           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5690           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5691           0 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5692           0 :                         const char *x = BUNtvar(lefti, p1);
    5693           0 :                         const char *y = BUNtvar(righti, p2);
    5694           0 :                         z = svals[p3];
    5695             : 
    5696           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5697           0 :                                 vals[i] = int_nil;
    5698           0 :                                 nils = true;
    5699             :                         } else {
    5700           0 :                                 vals[i] = str_locate2(x, y, z);
    5701             :                         }
    5702             :                 }
    5703             :         } else {
    5704           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5705           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5706           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5707           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5708           0 :                         const char *x = BUNtvar(lefti, p1);
    5709           0 :                         const char *y = BUNtvar(righti, p2);
    5710           0 :                         z = svals[p3];
    5711             : 
    5712           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5713           0 :                                 vals[i] = int_nil;
    5714           0 :                                 nils = true;
    5715             :                         } else {
    5716           0 :                                 vals[i] = str_locate2(x, y, z);
    5717             :                         }
    5718             :                 }
    5719             :         }
    5720           0 :         bat_iterator_end(&starti);
    5721           0 :         bat_iterator_end(&lefti);
    5722           0 :         bat_iterator_end(&righti);
    5723           0 :   bailout:
    5724           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5725           0 :         unfix_inputs(6, left, ls, right, rs, start, ss);
    5726           0 :         return msg;
    5727             : }
    5728             : 
    5729             : static str
    5730          12 : BATSTRasciify(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5731             : {
    5732          12 :         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