1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * M.L. Kersten
11 * String multiplexes
12 * [TODO: property propagations]
13 * The collection of routines provided here are map operations
14 * for the atom string primitives.
15 *
16 * In line with the batcalc module, we assume that if two bat operands
17 * are provided that they are aligned.
18 */
19#include "monetdb_config.h"
20#include "gdk.h"
21#include <ctype.h>
22#include <string.h>
23#include "mal_exception.h"
24#include "str.h"
25
26mal_export str STRbatPrefix(bat *ret, const bat *l, const bat *r);
27mal_export str STRbatPrefixcst(bat *ret, const bat *l, const str *cst);
28mal_export str STRbatSuffix(bat *ret, const bat *l, const bat *r);
29mal_export str STRbatSuffixcst(bat *ret, const bat *l, const str *cst);
30mal_export str STRbatstrSearch(bat *ret, const bat *l, const bat *r);
31mal_export str STRbatstrSearchcst(bat *ret, const bat *l, const str *cst);
32mal_export str STRbatRstrSearch(bat *ret, const bat *l, const bat *r);
33mal_export str STRbatRstrSearchcst(bat *ret, const bat *l, const str *cst);
34mal_export str STRbatTail(bat *ret, const bat *l, const bat *r);
35mal_export str STRbatTailcst(bat *ret, const bat *l, const int *cst);
36mal_export str STRbatWChrAt(bat *ret, const bat *l, const bat *r);
37mal_export str STRbatWChrAtcst(bat *ret, const bat *l, const int *cst);
38mal_export str STRbatSubstitutecst(bat *ret, const bat *l, const str *arg2, const str *arg3, const bit *rep);
39
40mal_export str STRbatLower(bat *ret, const bat *l);
41mal_export str STRbatUpper(bat *ret, const bat *l);
42mal_export str STRbatStrip(bat *ret, const bat *l);
43mal_export str STRbatLtrim(bat *ret, const bat *l);
44mal_export str STRbatRtrim(bat *ret, const bat *l);
45mal_export str STRbatStrip2_const(bat *ret, const bat *l, const str *s2);
46mal_export str STRbatLtrim2_const(bat *ret, const bat *l, const str *s2);
47mal_export str STRbatRtrim2_const(bat *ret, const bat *l, const str *s2);
48mal_export str STRbatStrip2_bat(bat *ret, const bat *l, const bat *l2);
49mal_export str STRbatLtrim2_bat(bat *ret, const bat *l, const bat *l2);
50mal_export str STRbatRtrim2_bat(bat *ret, const bat *l, const bat *l2);
51
52mal_export str STRbatLpad_const(bat *ret, const bat *l, const int *n);
53mal_export str STRbatRpad_const(bat *ret, const bat *l, const int *n);
54mal_export str STRbatLpad_bat(bat *ret, const bat *l, const bat *n);
55mal_export str STRbatRpad_bat(bat *ret, const bat *l, const bat *n);
56mal_export str STRbatLpad2_const_const(bat *ret, const bat *l, const int *n, const str *s2);
57mal_export str STRbatRpad2_const_const(bat *ret, const bat *l, const int *n, const str *s2);
58mal_export str STRbatLpad2_bat_const(bat *ret, const bat *l, const bat *n, const str *s2);
59mal_export str STRbatRpad2_bat_const(bat *ret, const bat *l, const bat *n, const str *s2);
60mal_export str STRbatLpad2_const_bat(bat *ret, const bat *l, const int *n, const bat *l2);
61mal_export str STRbatRpad2_const_bat(bat *ret, const bat *l, const int *n, const bat *l2);
62mal_export str STRbatLpad2_bat_bat(bat *ret, const bat *l, const bat *n, const bat *l2);
63mal_export str STRbatRpad2_bat_bat(bat *ret, const bat *l, const bat *n, const bat *l2);
64
65mal_export str STRbatLength(bat *ret, const bat *l);
66mal_export str STRbatBytes(bat *ret, const bat *l);
67
68mal_export str STRbatsubstringcst(bat *ret, const bat *bid, const int *start, const int *length);
69mal_export str STRbatsubstring(bat *ret, const bat *l, const bat *r, const bat *t);
70
71
72#define prepareOperand(X,Y,Z) \
73 if( (X= BATdescriptor(*Y)) == NULL ) \
74 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
75#define prepareOperand2(X,Y,A,B,Z) \
76 if( (X= BATdescriptor(*Y)) == NULL ) \
77 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \
78 if( (A= BATdescriptor(*B)) == NULL ){ \
79 BBPunfix(X->batCacheid); \
80 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \
81 }
82#define prepareOperand3(X,Y,A,B,I,J,Z) \
83 if( (X= BATdescriptor(*Y)) == NULL ) \
84 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \
85 if( (A= BATdescriptor(*B)) == NULL ){ \
86 BBPunfix(X->batCacheid); \
87 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \
88 } \
89 if( (I= BATdescriptor(*J)) == NULL ){ \
90 BBPunfix(X->batCacheid); \
91 BBPunfix(A->batCacheid); \
92 throw(MAL, Z, SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); \
93 }
94#define prepareResult(X,Y,T,Z) \
95 X= COLnew((Y)->hseqbase,T,BATcount(Y), TRANSIENT); \
96 if( X == NULL){ \
97 BBPunfix(Y->batCacheid); \
98 throw(MAL, Z, SQLSTATE(HY001) MAL_MALLOC_FAIL); \
99 } \
100 X->tsorted=false; \
101 X->trevsorted=false;
102#define prepareResult2(X,Y,A,T,Z) \
103 X= COLnew((Y)->hseqbase,T,BATcount(Y), TRANSIENT); \
104 if( X == NULL){ \
105 BBPunfix(Y->batCacheid); \
106 BBPunfix(A->batCacheid); \
107 throw(MAL, Z, SQLSTATE(HY001) MAL_MALLOC_FAIL); \
108 } \
109 X->tsorted=false; \
110 X->trevsorted=false;
111#define finalizeResult(X,Y,Z) \
112 (Y)->theap.dirty |= BATcount(Y) > 0; \
113 *X = (Y)->batCacheid; \
114 BBPkeepref(*(X)); \
115 BBPunfix(Z->batCacheid);
116
117static str
118do_batstr_int(bat *ret, const bat *l, const char *name, str (*func)(int *, const str *))
119{
120 BATiter bi;
121 BAT *bn, *b;
122 BUN p, q;
123 str x;
124 int y;
125 str msg = MAL_SUCCEED;
126
127 prepareOperand(b, l, name);
128 prepareResult(bn, b, TYPE_int, name);
129
130 bi = bat_iterator(b);
131
132 BATloop(b, p, q) {
133 x = (str) BUNtvar(bi, p);
134 if (x == 0 || strcmp(x, str_nil) == 0) {
135 y = int_nil;
136 bn->tnonil = false;
137 bn->tnil = true;
138 } else if ((msg = (*func)(&y, &x)) != MAL_SUCCEED) {
139 goto bunins_failed;
140 }
141 bunfastappTYPE(int, bn, &y);
142 }
143 finalizeResult(ret, bn, b);
144 return MAL_SUCCEED;
145bunins_failed:
146 BBPunfix(b->batCacheid);
147 BBPunfix(bn->batCacheid);
148 if (msg != MAL_SUCCEED)
149 return msg;
150 throw(MAL, name, OPERATION_FAILED " During bulk operation");
151}
152
153str
154STRbatLength(bat *ret, const bat *l)
155{
156 return do_batstr_int(ret, l, "batstr.Length", STRLength);
157}
158
159str
160STRbatBytes(bat *ret, const bat *l)
161{
162 return do_batstr_int(ret, l, "batstr.Bytes", STRBytes);
163}
164
165static str
166do_batstr_str(bat *ret, const bat *l, const char *name, str (*func)(str *, const str *))
167{
168 BATiter bi;
169 BAT *bn, *b;
170 BUN p, q;
171 str x, y;
172 str msg = MAL_SUCCEED;
173
174 prepareOperand(b, l, name);
175 prepareResult(bn, b, TYPE_str, name);
176
177 bi = bat_iterator(b);
178
179 BATloop(b, p, q) {
180 y = NULL;
181 x = (str) BUNtvar(bi, p);
182 if (x != 0 && strcmp(x, str_nil) != 0 &&
183 (msg = (*func)(&y, &x)) != MAL_SUCCEED)
184 goto bunins_failed1;
185 if (y == NULL)
186 y = (str) str_nil;
187 bunfastappVAR(bn, y);
188 if (y == str_nil) {
189 bn->tnonil = false;
190 bn->tnil = true;
191 } else
192 GDKfree(y);
193 }
194 finalizeResult(ret, bn, b);
195 return MAL_SUCCEED;
196bunins_failed:
197 if (y != str_nil)
198 GDKfree(y);
199bunins_failed1:
200 BBPunfix(b->batCacheid);
201 BBPunfix(bn->batCacheid);
202 if (msg != MAL_SUCCEED)
203 return msg;
204 throw(MAL, name, OPERATION_FAILED " During bulk operation");
205}
206
207/* Input: a BAT of strings 'l' and a constant string 's2'
208 * Output type: str (a BAT of strings)
209 */
210static str
211do_batstr_conststr_str(bat *ret, const bat *l, const str *s2, const char *name, str (*func)(str *, const str *, const str *))
212{
213 BATiter bi;
214 BAT *bn, *b;
215 BUN p, q;
216 str x, y;
217 str msg = MAL_SUCCEED;
218
219 prepareOperand(b, l, name);
220 prepareResult(bn, b, TYPE_str, name);
221
222 bi = bat_iterator(b);
223
224 BATloop(b, p, q) {
225 y = NULL;
226 x = (str) BUNtvar(bi, p);
227 if (x != 0 && strcmp(x, str_nil) != 0 &&
228 (msg = (*func)(&y, &x, s2)) != MAL_SUCCEED)
229 goto bunins_failed1;
230 if (y == NULL)
231 y = (str) str_nil;
232 bunfastappVAR(bn, y);
233 if (y == str_nil) {
234 bn->tnonil = false;
235 bn->tnil = true;
236 } else
237 GDKfree(y);
238 }
239 finalizeResult(ret, bn, b);
240 return MAL_SUCCEED;
241bunins_failed:
242 if (y != str_nil)
243 GDKfree(y);
244bunins_failed1:
245 BBPunfix(b->batCacheid);
246 BBPunfix(bn->batCacheid);
247 if (msg != MAL_SUCCEED)
248 return msg;
249 throw(MAL, name, OPERATION_FAILED " During bulk operation");
250}
251
252/* Input: two BATs of strings 'l' and 'l2'
253 * Output type: str (a BAT of strings)
254 */
255static str
256do_batstr_batstr_str(bat *ret, const bat *l, const bat *l2, const char *name, str (*func)(str *, const str *, const str *))
257{
258 BATiter bi, bi2;
259 BAT *bn, *b, *b2;
260 BUN p, q;
261 str x, x2, y;
262 str msg = MAL_SUCCEED;
263
264 prepareOperand2(b, l, b2, l2, name);
265 if(BATcount(b) != BATcount(b2)) {
266 BBPunfix(b->batCacheid);
267 BBPunfix(b2->batCacheid);
268 throw(MAL, name, ILLEGAL_ARGUMENT " Requires bats of identical size");
269 }
270 prepareResult2(bn, b, b2, TYPE_str, name);
271
272 bi = bat_iterator(b);
273 bi2 = bat_iterator(b2);
274
275 BATloop(b, p, q) {
276 y = NULL;
277 x = (str) BUNtvar(bi, p);
278 x2 = (str) BUNtvar(bi2, p);
279 if (x != 0 && strcmp(x, str_nil) != 0 &&
280 x2 != 0 && strcmp(x2, str_nil) != 0 &&
281 (msg = (*func)(&y, &x, &x2)) != MAL_SUCCEED)
282 goto bunins_failed1;
283 if (y == NULL)
284 y = (str) str_nil;
285 bunfastappVAR(bn, y);
286 if (y == str_nil) {
287 bn->tnonil = false;
288 bn->tnil = true;
289 } else
290 GDKfree(y);
291 }
292 finalizeResult(ret, bn, b);
293 return MAL_SUCCEED;
294bunins_failed:
295 if (y != str_nil)
296 GDKfree(y);
297bunins_failed1:
298 BBPunfix(b->batCacheid);
299 BBPunfix(b2->batCacheid);
300 BBPunfix(bn->batCacheid);
301 if (msg != MAL_SUCCEED)
302 return msg;
303 throw(MAL, name, OPERATION_FAILED " During bulk operation");
304}
305
306/* Input: a BAT of strings 'l' and a constant int 'n'
307 * Output type: str (a BAT of strings)
308 */
309static str
310do_batstr_constint_str(bat *ret, const bat *l, const int *n, const char *name, str (*func)(str *, const str *, const int *))
311{
312 BATiter bi;
313 BAT *bn, *b;
314 BUN p, q;
315 str x, y;
316 str msg = MAL_SUCCEED;
317
318 prepareOperand(b, l, name);
319 prepareResult(bn, b, TYPE_str, name);
320
321 bi = bat_iterator(b);
322
323 BATloop(b, p, q) {
324 y = NULL;
325 x = (str) BUNtvar(bi, p);
326 if (x != 0 && strcmp(x, str_nil) != 0 &&
327 (msg = (*func)(&y, &x, n)) != MAL_SUCCEED)
328 goto bunins_failed1;
329 if (y == NULL)
330 y = (str) str_nil;
331 bunfastappVAR(bn, y);
332 if (y == str_nil) {
333 bn->tnonil = false;
334 bn->tnil = true;
335 } else
336 GDKfree(y);
337 }
338 finalizeResult(ret, bn, b);
339 return MAL_SUCCEED;
340bunins_failed:
341 if (y != str_nil)
342 GDKfree(y);
343bunins_failed1:
344 BBPunfix(b->batCacheid);
345 BBPunfix(bn->batCacheid);
346 if (msg != MAL_SUCCEED)
347 return msg;
348 throw(MAL, name, OPERATION_FAILED " During bulk operation");
349}
350
351/* Input: a BAT of strings 'l' and a BAT of integers 'n'
352 * Output type: str (a BAT of strings)
353 */
354static str
355do_batstr_batint_str(bat *ret, const bat *l, const bat *n, const char *name, str (*func)(str *, const str *, const int *))
356{
357 BATiter bi, bi2;
358 BAT *bn, *b, *b2;
359 BUN p, q;
360 int nn;
361 str x, y;
362 str msg = MAL_SUCCEED;
363
364 prepareOperand2(b, l, b2, n, name);
365 if(BATcount(b) != BATcount(b2)) {
366 BBPunfix(b->batCacheid);
367 BBPunfix(b2->batCacheid);
368 throw(MAL, name, ILLEGAL_ARGUMENT " Requires bats of identical size");
369 }
370 prepareResult2(bn, b, b2, TYPE_str, name);
371
372 bi = bat_iterator(b);
373 bi2 = bat_iterator(b2);
374
375 BATloop(b, p, q) {
376 y = NULL;
377 x = (str) BUNtvar(bi, p);
378 nn = *(int *)BUNtloc(bi2, p);
379 if (x != 0 && strcmp(x, str_nil) != 0 &&
380 (msg = (*func)(&y, &x, &nn)) != MAL_SUCCEED)
381 goto bunins_failed1;
382 if (y == NULL)
383 y = (str) str_nil;
384 bunfastappVAR(bn, y);
385 if (y == str_nil) {
386 bn->tnonil = false;
387 bn->tnil = true;
388 } else
389 GDKfree(y);
390 }
391 finalizeResult(ret, bn, b);
392 return MAL_SUCCEED;
393bunins_failed:
394 if (y != str_nil)
395 GDKfree(y);
396bunins_failed1:
397 BBPunfix(b->batCacheid);
398 BBPunfix(b2->batCacheid);
399 BBPunfix(bn->batCacheid);
400 if (msg != MAL_SUCCEED)
401 return msg;
402 throw(MAL, name, OPERATION_FAILED " During bulk operation");
403}
404
405/* Input: a BAT of strings 'l', a constant int 'n' and a constant str 's2'
406 * Output type: str (a BAT of strings)
407 */
408static str
409do_batstr_constint_conststr_str(bat *ret, const bat *l, const int *n, const str *s2, const char *name, str (*func)(str *, const str *, const int *, const str *))
410{
411 BATiter bi;
412 BAT *bn, *b;
413 BUN p, q;
414 str x, y;
415 str msg = MAL_SUCCEED;
416
417 prepareOperand(b, l, name);
418 prepareResult(bn, b, TYPE_str, name);
419
420 bi = bat_iterator(b);
421
422 BATloop(b, p, q) {
423 y = NULL;
424 x = (str) BUNtvar(bi, p);
425 if (x != 0 && strcmp(x, str_nil) != 0 &&
426 (msg = (*func)(&y, &x, n, s2)) != MAL_SUCCEED)
427 goto bunins_failed1;
428 if (y == NULL)
429 y = (str) str_nil;
430 bunfastappVAR(bn, y);
431 if (y == str_nil) {
432 bn->tnonil = false;
433 bn->tnil = true;
434 } else
435 GDKfree(y);
436 }
437 finalizeResult(ret, bn, b);
438 return MAL_SUCCEED;
439bunins_failed:
440 if (y != str_nil)
441 GDKfree(y);
442bunins_failed1:
443 BBPunfix(b->batCacheid);
444 BBPunfix(bn->batCacheid);
445 if (msg != MAL_SUCCEED)
446 return msg;
447 throw(MAL, name, OPERATION_FAILED " During bulk operation");
448}
449
450/* Input: a BAT of strings 'l', a BAT of integers 'n' and a constant str 's2'
451 * Output type: str (a BAT of strings)
452 */
453static str
454do_batstr_batint_conststr_str(bat *ret, const bat *l, const bat *n, const str *s2, const char *name, str (*func)(str *, const str *, const int *, const str *))
455{
456 BATiter bi, bi2;
457 BAT *bn, *b, *b2;
458 BUN p, q;
459 int nn;
460 str x, y;
461 str msg = MAL_SUCCEED;
462
463 prepareOperand2(b, l, b2, n, name);
464 if(BATcount(b) != BATcount(b2)) {
465 BBPunfix(b->batCacheid);
466 BBPunfix(b2->batCacheid);
467 throw(MAL, name, ILLEGAL_ARGUMENT " Requires bats of identical size");
468 }
469 prepareResult(bn, b, TYPE_str, name);
470
471 bi = bat_iterator(b);
472 bi2 = bat_iterator(b2);
473
474 BATloop(b, p, q) {
475 y = NULL;
476 x = (str) BUNtvar(bi, p);
477 nn = *(int *)BUNtloc(bi2, p);
478 if (x != 0 && strcmp(x, str_nil) != 0 &&
479 (msg = (*func)(&y, &x, &nn, s2)) != MAL_SUCCEED)
480 goto bunins_failed1;
481 if (y == NULL)
482 y = (str) str_nil;
483 bunfastappVAR(bn, y);
484 if (y == str_nil) {
485 bn->tnonil = false;
486 bn->tnil = true;
487 } else
488 GDKfree(y);
489 }
490 finalizeResult(ret, bn, b);
491 return MAL_SUCCEED;
492bunins_failed:
493 if (y != str_nil)
494 GDKfree(y);
495bunins_failed1:
496 BBPunfix(b->batCacheid);
497 BBPunfix(b2->batCacheid);
498 BBPunfix(bn->batCacheid);
499 if (msg != MAL_SUCCEED)
500 return msg;
501 throw(MAL, name, OPERATION_FAILED " During bulk operation");
502}
503
504/* Input: a BAT of strings 'l', a constant int 'n' and a BAT of strings 'l2'
505 * Output type: str (a BAT of strings)
506 */
507static str
508do_batstr_constint_batstr_str(bat *ret, const bat *l, const int *n, const bat *l2, const char *name, str (*func)(str *, const str *, const int *, const str *))
509{
510 BATiter bi, bi2;
511 BAT *bn, *b, *b2;
512 BUN p, q;
513 str x, x2, y;
514 str msg = MAL_SUCCEED;
515
516 prepareOperand2(b, l, b2, l2, name);
517 if(BATcount(b) != BATcount(b2)) {
518 BBPunfix(b->batCacheid);
519 BBPunfix(b2->batCacheid);
520 throw(MAL, name, ILLEGAL_ARGUMENT " Requires bats of identical size");
521 }
522 prepareResult(bn, b, TYPE_str, name);
523
524 bi = bat_iterator(b);
525 bi2 = bat_iterator(b2);
526
527 BATloop(b, p, q) {
528 y = NULL;
529 x = (str) BUNtvar(bi, p);
530 x2 = (str) BUNtvar(bi2, p);
531 if (x != 0 && strcmp(x, str_nil) != 0 &&
532 x2 != 0 && strcmp(x2, str_nil) != 0 &&
533 (msg = (*func)(&y, &x, n, &x2)) != MAL_SUCCEED)
534 goto bunins_failed1;
535 if (y == NULL)
536 y = (str) str_nil;
537 bunfastappVAR(bn, y);
538 if (y == str_nil) {
539 bn->tnonil = false;
540 bn->tnil = true;
541 } else
542 GDKfree(y);
543 }
544 finalizeResult(ret, bn, b);
545 return MAL_SUCCEED;
546bunins_failed:
547 if (y != str_nil)
548 GDKfree(y);
549bunins_failed1:
550 BBPunfix(b->batCacheid);
551 BBPunfix(b2->batCacheid);
552 BBPunfix(bn->batCacheid);
553 if (msg != MAL_SUCCEED)
554 return msg;
555 throw(MAL, name, OPERATION_FAILED " During bulk operation");
556}
557
558/* Input: a BAT of strings 'l', a BAT of int 'n' and a BAT of strings 'l2'
559 * Output type: str (a BAT of strings)
560 */
561static str
562do_batstr_batint_batstr_str(bat *ret, const bat *l, const bat *n, const bat *l2, const char *name, str (*func)(str *, const str *, const int *, const str *))
563{
564 BATiter bi, bi2, bi3;
565 BAT *bn, *b, *b2, *b3;
566 BUN p, q;
567 int nn;
568 str x, x2, y;
569 str msg = MAL_SUCCEED;
570
571
572 prepareOperand3(b, l, b2, n, b3, l2, name);
573 if (BATcount(b) != BATcount(b2) || BATcount(b) != BATcount(b3)) {
574 BBPunfix(b->batCacheid);
575 BBPunfix(b2->batCacheid);
576 BBPunfix(b3->batCacheid);
577 throw(MAL, name, ILLEGAL_ARGUMENT " Requires bats of identical size");
578 }
579 bn = COLnew(b->hseqbase, TYPE_str, BATcount(b), TRANSIENT);
580 if (bn == NULL) {
581 BBPunfix(b->batCacheid);
582 BBPunfix(b2->batCacheid);
583 BBPunfix(b3->batCacheid);
584 throw(MAL, name, SQLSTATE(HY001) MAL_MALLOC_FAIL);
585 }
586 bn->tsorted=false;
587 bn->trevsorted=false;
588
589 bi = bat_iterator(b);
590 bi2 = bat_iterator(b2);
591 bi3 = bat_iterator(b3);
592
593 BATloop(b, p, q) {
594 y = NULL;
595 x = (str) BUNtvar(bi, p);
596 nn = *(int *)BUNtloc(bi2, p);
597 x2 = (str) BUNtvar(bi3, p);
598 if (x != 0 && strcmp(x, str_nil) != 0 &&
599 x2 != 0 && strcmp(x2, str_nil) != 0 &&
600 (msg = (*func)(&y, &x, &nn, &x2)) != MAL_SUCCEED)
601 goto bunins_failed1;
602 if (y == NULL)
603 y = (str) str_nil;
604 bunfastappVAR(bn, y);
605 if (y == str_nil) {
606 bn->tnonil = false;
607 bn->tnil = true;
608 } else
609 GDKfree(y);
610 }
611 finalizeResult(ret, bn, b);
612 return MAL_SUCCEED;
613bunins_failed:
614 if (y != str_nil)
615 GDKfree(y);
616bunins_failed1:
617 BBPunfix(b->batCacheid);
618 BBPunfix(b2->batCacheid);
619 BBPunfix(b3->batCacheid);
620 BBPunfix(bn->batCacheid);
621 if (msg != MAL_SUCCEED)
622 return msg;
623 throw(MAL, name, OPERATION_FAILED " During bulk operation");
624}
625
626str
627STRbatLower(bat *ret, const bat *l)
628{
629 return do_batstr_str(ret, l, "batstr.Lower", STRLower);
630}
631
632str
633STRbatUpper(bat *ret, const bat *l)
634{
635 return do_batstr_str(ret, l, "batstr.Upper", STRUpper);
636}
637
638str
639STRbatStrip(bat *ret, const bat *l)
640{
641 return do_batstr_str(ret, l, "batstr.Strip", STRStrip);
642}
643
644str
645STRbatLtrim(bat *ret, const bat *l)
646{
647 return do_batstr_str(ret, l, "batstr.Ltrim", STRLtrim);
648}
649
650str
651STRbatRtrim(bat *ret, const bat *l)
652{
653 return do_batstr_str(ret, l, "batstr.Rtrim", STRRtrim);
654}
655
656str
657STRbatStrip2_const(bat *ret, const bat *l, const str *s2)
658{
659 return do_batstr_conststr_str(ret, l, s2, "batstr.Strip", STRStrip2);
660}
661
662str
663STRbatLtrim2_const(bat *ret, const bat *l, const str *s2)
664{
665 return do_batstr_conststr_str(ret, l, s2, "batstr.Ltrim", STRLtrim2);
666}
667
668str
669STRbatRtrim2_const(bat *ret, const bat *l, const str *s2)
670{
671 return do_batstr_conststr_str(ret, l, s2, "batstr.Rtrim", STRRtrim2);
672}
673
674str
675STRbatStrip2_bat(bat *ret, const bat *l, const bat *l2)
676{
677 return do_batstr_batstr_str(ret, l, l2, "batstr.Strip", STRStrip2);
678}
679
680str
681STRbatLtrim2_bat(bat *ret, const bat *l, const bat *l2)
682{
683 return do_batstr_batstr_str(ret, l, l2, "batstr.Ltrim", STRLtrim2);
684}
685
686str
687STRbatRtrim2_bat(bat *ret, const bat *l, const bat *l2)
688{
689 return do_batstr_batstr_str(ret, l, l2, "batstr.Rtrim", STRRtrim2);
690}
691
692str
693STRbatLpad_const(bat *ret, const bat *l, const int *n)
694{
695 return do_batstr_constint_str(ret, l, n, "batstr.Lpad", STRLpad);
696}
697
698str
699STRbatRpad_const(bat *ret, const bat *l, const int *n)
700{
701 return do_batstr_constint_str(ret, l, n, "batstr.Rpad", STRRpad);
702}
703
704str
705STRbatLpad_bat(bat *ret, const bat *l, const bat *n)
706{
707 return do_batstr_batint_str(ret, l, n, "batstr.Lpad", STRLpad);
708}
709
710str
711STRbatRpad_bat(bat *ret, const bat *l, const bat *n)
712{
713 return do_batstr_batint_str(ret, l, n, "batstr.Rpad", STRRpad);
714}
715
716str
717STRbatLpad2_const_const(bat *ret, const bat *l, const int *n, const str *s2)
718{
719 return do_batstr_constint_conststr_str(ret, l, n, s2, "batstr.Lpad", STRLpad2);
720}
721
722str
723STRbatRpad2_const_const(bat *ret, const bat *l, const int *n, const str *s2)
724{
725 return do_batstr_constint_conststr_str(ret, l, n, s2, "batstr.Rpad", STRRpad2);
726}
727
728str
729STRbatLpad2_bat_const(bat *ret, const bat *l, const bat *n, const str *s2)
730{
731 return do_batstr_batint_conststr_str(ret, l, n, s2, "batstr.Lpad", STRLpad2);
732}
733
734str
735STRbatRpad2_bat_const(bat *ret, const bat *l, const bat *n, const str *s2)
736{
737 return do_batstr_batint_conststr_str(ret, l, n, s2, "batstr.Rpad", STRRpad2);
738}
739
740str
741STRbatLpad2_const_bat(bat *ret, const bat *l, const int *n, const bat *l2)
742{
743 return do_batstr_constint_batstr_str(ret, l, n, l2, "batstr.Lpad", STRLpad2);
744}
745
746str
747STRbatRpad2_const_bat(bat *ret, const bat *l, const int *n, const bat *l2)
748{
749 return do_batstr_constint_batstr_str(ret, l, n, l2, "batstr.Rpad", STRRpad2);
750}
751
752str
753STRbatLpad2_bat_bat(bat *ret, const bat *l, const bat *n, const bat *l2)
754{
755 return do_batstr_batint_batstr_str(ret, l, n, l2, "batstr.Lpad", STRLpad2);
756}
757
758str
759STRbatRpad2_bat_bat(bat *ret, const bat *l, const bat *n, const bat *l2)
760{
761 return do_batstr_batint_batstr_str(ret, l, n, l2, "batstr.Rpad", STRRpad2);
762}
763
764/*
765 * A general assumption in all cases is the bats are synchronized on their
766 * head column. This is not checked and may be mis-used to deploy the
767 * implementation for shifted window arithmetic as well.
768 */
769
770str STRbatPrefix(bat *ret, const bat *l, const bat *r)
771{
772 BATiter lefti, righti;
773 BAT *bn, *left, *right;
774 BUN p,q;
775 bit v;
776
777 prepareOperand2(left,l,right,r,"batstr.startsWith");
778 if(BATcount(left) != BATcount(right)) {
779 BBPunfix(left->batCacheid);
780 BBPunfix(right->batCacheid);
781 throw(MAL, "batstr.startsWith", ILLEGAL_ARGUMENT " Requires bats of identical size");
782 }
783 prepareResult2(bn,left,right,TYPE_bit,"batstr.startsWith");
784
785 lefti = bat_iterator(left);
786 righti = bat_iterator(right);
787
788 BATloop(left, p, q) {
789 str tl = (str) BUNtvar(lefti,p);
790 str tr = (str) BUNtvar(righti,p);
791 STRPrefix(&v, &tl, &tr);
792 bunfastappTYPE(bit, bn, &v);
793 }
794 bn->tnonil = false;
795 BBPunfix(right->batCacheid);
796 finalizeResult(ret,bn,left);
797 return MAL_SUCCEED;
798
799bunins_failed:
800 BBPunfix(left->batCacheid);
801 BBPunfix(right->batCacheid);
802 BBPunfix(*ret);
803 throw(MAL, "batstr.startsWith", OPERATION_FAILED " During bulk operation");
804}
805
806str STRbatPrefixcst(bat *ret, const bat *l, const str *cst)
807{
808 BATiter lefti;
809 BAT *bn, *left;
810 BUN p,q;
811 bit v;
812
813 prepareOperand(left,l,"batstr.startsWith");
814 prepareResult(bn,left,TYPE_bit,"batstr.startsWith");
815
816 lefti = bat_iterator(left);
817
818 BATloop(left, p, q) {
819 str tl = (str) BUNtvar(lefti,p);
820 STRPrefix(&v, &tl, cst);
821 bunfastappTYPE(bit, bn, &v);
822 }
823 bn->tnonil = false;
824 finalizeResult(ret,bn,left);
825 return MAL_SUCCEED;
826
827bunins_failed:
828 BBPunfix(left->batCacheid);
829 BBPunfix(*ret);
830 throw(MAL, "batstr.startsWith", OPERATION_FAILED " During bulk operation");
831}
832
833str STRbatSuffix(bat *ret, const bat *l, const bat *r)
834{
835 BATiter lefti, righti;
836 BAT *bn, *left, *right;
837 BUN p,q;
838 bit v;
839
840 prepareOperand2(left,l,right,r,"batstr.endsWith");
841 if(BATcount(left) != BATcount(right)) {
842 BBPunfix(left->batCacheid);
843 BBPunfix(right->batCacheid);
844 throw(MAL, "batstr.endsWith", ILLEGAL_ARGUMENT " Requires bats of identical size");
845 }
846 prepareResult2(bn,left,right,TYPE_bit,"batstr.endsWith");
847
848 lefti = bat_iterator(left);
849 righti = bat_iterator(right);
850
851 BATloop(left, p, q) {
852 str tl = (str) BUNtvar(lefti,p);
853 str tr = (str) BUNtvar(righti,p);
854 STRSuffix(&v, &tl, &tr);
855 bunfastappTYPE(bit, bn, &v);
856 }
857 bn->tnonil = false;
858 BBPunfix(right->batCacheid);
859 finalizeResult(ret,bn,left);
860 return MAL_SUCCEED;
861
862bunins_failed:
863 BBPunfix(left->batCacheid);
864 BBPunfix(right->batCacheid);
865 BBPunfix(*ret);
866 throw(MAL, "batstr.endsWith", OPERATION_FAILED " During bulk operation");
867}
868
869str STRbatSuffixcst(bat *ret, const bat *l, const str *cst)
870{
871 BATiter lefti;
872 BAT *bn, *left;
873 BUN p,q;
874 bit v;
875
876 prepareOperand(left,l,"batstr.endsWith");
877 prepareResult(bn,left,TYPE_bit,"batstr.endsWith");
878
879 lefti = bat_iterator(left);
880
881 BATloop(left, p, q) {
882 str tl = (str) BUNtvar(lefti,p);
883 STRSuffix(&v, &tl, cst);
884 bunfastappTYPE(bit, bn, &v);
885 }
886 bn->tnonil = false;
887 finalizeResult(ret,bn,left);
888 return MAL_SUCCEED;
889
890bunins_failed:
891 BBPunfix(left->batCacheid);
892 BBPunfix(*ret);
893 throw(MAL, "batstr.endsWith", OPERATION_FAILED " During bulk operation");
894}
895
896str STRbatstrSearch(bat *ret, const bat *l, const bat *r)
897{
898 BATiter lefti, righti;
899 BAT *bn, *left, *right;
900 BUN p,q;
901 int v;
902
903 prepareOperand2(left,l,right,r,"batstr.search");
904 if(BATcount(left) != BATcount(right)) {
905 BBPunfix(left->batCacheid);
906 BBPunfix(right->batCacheid);
907 throw(MAL, "batstr.search", ILLEGAL_ARGUMENT " Requires bats of identical size");
908 }
909 prepareResult2(bn,left,right,TYPE_int,"batstr.search");
910
911 lefti = bat_iterator(left);
912 righti = bat_iterator(right);
913
914 BATloop(left, p, q) {
915 str tl = (str) BUNtvar(lefti,p);
916 str tr = (str) BUNtvar(righti,p);
917 STRstrSearch(&v, &tl, &tr);
918 bunfastappTYPE(int, bn, &v);
919 }
920 bn->tnonil = false;
921 BBPunfix(right->batCacheid);
922 finalizeResult(ret,bn,left);
923 return MAL_SUCCEED;
924
925bunins_failed:
926 BBPunfix(left->batCacheid);
927 BBPunfix(right->batCacheid);
928 BBPunfix(*ret);
929 throw(MAL, "batstr.search", OPERATION_FAILED " During bulk operation");
930}
931
932str STRbatstrSearchcst(bat *ret, const bat *l, const str *cst)
933{
934 BATiter lefti;
935 BAT *bn, *left;
936 BUN p,q;
937 int v;
938
939 prepareOperand(left,l,"batstr.search");
940 prepareResult(bn,left,TYPE_int,"batstr.search");
941
942 lefti = bat_iterator(left);
943
944 BATloop(left, p, q) {
945 str tl = (str) BUNtvar(lefti,p);
946 STRstrSearch(&v, &tl, cst);
947 bunfastappTYPE(int, bn, &v);
948 }
949 bn->tnonil = false;
950 finalizeResult(ret,bn,left);
951 return MAL_SUCCEED;
952
953bunins_failed:
954 BBPunfix(left->batCacheid);
955 BBPunfix(*ret);
956 throw(MAL, "batstr.search", OPERATION_FAILED " During bulk operation");
957}
958
959str STRbatRstrSearch(bat *ret, const bat *l, const bat *r)
960{
961 BATiter lefti, righti;
962 BAT *bn, *left, *right;
963 BUN p,q;
964 int v;
965
966 prepareOperand2(left,l,right,r,"batstr.r_search");
967 if(BATcount(left) != BATcount(right)) {
968 BBPunfix(left->batCacheid);
969 BBPunfix(right->batCacheid);
970 throw(MAL, "batstr.r_search", ILLEGAL_ARGUMENT " Requires bats of identical size");
971 }
972 prepareResult2(bn,left,right,TYPE_int,"batstr.r_search");
973
974 lefti = bat_iterator(left);
975 righti = bat_iterator(right);
976
977 BATloop(left, p, q) {
978 str tl = (str) BUNtvar(lefti,p);
979 str tr = (str) BUNtvar(righti,p);
980 STRReverseStrSearch(&v, &tl, &tr);
981 bunfastappTYPE(int, bn, &v);
982 }
983 bn->tnonil = false;
984 BBPunfix(right->batCacheid);
985 finalizeResult(ret,bn,left);
986 return MAL_SUCCEED;
987
988bunins_failed:
989 BBPunfix(left->batCacheid);
990 BBPunfix(right->batCacheid);
991 BBPunfix(*ret);
992 throw(MAL, "batstr.r_search", OPERATION_FAILED " During bulk operation");
993}
994
995str STRbatRstrSearchcst(bat *ret, const bat *l, const str *cst)
996{
997 BATiter lefti;
998 BAT *bn, *left;
999 BUN p,q;
1000 int v;
1001
1002 prepareOperand(left,l,"batstr.r_search");
1003 prepareResult(bn,left,TYPE_int,"batstr.r_search");
1004
1005 lefti = bat_iterator(left);
1006
1007 BATloop(left, p, q) {
1008 str tl = (str) BUNtvar(lefti,p);
1009 STRReverseStrSearch(&v, &tl, cst);
1010 bunfastappTYPE(int, bn, &v);
1011 }
1012 bn->tnonil = false;
1013 finalizeResult(ret,bn,left);
1014 return MAL_SUCCEED;
1015
1016bunins_failed:
1017 BBPunfix(left->batCacheid);
1018 BBPunfix(*ret);
1019 throw(MAL, "batstr.r_search", OPERATION_FAILED " During bulk operation");
1020}
1021
1022str STRbatTail(bat *ret, const bat *l, const bat *r)
1023{
1024 BATiter lefti, righti;
1025 BAT *bn, *left, *right;
1026 BUN p,q;
1027 str v;
1028 str msg = MAL_SUCCEED;
1029
1030 prepareOperand2(left,l,right,r,"batstr.string");
1031 if(BATcount(left) != BATcount(right)) {
1032 BBPunfix(left->batCacheid);
1033 BBPunfix(right->batCacheid);
1034 throw(MAL, "batstr.string", ILLEGAL_ARGUMENT " Requires bats of identical size");
1035 }
1036 prepareResult2(bn,left,right,TYPE_str,"batstr.string");
1037
1038 lefti = bat_iterator(left);
1039 righti = bat_iterator(right);
1040
1041 BATloop(left, p, q) {
1042 str tl = (str) BUNtvar(lefti,p);
1043 int *tr = (int *) BUNtloc(righti,p);
1044 if ((msg = STRTail(&v, &tl, tr)) != MAL_SUCCEED)
1045 goto bunins_failed;
1046 bunfastappVAR(bn, v);
1047 GDKfree(v);
1048 }
1049 bn->tnonil = false;
1050 BBPunfix(right->batCacheid);
1051 finalizeResult(ret,bn,left);
1052 return MAL_SUCCEED;
1053
1054bunins_failed:
1055 BBPunfix(left->batCacheid);
1056 BBPunfix(right->batCacheid);
1057 BBPunfix(*ret);
1058 if (msg)
1059 return msg;
1060 GDKfree(v);
1061 throw(MAL, "batstr.string" , OPERATION_FAILED " During bulk operation");
1062}
1063
1064str STRbatTailcst(bat *ret, const bat *l, const int *cst)
1065{
1066 BATiter lefti;
1067 BAT *bn, *left;
1068 BUN p,q;
1069 str v;
1070 str msg = MAL_SUCCEED;
1071
1072 prepareOperand(left,l,"batstr.string");
1073 prepareResult(bn,left,TYPE_str,"batstr.string");
1074
1075 lefti = bat_iterator(left);
1076
1077 BATloop(left, p, q) {
1078 str tl = (str) BUNtvar(lefti,p);
1079 if ((msg = STRTail(&v, &tl, cst)) != MAL_SUCCEED)
1080 goto bunins_failed;
1081 bunfastappVAR(bn, v);
1082 GDKfree(v);
1083 }
1084 bn->tnonil = false;
1085 finalizeResult(ret,bn,left);
1086 return MAL_SUCCEED;
1087
1088bunins_failed:
1089 BBPunfix(left->batCacheid);
1090 BBPunfix(*ret);
1091 if (msg)
1092 return msg;
1093 GDKfree(v);
1094 throw(MAL, "batstr.string", OPERATION_FAILED " During bulk operation");
1095}
1096
1097str STRbatWChrAt(bat *ret, const bat *l, const bat *r)
1098{
1099 BATiter lefti, righti;
1100 BAT *bn, *left, *right;
1101 BUN p,q;
1102 int v;
1103
1104 prepareOperand2(left,l,right,r,"batstr.unicodeAt");
1105 if(BATcount(left) != BATcount(right)) {
1106 BBPunfix(left->batCacheid);
1107 BBPunfix(right->batCacheid);
1108 throw(MAL, "batstr.unicodeAt", ILLEGAL_ARGUMENT " Requires bats of identical size");
1109 }
1110 prepareResult2(bn,left,right,TYPE_int,"batstr.unicodeAt");
1111
1112 lefti = bat_iterator(left);
1113 righti = bat_iterator(right);
1114
1115 BATloop(left, p, q) {
1116 str tl = (str) BUNtvar(lefti,p);
1117 ptr tr = BUNtail(righti,p);
1118 STRWChrAt(&v, &tl, tr);
1119 bunfastappTYPE(int, bn, &v);
1120 }
1121 bn->tnonil = false;
1122 BBPunfix(right->batCacheid);
1123 finalizeResult(ret,bn,left);
1124 return MAL_SUCCEED;
1125
1126bunins_failed:
1127 BBPunfix(left->batCacheid);
1128 BBPunfix(right->batCacheid);
1129 BBPunfix(*ret);
1130 throw(MAL, "batstr.unicodeAt", OPERATION_FAILED " During bulk operation");
1131}
1132
1133str STRbatWChrAtcst(bat *ret, const bat *l, const int *cst)
1134{
1135 BATiter lefti;
1136 BAT *bn, *left;
1137 BUN p,q;
1138 int v;
1139
1140 prepareOperand(left,l,"batstr.unicodeAt");
1141 prepareResult(bn,left,TYPE_int,"batstr.unicodeAt");
1142
1143 lefti = bat_iterator(left);
1144
1145 BATloop(left, p, q) {
1146 str tl = (str) BUNtvar(lefti,p);
1147 STRWChrAt(&v, &tl, cst);
1148 bunfastappTYPE(int, bn, &v);
1149 }
1150 bn->tnonil = false;
1151 finalizeResult(ret,bn,left);
1152 return MAL_SUCCEED;
1153
1154bunins_failed:
1155 BBPunfix(left->batCacheid);
1156 BBPunfix(*ret);
1157 throw(MAL, "batstr.unicodeAt", OPERATION_FAILED " During bulk operation");
1158}
1159
1160str
1161STRbatSubstitutecst(bat *ret, const bat *l, const str *arg2, const str *arg3, const bit *rep)
1162{
1163 BATiter bi;
1164 BAT *bn, *b;
1165 BUN p, q;
1166 str x;
1167 str y;
1168 str err = MAL_SUCCEED;
1169
1170 prepareOperand(b, l, "subString");
1171 prepareResult(bn, b, TYPE_int, "subString");
1172
1173 bi = bat_iterator(b);
1174
1175 BATloop(b, p, q) {
1176 y = (str) str_nil;
1177 x = (str) BUNtvar(bi, p);
1178 if (x != 0 && strcmp(x, str_nil) != 0 &&
1179 (err = STRSubstitute(&y, &x, arg2, arg3, rep)) != MAL_SUCCEED)
1180 goto bunins_failed;
1181 bunfastappVAR(bn, y);
1182 if (y != str_nil)
1183 GDKfree(y);
1184 }
1185 bn->tnonil = false;
1186 finalizeResult(ret, bn, b);
1187 return MAL_SUCCEED;
1188bunins_failed:
1189 if (err == MAL_SUCCEED && y != str_nil)
1190 GDKfree(y);
1191 BBPunfix(b->batCacheid);
1192 BBPunfix(bn->batCacheid);
1193 if (err)
1194 return err;
1195 throw(MAL, "batstr.subString", OPERATION_FAILED " During bulk operation");
1196}
1197
1198/*
1199 * The substring functions require slightly different arguments
1200 */
1201str
1202STRbatsubstringcst(bat *ret, const bat *bid, const int *start, const int *length)
1203{
1204 BATiter bi;
1205 BAT *b,*bn;
1206 BUN p, q;
1207 str res;
1208 char *msg = MAL_SUCCEED;
1209
1210 if( (b= BATdescriptor(*bid)) == NULL)
1211 throw(MAL, "batstr.substring", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1212 bn= COLnew(b->hseqbase, TYPE_str, BATcount(b)/10+5, TRANSIENT);
1213 if (bn == NULL) {
1214 BBPunfix(b->batCacheid);
1215 throw(MAL, "batstr.substring", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1216 }
1217 bn->tsorted = b->tsorted;
1218 bn->trevsorted = b->trevsorted;
1219
1220 bi = bat_iterator(b);
1221 BATloop(b, p, q) {
1222 str t = (str) BUNtvar(bi, p);
1223
1224 if ((msg = STRsubstring(&res, &t, start, length)) != MAL_SUCCEED ||
1225 BUNappend(bn, (ptr)res, false) != GDK_SUCCEED) {
1226 BBPunfix(b->batCacheid);
1227 BBPunfix(bn->batCacheid);
1228 if (msg != MAL_SUCCEED)
1229 return msg;
1230 GDKfree(res);
1231 throw(MAL, "batstr.substring", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1232 }
1233 GDKfree(res);
1234 }
1235
1236 bn->tnonil = false;
1237 *ret = bn->batCacheid;
1238 BBPkeepref(bn->batCacheid);
1239 BBPunfix(b->batCacheid);
1240 return msg;
1241}
1242
1243str STRbatsubstring(bat *ret, const bat *l, const bat *r, const bat *t)
1244{
1245 BATiter lefti, starti, lengthi;
1246 BAT *bn, *left, *start, *length;
1247 BUN p,q;
1248 str v;
1249
1250 if( (left= BATdescriptor(*l)) == NULL )
1251 throw(MAL, "batstr.substring", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1252 if( (start= BATdescriptor(*r)) == NULL ){
1253 BBPunfix(left->batCacheid);
1254 throw(MAL, "batstr.substring", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1255 }
1256 if( (length= BATdescriptor(*t)) == NULL ){
1257 BBPunfix(left->batCacheid);
1258 BBPunfix(start->batCacheid);
1259 throw(MAL, "batstr.substring", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1260 }
1261 if (BATcount(left) != BATcount(start) ||
1262 BATcount(left) != BATcount(length)) {
1263 BBPunfix(left->batCacheid);
1264 BBPunfix(start->batCacheid);
1265 BBPunfix(length->batCacheid);
1266 throw(MAL, "batstr.substring", ILLEGAL_ARGUMENT " Requires bats of identical size");
1267 }
1268
1269 bn= COLnew(left->hseqbase, TYPE_str,BATcount(left), TRANSIENT);
1270 if( bn == NULL){
1271 BBPunfix(left->batCacheid);
1272 BBPunfix(start->batCacheid);
1273 BBPunfix(length->batCacheid);
1274 throw(MAL, "batstr.substring", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1275 }
1276
1277 bn->tsorted=false;
1278 bn->trevsorted=false;
1279
1280 lefti = bat_iterator(left);
1281 starti = bat_iterator(start);
1282 lengthi = bat_iterator(length);
1283 BATloop(left, p, q) {
1284 str tl = (str) BUNtvar(lefti,p);
1285 int *t1 = (int *) BUNtloc(starti,p);
1286 int *t2 = (int *) BUNtloc(lengthi,p);
1287 str msg;
1288 if ((msg = STRsubstring(&v, &tl, t1, t2)) != MAL_SUCCEED ||
1289 BUNappend(bn, v, false) != GDK_SUCCEED) {
1290 BBPunfix(left->batCacheid);
1291 BBPunfix(start->batCacheid);
1292 BBPreclaim(bn);
1293 if (msg)
1294 return msg;
1295 GDKfree(v);
1296 throw(MAL, "batstr.substring", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1297 }
1298 GDKfree(v);
1299 }
1300 bn->tnonil = false;
1301 BBPunfix(start->batCacheid);
1302 BBPunfix(length->batCacheid);
1303 finalizeResult(ret,bn,left);
1304 return MAL_SUCCEED;
1305}
1306