LCOV - code coverage report
Current view: top level - monetdb5/modules/kernel - batstr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1406 3728 37.7 %
Date: 2024-04-26 00:35:57 Functions: 76 116 65.5 %

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

Generated by: LCOV version 1.14