LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - batstr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1415 3682 38.4 %
Date: 2024-12-19 23:10:26 Functions: 78 118 66.1 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "gdk.h"
      15             : #include <ctype.h>
      16             : #include <string.h>
      17             : #include "mal_client.h"
      18             : #include "mal_interpreter.h"
      19             : #include "mal_exception.h"
      20             : #include "str.h"
      21             : 
      22             : /* In order to make available a bulk version of a string function with
      23             :  * candidates, all possible combinations of scalar/vector version of
      24             :  * each argument must be available for the function. Obviously this won't
      25             :  * scale for functions with a large number of arguments, so we keep a
      26             :  * blacklist for functions without candidate versions. */
      27             : static const char *batstr_funcs_with_no_cands[8] =
      28             :                 { "lpad3", "rpad3", "splitpart", "substitute", "locate3", "insert",
      29             : "replace", NULL };
      30             : 
      31             : bool
      32         936 : batstr_func_has_candidates(const char *func)
      33             : {
      34        7474 :         for (size_t i = 0; batstr_funcs_with_no_cands[i]; i++)
      35        6550 :                 if (strcmp(batstr_funcs_with_no_cands[i], func) == 0)
      36             :                         return false;
      37             :         return true;
      38             : }
      39             : 
      40             : static inline void
      41        4891 : finalize_output(bat *res, BAT *bn, const char *msg, bool nils, BUN q)
      42             : {
      43        4891 :         if (bn && !msg) {
      44        4891 :                 BATsetcount(bn, q);
      45        4891 :                 bn->tnil = nils;
      46        4891 :                 bn->tnonil = !nils;
      47        4891 :                 bn->tkey = BATcount(bn) <= 1;
      48        4891 :                 bn->tsorted = BATcount(bn) <= 1;
      49        4891 :                 bn->trevsorted = BATcount(bn) <= 1;
      50        4891 :                 bn->theap->dirty |= BATcount(bn) > 0;
      51        4891 :                 *res = bn->batCacheid;
      52        4891 :                 BBPkeepref(bn);
      53           0 :         } else if (bn)
      54           0 :                 BBPreclaim(bn);
      55        4885 : }
      56             : 
      57             : static void
      58        5037 : unfix_inputs(int nargs, ...)
      59             : {
      60        5037 :         va_list valist;
      61             : 
      62        5037 :         va_start(valist, nargs);
      63       15454 :         for (int i = 0; i < nargs; i++) {
      64       10401 :                 BAT *b = va_arg(valist, BAT *);
      65       16733 :                 BBPreclaim(b);
      66             :         }
      67        5053 :         va_end(valist);
      68        5053 : }
      69             : 
      70             : static inline str
      71        5619 : str_prefix(str *buf, size_t *buflen, const char *s, int l)
      72             : {
      73        5619 :         return str_Sub_String(buf, buflen, s, 0, l);
      74             : }
      75             : 
      76             : static str
      77        3873 : do_batstr_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
      78             :                           const char *name, int (*func)(const char *))
      79             : {
      80        3873 :         BATiter bi;
      81        3873 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
      82        3873 :         int *restrict vals;
      83        3873 :         str msg = MAL_SUCCEED;
      84        3873 :         bool nils = false;
      85        3873 :         struct canditer ci1 = { 0 };
      86        3873 :         oid off1;
      87        3873 :         bat *res = getArgReference_bat(stk, pci, 0),
      88        3873 :                 bid = *getArgReference_bat(stk, pci, 1),
      89        3873 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
      90             : 
      91        3873 :         (void) cntxt;
      92        3873 :         (void) mb;
      93        3873 :         if (!(b = BATdescriptor(bid))) {
      94           0 :                 msg = createException(MAL, name,
      95             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
      96           0 :                 goto bailout;
      97             :         }
      98        3880 :         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        3881 :         canditer_init(&ci1, b, bs);
     104        3877 :         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        3877 :         off1 = b->hseqbase;
     110        3877 :         bi = bat_iterator(b);
     111        3872 :         vals = Tloc(bn, 0);
     112        3872 :         if (ci1.tpe == cand_dense) {
     113     1213086 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     114     1209250 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     115     1209250 :                         const char *restrict x = BUNtvar(bi, p1);
     116             : 
     117     1209250 :                         if (strNil(x)) {
     118           3 :                                 vals[i] = int_nil;
     119           3 :                                 nils = true;
     120             :                         } else {
     121     1209247 :                                 vals[i] = func(x);
     122             :                         }
     123             :                 }
     124             :         } else {
     125     1231856 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     126     1231816 :                         oid p1 = (canditer_next(&ci1) - off1);
     127     1231025 :                         const char *restrict x = BUNtvar(bi, p1);
     128             : 
     129     1231025 :                         if (strNil(x)) {
     130           0 :                                 vals[i] = int_nil;
     131           0 :                                 nils = true;
     132             :                         } else {
     133     1231025 :                                 vals[i] = func(x);
     134             :                         }
     135             :                 }
     136             :         }
     137        3876 :         bat_iterator_end(&bi);
     138        3878 :   bailout:
     139        3878 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     140        3874 :         unfix_inputs(2, b, bs);
     141        3878 :         return msg;
     142             : }
     143             : 
     144             : static str
     145        3870 : STRbatLength(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     146             : {
     147        3870 :         bat bid = *getArgReference_bat(stk, pci, 1);
     148        3870 :         BAT *b = BATdescriptor(bid);
     149        3879 :         str err;
     150        3879 :         if (b && b->tascii)
     151        3875 :                 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        3876 :         BBPreclaim(b);
     155        3877 :         return err;
     156             : }
     157             : 
     158             : static str
     159           1 : STRbatBytes(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     160             : {
     161           1 :         return do_batstr_int(cntxt, mb, stk, pci, "batstr.bytes", str_strlen);
     162             : }
     163             : 
     164             : static str
     165           3 : STRbatAscii(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     166             : {
     167           3 :         BATiter bi;
     168           3 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     169           3 :         int *restrict vals, next;
     170           3 :         str msg = MAL_SUCCEED;
     171           3 :         bool nils = false;
     172           3 :         struct canditer ci1 = { 0 };
     173           3 :         oid off1;
     174           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     175           3 :                 bid = *getArgReference_bat(stk, pci, 1),
     176           3 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     177             : 
     178           3 :         (void) cntxt;
     179           3 :         (void) mb;
     180           3 :         if (!(b = BATdescriptor(bid))) {
     181           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     182             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     183           0 :                 goto bailout;
     184             :         }
     185           3 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     186           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     187             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     188           0 :                 goto bailout;
     189             :         }
     190           3 :         canditer_init(&ci1, b, bs);
     191           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
     192           0 :                 msg = createException(MAL, "batstr.unicodeAt",
     193             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     194           0 :                 goto bailout;
     195             :         }
     196             : 
     197           3 :         off1 = b->hseqbase;
     198           3 :         bi = bat_iterator(b);
     199           3 :         vals = Tloc(bn, 0);
     200           3 :         if (ci1.tpe == cand_dense) {
     201          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     202           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     203           8 :                         const char *restrict x = BUNtvar(bi, p1);
     204             : 
     205           8 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     206           0 :                                 goto bailout1;
     207           8 :                         vals[i] = next;
     208           8 :                         nils |= is_int_nil(next);
     209             :                 }
     210             :         } else {
     211          15 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     212          14 :                         oid p1 = (canditer_next(&ci1) - off1);
     213          14 :                         const char *restrict x = BUNtvar(bi, p1);
     214             : 
     215          14 :                         if ((msg = str_wchr_at(&next, x, 0)) != MAL_SUCCEED)
     216           0 :                                 goto bailout1;
     217          14 :                         vals[i] = next;
     218          14 :                         nils |= is_int_nil(next);
     219             :                 }
     220             :         }
     221           1 :   bailout1:
     222           3 :         bat_iterator_end(&bi);
     223           3 :   bailout:
     224           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     225           3 :         unfix_inputs(2, b, bs);
     226           3 :         return msg;
     227             : }
     228             : 
     229             : static str
     230           1 : STRbatFromWChr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     231             : {
     232           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     233           1 :         size_t buflen = MAX(strlen(str_nil) + 1, 8);
     234           1 :         int *restrict vals, x;
     235           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     236           1 :         bool nils = false;
     237           1 :         struct canditer ci1 = { 0 };
     238           1 :         oid off1;
     239           1 :         bat *res = getArgReference_bat(stk, pci, 0),
     240           1 :                 bid = *getArgReference_bat(stk, pci, 1),
     241           1 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     242           1 :         BATiter bi;
     243             : 
     244           1 :         (void) cntxt;
     245           1 :         (void) mb;
     246           1 :         if (!buf) {
     247           0 :                 msg = createException(MAL, "batstr.unicode",
     248             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     249           0 :                 goto bailout;
     250             :         }
     251           1 :         if (!(b = BATdescriptor(bid))) {
     252           0 :                 msg = createException(MAL, "batstr.unicode",
     253             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     254           0 :                 goto bailout;
     255             :         }
     256           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     257           0 :                 msg = createException(MAL, "batstr.unicode",
     258             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     259           0 :                 goto bailout;
     260             :         }
     261           1 :         canditer_init(&ci1, b, bs);
     262           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     263           0 :                 msg = createException(MAL, "batstr.unicode",
     264             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     265           0 :                 goto bailout;
     266             :         }
     267             : 
     268           1 :         bi = bat_iterator(b);
     269           1 :         off1 = b->hseqbase;
     270           1 :         vals = bi.base;
     271           1 :         if (ci1.tpe == cand_dense) {
     272           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     273           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     274           4 :                         x = vals[p1];
     275             : 
     276           4 :                         if (is_int_nil(x)) {
     277           2 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     278           0 :                                         msg = createException(MAL, "batstr.unicode",
     279             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     280           0 :                                         goto bailout1;
     281             :                                 }
     282             :                                 nils = true;
     283             :                         } else {
     284           2 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     285           0 :                                         goto bailout1;
     286             :                                 }
     287           2 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     288           0 :                                         msg = createException(MAL, "batstr.unicode",
     289             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     290           0 :                                         goto bailout1;
     291             :                                 }
     292             :                         }
     293             :                 }
     294             :         } else {
     295           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     296           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     297           0 :                         x = vals[p1];
     298             : 
     299           0 :                         if (is_int_nil(x)) {
     300           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     301           0 :                                         msg = createException(MAL, "batstr.unicode",
     302             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     303           0 :                                         goto bailout1;
     304             :                                 }
     305             :                                 nils = true;
     306             :                         } else {
     307           0 :                                 if ((msg = str_from_wchr(&buf, &buflen, vals[p1])) != MAL_SUCCEED) {
     308           0 :                                         goto bailout1;
     309             :                                 }
     310           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     311           0 :                                         msg = createException(MAL, "batstr.unicode",
     312             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     313           0 :                                         goto bailout1;
     314             :                                 }
     315             :                         }
     316             :                 }
     317             :         }
     318           0 :   bailout1:
     319           1 :         bat_iterator_end(&bi);
     320           1 :   bailout:
     321           1 :         GDKfree(buf);
     322           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     323           1 :         unfix_inputs(2, b, bs);
     324           1 :         return msg;
     325             : }
     326             : 
     327             : static str
     328           0 : STRbatSpace(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     329             : {
     330           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     331           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     332           0 :         int *restrict vals, x;
     333           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     334           0 :         bool nils = false;
     335           0 :         const char space[] = " ", *s = space;
     336           0 :         struct canditer ci1 = { 0 };
     337           0 :         oid off1;
     338           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     339           0 :                 bid = *getArgReference_bat(stk, pci, 1),
     340           0 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     341           0 :         BATiter bi;
     342             : 
     343           0 :         (void) cntxt;
     344           0 :         (void) mb;
     345           0 :         if (!buf) {
     346           0 :                 msg = createException(MAL, "batstr.space",
     347             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     348           0 :                 goto bailout;
     349             :         }
     350           0 :         if (!(b = BATdescriptor(bid))) {
     351           0 :                 msg = createException(MAL, "batstr.space",
     352             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     353           0 :                 goto bailout;
     354             :         }
     355           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     356           0 :                 msg = createException(MAL, "batstr.search",
     357             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     358           0 :                 goto bailout;
     359             :         }
     360           0 :         canditer_init(&ci1, b, bs);
     361           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     362           0 :                 msg = createException(MAL, "batstr.space",
     363             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     364           0 :                 goto bailout;
     365             :         }
     366             : 
     367           0 :         off1 = b->hseqbase;
     368           0 :         bi = bat_iterator(b);
     369           0 :         vals = bi.base;
     370           0 :         if (ci1.tpe == cand_dense) {
     371           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     372           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     373           0 :                         x = vals[p1];
     374             : 
     375           0 :                         if (is_int_nil(x) || x < 0) {
     376           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     377           0 :                                         msg = createException(MAL, "batstr.space",
     378             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     379           0 :                                         goto bailout1;
     380             :                                 }
     381             :                                 nils = true;
     382             :                         } else {
     383           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     384           0 :                                         goto bailout1;
     385           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     386           0 :                                         msg = createException(MAL, "batstr.space",
     387             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     388           0 :                                         goto bailout1;
     389             :                                 }
     390             :                         }
     391             :                 }
     392             :         } else {
     393           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     394           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     395           0 :                         x = vals[p1];
     396             : 
     397           0 :                         if (is_int_nil(x) || x < 0) {
     398           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     399           0 :                                         msg = createException(MAL, "batstr.space",
     400             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     401           0 :                                         goto bailout1;
     402             :                                 }
     403             :                                 nils = true;
     404             :                         } else {
     405           0 :                                 if ((msg = str_repeat(&buf, &buflen, s, x)) != MAL_SUCCEED)
     406           0 :                                         goto bailout1;
     407           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     408           0 :                                         msg = createException(MAL, "batstr.space",
     409             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     410           0 :                                         goto bailout1;
     411             :                                 }
     412             :                         }
     413             :                 }
     414             :         }
     415           0 :   bailout1:
     416           0 :         bat_iterator_end(&bi);
     417           0 :   bailout:
     418           0 :         GDKfree(buf);
     419           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     420           0 :         unfix_inputs(2, b, bs);
     421           0 :         return msg;
     422             : }
     423             : 
     424             : static str
     425          50 : do_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     426             :                           const char *name, str (*func)(str *, size_t *, const char *))
     427             : {
     428          50 :         BATiter bi;
     429          50 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     430          50 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     431          50 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     432          50 :         bool nils = false;
     433          50 :         struct canditer ci1 = { 0 };
     434          50 :         oid off1;
     435          50 :         bat *res = getArgReference_bat(stk, pci, 0),
     436          50 :                 bid = *getArgReference_bat(stk, pci, 1),
     437          50 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
     438             : 
     439          50 :         (void) cntxt;
     440          50 :         (void) mb;
     441          50 :         if (!buf) {
     442           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     443           0 :                 goto bailout;
     444             :         }
     445          50 :         if (!(b = BATdescriptor(bid))) {
     446           0 :                 msg = createException(MAL, name,
     447             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     448           0 :                 goto bailout;
     449             :         }
     450          50 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     451           0 :                 msg = createException(MAL, name,
     452             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     453           0 :                 goto bailout;
     454             :         }
     455          50 :         canditer_init(&ci1, b, bs);
     456          50 :         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          50 :         off1 = b->hseqbase;
     462          50 :         bi = bat_iterator(b);
     463          50 :         if (ci1.tpe == cand_dense) {
     464         423 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     465         373 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     466         373 :                         const char *restrict x = BUNtvar(bi, p1);
     467             : 
     468         373 :                         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         368 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     477           0 :                                         goto bailout1;
     478         369 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     479           0 :                                         msg = createException(MAL, name,
     480             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     481           0 :                                         goto bailout1;
     482             :                                 }
     483             :                         }
     484             :                 }
     485             :         } else {
     486           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     487           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     488           0 :                         const char *restrict x = BUNtvar(bi, p1);
     489             : 
     490           0 :                         if (strNil(x)) {
     491           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     492           0 :                                         msg = createException(MAL, name,
     493             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     494           0 :                                         goto bailout1;
     495             :                                 }
     496             :                                 nils = true;
     497             :                         } else {
     498           0 :                                 if ((msg = (*func) (&buf, &buflen, x)) != MAL_SUCCEED)
     499           0 :                                         goto bailout1;
     500           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     501           0 :                                         msg = createException(MAL, name,
     502             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     503           0 :                                         goto bailout1;
     504             :                                 }
     505             :                         }
     506             :                 }
     507             :         }
     508           0 :   bailout1:
     509          50 :         bat_iterator_end(&bi);
     510          50 :   bailout:
     511          50 :         GDKfree(buf);
     512          50 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     513          50 :         unfix_inputs(2, b, bs);
     514          50 :         return msg;
     515             : }
     516             : 
     517             : /* Input: a BAT of strings 'b' and a constant string 'y'
     518             :  * Output type: str (a BAT of strings)
     519             :  */
     520             : static str
     521          11 : do_batstr_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     522             :                                            const char *name, size_t buflen,
     523             :                                            str (*func)(str *, size_t *, const char *, const char *))
     524             : {
     525          11 :         BATiter bi;
     526          11 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     527          11 :         const char *y = *getArgReference_str(stk, pci, 2);
     528          11 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     529          11 :         bool nils = false;
     530          11 :         struct canditer ci1 = { 0 };
     531          11 :         oid off1;
     532          11 :         bat *res = getArgReference_bat(stk, pci, 0),
     533          11 :                 bid = *getArgReference_bat(stk, pci, 1),
     534          11 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     535             : 
     536          11 :         (void) cntxt;
     537          11 :         (void) mb;
     538          11 :         if (!buf) {
     539           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     540           0 :                 goto bailout;
     541             :         }
     542          11 :         if (!(b = BATdescriptor(bid))) {
     543           0 :                 msg = createException(MAL, name,
     544             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     545           0 :                 goto bailout;
     546             :         }
     547          11 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     548           0 :                 msg = createException(MAL, name,
     549             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     550           0 :                 goto bailout;
     551             :         }
     552          11 :         canditer_init(&ci1, b, bs);
     553          11 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     554           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     555           0 :                 goto bailout;
     556             :         }
     557             : 
     558          11 :         off1 = b->hseqbase;
     559          11 :         bi = bat_iterator(b);
     560          11 :         if (ci1.tpe == cand_dense) {
     561          29 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     562          18 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     563          18 :                         const char *x = BUNtvar(bi, p1);
     564             : 
     565          36 :                         if (strNil(x) || strNil(y)) {
     566           9 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     567           0 :                                         msg = createException(MAL, name,
     568             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     569           0 :                                         goto bailout1;
     570             :                                 }
     571             :                                 nils = true;
     572             :                         } else {
     573           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     574           0 :                                         goto bailout1;
     575           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     576           0 :                                         msg = createException(MAL, name,
     577             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     578           0 :                                         goto bailout1;
     579             :                                 }
     580             :                         }
     581             :                 }
     582             :         } else {
     583           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     584           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     585           0 :                         const char *x = BUNtvar(bi, p1);
     586             : 
     587           0 :                         if (strNil(x) || strNil(y)) {
     588           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     589           0 :                                         msg = createException(MAL, name,
     590             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     591           0 :                                         goto bailout1;
     592             :                                 }
     593             :                                 nils = true;
     594             :                         } else {
     595           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     596           0 :                                         goto bailout1;
     597           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     598           0 :                                         msg = createException(MAL, name,
     599             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     600           0 :                                         goto bailout1;
     601             :                                 }
     602             :                         }
     603             :                 }
     604             :         }
     605           0 :   bailout1:
     606          11 :         bat_iterator_end(&bi);
     607          10 :   bailout:
     608          10 :         GDKfree(buf);
     609          11 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     610          11 :         unfix_inputs(2, b, bs);
     611          11 :         return msg;
     612             : }
     613             : 
     614             : /* Input: a const string 'x' and a BAT of strings 'y'
     615             :  * Output type: str (a BAT of strings)
     616             :  */
     617             : static str
     618           0 : do_batstr_str_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     619             :                                            const char *name, size_t buflen,
     620             :                                            str (*func)(str *, size_t *, const char *, const char *))
     621             : {
     622           0 :         BATiter bi;
     623           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     624           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     625           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     626           0 :         bool nils = false;
     627           0 :         struct canditer ci1 = { 0 };
     628           0 :         oid off1;
     629           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     630           0 :                 bid = *getArgReference_bat(stk, pci, 2),
     631           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     632             : 
     633           0 :         (void) cntxt;
     634           0 :         (void) mb;
     635           0 :         if (!buf) {
     636           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     637           0 :                 goto bailout;
     638             :         }
     639           0 :         if (!(b = BATdescriptor(bid))) {
     640           0 :                 msg = createException(MAL, name,
     641             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     642           0 :                 goto bailout;
     643             :         }
     644           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     645           0 :                 msg = createException(MAL, name,
     646             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     647           0 :                 goto bailout;
     648             :         }
     649           0 :         canditer_init(&ci1, b, bs);
     650           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     651           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     652           0 :                 goto bailout;
     653             :         }
     654             : 
     655           0 :         off1 = b->hseqbase;
     656           0 :         bi = bat_iterator(b);
     657           0 :         if (ci1.tpe == cand_dense) {
     658           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     659           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     660           0 :                         const char *y = BUNtvar(bi, p1);
     661             : 
     662           0 :                         if (strNil(x) || strNil(y)) {
     663           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     664           0 :                                         msg = createException(MAL, name,
     665             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     666           0 :                                         goto bailout1;
     667             :                                 }
     668             :                                 nils = true;
     669             :                         } else {
     670           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     671           0 :                                         goto bailout1;
     672           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     673           0 :                                         msg = createException(MAL, name,
     674             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     675           0 :                                         goto bailout1;
     676             :                                 }
     677             :                         }
     678             :                 }
     679             :         } else {
     680           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     681           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     682           0 :                         const char *y = BUNtvar(bi, p1);
     683             : 
     684           0 :                         if (strNil(x) || strNil(y)) {
     685           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     686           0 :                                         msg = createException(MAL, name,
     687             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     688           0 :                                         goto bailout1;
     689             :                                 }
     690             :                                 nils = true;
     691             :                         } else {
     692           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     693           0 :                                         goto bailout1;
     694           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     695           0 :                                         msg = createException(MAL, name,
     696             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     697           0 :                                         goto bailout1;
     698             :                                 }
     699             :                         }
     700             :                 }
     701             :         }
     702           0 :   bailout1:
     703           0 :         bat_iterator_end(&bi);
     704           0 :   bailout:
     705           0 :         GDKfree(buf);
     706           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     707           0 :         unfix_inputs(2, b, bs);
     708           0 :         return msg;
     709             : }
     710             : 
     711             : /* Input: two BATs of strings 'l' and 'l2'
     712             :  * Output type: str (a BAT of strings)
     713             :  */
     714             : static str
     715           3 : do_batstr_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     716             :                                          const char *name, size_t buflen,
     717             :                                          str (*func)(str *, size_t *, const char *, const char *))
     718             : {
     719           3 :         BATiter lefti, righti;
     720           3 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
     721           3 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     722           3 :         bool nils = false;
     723           3 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
     724           3 :         oid off1, off2;
     725           3 :         bat *res = getArgReference_bat(stk, pci, 0),
     726           3 :                 l = *getArgReference_bat(stk, pci, 1),
     727           3 :                 l2 = *getArgReference_bat(stk, pci, 2),
     728           3 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
     729           3 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
     730             : 
     731           3 :         (void) cntxt;
     732           3 :         (void) mb;
     733           3 :         if (!buf) {
     734           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     735           0 :                 goto bailout;
     736             :         }
     737           3 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(l2))) {
     738           0 :                 msg = createException(MAL, name,
     739             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     740           0 :                 goto bailout;
     741             :         }
     742           3 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
     743           3 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
     744           0 :                 msg = createException(MAL, name,
     745             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     746           0 :                 goto bailout;
     747             :         }
     748           3 :         canditer_init(&ci1, left, lefts);
     749           3 :         canditer_init(&ci2, right, rights);
     750           3 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
     751           0 :                 msg = createException(MAL, name,
     752             :                                                           ILLEGAL_ARGUMENT
     753             :                                                           " Requires bats of identical size");
     754           0 :                 goto bailout;
     755             :         }
     756           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     757           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     758           0 :                 goto bailout;
     759             :         }
     760             : 
     761           3 :         off1 = left->hseqbase;
     762           3 :         off2 = right->hseqbase;
     763           3 :         lefti = bat_iterator(left);
     764           3 :         righti = bat_iterator(right);
     765           3 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
     766          12 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     767           9 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
     768           9 :                                 p2 = (canditer_next_dense(&ci2) - off2);
     769           9 :                         const char *x = BUNtvar(lefti, p1);
     770           9 :                         const char *y = BUNtvar(righti, p2);
     771             : 
     772          18 :                         if (strNil(x) || strNil(y)) {
     773           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     774           0 :                                         msg = createException(MAL, name,
     775             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     776           0 :                                         goto bailout1;
     777             :                                 }
     778             :                                 nils = true;
     779             :                         } else {
     780           9 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     781           0 :                                         goto bailout1;
     782           9 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     783           0 :                                         msg = createException(MAL, name,
     784             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     785           0 :                                         goto bailout1;
     786             :                                 }
     787             :                         }
     788             :                 }
     789             :         } else {
     790           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     791           0 :                         oid p1 = (canditer_next(&ci1) - off1),
     792           0 :                                 p2 = (canditer_next(&ci2) - off2);
     793           0 :                         const char *x = BUNtvar(lefti, p1);
     794           0 :                         const char *y = BUNtvar(righti, p2);
     795             : 
     796           0 :                         if (strNil(x) || strNil(y)) {
     797           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     798           0 :                                         msg = createException(MAL, name,
     799             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     800           0 :                                         goto bailout1;
     801             :                                 }
     802             :                                 nils = true;
     803             :                         } else {
     804           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     805           0 :                                         goto bailout1;
     806           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     807           0 :                                         msg = createException(MAL, name,
     808             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     809           0 :                                         goto bailout1;
     810             :                                 }
     811             :                         }
     812             :                 }
     813             :         }
     814           0 :   bailout1:
     815           3 :         bat_iterator_end(&lefti);
     816           3 :         bat_iterator_end(&righti);
     817           3 :   bailout:
     818           3 :         GDKfree(buf);
     819           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     820           3 :         unfix_inputs(4, left, lefts, right, rights);
     821           3 :         return msg;
     822             : }
     823             : 
     824             : /* Input: a BAT of strings 'l' and a constant int 'y'
     825             :  * Output type: str (a BAT of strings)
     826             :  */
     827             : static str
     828           2 : do_batstr_constint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     829             :                                            const char *name,
     830             :                                            str (*func)(str *, size_t *, const char *, int))
     831             : {
     832           2 :         BATiter bi;
     833           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     834           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     835           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     836           2 :         int y = *getArgReference_int(stk, pci, 2);
     837           2 :         bool nils = false;
     838           2 :         struct canditer ci1 = { 0 };
     839           2 :         oid off1;
     840           2 :         bat *res = getArgReference_bat(stk, pci, 0),
     841           2 :                 bid = *getArgReference_bat(stk, pci, 1),
     842           2 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     843             : 
     844           2 :         (void) cntxt;
     845           2 :         (void) mb;
     846           2 :         if (!buf) {
     847           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     848           0 :                 goto bailout;
     849             :         }
     850           2 :         if (!(b = BATdescriptor(bid))) {
     851           0 :                 msg = createException(MAL, name,
     852             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     853           0 :                 goto bailout;
     854             :         }
     855           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     856           0 :                 msg = createException(MAL, name,
     857             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     858           0 :                 goto bailout;
     859             :         }
     860           2 :         canditer_init(&ci1, b, bs);
     861           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     862           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     863           0 :                 goto bailout;
     864             :         }
     865             : 
     866           2 :         off1 = b->hseqbase;
     867           2 :         bi = bat_iterator(b);
     868           2 :         if (ci1.tpe == cand_dense) {
     869           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     870           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     871           4 :                         const char *x = BUNtvar(bi, p1);
     872             : 
     873           8 :                         if (strNil(x) || is_int_nil(y)) {
     874           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     875           0 :                                         msg = createException(MAL, name,
     876             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     877           0 :                                         goto bailout1;
     878             :                                 }
     879             :                                 nils = true;
     880             :                         } else {
     881           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     882           0 :                                         goto bailout1;
     883           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     884           0 :                                         msg = createException(MAL, name,
     885             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     886           0 :                                         goto bailout1;
     887             :                                 }
     888             :                         }
     889             :                 }
     890             :         } else {
     891           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     892           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     893           0 :                         const char *x = BUNtvar(bi, p1);
     894             : 
     895           0 :                         if (strNil(x) || is_int_nil(y)) {
     896           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     897           0 :                                         msg = createException(MAL, name,
     898             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     899           0 :                                         goto bailout1;
     900             :                                 }
     901             :                                 nils = true;
     902             :                         } else {
     903           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     904           0 :                                         goto bailout1;
     905           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     906           0 :                                         msg = createException(MAL, name,
     907             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     908           0 :                                         goto bailout1;
     909             :                                 }
     910             :                         }
     911             :                 }
     912             :         }
     913           0 :   bailout1:
     914           2 :         bat_iterator_end(&bi);
     915           2 :   bailout:
     916           2 :         GDKfree(buf);
     917           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
     918           2 :         unfix_inputs(2, b, bs);
     919           2 :         return msg;
     920             : }
     921             : 
     922             : /* Input: a constant string 'x' and a BAT of integers 'y'
     923             :  * Output type: str (a BAT of strings)
     924             :  */
     925             : static str
     926           0 : do_batstr_int_conststr(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     927             :                                            const char *name,
     928             :                                            str (*func)(str *, size_t *, const char *, int))
     929             : {
     930           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
     931           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
     932           0 :         const char *x = *getArgReference_str(stk, pci, 1);
     933           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
     934           0 :         int y, *restrict inputs;
     935           0 :         bool nils = false;
     936           0 :         struct canditer ci1 = { 0 };
     937           0 :         oid off1;
     938           0 :         bat *res = getArgReference_bat(stk, pci, 0),
     939           0 :                 bid = *getArgReference_bat(stk, pci, 2),
     940           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
     941           0 :         BATiter bi;
     942             : 
     943           0 :         (void) cntxt;
     944           0 :         (void) mb;
     945           0 :         if (!buf) {
     946           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     947           0 :                 goto bailout;
     948             :         }
     949           0 :         if (!(b = BATdescriptor(bid))) {
     950           0 :                 msg = createException(MAL, name,
     951             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     952           0 :                 goto bailout;
     953             :         }
     954           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
     955           0 :                 msg = createException(MAL, name,
     956             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     957           0 :                 goto bailout;
     958             :         }
     959           0 :         canditer_init(&ci1, b, bs);
     960           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
     961           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     962           0 :                 goto bailout;
     963             :         }
     964             : 
     965           0 :         off1 = b->hseqbase;
     966           0 :         bi = bat_iterator(b);
     967           0 :         inputs = bi.base;
     968           0 :         if (ci1.tpe == cand_dense) {
     969           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     970           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
     971           0 :                         y = inputs[p1];
     972             : 
     973           0 :                         if (strNil(x) || is_int_nil(y)) {
     974           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     975           0 :                                         msg = createException(MAL, name,
     976             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     977           0 :                                         goto bailout1;
     978             :                                 }
     979             :                                 nils = true;
     980             :                         } else {
     981           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
     982           0 :                                         goto bailout1;
     983           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
     984           0 :                                         msg = createException(MAL, name,
     985             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     986           0 :                                         goto bailout1;
     987             :                                 }
     988             :                         }
     989             :                 }
     990             :         } else {
     991           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
     992           0 :                         oid p1 = (canditer_next(&ci1) - off1);
     993           0 :                         y = inputs[p1];
     994             : 
     995           0 :                         if (strNil(x) || is_int_nil(y)) {
     996           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
     997           0 :                                         msg = createException(MAL, name,
     998             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     999           0 :                                         goto bailout1;
    1000             :                                 }
    1001             :                                 nils = true;
    1002             :                         } else {
    1003           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1004           0 :                                         goto bailout1;
    1005           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1006           0 :                                         msg = createException(MAL, name,
    1007             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1008           0 :                                         goto bailout1;
    1009             :                                 }
    1010             :                         }
    1011             :                 }
    1012             :         }
    1013           0 :   bailout1:
    1014           0 :         bat_iterator_end(&bi);
    1015           0 :   bailout:
    1016           0 :         GDKfree(buf);
    1017           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1018           0 :         unfix_inputs(2, b, bs);
    1019           0 :         return msg;
    1020             : }
    1021             : 
    1022             : /* Input: a BAT of strings 'l' and a BAT of integers 'n'
    1023             :  * Output type: str (a BAT of strings)
    1024             :  */
    1025             : static str
    1026           2 : do_batstr_batint_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1027             :                                          const char *name,
    1028             :                                          str (*func)(str *, size_t *, const char *, int))
    1029             : {
    1030           2 :         BATiter lefti;
    1031           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1032           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1033           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1034           2 :         bool nils = false;
    1035           2 :         int *restrict righti, y;
    1036           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1037           2 :         oid off1, off2;
    1038           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1039           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1040           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1041           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    1042           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1043           2 :         BATiter bi;
    1044             : 
    1045           2 :         (void) cntxt;
    1046           2 :         (void) mb;
    1047           2 :         if (!buf) {
    1048           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1049           0 :                 goto bailout;
    1050             :         }
    1051           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(n))) {
    1052           0 :                 msg = createException(MAL, name,
    1053             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1054           0 :                 goto bailout;
    1055             :         }
    1056           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1057           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1058           0 :                 msg = createException(MAL, name,
    1059             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1060           0 :                 goto bailout;
    1061             :         }
    1062           2 :         canditer_init(&ci1, left, ls);
    1063           2 :         canditer_init(&ci2, right, rs);
    1064           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1065           0 :                 msg = createException(MAL, name,
    1066             :                                                           ILLEGAL_ARGUMENT
    1067             :                                                           " Requires bats of identical size");
    1068           0 :                 goto bailout;
    1069             :         }
    1070           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1071           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1072           0 :                 goto bailout;
    1073             :         }
    1074             : 
    1075           2 :         off1 = left->hseqbase;
    1076           2 :         off2 = right->hseqbase;
    1077           2 :         lefti = bat_iterator(left);
    1078           2 :         bi = bat_iterator(right);
    1079           2 :         righti = bi.base;
    1080           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1081           6 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1082           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1083           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1084           4 :                         const char *x = BUNtvar(lefti, p1);
    1085           4 :                         y = righti[p2];
    1086             : 
    1087           8 :                         if (strNil(x) || is_int_nil(y)) {
    1088           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1089           0 :                                         msg = createException(MAL, name,
    1090             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1091           0 :                                         goto bailout1;
    1092             :                                 }
    1093             :                                 nils = true;
    1094             :                         } else {
    1095           4 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1096           0 :                                         goto bailout1;
    1097           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1098           0 :                                         msg = createException(MAL, name,
    1099             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1100           0 :                                         goto bailout1;
    1101             :                                 }
    1102             :                         }
    1103             :                 }
    1104             :         } else {
    1105           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1106           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1107           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1108           0 :                         const char *x = BUNtvar(lefti, p1);
    1109           0 :                         y = righti[p2];
    1110             : 
    1111           0 :                         if (strNil(x) || is_int_nil(y)) {
    1112           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1113           0 :                                         msg = createException(MAL, name,
    1114             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1115           0 :                                         goto bailout1;
    1116             :                                 }
    1117             :                                 nils = true;
    1118             :                         } else {
    1119           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    1120           0 :                                         goto bailout1;
    1121           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1122           0 :                                         msg = createException(MAL, name,
    1123             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1124           0 :                                         goto bailout1;
    1125             :                                 }
    1126             :                         }
    1127             :                 }
    1128             :         }
    1129           0 :   bailout1:
    1130           2 :         bat_iterator_end(&bi);
    1131           2 :         bat_iterator_end(&lefti);
    1132           2 :   bailout:
    1133           2 :         GDKfree(buf);
    1134           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1135           2 :         unfix_inputs(4, left, ls, right, rs);
    1136           2 :         return msg;
    1137             : }
    1138             : 
    1139             : /* Input: a BAT of strings 'l', a constant int 'y' and a constant str 'z'
    1140             :  * Output type: str (a BAT of strings)
    1141             :  */
    1142             : static str
    1143           2 : do_batstr_constint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1144             :                                                                 InstrPtr pci, const char *name,
    1145             :                                                                 str (*func)(str *, size_t *, const char *, int, const char *))
    1146             : {
    1147           2 :         BATiter bi;
    1148           2 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1149           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1150           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1151           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1152           2 :         int y = *getArgReference_int(stk, pci, 2);
    1153           2 :         bool nils = false;
    1154           2 :         struct canditer ci1 = { 0 };
    1155           2 :         oid off1;
    1156           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1157           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1158           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    1159             : 
    1160           2 :         (void) cntxt;
    1161           2 :         (void) mb;
    1162           2 :         if (!buf) {
    1163           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1164           0 :                 goto bailout;
    1165             :         }
    1166           2 :         if (!(b = BATdescriptor(l))) {
    1167           0 :                 msg = createException(MAL, name,
    1168             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1169           0 :                 goto bailout;
    1170             :         }
    1171           2 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    1172           0 :                 msg = createException(MAL, name,
    1173             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1174           0 :                 goto bailout;
    1175             :         }
    1176           2 :         canditer_init(&ci1, b, bs);
    1177           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1178           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1179           0 :                 goto bailout;
    1180             :         }
    1181             : 
    1182           2 :         off1 = b->hseqbase;
    1183           2 :         bi = bat_iterator(b);
    1184           2 :         if (ci1.tpe == cand_dense) {
    1185          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1186           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    1187           8 :                         const char *x = BUNtvar(bi, p1);
    1188             : 
    1189          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1190           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1191           0 :                                         msg = createException(MAL, name,
    1192             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1193           0 :                                         goto bailout1;
    1194             :                                 }
    1195             :                                 nils = true;
    1196             :                         } else {
    1197           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1198           0 :                                         goto bailout1;
    1199           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1200           0 :                                         msg = createException(MAL, name,
    1201             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1202           0 :                                         goto bailout1;
    1203             :                                 }
    1204             :                         }
    1205             :                 }
    1206             :         } else {
    1207           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1208           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    1209           0 :                         const char *x = BUNtvar(bi, p1);
    1210             : 
    1211           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1212           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1213           0 :                                         msg = createException(MAL, name,
    1214             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1215           0 :                                         goto bailout1;
    1216             :                                 }
    1217             :                                 nils = true;
    1218             :                         } else {
    1219           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1220           0 :                                         goto bailout1;
    1221           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1222           0 :                                         msg = createException(MAL, name,
    1223             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1224           0 :                                         goto bailout1;
    1225             :                                 }
    1226             :                         }
    1227             :                 }
    1228             :         }
    1229           0 :   bailout1:
    1230           2 :         bat_iterator_end(&bi);
    1231           2 :   bailout:
    1232           2 :         GDKfree(buf);
    1233           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1234           2 :         unfix_inputs(2, b, bs);
    1235           2 :         return msg;
    1236             : }
    1237             : 
    1238             : /* Input: a BAT of strings 'l', a BAT of integers 'n' and a constant str 'z'
    1239             :  * Output type: str (a BAT of strings)
    1240             :  */
    1241             : static str
    1242           2 : do_batstr_batint_conststr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1243             :                                                           InstrPtr pci, const char *name,
    1244             :                                                           str (*func)(str *, size_t *, const char *,
    1245             :                                                                                   int, const char *))
    1246             : {
    1247           2 :         BATiter lefti;
    1248           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1249           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1250           2 :         const char *z = *getArgReference_str(stk, pci, 3);
    1251           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1252           2 :         bool nils = false;
    1253           2 :         int *restrict righti, y;
    1254           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1255           2 :         oid off1, off2;
    1256           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1257           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1258           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1259           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1260           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1261           2 :         BATiter bi;
    1262             : 
    1263           2 :         (void) cntxt;
    1264           2 :         (void) mb;
    1265           2 :         if (!buf) {
    1266           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1267           0 :                 goto bailout;
    1268             :         }
    1269           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(n))) {
    1270           0 :                 msg = createException(MAL, name,
    1271             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1272           0 :                 goto bailout;
    1273             :         }
    1274           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1275           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1276           0 :                 msg = createException(MAL, name,
    1277             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1278           0 :                 goto bailout;
    1279             :         }
    1280           2 :         canditer_init(&ci1, left, ls);
    1281           2 :         canditer_init(&ci2, right, rs);
    1282           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1283           0 :                 msg = createException(MAL, name,
    1284             :                                                           ILLEGAL_ARGUMENT
    1285             :                                                           " Requires bats of identical size");
    1286           0 :                 goto bailout;
    1287             :         }
    1288           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1289           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1290           0 :                 goto bailout;
    1291             :         }
    1292             : 
    1293           2 :         off1 = left->hseqbase;
    1294           2 :         off2 = right->hseqbase;
    1295           2 :         lefti = bat_iterator(left);
    1296           2 :         bi = bat_iterator(right);
    1297           2 :         righti = bi.base;
    1298           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1299          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1300           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1301           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1302           8 :                         const char *x = BUNtvar(lefti, p1);
    1303           8 :                         y = righti[p2];
    1304             : 
    1305          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1306           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1307           0 :                                         msg = createException(MAL, name,
    1308             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1309           0 :                                         goto bailout1;
    1310             :                                 }
    1311             :                                 nils = true;
    1312             :                         } else {
    1313           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1314           0 :                                         goto bailout1;
    1315           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1316           0 :                                         msg = createException(MAL, name,
    1317             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1318           0 :                                         goto bailout1;
    1319             :                                 }
    1320             :                         }
    1321             :                 }
    1322             :         } else {
    1323           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1324           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1325           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1326           0 :                         const char *x = BUNtvar(lefti, p1);
    1327           0 :                         y = righti[p2];
    1328             : 
    1329           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1330           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1331           0 :                                         msg = createException(MAL, name,
    1332             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1333           0 :                                         goto bailout1;
    1334             :                                 }
    1335             :                                 nils = true;
    1336             :                         } else {
    1337           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1338           0 :                                         goto bailout1;
    1339           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1340           0 :                                         msg = createException(MAL, name,
    1341             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1342           0 :                                         goto bailout1;
    1343             :                                 }
    1344             :                         }
    1345             :                 }
    1346             :         }
    1347           0 :   bailout1:
    1348           2 :         bat_iterator_end(&bi);
    1349           2 :         bat_iterator_end(&lefti);
    1350           2 :   bailout:
    1351           2 :         GDKfree(buf);
    1352           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1353           2 :         unfix_inputs(4, left, ls, right, rs);
    1354           2 :         return msg;
    1355             : }
    1356             : 
    1357             : /* Input: a BAT of strings 'l', a constant int 'y' and a BAT of strings 'l2'
    1358             :  * Output type: str (a BAT of strings)
    1359             :  */
    1360             : static str
    1361           2 : do_batstr_constint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1362             :                                                           InstrPtr pci, const char *name,
    1363             :                                                           str (*func)(str *, size_t *, const char *,
    1364             :                                                                                   int, const char *))
    1365             : {
    1366           2 :         BATiter lefti, righti;
    1367           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    1368           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1369           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1370           2 :         bool nils = false;
    1371           2 :         int y = *getArgReference_int(stk, pci, 2);
    1372           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1373           2 :         oid off1, off2;
    1374           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1375           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1376           2 :                 l2 = *getArgReference_bat(stk, pci, 3),
    1377           2 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    1378           2 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    1379             : 
    1380           2 :         (void) cntxt;
    1381           2 :         (void) mb;
    1382           2 :         if (!buf) {
    1383           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1384           0 :                 goto bailout;
    1385             :         }
    1386           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(l2))) {
    1387           0 :                 msg = createException(MAL, name,
    1388             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1389           0 :                 goto bailout;
    1390             :         }
    1391           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    1392           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    1393           0 :                 msg = createException(MAL, name,
    1394             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1395           0 :                 goto bailout;
    1396             :         }
    1397           2 :         canditer_init(&ci1, left, ls);
    1398           2 :         canditer_init(&ci2, right, rs);
    1399           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1400           0 :                 msg = createException(MAL, name,
    1401             :                                                           ILLEGAL_ARGUMENT
    1402             :                                                           " Requires bats of identical size");
    1403           0 :                 goto bailout;
    1404             :         }
    1405           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1406           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1407           0 :                 goto bailout;
    1408             :         }
    1409             : 
    1410           2 :         off1 = left->hseqbase;
    1411           2 :         off2 = right->hseqbase;
    1412           2 :         lefti = bat_iterator(left);
    1413           2 :         righti = bat_iterator(right);
    1414           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1415          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1416           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1417           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1418           8 :                         const char *x = BUNtvar(lefti, p1);
    1419           8 :                         const char *z = BUNtvar(righti, p2);
    1420             : 
    1421          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1422           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1423           0 :                                         msg = createException(MAL, name,
    1424             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1425           0 :                                         goto bailout1;
    1426             :                                 }
    1427             :                                 nils = true;
    1428             :                         } else {
    1429           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1430           0 :                                         goto bailout1;
    1431           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1432           0 :                                         msg = createException(MAL, name,
    1433             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1434           0 :                                         goto bailout1;
    1435             :                                 }
    1436             :                         }
    1437             :                 }
    1438             :         } else {
    1439           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1440           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1441           0 :                                 p2 = (canditer_next(&ci2) - off2);
    1442           0 :                         const char *x = BUNtvar(lefti, p1);
    1443           0 :                         const char *z = BUNtvar(righti, p2);
    1444             : 
    1445           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1446           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1447           0 :                                         msg = createException(MAL, name,
    1448             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1449           0 :                                         goto bailout1;
    1450             :                                 }
    1451             :                                 nils = true;
    1452             :                         } else {
    1453           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1454           0 :                                         goto bailout1;
    1455           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1456           0 :                                         msg = createException(MAL, name,
    1457             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1458           0 :                                         goto bailout1;
    1459             :                                 }
    1460             :                         }
    1461             :                 }
    1462             :         }
    1463           0 :   bailout1:
    1464           2 :         bat_iterator_end(&lefti);
    1465           2 :         bat_iterator_end(&righti);
    1466           2 :   bailout:
    1467           2 :         GDKfree(buf);
    1468           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1469           2 :         unfix_inputs(4, left, ls, right, rs);
    1470           2 :         return msg;
    1471             : }
    1472             : 
    1473             : /* Input: a BAT of strings 'l', a BAT of int 'n' and a BAT of strings 'l2'
    1474             :  * Output type: str (a BAT of strings)
    1475             :  */
    1476             : static str
    1477           2 : do_batstr_batint_batstr_str(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    1478             :                                                         InstrPtr pci, const char *name,
    1479             :                                                         str (*func)(str *, size_t *, const char *,
    1480             :                                                                                 int, const char *))
    1481             : {
    1482           2 :         BATiter arg1i, arg3i, bi;
    1483           2 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL, *arg2s = NULL,
    1484           2 :                 *arg3 = NULL, *arg3s = NULL;
    1485           2 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    1486           2 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    1487           2 :         bool nils = false;
    1488           2 :         int *restrict arg2i, y;
    1489           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    1490           2 :         oid off1, off2, off3;
    1491           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    1492           2 :                 l = *getArgReference_bat(stk, pci, 1),
    1493           2 :                 n = *getArgReference_bat(stk, pci, 2),
    1494           2 :                 l2 = *getArgReference_bat(stk, pci, 3),
    1495           2 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    1496           2 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    1497           2 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    1498             : 
    1499           2 :         (void) cntxt;
    1500           2 :         (void) mb;
    1501           2 :         if (!buf) {
    1502           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1503           0 :                 goto bailout;
    1504             :         }
    1505           2 :         if (!(arg1 = BATdescriptor(l)) || !(arg2 = BATdescriptor(n))
    1506           2 :                 || !(arg3 = BATdescriptor(l2))) {
    1507           0 :                 msg = createException(MAL, name,
    1508             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1509           0 :                 goto bailout;
    1510             :         }
    1511           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1)))
    1512           2 :                 || (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2)))
    1513           2 :                 || (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3)))) {
    1514           0 :                 msg = createException(MAL, name,
    1515             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1516           0 :                 goto bailout;
    1517             :         }
    1518           2 :         canditer_init(&ci1, arg1, arg1s);
    1519           2 :         canditer_init(&ci2, arg2, arg2s);
    1520           2 :         canditer_init(&ci3, arg3, arg3s);
    1521           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    1522           2 :                 || ci2.hseq != ci3.hseq) {
    1523           0 :                 msg = createException(MAL, name,
    1524             :                                                           ILLEGAL_ARGUMENT
    1525             :                                                           " Requires bats of identical size");
    1526           0 :                 goto bailout;
    1527             :         }
    1528           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    1529           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1530           0 :                 goto bailout;
    1531             :         }
    1532             : 
    1533           2 :         off1 = arg1->hseqbase;
    1534           2 :         off2 = arg2->hseqbase;
    1535           2 :         off3 = arg3->hseqbase;
    1536           2 :         arg1i = bat_iterator(arg1);
    1537           2 :         bi = bat_iterator(arg2);
    1538           2 :         arg2i = bi.base;
    1539           2 :         arg3i = bat_iterator(arg3);
    1540           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    1541          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1542           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1543           8 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    1544           8 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    1545           8 :                         const char *x = BUNtvar(arg1i, p1);
    1546           8 :                         y = arg2i[p2];
    1547           8 :                         const char *z = BUNtvar(arg3i, p3);
    1548             : 
    1549          16 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1550           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1551           0 :                                         msg = createException(MAL, name,
    1552             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1553           0 :                                         goto bailout1;
    1554             :                                 }
    1555             :                                 nils = true;
    1556             :                         } else {
    1557           8 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1558           0 :                                         goto bailout1;
    1559           8 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1560           0 :                                         msg = createException(MAL, name,
    1561             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1562           0 :                                         goto bailout1;
    1563             :                                 }
    1564             :                         }
    1565             :                 }
    1566             :         } else {
    1567           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1568           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    1569           0 :                                 p2 = (canditer_next(&ci2) - off2),
    1570           0 :                                 p3 = (canditer_next(&ci3) - off3);
    1571           0 :                         const char *x = BUNtvar(arg1i, p1);
    1572           0 :                         y = arg2i[p2];
    1573           0 :                         const char *z = BUNtvar(arg3i, p3);
    1574             : 
    1575           0 :                         if (strNil(x) || is_int_nil(y) || strNil(z)) {
    1576           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    1577           0 :                                         msg = createException(MAL, name,
    1578             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1579           0 :                                         goto bailout1;
    1580             :                                 }
    1581             :                                 nils = true;
    1582             :                         } else {
    1583           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    1584           0 :                                         goto bailout1;
    1585           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    1586           0 :                                         msg = createException(MAL, name,
    1587             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1588           0 :                                         goto bailout1;
    1589             :                                 }
    1590             :                         }
    1591             :                 }
    1592             :         }
    1593           0 :   bailout1:
    1594           2 :         bat_iterator_end(&arg1i);
    1595           2 :         bat_iterator_end(&arg3i);
    1596           2 :         bat_iterator_end(&bi);
    1597           2 :   bailout:
    1598           2 :         GDKfree(buf);
    1599           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    1600           2 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    1601           2 :         return msg;
    1602             : }
    1603             : 
    1604             : static str
    1605         160 : STRbatConvert(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1606             :                           BAT *(*func)(BAT *, BAT *), const char *malfunc)
    1607             : {
    1608         160 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    1609         160 :         bat *res = getArgReference_bat(stk, pci, 0),
    1610         160 :                 *bid = getArgReference_bat(stk, pci, 1),
    1611         160 :                 *sid1 = pci->argc == 3 ? getArgReference_bat(stk, pci, 2) : NULL;
    1612             : 
    1613         160 :         (void) cntxt;
    1614         160 :         (void) mb;
    1615         160 :         if (!(b = BATdescriptor(*bid))) {
    1616           0 :                 throw(MAL, malfunc, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1617             :         }
    1618         161 :         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         160 :         bn = (*func)(b, bs);
    1623         161 :         unfix_inputs(2, b, bs);
    1624         161 :         if (bn == NULL)
    1625           0 :                 throw(MAL, malfunc, GDK_EXCEPTION);
    1626         161 :         *res = bn->batCacheid;
    1627         161 :         BBPkeepref(bn);
    1628         161 :         return MAL_SUCCEED;
    1629             : }
    1630             : 
    1631             : static str
    1632         108 : STRbatLower(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1633             : {
    1634         108 :         return STRbatConvert(cntxt, mb, stk, pci, BATtolower, "batstr.toLower");
    1635             : }
    1636             : 
    1637             : static str
    1638          19 : STRbatUpper(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1639             : {
    1640          19 :         return STRbatConvert(cntxt, mb, stk, pci, BATtoupper, "batstr.toUpper");
    1641             : }
    1642             : 
    1643             : static str
    1644           0 : STRbatCaseFold(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1645             : {
    1646           0 :         return STRbatConvert(cntxt, mb, stk, pci, BATcasefold, "batstr.caseFold");
    1647             : }
    1648             : 
    1649             : static str
    1650          10 : STRbatStrip(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1651             : {
    1652          10 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.strip", str_strip);
    1653             : }
    1654             : 
    1655             : static str
    1656           2 : STRbatLtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1657             : {
    1658           2 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim", str_ltrim);
    1659             : }
    1660             : 
    1661             : static str
    1662          38 : STRbatRtrim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1663             : {
    1664          38 :         return do_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim", str_rtrim);
    1665             : }
    1666             : 
    1667             : static str
    1668           9 : STRbatStrip2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1669             : {
    1670           9 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.strip",
    1671             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1672             :                                                                   str_strip2);
    1673             : }
    1674             : 
    1675             : static str
    1676           1 : STRbatLtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1677             : {
    1678           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1679             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1680             :                                                                   str_ltrim2);
    1681             : }
    1682             : 
    1683             : static str
    1684           1 : STRbatRtrim2_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1685             : {
    1686           1 :         return do_batstr_conststr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1687             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1688             :                                                                   str_rtrim2);
    1689             : }
    1690             : 
    1691             : static str
    1692           0 : STRbatStrip2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1693             : {
    1694           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.strip",
    1695             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1696             :                                                                   str_strip2);
    1697             : }
    1698             : 
    1699             : static str
    1700           0 : STRbatLtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1701             : {
    1702           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.ltrim",
    1703             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1704             :                                                                   str_ltrim2);
    1705             : }
    1706             : 
    1707             : static str
    1708           0 : STRbatRtrim2_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1709             : {
    1710           0 :         return do_batstr_str_conststr(cntxt, mb, stk, pci, "batstr.rtrim",
    1711             :                                                                   INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1712             :                                                                   str_rtrim2);
    1713             : }
    1714             : 
    1715             : static str
    1716           1 : STRbatStrip2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1717             : {
    1718           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.strip",
    1719             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1720             :                                                                 str_strip2);
    1721             : }
    1722             : 
    1723             : static str
    1724           1 : STRbatLtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1725             : {
    1726           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.ltrim",
    1727             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1728             :                                                                 str_ltrim2);
    1729             : }
    1730             : 
    1731             : static str
    1732           1 : STRbatRtrim2_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1733             : {
    1734           1 :         return do_batstr_batstr_str(cntxt, mb, stk, pci, "batstr.rtrim",
    1735             :                                                                 INITIAL_STR_BUFFER_LENGTH * sizeof(int),
    1736             :                                                                 str_rtrim2);
    1737             : }
    1738             : 
    1739             : static str
    1740           1 : STRbatLpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1741             : {
    1742           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1743             : }
    1744             : 
    1745             : static str
    1746           1 : STRbatRpad_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1747             : {
    1748           1 :         return do_batstr_constint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1749             : }
    1750             : 
    1751             : static str
    1752           0 : STRbatLpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1753             : {
    1754           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1755             : }
    1756             : 
    1757             : static str
    1758           0 : STRbatRpad_1st_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1759             : {
    1760           0 :         return do_batstr_int_conststr(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1761             : }
    1762             : 
    1763             : static str
    1764           1 : STRbatLpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1765             : {
    1766           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.lpad", str_lpad);
    1767             : }
    1768             : 
    1769             : static str
    1770           1 : STRbatRpad_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1771             : {
    1772           1 :         return do_batstr_batint_str(cntxt, mb, stk, pci, "batstr.rpad", str_rpad);
    1773             : }
    1774             : 
    1775             : static str
    1776           1 : STRbatLpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1777             : {
    1778           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1779             :                                                                                    str_lpad3);
    1780             : }
    1781             : 
    1782             : static str
    1783           1 : STRbatRpad3_const_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1784             : {
    1785           1 :         return do_batstr_constint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1786             :                                                                                    str_rpad3);
    1787             : }
    1788             : 
    1789             : static str
    1790           1 : STRbatLpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1791             : {
    1792           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1793             :                                                                                  str_lpad3);
    1794             : }
    1795             : 
    1796             : static str
    1797           1 : STRbatRpad3_bat_const(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1798             : {
    1799           1 :         return do_batstr_batint_conststr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1800             :                                                                                  str_rpad3);
    1801             : }
    1802             : 
    1803             : static str
    1804           1 : STRbatLpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1805             : {
    1806           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1807             :                                                                                  str_lpad3);
    1808             : }
    1809             : 
    1810             : static str
    1811           1 : STRbatRpad3_const_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1812             : {
    1813           1 :         return do_batstr_constint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1814             :                                                                                  str_rpad3);
    1815             : }
    1816             : 
    1817             : static str
    1818           1 : STRbatLpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1819             : {
    1820           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.lpad",
    1821             :                                                                            str_lpad3);
    1822             : }
    1823             : 
    1824             : static str
    1825           1 : STRbatRpad3_bat_bat(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    1826             : {
    1827           1 :         return do_batstr_batint_batstr_str(cntxt, mb, stk, pci, "batstr.rpad",
    1828             :                                                                            str_rpad3);
    1829             : }
    1830             : 
    1831             : /*
    1832             :  * A general assumption in all cases is the bats are synchronized on their
    1833             :  * head column. This is not checked and may be mis-used to deploy the
    1834             :  * implementation for shifted window arithmetic as well.
    1835             :  */
    1836             : static str
    1837          15 : prefix_or_suffix(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    1838             :                                  const char *name, int (*func)(const char *, const char *, int),
    1839             :                                  bit *icase)
    1840             : {
    1841          15 :          (void) cntxt;
    1842          15 :         (void) mb;
    1843             : 
    1844          15 :         BATiter lefti, righti;
    1845          15 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    1846          15 :         bit *restrict vals;
    1847          15 :         str msg = MAL_SUCCEED;
    1848          15 :         bool nils = false;
    1849          15 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    1850          15 :         oid off1, off2;
    1851          15 :         bat *res = getArgReference_bat(stk, pci, 0),
    1852          15 :                 l = *getArgReference_bat(stk, pci, 1),
    1853          15 :                 r = *getArgReference_bat(stk, pci, 2),
    1854          28 :                 *sid1 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 4 : 3) : NULL,
    1855          28 :                 *sid2 = pci->argc >= 5 ? getArgReference_bat(stk, pci, icase ? 5 : 4) : NULL;
    1856             : 
    1857          15 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    1858           0 :                 msg = createException(MAL, name,
    1859             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1860           0 :                 goto exit2;
    1861             :         }
    1862          15 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) ||
    1863          13 :                 (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    1864           0 :                 msg = createException(MAL, name,
    1865             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    1866           0 :                 goto exit2;
    1867             :         }
    1868          15 :         canditer_init(&ci1, left, lefts);
    1869          15 :         canditer_init(&ci2, right, rights);
    1870          15 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    1871           0 :                 msg = createException(MAL, name,
    1872             :                                                           ILLEGAL_ARGUMENT
    1873             :                                                           " Requires bats of identical size");
    1874           0 :                 goto exit2;
    1875             :         }
    1876          15 :         if (!(bn = COLnew(ci1.hseq, TYPE_bit, ci1.ncand, TRANSIENT))) {
    1877           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1878           0 :                 goto exit2;
    1879             :         }
    1880             : 
    1881          15 :         off1 = left->hseqbase;
    1882          15 :         off2 = right->hseqbase;
    1883          15 :         lefti = bat_iterator(left);
    1884          15 :         righti = bat_iterator(right);
    1885          15 :         vals = Tloc(bn, 0);
    1886          15 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    1887          46 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    1888          32 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    1889          32 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    1890          32 :                         char *x = BUNtvar(lefti, p1);
    1891          32 :                         char *y = BUNtvar(righti, p2);
    1892             : 
    1893          64 :                         if (strNil(x) || strNil(y)) {
    1894           0 :                                 vals[i] = bit_nil;
    1895           0 :                                 nils = true;
    1896             :                         } else {
    1897          32 :                                 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          14 :         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        2022 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2012        1964 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2013        1964 :                         char *x = BUNtvar(bi, p1);
    2014             : 
    2015        1964 :                         if (ynil || strNil(x)) {
    2016           6 :                                 vals[i] = bit_nil;
    2017           6 :                                 nils = true;
    2018             :                         } else {
    2019        1958 :                                 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          95 : 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          95 :         BATiter bi;
    2815          95 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2816          95 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2817          95 :         int y = *getArgReference_int(stk, pci, 2);
    2818          95 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2819          95 :         bool nils = false;
    2820          95 :         struct canditer ci1 = { 0 };
    2821          95 :         oid off1;
    2822          95 :         bat *res = getArgReference_bat(stk, pci, 0),
    2823          95 :                 l = *getArgReference_bat(stk, pci, 1),
    2824          95 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2825             : 
    2826          95 :         (void) cntxt;
    2827          95 :         (void) mb;
    2828          95 :         if (!buf) {
    2829           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2830           0 :                 goto bailout;
    2831             :         }
    2832          95 :         if (!(b = BATdescriptor(l))) {
    2833           0 :                 msg = createException(MAL, name,
    2834             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2835           0 :                 goto bailout;
    2836             :         }
    2837          95 :         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          95 :         canditer_init(&ci1, b, bs);
    2843          95 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2844           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2845           0 :                 goto bailout;
    2846             :         }
    2847             : 
    2848          95 :         off1 = b->hseqbase;
    2849          95 :         bi = bat_iterator(b);
    2850          95 :         if (ci1.tpe == cand_dense) {
    2851        6167 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2852        6072 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2853        6072 :                         const char *x = BUNtvar(bi, p1);
    2854             : 
    2855       11713 :                         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        5638 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    2864           0 :                                         goto bailout1;
    2865        5638 :                                 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          95 :         bat_iterator_end(&bi);
    2897          95 :   bailout:
    2898          95 :         GDKfree(buf);
    2899          95 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    2900          95 :         unfix_inputs(2, b, bs);
    2901          95 :         return msg;
    2902             : }
    2903             : 
    2904             : static str
    2905          85 : STRbatprefixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2906             : {
    2907          85 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.prefix",
    2908             :                                                                  str_prefix);
    2909             : }
    2910             : 
    2911             : static str
    2912           1 : STRbatsuffixcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2913             : {
    2914           1 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.suffix",
    2915             :                                                                  str_suffix);
    2916             : }
    2917             : 
    2918             : static str
    2919           5 : STRbatTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2920             : {
    2921           5 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    2922             : }
    2923             : 
    2924             : static str
    2925           4 : STRbatsubstringTailcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2926             : {
    2927           4 :         return do_batstr_str_int_cst(cntxt, mb, stk, pci, "batstr.substring",
    2928             :                                                                  str_substring_tail);
    2929             : }
    2930             : 
    2931             : static str
    2932           1 : STRbatrepeatcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    2933             : {
    2934           1 :         BATiter bi;
    2935           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    2936           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    2937           1 :         int y = *getArgReference_int(stk, pci, 2);
    2938           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    2939           1 :         bool nils = false;
    2940           1 :         struct canditer ci1 = { 0 };
    2941           1 :         oid off1;
    2942           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    2943           1 :                 l = *getArgReference_bat(stk, pci, 1),
    2944           1 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    2945             : 
    2946           1 :         (void) cntxt;
    2947           1 :         (void) mb;
    2948           1 :         if (!buf) {
    2949           0 :                 msg = createException(MAL, "batstr.repeat",
    2950             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2951           0 :                 goto bailout;
    2952             :         }
    2953           1 :         if (!(b = BATdescriptor(l))) {
    2954           0 :                 msg = createException(MAL, "batstr.repeat",
    2955             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2956           0 :                 goto bailout;
    2957             :         }
    2958           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    2959           0 :                 msg = createException(MAL, "batstr.repeat",
    2960             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    2961           0 :                 goto bailout;
    2962             :         }
    2963           1 :         canditer_init(&ci1, b, bs);
    2964           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    2965           0 :                 msg = createException(MAL, "batstr.repeat",
    2966             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2967           0 :                 goto bailout;
    2968             :         }
    2969             : 
    2970           1 :         off1 = b->hseqbase;
    2971           1 :         bi = bat_iterator(b);
    2972           1 :         if (ci1.tpe == cand_dense) {
    2973           5 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2974           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    2975           4 :                         const char *x = BUNtvar(bi, p1);
    2976             : 
    2977           8 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    2978           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    2979           0 :                                         msg = createException(MAL, "batstr.repeat",
    2980             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2981           0 :                                         goto bailout1;
    2982             :                                 }
    2983             :                                 nils = true;
    2984             :                         } else {
    2985           4 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    2986           0 :                                         goto bailout1;
    2987           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    2988           0 :                                         msg = createException(MAL, "batstr.repeat",
    2989             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2990           0 :                                         goto bailout1;
    2991             :                                 }
    2992             :                         }
    2993             :                 }
    2994             :         } else {
    2995           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    2996           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    2997           0 :                         const char *x = BUNtvar(bi, p1);
    2998             : 
    2999           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3000           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3001           0 :                                         msg = createException(MAL, "batstr.repeat",
    3002             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3003           0 :                                         goto bailout1;
    3004             :                                 }
    3005             :                                 nils = true;
    3006             :                         } else {
    3007           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3008           0 :                                         goto bailout1;
    3009           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3010           0 :                                         msg = createException(MAL, "batstr.repeat",
    3011             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3012           0 :                                         goto bailout1;
    3013             :                                 }
    3014             :                         }
    3015             :                 }
    3016             :         }
    3017           0 :   bailout1:
    3018           1 :         bat_iterator_end(&bi);
    3019           1 :   bailout:
    3020           1 :         GDKfree(buf);
    3021           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3022           1 :         unfix_inputs(2, b, bs);
    3023           1 :         return msg;
    3024             : }
    3025             : 
    3026             : static str
    3027           5 : do_batstr_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3028             :                                  const char *name,
    3029             :                                  str (*func)(str *, size_t *, const char *, int))
    3030             : {
    3031           5 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3032           5 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3033           5 :         int *restrict vals, y;
    3034           5 :         const char *x = *getArgReference_str(stk, pci, 1);
    3035           5 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3036           5 :         bool nils = false;
    3037           5 :         struct canditer ci1 = { 0 };
    3038           5 :         oid off1;
    3039           5 :         bat *res = getArgReference_bat(stk, pci, 0),
    3040           5 :                 l = *getArgReference_bat(stk, pci, 2),
    3041           5 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3042           5 :         BATiter bi;
    3043             : 
    3044           5 :         (void) cntxt;
    3045           5 :         (void) mb;
    3046           5 :         if (!buf) {
    3047           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3048           0 :                 goto bailout;
    3049             :         }
    3050           5 :         if (!(b = BATdescriptor(l))) {
    3051           0 :                 msg = createException(MAL, name,
    3052             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3053           0 :                 goto bailout;
    3054             :         }
    3055           5 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3056           0 :                 msg = createException(MAL, name,
    3057             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3058           0 :                 goto bailout;
    3059             :         }
    3060           5 :         canditer_init(&ci1, b, bs);
    3061           5 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3062           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3063           0 :                 goto bailout;
    3064             :         }
    3065             : 
    3066           5 :         off1 = b->hseqbase;
    3067           5 :         bi = bat_iterator(b);
    3068           5 :         vals = bi.base;
    3069           5 :         if (ci1.tpe == cand_dense) {
    3070          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3071           5 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3072           5 :                         y = vals[p1];
    3073             : 
    3074          10 :                         if (strNil(x) || is_int_nil(y)) {
    3075           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3076           0 :                                         msg = createException(MAL, name,
    3077             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3078           0 :                                         goto bailout1;
    3079             :                                 }
    3080             :                                 nils = true;
    3081             :                         } else {
    3082           5 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3083           0 :                                         goto bailout1;
    3084           5 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3085           0 :                                         msg = createException(MAL, name,
    3086             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3087           0 :                                         goto bailout1;
    3088             :                                 }
    3089             :                         }
    3090             :                 }
    3091             :         } else {
    3092           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3093           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3094           0 :                         y = vals[p1];
    3095             : 
    3096           0 :                         if (strNil(x) || is_int_nil(y)) {
    3097           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3098           0 :                                         msg = createException(MAL, name,
    3099             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3100           0 :                                         goto bailout1;
    3101             :                                 }
    3102             :                                 nils = true;
    3103             :                         } else {
    3104           0 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3105           0 :                                         goto bailout1;
    3106           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3107           0 :                                         msg = createException(MAL, name,
    3108             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3109           0 :                                         goto bailout1;
    3110             :                                 }
    3111             :                         }
    3112             :                 }
    3113             :         }
    3114           0 :   bailout1:
    3115           5 :         bat_iterator_end(&bi);
    3116           4 :   bailout:
    3117           4 :         GDKfree(buf);
    3118           5 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3119           4 :         unfix_inputs(2, b, bs);
    3120           5 :         return msg;
    3121             : }
    3122             : 
    3123             : static str
    3124           5 : STRbatprefix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3125             : {
    3126           5 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.prefix", str_prefix);
    3127             : }
    3128             : 
    3129             : static str
    3130           0 : STRbatsuffix_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3131             : {
    3132           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.suffix", str_suffix);
    3133             : }
    3134             : 
    3135             : static str
    3136           0 : STRbatTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3137             : {
    3138           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.tail", str_tail);
    3139             : }
    3140             : 
    3141             : static str
    3142           0 : STRbatsubstringTail_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3143             :                                                    InstrPtr pci)
    3144             : {
    3145           0 :         return do_batstr_strcst(cntxt, mb, stk, pci, "batstr.substring",
    3146             :                                                         str_substring_tail);
    3147             : }
    3148             : 
    3149             : static str
    3150           0 : STRbatrepeat_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3151             : {
    3152           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3153           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3154           0 :         int *restrict vals, y;
    3155           0 :         const char *x = *getArgReference_str(stk, pci, 1);
    3156           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3157           0 :         bool nils = false;
    3158           0 :         struct canditer ci1 = { 0 };
    3159           0 :         oid off1;
    3160           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3161           0 :                 l = *getArgReference_bat(stk, pci, 2),
    3162           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    3163           0 :         BATiter bi;
    3164             : 
    3165           0 :         (void) cntxt;
    3166           0 :         (void) mb;
    3167           0 :         if (!buf) {
    3168           0 :                 msg = createException(MAL, "batstr.repeat",
    3169             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3170           0 :                 goto bailout;
    3171             :         }
    3172           0 :         if (!(b = BATdescriptor(l))) {
    3173           0 :                 msg = createException(MAL, "batstr.repeat",
    3174             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3175           0 :                 goto bailout;
    3176             :         }
    3177           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3178           0 :                 msg = createException(MAL, "batstr.repeat",
    3179             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3180           0 :                 goto bailout;
    3181             :         }
    3182           0 :         canditer_init(&ci1, b, bs);
    3183           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3184           0 :                 msg = createException(MAL, "batstr.repeat",
    3185             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3186           0 :                 goto bailout;
    3187             :         }
    3188             : 
    3189           0 :         off1 = b->hseqbase;
    3190           0 :         bi = bat_iterator(b);
    3191           0 :         vals = bi.base;
    3192           0 :         if (ci1.tpe == cand_dense) {
    3193           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3194           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3195           0 :                         y = vals[p1];
    3196             : 
    3197           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3198           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3199           0 :                                         msg = createException(MAL, "batstr.repeat",
    3200             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3201           0 :                                         goto bailout1;
    3202             :                                 }
    3203             :                                 nils = true;
    3204             :                         } else {
    3205           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3206           0 :                                         goto bailout1;
    3207           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3208           0 :                                         msg = createException(MAL, "batstr.repeat",
    3209             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3210           0 :                                         goto bailout1;
    3211             :                                 }
    3212             :                         }
    3213             :                 }
    3214             :         } else {
    3215           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3216           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3217           0 :                         y = vals[p1];
    3218             : 
    3219           0 :                         if (strNil(x) || is_int_nil(y) || y < 0) {
    3220           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3221           0 :                                         msg = createException(MAL, "batstr.repeat",
    3222             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3223           0 :                                         goto bailout1;
    3224             :                                 }
    3225             :                                 nils = true;
    3226             :                         } else {
    3227           0 :                                 if ((msg = str_repeat(&buf, &buflen, x, y)) != MAL_SUCCEED)
    3228           0 :                                         goto bailout1;
    3229           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3230           0 :                                         msg = createException(MAL, "batstr.repeat",
    3231             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3232           0 :                                         goto bailout1;
    3233             :                                 }
    3234             :                         }
    3235             :                 }
    3236             :         }
    3237           0 :   bailout1:
    3238           0 :         bat_iterator_end(&bi);
    3239           0 :   bailout:
    3240           0 :         GDKfree(buf);
    3241           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3242           0 :         unfix_inputs(2, b, bs);
    3243           0 :         return msg;
    3244             : }
    3245             : 
    3246             : static str
    3247          33 : do_batstr_str_int(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3248             :                                   const char *name, str (*func)(str *, size_t *, const char *,
    3249             :                                                                                                 int))
    3250             : {
    3251          33 :         BATiter lefti;
    3252          33 :         BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
    3253          33 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3254          33 :         int *restrict righti, y;
    3255          33 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3256          33 :         bool nils = false;
    3257          33 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3258          33 :         oid off1, off2;
    3259          33 :         bat *res = getArgReference_bat(stk, pci, 0),
    3260          33 :                 l = *getArgReference_bat(stk, pci, 1),
    3261          33 :                 r = *getArgReference_bat(stk, pci, 2),
    3262          33 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    3263          33 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3264          33 :         BATiter bi;
    3265             : 
    3266          33 :         (void) cntxt;
    3267          33 :         (void) mb;
    3268          33 :         if (!buf) {
    3269           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3270           0 :                 goto bailout;
    3271             :         }
    3272          33 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    3273           0 :                 msg = createException(MAL, name,
    3274             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3275           0 :                 goto bailout;
    3276             :         }
    3277          33 :         if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1)))
    3278          33 :                 || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
    3279           0 :                 msg = createException(MAL, name,
    3280             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3281           0 :                 goto bailout;
    3282             :         }
    3283          33 :         canditer_init(&ci1, left, lefts);
    3284          33 :         canditer_init(&ci2, right, rights);
    3285          33 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3286           0 :                 msg = createException(MAL, name,
    3287             :                                                           ILLEGAL_ARGUMENT
    3288             :                                                           " Requires bats of identical size");
    3289           0 :                 goto bailout;
    3290             :         }
    3291          33 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3292           0 :                 msg = createException(MAL, name, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3293           0 :                 goto bailout;
    3294             :         }
    3295             : 
    3296          33 :         off1 = left->hseqbase;
    3297          33 :         off2 = right->hseqbase;
    3298          33 :         lefti = bat_iterator(left);
    3299          33 :         bi = bat_iterator(right);
    3300          33 :         righti = bi.base;
    3301          33 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3302       32515 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3303       32482 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3304       32482 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3305       32482 :                         const char *x = BUNtvar(lefti, p1);
    3306       32482 :                         y = righti[p2];
    3307             : 
    3308       36302 :                         if (strNil(x) || is_int_nil(y)) {
    3309       28662 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3310           0 :                                         msg = createException(MAL, name,
    3311             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3312           0 :                                         goto bailout1;
    3313             :                                 }
    3314             :                                 nils = true;
    3315             :                         } else {
    3316        3820 :                                 if ((msg = (*func) (&buf, &buflen, x, y)) != MAL_SUCCEED)
    3317           0 :                                         goto bailout1;
    3318        3804 :                                 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         469 : STRbatSubstitutecst_imp(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
    3501             :                                                 int cand_nargs, const bit *rep)
    3502             : {
    3503         469 :         BATiter bi;
    3504         469 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3505         469 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3506         469 :         const char *y = *getArgReference_str(stk, pci, 2),
    3507         469 :                 *z = *getArgReference_str(stk, pci, 3);
    3508         469 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3509         472 :         bool nils = false;
    3510         472 :         bit w = *rep;
    3511         472 :         struct canditer ci1 = { 0 };
    3512         472 :         oid off1;
    3513         472 :         bat *res = getArgReference_bat(stk, pci, 0),
    3514         472 :                 bid = *getArgReference_bat(stk, pci, 1),
    3515         472 :                 *sid1 = pci->argc == cand_nargs ? getArgReference_bat(stk, pci, cand_nargs - 1) : NULL;
    3516             : 
    3517         472 :         if (!buf) {
    3518           0 :                 msg = createException(MAL, "batstr.substritute",
    3519             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3520           0 :                 goto bailout;
    3521             :         }
    3522         472 :         if (!(b = BATdescriptor(bid))) {
    3523           0 :                 msg = createException(MAL, "batstr.substritute",
    3524             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3525           0 :                 goto bailout;
    3526             :         }
    3527         472 :         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         472 :         canditer_init(&ci1, b, bs);
    3533         472 :         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         472 :         (void) cntxt;
    3540         472 :         (void) mb;
    3541         472 :         off1 = b->hseqbase;
    3542         472 :         bi = bat_iterator(b);
    3543         471 :         if (ci1.tpe == cand_dense) {
    3544      132385 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3545      131914 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3546      131914 :                         const char *x = BUNtvar(bi, p1);
    3547             : 
    3548      525136 :                         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      131074 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3557           0 :                                         goto bailout1;
    3558      131001 :                                 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         471 :         bat_iterator_end(&bi);
    3590         472 :   bailout:
    3591         472 :         GDKfree(buf);
    3592         472 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3593         472 :         unfix_inputs(2, b, bs);
    3594         472 :         return msg;
    3595             : }
    3596             : 
    3597             : static str
    3598           0 : STRbatSubstitutecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3599             : {
    3600           0 :         const bit *rep = getArgReference_bit(stk, pci, 4);
    3601           0 :         return STRbatSubstitutecst_imp(cntxt, mb, stk, pci, 6, rep);
    3602             : }
    3603             : 
    3604             : static str
    3605           0 : STRbatSubstitute(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3606             : {
    3607           0 :         BATiter arg1i, arg2i, arg3i;
    3608           0 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL, *arg2s = NULL,
    3609           0 :                 *arg3 = NULL, *arg3s = NULL, *arg4 = NULL, *arg4s = NULL;
    3610           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3611           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3612           0 :         bool nils = false;
    3613           0 :         bit *restrict arg4i, w;
    3614           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 }, ci4 = { 0 };
    3615           0 :         oid off1, off2, off3, off4;
    3616           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3617           0 :                 l = *getArgReference_bat(stk, pci, 1),
    3618           0 :                 r = *getArgReference_bat(stk, pci, 2),
    3619           0 :                 s = *getArgReference_bat(stk, pci, 3),
    3620           0 :                 rep = *getArgReference_bat(stk, pci, 4),
    3621           0 :                 *sid1 = pci->argc == 9 ? getArgReference_bat(stk, pci, 5) : NULL,
    3622           0 :                 *sid2 = pci->argc == 9 ? getArgReference_bat(stk, pci, 6) : NULL,
    3623           0 :                 *sid3 = pci->argc == 9 ? getArgReference_bat(stk, pci, 7) : NULL,
    3624           0 :                 *sid4 = pci->argc == 9 ? getArgReference_bat(stk, pci, 8) : NULL;
    3625           0 :         BATiter bi;
    3626             : 
    3627           0 :         if (!buf) {
    3628           0 :                 msg = createException(MAL, "batstr.substritute",
    3629             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3630           0 :                 goto bailout;
    3631             :         }
    3632           0 :         if (!(arg1 = BATdescriptor(l)) || !(arg2 = BATdescriptor(r))
    3633           0 :                 || !(arg3 = BATdescriptor(s)) || !(arg4 = BATdescriptor(rep))) {
    3634           0 :                 msg = createException(MAL, "batstr.substritute",
    3635             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3636           0 :                 goto bailout;
    3637             :         }
    3638           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1)))
    3639           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2)))
    3640           0 :                 || (sid3 && !is_bat_nil(*sid3) && !(arg2s = BATdescriptor(*sid3)))
    3641           0 :                 || (sid4 && !is_bat_nil(*sid4) && !(arg4s = BATdescriptor(*sid4)))) {
    3642           0 :                 msg = createException(MAL, "batstr.substritute",
    3643             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3644           0 :                 goto bailout;
    3645             :         }
    3646           0 :         canditer_init(&ci1, arg1, arg1s);
    3647           0 :         canditer_init(&ci2, arg2, arg2s);
    3648           0 :         canditer_init(&ci3, arg3, arg3s);
    3649           0 :         canditer_init(&ci4, arg4, arg4s);
    3650           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    3651           0 :                 || ci2.hseq != ci3.hseq || ci4.ncand != ci1.ncand
    3652           0 :                 || ci3.hseq != ci4.hseq) {
    3653           0 :                 msg = createException(MAL, "batstr.substritute",
    3654             :                                                           ILLEGAL_ARGUMENT
    3655             :                                                           " Requires bats of identical size");
    3656           0 :                 goto bailout;
    3657             :         }
    3658           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3659           0 :                 msg = createException(MAL, "batstr.substritute",
    3660             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3661           0 :                 goto bailout;
    3662             :         }
    3663             : 
    3664           0 :         (void) cntxt;
    3665           0 :         (void) mb;
    3666           0 :         off1 = arg1->hseqbase;
    3667           0 :         off2 = arg2->hseqbase;
    3668           0 :         off3 = arg3->hseqbase;
    3669           0 :         off4 = arg4->hseqbase;
    3670           0 :         arg1i = bat_iterator(arg1);
    3671           0 :         arg2i = bat_iterator(arg2);
    3672           0 :         arg3i = bat_iterator(arg3);
    3673           0 :         bi = bat_iterator(arg4);
    3674           0 :         arg4i = bi.base;
    3675           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense
    3676           0 :                 && ci4.tpe == cand_dense) {
    3677           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3678           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3679           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    3680           0 :                                 p3 = (canditer_next_dense(&ci3) - off3),
    3681           0 :                                 p4 = (canditer_next_dense(&ci4) - off4);
    3682           0 :                         const char *x = BUNtvar(arg1i, p1);
    3683           0 :                         const char *y = BUNtvar(arg2i, p2);
    3684           0 :                         const char *z = BUNtvar(arg3i, p3);
    3685           0 :                         w = arg4i[p4];
    3686             : 
    3687           0 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3688           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3689           0 :                                         msg = createException(MAL, "batstr.substritute",
    3690             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3691           0 :                                         goto bailout1;
    3692             :                                 }
    3693             :                                 nils = true;
    3694             :                         } else {
    3695           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3696           0 :                                         goto bailout1;
    3697           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3698           0 :                                         msg = createException(MAL, "batstr.substritute",
    3699             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3700           0 :                                         goto bailout1;
    3701             :                                 }
    3702             :                         }
    3703             :                 }
    3704             :         } else {
    3705           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3706           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3707           0 :                                 p2 = (canditer_next(&ci2) - off2),
    3708           0 :                                 p3 = (canditer_next(&ci3) - off3),
    3709           0 :                                 p4 = (canditer_next(&ci4) - off4);
    3710           0 :                         const char *x = BUNtvar(arg1i, p1);
    3711           0 :                         const char *y = BUNtvar(arg2i, p2);
    3712           0 :                         const char *z = BUNtvar(arg3i, p3);
    3713           0 :                         w = arg4i[p4];
    3714             : 
    3715           0 :                         if (strNil(x) || strNil(y) || strNil(z) || is_bit_nil(w)) {
    3716           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3717           0 :                                         msg = createException(MAL, "batstr.substritute",
    3718             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3719           0 :                                         goto bailout1;
    3720             :                                 }
    3721             :                                 nils = true;
    3722             :                         } else {
    3723           0 :                                 if ((msg = str_substitute(&buf, &buflen, x, y, z, w)) != MAL_SUCCEED)
    3724           0 :                                         goto bailout1;
    3725           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3726           0 :                                         msg = createException(MAL, "batstr.substritute",
    3727             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3728           0 :                                         goto bailout1;
    3729             :                                 }
    3730             :                         }
    3731             :                 }
    3732             :         }
    3733           0 :   bailout1:
    3734           0 :         bat_iterator_end(&bi);
    3735           0 :         bat_iterator_end(&arg1i);
    3736           0 :         bat_iterator_end(&arg2i);
    3737           0 :         bat_iterator_end(&arg3i);
    3738           0 :   bailout:
    3739           0 :         GDKfree(buf);
    3740           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3741           0 :         unfix_inputs(8, arg1, arg1, arg2, arg2s, arg3, arg3s, arg4, arg4s);
    3742           0 :         return msg;
    3743             : }
    3744             : 
    3745             : static str
    3746           3 : STRbatsplitpartcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    3747             : {
    3748           3 :         BATiter bi;
    3749           3 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    3750           3 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3751           3 :         int z = *getArgReference_int(stk, pci, 3);
    3752           3 :         const char *y = *getArgReference_str(stk, pci, 2);
    3753           3 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3754           3 :         bool nils = false;
    3755           3 :         struct canditer ci1 = { 0 };
    3756           3 :         oid off1;
    3757           3 :         bat *res = getArgReference_bat(stk, pci, 0),
    3758           3 :                 bid = *getArgReference_bat(stk, pci, 1),
    3759           3 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    3760             : 
    3761           3 :         (void) cntxt;
    3762           3 :         (void) mb;
    3763           3 :         if (!buf) {
    3764           0 :                 msg = createException(MAL, "batstr.splitpart",
    3765             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3766           0 :                 goto bailout;
    3767             :         }
    3768           3 :         if (!(b = BATdescriptor(bid))) {
    3769           0 :                 msg = createException(MAL, "batstr.splitpart",
    3770             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3771           0 :                 goto bailout;
    3772             :         }
    3773           3 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    3774           0 :                 msg = createException(MAL, "batstr.splitpart",
    3775             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3776           0 :                 goto bailout;
    3777             :         }
    3778           3 :         canditer_init(&ci1, b, bs);
    3779           3 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3780           0 :                 msg = createException(MAL, "batstr.splitpart",
    3781             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3782           0 :                 goto bailout;
    3783             :         }
    3784             : 
    3785           3 :         off1 = b->hseqbase;
    3786           3 :         bi = bat_iterator(b);
    3787           3 :         if (ci1.tpe == cand_dense) {
    3788         128 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3789         125 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    3790         125 :                         const char *x = BUNtvar(bi, p1);
    3791             : 
    3792         375 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3793           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3794           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3795             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3796           0 :                                         goto bailout1;
    3797             :                                 }
    3798             :                                 nils = true;
    3799             :                         } else {
    3800         125 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3801           0 :                                         goto bailout1;
    3802         125 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3803           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3804             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3805           0 :                                         goto bailout1;
    3806             :                                 }
    3807             :                         }
    3808             :                 }
    3809             :         } else {
    3810           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3811           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    3812           0 :                         const char *x = BUNtvar(bi, p1);
    3813             : 
    3814           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3815           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3816           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3817             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3818           0 :                                         goto bailout1;
    3819             :                                 }
    3820             :                                 nils = true;
    3821             :                         } else {
    3822           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3823           0 :                                         goto bailout1;
    3824           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3825           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3826             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3827           0 :                                         goto bailout1;
    3828             :                                 }
    3829             :                         }
    3830             :                 }
    3831             :         }
    3832           0 :   bailout1:
    3833           3 :         bat_iterator_end(&bi);
    3834           3 :   bailout:
    3835           3 :         GDKfree(buf);
    3836           3 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3837           3 :         unfix_inputs(2, b, bs);
    3838           3 :         return msg;
    3839             : }
    3840             : 
    3841             : static str
    3842           0 : STRbatsplitpart_needlecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3843             :                                                   InstrPtr pci)
    3844             : {
    3845           0 :         BATiter bi, fi;
    3846           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *f = NULL, *fs = NULL;
    3847           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3848           0 :         int *restrict field, z;
    3849           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    3850           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3851           0 :         bool nils = false;
    3852           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3853           0 :         oid off1, off2;
    3854           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3855           0 :                 bid = *getArgReference_bat(stk, pci, 1),
    3856           0 :                 fid = *getArgReference_bat(stk, pci, 3),
    3857           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    3858           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    3859             : 
    3860           0 :         if (!buf) {
    3861           0 :                 msg = createException(MAL, "batstr.splitpart",
    3862             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3863           0 :                 goto bailout;
    3864             :         }
    3865           0 :         if (!(b = BATdescriptor(bid)) || !(f = BATdescriptor(fid))) {
    3866           0 :                 msg = createException(MAL, "batstr.splitpart",
    3867             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3868           0 :                 goto bailout;
    3869             :         }
    3870           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    3871           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(fs = BATdescriptor(*sid2)))) {
    3872           0 :                 msg = createException(MAL, "batstr.splitpart",
    3873             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3874           0 :                 goto bailout;
    3875             :         }
    3876           0 :         canditer_init(&ci1, b, bs);
    3877           0 :         canditer_init(&ci2, f, fs);
    3878           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3879           0 :                 msg = createException(MAL, "batstr.splitpart",
    3880             :                                                           ILLEGAL_ARGUMENT
    3881             :                                                           " Requires bats of identical size");
    3882           0 :                 goto bailout;
    3883             :         }
    3884           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    3885           0 :                 msg = createException(MAL, "batstr.splitpart",
    3886             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3887           0 :                 goto bailout;
    3888             :         }
    3889             : 
    3890           0 :         (void) cntxt;
    3891           0 :         (void) mb;
    3892           0 :         off1 = b->hseqbase;
    3893           0 :         off2 = f->hseqbase;
    3894           0 :         bi = bat_iterator(b);
    3895           0 :         fi = bat_iterator(f);
    3896           0 :         field = fi.base;
    3897           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    3898           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3899           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    3900           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    3901           0 :                         const char *x = BUNtvar(bi, p1);
    3902           0 :                         z = field[p2];
    3903             : 
    3904           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3905           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3906           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3907             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3908           0 :                                         goto bailout1;
    3909             :                                 }
    3910             :                                 nils = true;
    3911             :                         } else {
    3912           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3913           0 :                                         goto bailout1;
    3914           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3915           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3916             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3917           0 :                                         goto bailout1;
    3918             :                                 }
    3919             :                         }
    3920             :                 }
    3921             :         } else {
    3922           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    3923           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    3924           0 :                                 p2 = (canditer_next(&ci2) - off2);
    3925           0 :                         const char *x = BUNtvar(bi, p1);
    3926           0 :                         z = field[p2];
    3927             : 
    3928           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    3929           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    3930           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3931             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3932           0 :                                         goto bailout1;
    3933             :                                 }
    3934             :                                 nils = true;
    3935             :                         } else {
    3936           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    3937           0 :                                         goto bailout1;
    3938           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    3939           0 :                                         msg = createException(MAL, "batstr.splitpart",
    3940             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3941           0 :                                         goto bailout1;
    3942             :                                 }
    3943             :                         }
    3944             :                 }
    3945             :         }
    3946           0 :   bailout1:
    3947           0 :         bat_iterator_end(&fi);
    3948           0 :         bat_iterator_end(&bi);
    3949           0 :   bailout:
    3950           0 :         GDKfree(buf);
    3951           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    3952           0 :         unfix_inputs(4, b, bs, f, fs);
    3953           0 :         return msg;
    3954             : }
    3955             : 
    3956             : static str
    3957           0 : STRbatsplitpart_fieldcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    3958             :                                                  InstrPtr pci)
    3959             : {
    3960           0 :         BATiter bi, ni;
    3961           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *n = NULL, *ns = NULL;
    3962           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    3963           0 :         int z = *getArgReference_int(stk, pci, 3);
    3964           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    3965           0 :         bool nils = false;
    3966           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    3967           0 :         oid off1, off2;
    3968           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    3969           0 :                 bid = *getArgReference_bat(stk, pci, 1),
    3970           0 :                 nid = *getArgReference_bat(stk, pci, 2),
    3971           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    3972           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    3973             : 
    3974           0 :         (void) cntxt;
    3975           0 :         (void) mb;
    3976           0 :         if (!buf) {
    3977           0 :                 msg = createException(MAL, "batstr.splitpart",
    3978             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    3979           0 :                 goto bailout;
    3980             :         }
    3981           0 :         if (!(b = BATdescriptor(bid)) || !(n = BATdescriptor(nid))) {
    3982           0 :                 msg = createException(MAL, "batstr.splitpart",
    3983             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3984           0 :                 goto bailout;
    3985             :         }
    3986           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    3987           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(ns = BATdescriptor(*sid2)))) {
    3988           0 :                 msg = createException(MAL, "batstr.splitpart",
    3989             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    3990           0 :                 goto bailout;
    3991             :         }
    3992           0 :         canditer_init(&ci1, b, bs);
    3993           0 :         canditer_init(&ci2, n, ns);
    3994           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    3995           0 :                 msg = createException(MAL, "batstr.splitpart",
    3996             :                                                           ILLEGAL_ARGUMENT
    3997             :                                                           " Requires bats of identical size");
    3998           0 :                 goto bailout;
    3999             :         }
    4000           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4001           0 :                 msg = createException(MAL, "batstr.splitpart",
    4002             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4003           0 :                 goto bailout;
    4004             :         }
    4005             : 
    4006           0 :         off1 = b->hseqbase;
    4007           0 :         off2 = n->hseqbase;
    4008           0 :         bi = bat_iterator(b);
    4009           0 :         ni = bat_iterator(n);
    4010           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    4011           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4012           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4013           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    4014           0 :                         const char *x = BUNtvar(bi, p1);
    4015           0 :                         const char *y = BUNtvar(ni, p2);
    4016             : 
    4017           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4018           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4019           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4020             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4021           0 :                                         goto bailout1;
    4022             :                                 }
    4023             :                                 nils = true;
    4024             :                         } else {
    4025           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4026           0 :                                         goto bailout1;
    4027           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4028           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4029             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4030           0 :                                         goto bailout1;
    4031             :                                 }
    4032             :                         }
    4033             :                 }
    4034             :         } else {
    4035           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4036           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4037           0 :                                 p2 = (canditer_next(&ci2) - off2);
    4038           0 :                         const char *x = BUNtvar(bi, p1);
    4039           0 :                         const char *y = BUNtvar(ni, p2);
    4040             : 
    4041           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4042           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4043           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4044             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4045           0 :                                         goto bailout1;
    4046             :                                 }
    4047             :                                 nils = true;
    4048             :                         } else {
    4049           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4050           0 :                                         goto bailout1;
    4051           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4052           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4053             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4054           0 :                                         goto bailout1;
    4055             :                                 }
    4056             :                         }
    4057             :                 }
    4058             :         }
    4059           0 :   bailout1:
    4060           0 :         bat_iterator_end(&bi);
    4061           0 :         bat_iterator_end(&ni);
    4062           0 :   bailout:
    4063           0 :         GDKfree(buf);
    4064           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4065           0 :         unfix_inputs(4, b, bs, n, ns);
    4066           0 :         return msg;
    4067             : }
    4068             : 
    4069             : static str
    4070           0 : STRbatsplitpart(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4071             : {
    4072           0 :         BATiter arg1i, arg2i;
    4073           0 :         BAT *bn = NULL, *arg1 = NULL, *arg1s = NULL, *arg2 = NULL,
    4074           0 :                 *arg2s = NULL, *arg3 = NULL, *arg3s = NULL;
    4075           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4076           0 :         int *restrict arg3i, z;
    4077           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4078           0 :         bool nils = false;
    4079           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    4080           0 :         oid off1, off2, off3;
    4081           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    4082           0 :                 l = *getArgReference_bat(stk, pci, 1),
    4083           0 :                 r = *getArgReference_bat(stk, pci, 2),
    4084           0 :                 t = *getArgReference_bat(stk, pci, 3),
    4085           0 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    4086           0 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    4087           0 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    4088           0 :         BATiter bi;
    4089             : 
    4090           0 :         (void) cntxt;
    4091           0 :         (void) mb;
    4092           0 :         if (!buf) {
    4093           0 :                 msg = createException(MAL, "batstr.splitpart",
    4094             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4095           0 :                 goto bailout;
    4096             :         }
    4097           0 :         if (!(arg1 = BATdescriptor(l)) || !(arg2 = BATdescriptor(r))
    4098           0 :                 || !(arg3 = BATdescriptor(t))) {
    4099           0 :                 msg = createException(MAL, "batstr.splitpart",
    4100             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4101           0 :                 goto bailout;
    4102             :         }
    4103           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(arg1s = BATdescriptor(*sid1))) ||
    4104           0 :                 (sid2 && !is_bat_nil(*sid2) && !(arg2s = BATdescriptor(*sid2))) ||
    4105           0 :                 (sid3 && !is_bat_nil(*sid3) && ! (arg3s = BATdescriptor(*sid3))))
    4106             :         {
    4107           0 :                 msg = createException(MAL, "batstr.splitpart",
    4108             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4109           0 :                 goto bailout;
    4110             :         }
    4111           0 :         canditer_init(&ci1, arg1, arg1s);
    4112           0 :         canditer_init(&ci2, arg2, arg2s);
    4113           0 :         canditer_init(&ci3, arg3, arg3s);
    4114           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    4115           0 :                 || ci2.hseq != ci3.hseq) {
    4116           0 :                 msg = createException(MAL, "batstr.splitpart",
    4117             :                                                           ILLEGAL_ARGUMENT
    4118             :                                                           " Requires bats of identical size");
    4119           0 :                 goto bailout;
    4120             :         }
    4121           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4122           0 :                 msg = createException(MAL, "batstr.splitpart",
    4123             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4124           0 :                 goto bailout;
    4125             :         }
    4126             : 
    4127           0 :         off1 = arg1->hseqbase;
    4128           0 :         off2 = arg2->hseqbase;
    4129           0 :         off3 = arg3->hseqbase;
    4130           0 :         arg1i = bat_iterator(arg1);
    4131           0 :         arg2i = bat_iterator(arg2);
    4132           0 :         bi = bat_iterator(arg3);
    4133           0 :         arg3i = bi.base;
    4134           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    4135           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4136           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    4137           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    4138           0 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    4139           0 :                         const char *x = BUNtvar(arg1i, p1);
    4140           0 :                         const char *y = BUNtvar(arg2i, p2);
    4141           0 :                         z = arg3i[p3];
    4142             : 
    4143           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4144           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4145           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4146             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4147           0 :                                         goto bailout1;
    4148             :                                 }
    4149             :                                 nils = true;
    4150             :                         } else {
    4151           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4152           0 :                                         goto bailout1;
    4153           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4154           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4155             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4156           0 :                                         goto bailout1;
    4157             :                                 }
    4158             :                         }
    4159             :                 }
    4160             :         } else {
    4161           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4162           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    4163           0 :                                 p2 = (canditer_next(&ci2) - off2),
    4164           0 :                                 p3 = (canditer_next(&ci3) - off3);
    4165           0 :                         const char *x = BUNtvar(arg1i, p1);
    4166           0 :                         const char *y = BUNtvar(arg2i, p2);
    4167           0 :                         z = arg3i[p3];
    4168             : 
    4169           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    4170           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4171           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4172             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4173           0 :                                         goto bailout1;
    4174             :                                 }
    4175             :                                 nils = true;
    4176             :                         } else {
    4177           0 :                                 if ((msg = str_splitpart(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4178           0 :                                         goto bailout1;
    4179           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4180           0 :                                         msg = createException(MAL, "batstr.splitpart",
    4181             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4182           0 :                                         goto bailout1;
    4183             :                                 }
    4184             :                         }
    4185             :                 }
    4186             :         }
    4187           0 :   bailout1:
    4188           0 :         bat_iterator_end(&bi);
    4189           0 :         bat_iterator_end(&arg1i);
    4190           0 :         bat_iterator_end(&arg2i);
    4191           0 :   bailout:
    4192           0 :         GDKfree(buf);
    4193           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4194           0 :         unfix_inputs(6, arg1, arg1s, arg2, arg2s, arg3, arg3s);
    4195           0 :         return msg;
    4196             : }
    4197             : 
    4198             : static str
    4199         471 : STRbatReplacecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4200             : {
    4201         471 :         bit rep = TRUE;
    4202             : 
    4203         471 :         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         121 : STRbatsubstring_2nd_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4575             :                                                         InstrPtr pci)
    4576             : {
    4577         121 :         BATiter bi;
    4578         121 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4579         121 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4580         121 :         int y = *getArgReference_int(stk, pci, 2),
    4581         121 :                 z = *getArgReference_int(stk, pci, 3);
    4582         121 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4583         122 :         bool nils = false;
    4584         122 :         struct canditer ci1 = { 0 };
    4585         122 :         oid off1;
    4586         122 :         bat *res = getArgReference_bat(stk, pci, 0),
    4587         122 :                 bid = *getArgReference_bat(stk, pci, 1),
    4588         122 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4589             : 
    4590         122 :         (void) cntxt;
    4591         122 :         (void) mb;
    4592         122 :         if (!buf) {
    4593           0 :                 msg = createException(MAL, "batstr.substring",
    4594             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4595           0 :                 goto bailout;
    4596             :         }
    4597         122 :         if (!(b = BATdescriptor(bid))) {
    4598           0 :                 msg = createException(MAL, "batstr.substring",
    4599             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4600           0 :                 goto bailout;
    4601             :         }
    4602         123 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4603           0 :                 msg = createException(MAL, "batstr.substring",
    4604             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4605           0 :                 goto bailout;
    4606             :         }
    4607         123 :         canditer_init(&ci1, b, bs);
    4608         123 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4609           0 :                 msg = createException(MAL, "batstr.substring",
    4610             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4611           0 :                 goto bailout;
    4612             :         }
    4613             : 
    4614         123 :         off1 = b->hseqbase;
    4615         123 :         bi = bat_iterator(b);
    4616         123 :         if (ci1.tpe == cand_dense) {
    4617     3878697 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4618     3878575 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4619     3878575 :                         const char *x = BUNtvar(bi, p1);
    4620             : 
    4621     7657699 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4622      102004 :                                 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     3776571 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4630           0 :                                         goto bailout1;
    4631     3737565 :                                 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           1 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4640           1 :                         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         122 :         bat_iterator_end(&bi);
    4663         123 :   bailout:
    4664         123 :         GDKfree(buf);
    4665         123 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4666         122 :         unfix_inputs(2, b, bs);
    4667         123 :         return msg;
    4668             : }
    4669             : 
    4670             : static str
    4671           1 : STRbatsubstring_1st_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4672             :                                                         InstrPtr pci)
    4673             : {
    4674           1 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4675           1 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4676           1 :         int y = *getArgReference_int(stk, pci, 2), z, *restrict input;
    4677           1 :         const char *x = *getArgReference_str(stk, pci, 1);
    4678           1 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4679           1 :         bool nils = false;
    4680           1 :         struct canditer ci1 = { 0 };
    4681           1 :         oid off1;
    4682           1 :         bat *res = getArgReference_bat(stk, pci, 0),
    4683           1 :                 bid = *getArgReference_bat(stk, pci, 3),
    4684           1 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4685           1 :         BATiter bi;
    4686             : 
    4687           1 :         (void) cntxt;
    4688           1 :         (void) mb;
    4689           1 :         if (!buf) {
    4690           0 :                 msg = createException(MAL, "batstr.substring",
    4691             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4692           0 :                 goto bailout;
    4693             :         }
    4694           1 :         if (!(b = BATdescriptor(bid))) {
    4695           0 :                 msg = createException(MAL, "batstr.substring",
    4696             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4697           0 :                 goto bailout;
    4698             :         }
    4699           1 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4700           0 :                 msg = createException(MAL, "batstr.substring",
    4701             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4702           0 :                 goto bailout;
    4703             :         }
    4704           1 :         canditer_init(&ci1, b, bs);
    4705           1 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4706           0 :                 msg = createException(MAL, "batstr.substring",
    4707             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4708           0 :                 goto bailout;
    4709             :         }
    4710             : 
    4711           1 :         off1 = b->hseqbase;
    4712           1 :         bi = bat_iterator(b);
    4713           1 :         input = bi.base;
    4714           1 :         if (ci1.tpe == cand_dense) {
    4715           2 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4716           1 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4717           1 :                         z = input[p1];
    4718             : 
    4719           2 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4720           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4721           0 :                                         msg = createException(MAL, "batstr.substring",
    4722             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4723           0 :                                         goto bailout1;
    4724             :                                 }
    4725             :                                 nils = true;
    4726             :                         } else {
    4727           1 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4728           0 :                                         goto bailout1;
    4729           1 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4730           0 :                                         msg = createException(MAL, "batstr.substring",
    4731             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4732           0 :                                         goto bailout1;
    4733             :                                 }
    4734             :                         }
    4735             :                 }
    4736             :         } else {
    4737           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4738           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4739           0 :                         z = input[p1];
    4740             : 
    4741           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4742           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4743           0 :                                         msg = createException(MAL, "batstr.substring",
    4744             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4745           0 :                                         goto bailout1;
    4746             :                                 }
    4747             :                                 nils = true;
    4748             :                         } else {
    4749           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4750           0 :                                         goto bailout1;
    4751           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4752           0 :                                         msg = createException(MAL, "batstr.substring",
    4753             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4754           0 :                                         goto bailout1;
    4755             :                                 }
    4756             :                         }
    4757             :                 }
    4758             :         }
    4759           0 :   bailout1:
    4760           1 :         bat_iterator_end(&bi);
    4761           1 :   bailout:
    4762           1 :         GDKfree(buf);
    4763           1 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4764           1 :         unfix_inputs(2, b, bs);
    4765           1 :         return msg;
    4766             : }
    4767             : 
    4768             : static str
    4769           5 : STRbatsubstring_1st_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    4770             :                                                         InstrPtr pci)
    4771             : {
    4772           5 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    4773           5 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4774           5 :         int y, z = *getArgReference_int(stk, pci, 3), *restrict input;
    4775           5 :         const char *x = *getArgReference_str(stk, pci, 1);
    4776           5 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4777           5 :         bool nils = false;
    4778           5 :         struct canditer ci1 = { 0 };
    4779           5 :         oid off1;
    4780           5 :         bat *res = getArgReference_bat(stk, pci, 0),
    4781           5 :                 bid = *getArgReference_bat(stk, pci, 2),
    4782           5 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    4783           5 :         BATiter bi;
    4784             : 
    4785           5 :         (void) cntxt;
    4786           5 :         (void) mb;
    4787           5 :         if (!buf) {
    4788           0 :                 msg = createException(MAL, "batstr.substring",
    4789             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4790           0 :                 goto bailout;
    4791             :         }
    4792           5 :         if (!(b = BATdescriptor(bid))) {
    4793           0 :                 msg = createException(MAL, "batstr.substring",
    4794             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4795           0 :                 goto bailout;
    4796             :         }
    4797           5 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    4798           0 :                 msg = createException(MAL, "batstr.substring",
    4799             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4800           0 :                 goto bailout;
    4801             :         }
    4802           5 :         canditer_init(&ci1, b, bs);
    4803           5 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    4804           0 :                 msg = createException(MAL, "batstr.substring",
    4805             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4806           0 :                 goto bailout;
    4807             :         }
    4808             : 
    4809           5 :         off1 = b->hseqbase;
    4810           5 :         bi = bat_iterator(b);
    4811           5 :         input = bi.base;
    4812           5 :         if (ci1.tpe == cand_dense) {
    4813           9 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4814           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    4815           4 :                         y = input[p1];
    4816             : 
    4817           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4818           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4819           0 :                                         msg = createException(MAL, "batstr.substring",
    4820             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4821           0 :                                         goto bailout1;
    4822             :                                 }
    4823             :                                 nils = true;
    4824             :                         } else {
    4825           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4826           0 :                                         goto bailout1;
    4827           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4828           0 :                                         msg = createException(MAL, "batstr.substring",
    4829             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4830           0 :                                         goto bailout1;
    4831             :                                 }
    4832             :                         }
    4833             :                 }
    4834             :         } else {
    4835           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    4836           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    4837           0 :                         y = input[p1];
    4838             : 
    4839           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    4840           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    4841           0 :                                         msg = createException(MAL, "batstr.substring",
    4842             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4843           0 :                                         goto bailout1;
    4844             :                                 }
    4845             :                                 nils = true;
    4846             :                         } else {
    4847           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    4848           0 :                                         goto bailout1;
    4849           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    4850           0 :                                         msg = createException(MAL, "batstr.substring",
    4851             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4852           0 :                                         goto bailout1;
    4853             :                                 }
    4854             :                         }
    4855             :                 }
    4856             :         }
    4857           0 :   bailout1:
    4858           5 :         bat_iterator_end(&bi);
    4859           5 :   bailout:
    4860           5 :         GDKfree(buf);
    4861           5 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    4862           5 :         unfix_inputs(2, b, bs);
    4863           5 :         return msg;
    4864             : }
    4865             : 
    4866             : static str
    4867           4 : STRbatsubstring_1st_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4868             : {
    4869           4 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4870           4 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4871           4 :         int y, z, *vals1, *vals2;
    4872           4 :         const char *x = *getArgReference_str(stk, pci, 1);
    4873           4 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4874           4 :         bool nils = false;
    4875           4 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4876           4 :         oid off1, off2;
    4877           4 :         bat *res = getArgReference_bat(stk, pci, 0),
    4878           4 :                 bid = *getArgReference_bat(stk, pci, 2),
    4879           4 :                 l = *getArgReference_bat(stk, pci, 3),
    4880           4 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4881           4 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4882           4 :         BATiter bi;
    4883           4 :         BATiter lbi;
    4884             : 
    4885           4 :         (void) cntxt;
    4886           4 :         (void) mb;
    4887           4 :         if (!buf) {
    4888           0 :                 msg = createException(MAL, "batstr.substring",
    4889             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    4890           0 :                 goto bailout;
    4891             :         }
    4892           4 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    4893           0 :                 msg = createException(MAL, "batstr.substring",
    4894             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4895           0 :                 goto bailout;
    4896             :         }
    4897           4 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    4898           4 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    4899           0 :                 msg = createException(MAL, "batstr.substring",
    4900             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    4901           0 :                 goto bailout;
    4902             :         }
    4903           4 :         canditer_init(&ci1, b, bs);
    4904           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           7 :                                 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          32 : STRbatsubstring_2nd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    4984             : {
    4985          32 :         BATiter bi;
    4986          32 :         BATiter lbi;
    4987          32 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    4988          32 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    4989          32 :         int y = *getArgReference_int(stk, pci, 2), *len, z;
    4990          32 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    4991          32 :         bool nils = false;
    4992          32 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    4993          32 :         oid off1, off2;
    4994          32 :         bat *res = getArgReference_bat(stk, pci, 0),
    4995          32 :                 bid = *getArgReference_bat(stk, pci, 1),
    4996          32 :                 l = *getArgReference_bat(stk, pci, 3),
    4997          32 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    4998          32 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    4999             : 
    5000          32 :         (void) cntxt;
    5001          32 :         (void) mb;
    5002          32 :         if (!buf) {
    5003           0 :                 msg = createException(MAL, "batstr.substring",
    5004             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5005           0 :                 goto bailout;
    5006             :         }
    5007          32 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    5008           0 :                 msg = createException(MAL, "batstr.substring",
    5009             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5010           0 :                 goto bailout;
    5011             :         }
    5012          32 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5013          32 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    5014           0 :                 msg = createException(MAL, "batstr.substring",
    5015             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5016           0 :                 goto bailout;
    5017             :         }
    5018          32 :         canditer_init(&ci1, b, bs);
    5019          32 :         canditer_init(&ci2, lb, lbs);
    5020          32 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5021           0 :                 msg = createException(MAL, "batstr.substring",
    5022             :                                                           ILLEGAL_ARGUMENT
    5023             :                                                           " Requires bats of identical size");
    5024           0 :                 goto bailout;
    5025             :         }
    5026          32 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5027           0 :                 msg = createException(MAL, "batstr.substring",
    5028             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5029           0 :                 goto bailout;
    5030             :         }
    5031             : 
    5032          32 :         off1 = b->hseqbase;
    5033          32 :         off2 = lb->hseqbase;
    5034          32 :         bi = bat_iterator(b);
    5035          32 :         lbi = bat_iterator(lb);
    5036          32 :         len = lbi.base;
    5037          32 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5038          36 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5039           4 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5040           4 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5041           4 :                         const char *x = BUNtvar(bi, p1);
    5042           4 :                         z = len[p2];
    5043             : 
    5044           8 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5045           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5046           0 :                                         msg = createException(MAL, "batstr.substring",
    5047             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5048           0 :                                         goto bailout1;
    5049             :                                 }
    5050             :                                 nils = true;
    5051             :                         } else {
    5052           4 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5053           0 :                                         goto bailout1;
    5054           4 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5055           0 :                                         msg = createException(MAL, "batstr.substring",
    5056             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5057           0 :                                         goto bailout1;
    5058             :                                 }
    5059             :                         }
    5060             :                 }
    5061             :         } else {
    5062           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5063           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5064           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5065           0 :                         const char *x = BUNtvar(bi, p1);
    5066           0 :                         z = len[p2];
    5067             : 
    5068           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5069           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5070           0 :                                         msg = createException(MAL, "batstr.substring",
    5071             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5072           0 :                                         goto bailout1;
    5073             :                                 }
    5074             :                                 nils = true;
    5075             :                         } else {
    5076           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5077           0 :                                         goto bailout1;
    5078           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5079           0 :                                         msg = createException(MAL, "batstr.substring",
    5080             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5081           0 :                                         goto bailout1;
    5082             :                                 }
    5083             :                         }
    5084             :                 }
    5085             :         }
    5086           0 :   bailout1:
    5087          32 :         bat_iterator_end(&lbi);
    5088          32 :         bat_iterator_end(&bi);
    5089          32 :   bailout:
    5090          32 :         GDKfree(buf);
    5091          32 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5092          32 :         unfix_inputs(4, b, bs, lb, lbs);
    5093          32 :         return msg;
    5094             : }
    5095             : 
    5096             : static str
    5097           0 : STRbatsubstring_3rd_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5098             : {
    5099           0 :         BATiter bi, lbi;
    5100           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL, *lb = NULL, *lbs = NULL;
    5101           0 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5102           0 :         int *start, y, z = *getArgReference_int(stk, pci, 3);
    5103           0 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5104           0 :         bool nils = false;
    5105           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5106           0 :         oid off1, off2;
    5107           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5108           0 :                 bid = *getArgReference_bat(stk, pci, 1),
    5109           0 :                 l = *getArgReference_bat(stk, pci, 2),
    5110           0 :                 *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 4) : NULL,
    5111           0 :                 *sid2 = pci->argc == 6 ? getArgReference_bat(stk, pci, 5) : NULL;
    5112             : 
    5113           0 :         (void) cntxt;
    5114           0 :         (void) mb;
    5115           0 :         if (!buf) {
    5116           0 :                 msg = createException(MAL, "batstr.substring",
    5117             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5118           0 :                 goto bailout;
    5119             :         }
    5120           0 :         if (!(b = BATdescriptor(bid)) || !(lb = BATdescriptor(l))) {
    5121           0 :                 msg = createException(MAL, "batstr.substring",
    5122             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5123           0 :                 goto bailout;
    5124             :         }
    5125           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1)))
    5126           0 :                 || (sid2 && !is_bat_nil(*sid2) && !(lbs = BATdescriptor(*sid2)))) {
    5127           0 :                 msg = createException(MAL, "batstr.substring",
    5128             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5129           0 :                 goto bailout;
    5130             :         }
    5131           0 :         canditer_init(&ci1, b, bs);
    5132           0 :         canditer_init(&ci2, lb, lbs);
    5133           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5134           0 :                 msg = createException(MAL, "batstr.substring",
    5135             :                                                           ILLEGAL_ARGUMENT
    5136             :                                                           " Requires bats of identical size");
    5137           0 :                 goto bailout;
    5138             :         }
    5139           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5140           0 :                 msg = createException(MAL, "batstr.substring",
    5141             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5142           0 :                 goto bailout;
    5143             :         }
    5144             : 
    5145           0 :         off1 = b->hseqbase;
    5146           0 :         off2 = lb->hseqbase;
    5147           0 :         bi = bat_iterator(b);
    5148           0 :         lbi = bat_iterator(lb);
    5149           0 :         start = lbi.base;
    5150           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5151           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5152           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5153           0 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5154           0 :                         const char *x = BUNtvar(bi, p1);
    5155           0 :                         y = start[p2];
    5156             : 
    5157           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5158           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5159           0 :                                         msg = createException(MAL, "batstr.substring",
    5160             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5161           0 :                                         goto bailout1;
    5162             :                                 }
    5163             :                                 nils = true;
    5164             :                         } else {
    5165           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5166           0 :                                         goto bailout1;
    5167           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5168           0 :                                         msg = createException(MAL, "batstr.substring",
    5169             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5170           0 :                                         goto bailout1;
    5171             :                                 }
    5172             :                         }
    5173             :                 }
    5174             :         } else {
    5175           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5176           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5177           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5178           0 :                         const char *x = BUNtvar(bi, p1);
    5179           0 :                         y = start[p2];
    5180             : 
    5181           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5182           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5183           0 :                                         msg = createException(MAL, "batstr.substring",
    5184             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5185           0 :                                         goto bailout1;
    5186             :                                 }
    5187             :                                 nils = true;
    5188             :                         } else {
    5189           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5190           0 :                                         goto bailout1;
    5191           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5192           0 :                                         msg = createException(MAL, "batstr.substring",
    5193             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5194           0 :                                         goto bailout1;
    5195             :                                 }
    5196             :                         }
    5197             :                 }
    5198             :         }
    5199           0 :   bailout1:
    5200           0 :         bat_iterator_end(&lbi);
    5201           0 :         bat_iterator_end(&bi);
    5202           0 :   bailout:
    5203           0 :         GDKfree(buf);
    5204           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5205           0 :         unfix_inputs(4, b, bs, lb, lbs);
    5206           0 :         return msg;
    5207             : }
    5208             : 
    5209             : static str
    5210          28 : STRbatsubstring(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5211             : {
    5212          28 :         BATiter lefti, starti, lengthi;
    5213          28 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *start = NULL,
    5214          28 :                 *ss = NULL, *length = NULL, *lens = NULL;
    5215          28 :         size_t buflen = INITIAL_STR_BUFFER_LENGTH;
    5216          28 :         int *svals, *lvals, y, z;
    5217          28 :         str buf = GDKmalloc(buflen), msg = MAL_SUCCEED;
    5218          28 :         bool nils = false;
    5219          28 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5220          28 :         oid off1, off2, off3;
    5221          28 :         bat *res = getArgReference_bat(stk, pci, 0),
    5222          28 :                 l = *getArgReference_bat(stk, pci, 1),
    5223          28 :                 r = *getArgReference_bat(stk, pci, 2),
    5224          28 :                 t = *getArgReference_bat(stk, pci, 3),
    5225          28 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5226          28 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5227          28 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5228             : 
    5229          28 :         (void) cntxt;
    5230          28 :         (void) mb;
    5231          28 :         if (!buf) {
    5232           0 :                 msg = createException(MAL, "batstr.substring",
    5233             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5234           0 :                 goto bailout;
    5235             :         }
    5236          28 :         if (!(left = BATdescriptor(l)) || !(start = BATdescriptor(r))
    5237          28 :                 || !(length = BATdescriptor(t))) {
    5238           0 :                 msg = createException(MAL, "batstr.substring",
    5239             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5240           0 :                 goto bailout;
    5241             :         }
    5242          28 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5243          28 :                 (sid2 && !is_bat_nil(*sid2) && !(ss = BATdescriptor(*sid2))) ||
    5244           0 :                 (sid3 && !is_bat_nil(*sid3) && !(lens = BATdescriptor(*sid3)))) {
    5245           0 :                 msg = createException(MAL, "batstr.substring",
    5246             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5247           0 :                 goto bailout;
    5248             :         }
    5249          28 :         canditer_init(&ci1, left, ls);
    5250          28 :         canditer_init(&ci2, start, ss);
    5251          28 :         canditer_init(&ci3, length, lens);
    5252          28 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5253          28 :                 || ci2.hseq != ci3.hseq) {
    5254           0 :                 msg = createException(MAL, "batstr.substring",
    5255             :                                                           ILLEGAL_ARGUMENT
    5256             :                                                           " Requires bats of identical size");
    5257           0 :                 goto bailout;
    5258             :         }
    5259          28 :         if (!(bn = COLnew(ci1.hseq, TYPE_str, ci1.ncand, TRANSIENT))) {
    5260           0 :                 msg = createException(MAL, "batstr.substring",
    5261             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5262           0 :                 goto bailout;
    5263             :         }
    5264             : 
    5265          28 :         off1 = left->hseqbase;
    5266          28 :         off2 = start->hseqbase;
    5267          28 :         off3 = length->hseqbase;
    5268          28 :         lefti = bat_iterator(left);
    5269          28 :         starti = bat_iterator(start);
    5270          28 :         lengthi = bat_iterator(length);
    5271          28 :         svals = starti.base;
    5272          28 :         lvals = lengthi.base;
    5273          28 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5274        3861 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5275        3833 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5276        3833 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5277        3833 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5278        3833 :                         const char *x = BUNtvar(lefti, p1);
    5279        3833 :                         y = svals[p2];
    5280        3833 :                         z = lvals[p3];
    5281             : 
    5282        7636 :                         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        3785 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5291           0 :                                         goto bailout1;
    5292        3689 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5293           0 :                                         msg = createException(MAL, "batstr.substring",
    5294             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5295           0 :                                         goto bailout1;
    5296             :                                 }
    5297             :                         }
    5298             :                 }
    5299             :         } else {
    5300           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5301           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5302           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5303           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5304           0 :                         const char *x = BUNtvar(lefti, p1);
    5305           0 :                         y = svals[p2];
    5306           0 :                         z = lvals[p3];
    5307             : 
    5308           0 :                         if (strNil(x) || is_int_nil(y) || is_int_nil(z)) {
    5309           0 :                                 if (tfastins_nocheckVAR(bn, i, str_nil) != GDK_SUCCEED) {
    5310           0 :                                         msg = createException(MAL, "batstr.substring",
    5311             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5312           0 :                                         goto bailout1;
    5313             :                                 }
    5314             :                                 nils = true;
    5315             :                         } else {
    5316           0 :                                 if ((msg = str_sub_string(&buf, &buflen, x, y, z)) != MAL_SUCCEED)
    5317           0 :                                         goto bailout1;
    5318           0 :                                 if (tfastins_nocheckVAR(bn, i, buf) != GDK_SUCCEED) {
    5319           0 :                                         msg = createException(MAL, "batstr.substring",
    5320             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5321           0 :                                         goto bailout1;
    5322             :                                 }
    5323             :                         }
    5324             :                 }
    5325             :         }
    5326           0 :   bailout1:
    5327          28 :         bat_iterator_end(&lefti);
    5328          28 :         bat_iterator_end(&starti);
    5329          28 :         bat_iterator_end(&lengthi);
    5330          28 :   bailout:
    5331          28 :         GDKfree(buf);
    5332          28 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5333          28 :         unfix_inputs(6, left, ls, start, ss, length, lens);
    5334          28 :         return msg;
    5335             : }
    5336             : 
    5337             : static str
    5338           0 : STRbatstrLocatecst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5339             : {
    5340           0 :         BATiter bi;
    5341           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5342           0 :         int *restrict vals;
    5343           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5344           0 :         str msg = MAL_SUCCEED;
    5345           0 :         bool nils = false;
    5346           0 :         struct canditer ci1 = { 0 };
    5347           0 :         oid off1;
    5348           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5349           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5350           0 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5351             : 
    5352           0 :         (void) cntxt;
    5353           0 :         (void) mb;
    5354           0 :         if (!(b = BATdescriptor(l))) {
    5355           0 :                 msg = createException(MAL, "batstr.locate",
    5356             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5357           0 :                 goto bailout;
    5358             :         }
    5359           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5360           0 :                 msg = createException(MAL, "batstr.locate",
    5361             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5362           0 :                 goto bailout;
    5363             :         }
    5364           0 :         canditer_init(&ci1, b, bs);
    5365           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5366           0 :                 msg = createException(MAL, "batstr.locate",
    5367             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5368           0 :                 goto bailout;
    5369             :         }
    5370             : 
    5371           0 :         off1 = b->hseqbase;
    5372           0 :         bi = bat_iterator(b);
    5373           0 :         vals = Tloc(bn, 0);
    5374           0 :         if (ci1.tpe == cand_dense) {
    5375           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5376           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5377           0 :                         const char *x = BUNtvar(bi, p1);
    5378             : 
    5379           0 :                         if (strNil(x) || strNil(y)) {
    5380           0 :                                 vals[i] = int_nil;
    5381           0 :                                 nils = true;
    5382             :                         } else {
    5383           0 :                                 vals[i] = str_locate2(x, y, 1);
    5384             :                         }
    5385             :                 }
    5386             :         } else {
    5387           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5388           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5389           0 :                         const char *x = BUNtvar(bi, p1);
    5390             : 
    5391           0 :                         if (strNil(x) || strNil(y)) {
    5392           0 :                                 vals[i] = int_nil;
    5393           0 :                                 nils = true;
    5394             :                         } else {
    5395           0 :                                 vals[i] = str_locate2(x, y, 1);
    5396             :                         }
    5397             :                 }
    5398             :         }
    5399           0 :         bat_iterator_end(&bi);
    5400           0 :   bailout:
    5401           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5402           0 :         unfix_inputs(2, b, bs);
    5403           0 :         return msg;
    5404             : }
    5405             : 
    5406             : static str
    5407          52 : STRbatstrLocate_strcst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5408             : {
    5409          52 :         BATiter bi;
    5410          52 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5411          52 :         int *restrict vals;
    5412          52 :         const char *x = *getArgReference_str(stk, pci, 1);
    5413          52 :         str msg = MAL_SUCCEED;
    5414          52 :         bool nils = false;
    5415          52 :         struct canditer ci1 = { 0 };
    5416          52 :         oid off1;
    5417          52 :         bat *res = getArgReference_bat(stk, pci, 0),
    5418          52 :                 l = *getArgReference_bat(stk, pci, 2),
    5419          52 :                 *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
    5420             : 
    5421          52 :         (void) cntxt;
    5422          52 :         (void) mb;
    5423          52 :         if (!(b = BATdescriptor(l))) {
    5424           0 :                 msg = createException(MAL, "batstr.locate",
    5425             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5426           0 :                 goto bailout;
    5427             :         }
    5428          52 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5429           0 :                 msg = createException(MAL, "batstr.locate",
    5430             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5431           0 :                 goto bailout;
    5432             :         }
    5433          52 :         canditer_init(&ci1, b, bs);
    5434          52 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5435           0 :                 msg = createException(MAL, "batstr.locate",
    5436             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5437           0 :                 goto bailout;
    5438             :         }
    5439             : 
    5440          52 :         off1 = b->hseqbase;
    5441          52 :         bi = bat_iterator(b);
    5442          52 :         vals = Tloc(bn, 0);
    5443          52 :         if (ci1.tpe == cand_dense) {
    5444        3835 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5445        3783 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5446        3783 :                         const char *y = BUNtvar(bi, p1);
    5447             : 
    5448        7566 :                         if (strNil(x) || strNil(y)) {
    5449           0 :                                 vals[i] = int_nil;
    5450           0 :                                 nils = true;
    5451             :                         } else {
    5452        3783 :                                 vals[i] = str_locate2(x, y, 1);
    5453             :                         }
    5454             :                 }
    5455             :         } else {
    5456           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5457           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5458           0 :                         const char *y = BUNtvar(bi, p1);
    5459             : 
    5460           0 :                         if (strNil(x) || strNil(y)) {
    5461           0 :                                 vals[i] = int_nil;
    5462           0 :                                 nils = true;
    5463             :                         } else {
    5464           0 :                                 vals[i] = str_locate2(x, y, 1);
    5465             :                         }
    5466             :                 }
    5467             :         }
    5468          52 :         bat_iterator_end(&bi);
    5469          52 :   bailout:
    5470          52 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5471          52 :         unfix_inputs(2, b, bs);
    5472          52 :         return msg;
    5473             : }
    5474             : 
    5475             : static str
    5476           2 : STRbatstrLocate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5477             : {
    5478           2 :         BATiter lefti, righti;
    5479           2 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL, *rs = NULL;
    5480           2 :         int *restrict vals;
    5481           2 :         str msg = MAL_SUCCEED;
    5482           2 :         bool nils = false;
    5483           2 :         struct canditer ci1 = { 0 }, ci2 = { 0 };
    5484           2 :         oid off1, off2;
    5485           2 :         bat *res = getArgReference_bat(stk, pci, 0),
    5486           2 :                 l = *getArgReference_bat(stk, pci, 1),
    5487           2 :                 r = *getArgReference_bat(stk, pci, 2),
    5488           2 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
    5489           2 :                 *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5490             : 
    5491           2 :         (void) cntxt;
    5492           2 :         (void) mb;
    5493           2 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))) {
    5494           0 :                 msg = createException(MAL, "batstr.locate",
    5495             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5496           0 :                 goto bailout;
    5497             :         }
    5498           2 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5499           2 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2)))) {
    5500           0 :                 msg = createException(MAL, "batstr.locate",
    5501             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5502           0 :                 goto bailout;
    5503             :         }
    5504           2 :         canditer_init(&ci1, left, ls);
    5505           2 :         canditer_init(&ci2, right, rs);
    5506           2 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
    5507           0 :                 msg = createException(MAL, "batstr.locate",
    5508             :                                                           ILLEGAL_ARGUMENT
    5509             :                                                           " Requires bats of identical size");
    5510           0 :                 goto bailout;
    5511             :         }
    5512           2 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5513           0 :                 msg = createException(MAL, "batstr.locate",
    5514             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5515           0 :                 goto bailout;
    5516             :         }
    5517             : 
    5518           2 :         off1 = left->hseqbase;
    5519           2 :         off2 = right->hseqbase;
    5520           2 :         lefti = bat_iterator(left);
    5521           2 :         righti = bat_iterator(right);
    5522           2 :         vals = Tloc(bn, 0);
    5523           2 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
    5524          10 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5525           8 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5526           8 :                                 p2 = (canditer_next_dense(&ci2) - off2);
    5527           8 :                         const char *x = BUNtvar(lefti, p1);
    5528           8 :                         const char *y = BUNtvar(righti, p2);
    5529             : 
    5530          16 :                         if (strNil(x) || strNil(y)) {
    5531           0 :                                 vals[i] = int_nil;
    5532           0 :                                 nils = true;
    5533             :                         } else {
    5534           8 :                                 vals[i] = str_locate2(x, y, 1);
    5535             :                         }
    5536             :                 }
    5537             :         } else {
    5538           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5539           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5540           0 :                                 p2 = (canditer_next(&ci2) - off2);
    5541           0 :                         const char *x = BUNtvar(lefti, p1);
    5542           0 :                         const char *y = BUNtvar(righti, p2);
    5543             : 
    5544           0 :                         if (strNil(x) || strNil(y)) {
    5545           0 :                                 vals[i] = int_nil;
    5546           0 :                                 nils = true;
    5547             :                         } else {
    5548           0 :                                 vals[i] = str_locate2(x, y, 1);
    5549             :                         }
    5550             :                 }
    5551             :         }
    5552           2 :         bat_iterator_end(&lefti);
    5553           2 :         bat_iterator_end(&righti);
    5554           2 :   bailout:
    5555           2 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5556           2 :         unfix_inputs(4, left, ls, right, rs);
    5557           2 :         return msg;
    5558             : }
    5559             : 
    5560             : static str
    5561           0 : STRbatstrLocate3cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5562             : {
    5563           0 :         BATiter bi;
    5564           0 :         BAT *bn = NULL, *b = NULL, *bs = NULL;
    5565           0 :         int *restrict vals, z = *getArgReference_int(stk, pci, 3);
    5566           0 :         const char *y = *getArgReference_str(stk, pci, 2);
    5567           0 :         str msg = MAL_SUCCEED;
    5568           0 :         bool nils = false;
    5569           0 :         struct canditer ci1 = { 0 };
    5570           0 :         oid off1;
    5571           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5572           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5573           0 :                 *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
    5574             : 
    5575           0 :         (void) cntxt;
    5576           0 :         (void) mb;
    5577           0 :         if (!(b = BATdescriptor(l))) {
    5578           0 :                 msg = createException(MAL, "batstr.locate2",
    5579             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5580           0 :                 goto bailout;
    5581             :         }
    5582           0 :         if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
    5583           0 :                 msg = createException(MAL, "batstr.locate2",
    5584             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5585           0 :                 goto bailout;
    5586             :         }
    5587           0 :         canditer_init(&ci1, b, bs);
    5588           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5589           0 :                 msg = createException(MAL, "batstr.locate2",
    5590             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5591           0 :                 goto bailout;
    5592             :         }
    5593             : 
    5594           0 :         off1 = b->hseqbase;
    5595           0 :         bi = bat_iterator(b);
    5596           0 :         vals = Tloc(bn, 0);
    5597           0 :         if (ci1.tpe == cand_dense) {
    5598           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5599           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1);
    5600           0 :                         const char *x = BUNtvar(bi, p1);
    5601             : 
    5602           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5603           0 :                                 vals[i] = int_nil;
    5604           0 :                                 nils = true;
    5605             :                         } else {
    5606           0 :                                 vals[i] = str_locate2(x, y, z);
    5607             :                         }
    5608             :                 }
    5609             :         } else {
    5610           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5611           0 :                         oid p1 = (canditer_next(&ci1) - off1);
    5612           0 :                         const char *x = BUNtvar(bi, p1);
    5613             : 
    5614           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5615           0 :                                 vals[i] = int_nil;
    5616           0 :                                 nils = true;
    5617             :                         } else {
    5618           0 :                                 vals[i] = str_locate2(x, y, z);
    5619             :                         }
    5620             :                 }
    5621             :         }
    5622           0 :         bat_iterator_end(&bi);
    5623           0 :   bailout:
    5624           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5625           0 :         unfix_inputs(2, b, bs);
    5626           0 :         return msg;
    5627             : }
    5628             : 
    5629             : static str
    5630           0 : STRbatstrLocate3(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5631             : {
    5632           0 :         BATiter lefti, righti, starti;
    5633           0 :         BAT *bn = NULL, *left = NULL, *ls = NULL, *right = NULL,
    5634           0 :                 *rs = NULL, *start = NULL, *ss = NULL;
    5635           0 :         int *restrict vals, *restrict svals, z;
    5636           0 :         str msg = MAL_SUCCEED;
    5637           0 :         bool nils = false;
    5638           0 :         struct canditer ci1 = { 0 }, ci2 = { 0 }, ci3 = { 0 };
    5639           0 :         oid off1, off2, off3;
    5640           0 :         bat *res = getArgReference_bat(stk, pci, 0),
    5641           0 :                 l = *getArgReference_bat(stk, pci, 1),
    5642           0 :                 r = *getArgReference_bat(stk, pci, 2),
    5643           0 :                 s = *getArgReference_bat(stk, pci, 3),
    5644           0 :                 *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL,
    5645           0 :                 *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 5) : NULL,
    5646           0 :                 *sid3 = pci->argc == 7 ? getArgReference_bat(stk, pci, 6) : NULL;
    5647             : 
    5648           0 :         (void) cntxt;
    5649           0 :         (void) mb;
    5650           0 :         if (!(left = BATdescriptor(l)) || !(right = BATdescriptor(r))
    5651           0 :                 || !(start = BATdescriptor(s))) {
    5652           0 :                 msg = createException(MAL, "batstr.locate2",
    5653             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5654           0 :                 goto bailout;
    5655             :         }
    5656           0 :         if ((sid1 && !is_bat_nil(*sid1) && !(ls = BATdescriptor(*sid1))) ||
    5657           0 :                 (sid2 && !is_bat_nil(*sid2) && !(rs = BATdescriptor(*sid2))) ||
    5658           0 :                 (sid3 && !is_bat_nil(*sid3) && !(ss = BATdescriptor(*sid3)))) {
    5659           0 :                 msg = createException(MAL, "batstr.locate2",
    5660             :                                                           SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
    5661           0 :                 goto bailout;
    5662             :         }
    5663           0 :         canditer_init(&ci1, left, ls);
    5664           0 :         canditer_init(&ci2, right, rs);
    5665           0 :         canditer_init(&ci3, start, ss);
    5666           0 :         if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq || ci3.ncand != ci1.ncand
    5667           0 :                 || ci2.hseq != ci3.hseq) {
    5668           0 :                 msg = createException(MAL, "batstr.locate2",
    5669             :                                                           ILLEGAL_ARGUMENT
    5670             :                                                           " Requires bats of identical size");
    5671           0 :                 goto bailout;
    5672             :         }
    5673           0 :         if (!(bn = COLnew(ci1.hseq, TYPE_int, ci1.ncand, TRANSIENT))) {
    5674           0 :                 msg = createException(MAL, "batstr.locate2",
    5675             :                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    5676           0 :                 goto bailout;
    5677             :         }
    5678             : 
    5679           0 :         off1 = left->hseqbase;
    5680           0 :         off2 = right->hseqbase;
    5681           0 :         off3 = start->hseqbase;
    5682           0 :         lefti = bat_iterator(left);
    5683           0 :         righti = bat_iterator(right);
    5684           0 :         starti = bat_iterator(start);
    5685           0 :         svals = starti.base;
    5686           0 :         vals = Tloc(bn, 0);
    5687           0 :         if (ci1.tpe == cand_dense && ci2.tpe == cand_dense && ci3.tpe == cand_dense) {
    5688           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5689           0 :                         oid p1 = (canditer_next_dense(&ci1) - off1),
    5690           0 :                                 p2 = (canditer_next_dense(&ci2) - off2),
    5691           0 :                                 p3 = (canditer_next_dense(&ci3) - off3);
    5692           0 :                         const char *x = BUNtvar(lefti, p1);
    5693           0 :                         const char *y = BUNtvar(righti, p2);
    5694           0 :                         z = svals[p3];
    5695             : 
    5696           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5697           0 :                                 vals[i] = int_nil;
    5698           0 :                                 nils = true;
    5699             :                         } else {
    5700           0 :                                 vals[i] = str_locate2(x, y, z);
    5701             :                         }
    5702             :                 }
    5703             :         } else {
    5704           0 :                 for (BUN i = 0; i < ci1.ncand; i++) {
    5705           0 :                         oid p1 = (canditer_next(&ci1) - off1),
    5706           0 :                                 p2 = (canditer_next(&ci2) - off2),
    5707           0 :                                 p3 = (canditer_next(&ci3) - off3);
    5708           0 :                         const char *x = BUNtvar(lefti, p1);
    5709           0 :                         const char *y = BUNtvar(righti, p2);
    5710           0 :                         z = svals[p3];
    5711             : 
    5712           0 :                         if (strNil(x) || strNil(y) || is_int_nil(z)) {
    5713           0 :                                 vals[i] = int_nil;
    5714           0 :                                 nils = true;
    5715             :                         } else {
    5716           0 :                                 vals[i] = str_locate2(x, y, z);
    5717             :                         }
    5718             :                 }
    5719             :         }
    5720           0 :         bat_iterator_end(&starti);
    5721           0 :         bat_iterator_end(&lefti);
    5722           0 :         bat_iterator_end(&righti);
    5723           0 :   bailout:
    5724           0 :         finalize_output(res, bn, msg, nils, ci1.ncand);
    5725           0 :         unfix_inputs(6, left, ls, right, rs, start, ss);
    5726           0 :         return msg;
    5727             : }
    5728             : 
    5729             : static str
    5730          33 : BATSTRasciify(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
    5731             : {
    5732          33 :         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         345 : LIB_STARTUP_FUNC(init_batstr_mal)
    5935         345 : { mal_module("batstr", NULL, batstr_init_funcs); }

Generated by: LCOV version 1.14