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 "sql.h"
15 : #include "sql_cast.h"
16 : #include "sql_result.h"
17 : #include "mal_instruction.h"
18 :
19 : /* TODO get max size for all from type */
20 : static size_t
21 30117 : str_buf_initial_capacity(sql_class eclass, int digits)
22 : {
23 30117 : switch (eclass)
24 : {
25 69 : case EC_BIT:
26 : /* should hold false for clob type and (var)char > 4 */
27 69 : return (digits == 0 || digits > 4) ? 8 : 2;
28 : case EC_SEC:
29 : case EC_MONTH:
30 : case EC_NUM:
31 : case EC_DEC:
32 : case EC_POS:
33 : case EC_TIME:
34 : case EC_TIME_TZ:
35 : case EC_DATE:
36 : case EC_TIMESTAMP:
37 : case EC_TIMESTAMP_TZ:
38 : return 64;
39 : case EC_FLT:
40 : return 128;
41 109 : case EC_CHAR:
42 : case EC_STRING:
43 : case EC_BLOB:
44 : case EC_GEOM:
45 109 : return 1024;
46 : default:
47 : return 128;
48 : }
49 : }
50 :
51 : static inline str
52 11658985 : SQLstr_cast_any_type(str *r, size_t *rlen, mvc *m, sql_class eclass, int d, int s, int has_tz, const void *p, int tpe, int len)
53 : {
54 11658985 : ssize_t sz = convert2str(m, eclass, d, s, has_tz, p, tpe, r, rlen);
55 11150024 : if ((len > 0 && sz > (ssize_t) len) || sz < 0)
56 20 : throw(SQL, "str_cast", SQLSTATE(22001) "value too long for type (var)char(%d)", len);
57 : return MAL_SUCCEED;
58 : }
59 :
60 : str
61 29793 : SQLstr_cast(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
62 : {
63 29793 : str *res = getArgReference_str(stk, pci, 0), r = NULL, msg;
64 29793 : sql_class eclass = (sql_class)*getArgReference_int(stk, pci, 1);
65 29793 : int d = *getArgReference_int(stk, pci, 2), s = *getArgReference_int(stk, pci, 3);
66 29793 : int has_tz = *getArgReference_int(stk, pci, 4), tpe = getArgType(mb, pci, 5), digits = *getArgReference_int(stk, pci, 6);
67 29793 : const void *p = getArgReference(stk, pci, 5);
68 29793 : mvc *m = NULL;
69 29793 : bool from_str = EC_VARCHAR(eclass) || tpe == TYPE_str;
70 :
71 29793 : if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
72 : return msg;
73 29793 : if ((msg = checkSQLContext(cntxt)) != NULL)
74 : return msg;
75 29793 : if (ATOMextern(tpe))
76 608 : p = *(ptr *) p;
77 :
78 29793 : if (from_str) {
79 600 : r = (str) p;
80 665 : if (digits > 0 && !strNil(r) && UTF8_strlen(r) > digits)
81 22 : throw(SQL, "calc.str_cast", SQLSTATE(22001) "value too long for type (var)char(%d)", digits);
82 : } else {
83 29193 : size_t rlen = MAX(str_buf_initial_capacity(eclass, digits), strlen(str_nil) + 1); /* don't reallocate on str_nil */
84 29193 : if (!(r = GDKmalloc(rlen)))
85 2 : throw(SQL, "calc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
86 29193 : if ((msg = SQLstr_cast_any_type(&r, &rlen, m, eclass, d, s, has_tz, p, tpe, digits)) != MAL_SUCCEED) {
87 2 : GDKfree(r);
88 2 : return msg;
89 : }
90 : }
91 :
92 29769 : *res = GDKstrdup(r);
93 29769 : if (!from_str)
94 29191 : GDKfree(r);
95 29769 : if (!*res)
96 0 : throw(SQL, "calc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
97 : return MAL_SUCCEED;
98 : }
99 :
100 : #define SQLstr_cast_str(v, digits) \
101 : if (UTF8_strlen(v) > digits) { \
102 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(22001) "value too long for type (var)char(%d)", digits); \
103 : goto bailout1; \
104 : }
105 :
106 : /* str SQLbatstr_cast(int *res, int *eclass, int *d1, int *s1, int *has_tz, int *bid, int *digits); */
107 : str
108 1137 : SQLbatstr_cast(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
109 : {
110 1137 : BAT *b = NULL, *s = NULL, *dst = NULL;
111 1137 : BATiter bi;
112 1137 : mvc *m = NULL;
113 1137 : str msg, r = NULL;
114 1137 : bat *res = getArgReference_bat(stk, pci, 0);
115 1137 : sql_class eclass = (sql_class) *getArgReference_int(stk, pci, 1);
116 1137 : int d1 = *getArgReference_int(stk, pci, 2), s1 = *getArgReference_int(stk, pci, 3), has_tz = *getArgReference_int(stk, pci, 4);
117 1137 : bat *bid = getArgReference_bat(stk, pci, 5), *sid = pci->argc == 7 ? NULL : getArgReference_bat(stk, pci, 6);
118 1137 : int tpe = getBatType(getArgType(mb, pci, 5)), digits = pci->argc == 7 ? *getArgReference_int(stk, pci, 6) : *getArgReference_int(stk, pci, 7);
119 1137 : struct canditer ci;
120 1137 : oid off;
121 1137 : bool nils = false, from_str = EC_VARCHAR(eclass) || tpe == TYPE_str, btkey = false, btsorted = false, btrevsorted = false;
122 1137 : size_t rlen = 0;
123 :
124 1137 : if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
125 : return msg;
126 1138 : if ((msg = checkSQLContext(cntxt)) != NULL)
127 : return msg;
128 1138 : if ((b = BATdescriptor(*bid)) == NULL) {
129 0 : msg = createException(SQL, "batcalc.str", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
130 0 : goto bailout;
131 : }
132 1142 : if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
133 0 : msg = createException(SQL, "batcalc.str", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
134 0 : goto bailout;
135 : }
136 :
137 1142 : assert(digits >= 0);
138 1142 : if (from_str && digits == 0) {
139 0 : if (s) {
140 0 : if (!(dst = BATproject(s, b))) {
141 0 : msg = createException(SQL, "batcalc.str", GDK_EXCEPTION);
142 0 : goto bailout;
143 : }
144 0 : BBPunfix(s->batCacheid);
145 0 : BBPunfix(b->batCacheid);
146 0 : *res = dst->batCacheid;
147 0 : BBPkeepref(dst);
148 : } else {
149 0 : *res = b->batCacheid;
150 0 : BBPkeepref(b);
151 : }
152 0 : return MAL_SUCCEED;
153 : }
154 1142 : off = b->hseqbase;
155 1142 : canditer_init(&ci, b, s);
156 1137 : bi = bat_iterator(b);
157 :
158 1141 : if (from_str && ci.tpe == cand_dense && ci.ncand == BATcount(b)) { /* from string case, just do validation, if right, return */
159 1006350 : for (BUN i = 0; i < ci.ncand; i++) {
160 1006137 : oid p = (canditer_next_dense(&ci) - off);
161 1006137 : const char *v = BUNtvar(bi, p);
162 :
163 2012274 : if (!strNil(v))
164 1006137 : SQLstr_cast_str(v, digits);
165 : }
166 213 : BBPreclaim(s);
167 213 : bat_iterator_end(&bi);
168 214 : *res = b->batCacheid;
169 214 : BBPkeepref(b);
170 214 : return MAL_SUCCEED;
171 : }
172 :
173 928 : if (!(dst = COLnew(ci.hseq, TYPE_str, ci.ncand, TRANSIENT))) {
174 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
175 0 : goto bailout1;
176 : }
177 :
178 919 : rlen = MAX(str_buf_initial_capacity(eclass, digits), strlen(str_nil) + 1); /* don't reallocate on str_nil */
179 919 : assert(rlen > 0);
180 919 : if (!from_str && !(r = GDKmalloc(rlen))) {
181 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
182 0 : goto bailout1;
183 : }
184 :
185 927 : if (ci.tpe == cand_dense) {
186 914 : if (from_str) { /* string to string */
187 0 : for (BUN i = 0; i < ci.ncand; i++) {
188 0 : oid p = (canditer_next_dense(&ci) - off);
189 0 : const char *v = BUNtvar(bi, p);
190 :
191 0 : if (strNil(v)) {
192 0 : if (tfastins_nocheckVAR(dst, i, str_nil) != GDK_SUCCEED) {
193 0 : msg = createException(MAL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
194 0 : goto bailout1;
195 : }
196 : nils = true;
197 : } else {
198 0 : SQLstr_cast_str(v, digits);
199 0 : if (tfastins_nocheckVAR(dst, i, v) != GDK_SUCCEED) {
200 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
201 0 : goto bailout1;
202 : }
203 : }
204 : }
205 : } else { /* any other type to string */
206 11652813 : for (BUN i = 0; i < ci.ncand; i++) {
207 11651919 : oid p = (canditer_next_dense(&ci) - off);
208 11651919 : const void *v = BUNtail(bi, p);
209 :
210 11651919 : if ((msg = SQLstr_cast_any_type(&r, &rlen, m, eclass, d1, s1, has_tz, v, tpe, digits)) != MAL_SUCCEED)
211 18 : goto bailout1;
212 11165219 : if (tfastins_nocheckVAR(dst, i, r) != GDK_SUCCEED) {
213 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
214 0 : goto bailout1;
215 : }
216 23338513 : nils |= strNil(r);
217 : }
218 : }
219 : } else {
220 13 : if (from_str) { /* string to string */
221 0 : for (BUN i = 0; i < ci.ncand; i++) {
222 0 : oid p = (canditer_next(&ci) - off);
223 0 : const char *v = BUNtvar(bi, p);
224 :
225 0 : if (strNil(v)) {
226 0 : if (tfastins_nocheckVAR(dst, i, str_nil) != GDK_SUCCEED) {
227 0 : msg = createException(MAL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
228 0 : goto bailout1;
229 : }
230 : nils = true;
231 : } else {
232 0 : SQLstr_cast_str(v, digits);
233 0 : if (tfastins_nocheckVAR(dst, i, v) != GDK_SUCCEED) {
234 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
235 0 : goto bailout1;
236 : }
237 : }
238 : }
239 : } else { /* any other type to string */
240 48 : for (BUN i = 0; i < ci.ncand; i++) {
241 35 : oid p = (canditer_next(&ci) - off);
242 35 : const void *v = BUNtail(bi, p);
243 :
244 35 : if ((msg = SQLstr_cast_any_type(&r, &rlen, m, eclass, d1, s1, has_tz, v, tpe, digits)) != MAL_SUCCEED)
245 0 : goto bailout1;
246 35 : if (tfastins_nocheckVAR(dst, i, r) != GDK_SUCCEED) {
247 0 : msg = createException(SQL, "batcalc.str_cast", SQLSTATE(HY013) MAL_MALLOC_FAIL);
248 0 : goto bailout1;
249 : }
250 70 : nils |= strNil(r);
251 : }
252 : }
253 : }
254 908 : btkey = from_str ? bi.key : ci.ncand <= 1;
255 908 : btsorted = from_str ? bi.sorted : ci.ncand <= 1;
256 908 : btrevsorted = from_str ? bi.revsorted : ci.ncand <= 1;
257 926 : bailout1:
258 926 : bat_iterator_end(&bi);
259 :
260 925 : bailout:
261 925 : GDKfree(r);
262 929 : BBPreclaim(b);
263 928 : BBPreclaim(s);
264 925 : if (dst && !msg) {
265 907 : BATsetcount(dst, ci.ncand);
266 910 : dst->tnil = nils;
267 910 : dst->tnonil = !nils;
268 910 : dst->tkey = btkey;
269 910 : dst->tsorted = btsorted;
270 910 : dst->trevsorted = btrevsorted;
271 910 : *res = dst->batCacheid;
272 910 : BBPkeepref(dst);
273 18 : } else if (dst)
274 18 : BBPreclaim(dst);
275 : return msg;
276 : }
277 :
278 : #define flt_is_numeric 0
279 : #define dbl_is_numeric 0
280 : #define bte_is_numeric 1
281 : #define sht_is_numeric 1
282 : #define int_is_numeric 1
283 : #define lng_is_numeric 1
284 : #define hge_is_numeric 1
285 :
286 : /* stringify token */
287 : #define _STRNG_(s) #s
288 : #define STRNG(t) _STRNG_(t)
289 :
290 : /* concatenate two, three or four tokens */
291 : #define CONCAT_2(a,b) a##b
292 : #define CONCAT_3(a,b,c) a##b##c
293 : #define CONCAT_4(a,b,c,d) a##b##c##d
294 :
295 : #define NIL(t) CONCAT_2(t,_nil)
296 : #define ISNIL(t) CONCAT_3(is_,t,_nil)
297 : #define TPE(t) CONCAT_2(TYPE_,t)
298 : #define GDKmin(t) CONCAT_3(GDK_,t,_min)
299 : #define GDKmax(t) CONCAT_3(GDK_,t,_max)
300 : #define FUN(a,b,c,d) CONCAT_4(a,b,c,d)
301 : #define IS_NUMERIC(t) CONCAT_2(t,_is_numeric)
302 :
303 : /* up casting */
304 :
305 : #define TP1 bte
306 : #define TP2 bte
307 : #include "sql_cast_impl_int.h"
308 : #undef TP2
309 : #undef TP1
310 :
311 : #define TP1 bte
312 : #define TP2 sht
313 : #include "sql_cast_impl_int.h"
314 : #undef TP2
315 : #undef TP1
316 :
317 : #define TP1 sht
318 : #define TP2 sht
319 : #include "sql_cast_impl_int.h"
320 : #undef TP2
321 : #undef TP1
322 :
323 : #define TP1 bte
324 : #define TP2 int
325 : #include "sql_cast_impl_int.h"
326 : #undef TP2
327 : #undef TP1
328 :
329 : #define TP1 sht
330 : #define TP2 int
331 : #include "sql_cast_impl_int.h"
332 : #undef TP2
333 : #undef TP1
334 :
335 : #define TP1 int
336 : #define TP2 int
337 : #include "sql_cast_impl_int.h"
338 : #undef TP2
339 : #undef TP1
340 :
341 : #define TP1 bte
342 : #define TP2 lng
343 : #include "sql_cast_impl_int.h"
344 : #undef TP2
345 : #undef TP1
346 :
347 : #define TP1 sht
348 : #define TP2 lng
349 : #include "sql_cast_impl_int.h"
350 : #undef TP2
351 : #undef TP1
352 :
353 : #define TP1 int
354 : #define TP2 lng
355 : #include "sql_cast_impl_int.h"
356 : #undef TP2
357 : #undef TP1
358 :
359 : #define TP1 lng
360 : #define TP2 lng
361 : #include "sql_cast_impl_int.h"
362 : #undef TP2
363 : #undef TP1
364 :
365 : #ifdef HAVE_HGE
366 : #define TP1 bte
367 : #define TP2 hge
368 : #include "sql_cast_impl_int.h"
369 : #undef TP2
370 : #undef TP1
371 :
372 : #define TP1 sht
373 : #define TP2 hge
374 : #include "sql_cast_impl_int.h"
375 : #undef TP2
376 : #undef TP1
377 :
378 : #define TP1 int
379 : #define TP2 hge
380 : #include "sql_cast_impl_int.h"
381 : #undef TP2
382 : #undef TP1
383 :
384 : #define TP1 lng
385 : #define TP2 hge
386 : #include "sql_cast_impl_int.h"
387 : #undef TP2
388 : #undef TP1
389 :
390 : #define TP1 hge
391 : #define TP2 hge
392 : #include "sql_cast_impl_int.h"
393 : #undef TP2
394 : #undef TP1
395 : #endif
396 :
397 : /* sql_cast_impl_down_from_flt */
398 :
399 : #define TP1 flt
400 : #define TP2 bte
401 : #include "sql_cast_impl_int.h"
402 : #undef TP2
403 : #undef TP1
404 :
405 : #define TP1 flt
406 : #define TP2 sht
407 : #include "sql_cast_impl_int.h"
408 : #undef TP2
409 : #undef TP1
410 :
411 : #define TP1 flt
412 : #define TP2 int
413 : #include "sql_cast_impl_int.h"
414 : #undef TP2
415 : #undef TP1
416 :
417 : #define TP1 flt
418 : #define TP2 lng
419 : #include "sql_cast_impl_int.h"
420 : #undef TP2
421 : #undef TP1
422 :
423 : #ifdef HAVE_HGE
424 : #define TP1 flt
425 : #define TP2 hge
426 : #include "sql_cast_impl_int.h"
427 : #undef TP2
428 : #undef TP1
429 : #endif
430 :
431 : #define TP1 dbl
432 : #define TP2 bte
433 : #include "sql_cast_impl_int.h"
434 : #undef TP2
435 : #undef TP1
436 :
437 : #define TP1 dbl
438 : #define TP2 sht
439 : #include "sql_cast_impl_int.h"
440 : #undef TP2
441 : #undef TP1
442 :
443 : #define TP1 dbl
444 : #define TP2 int
445 : #include "sql_cast_impl_int.h"
446 : #undef TP2
447 : #undef TP1
448 :
449 : #define TP1 dbl
450 : #define TP2 lng
451 : #include "sql_cast_impl_int.h"
452 : #undef TP2
453 : #undef TP1
454 :
455 : #ifdef HAVE_HGE
456 : #define TP1 dbl
457 : #define TP2 hge
458 : #include "sql_cast_impl_int.h"
459 : #undef TP2
460 : #undef TP1
461 : #endif
462 :
463 : /* sql_cast_impl_up_to_flt */
464 :
465 : #define TP1 bte
466 : #define TP2 flt
467 : #include "sql_cast_impl_int.h"
468 : #undef TP2
469 : #undef TP1
470 :
471 : #define TP1 sht
472 : #define TP2 flt
473 : #include "sql_cast_impl_int.h"
474 : #undef TP2
475 : #undef TP1
476 :
477 : #define TP1 int
478 : #define TP2 flt
479 : #include "sql_cast_impl_int.h"
480 : #undef TP2
481 : #undef TP1
482 :
483 : #define TP1 lng
484 : #define TP2 flt
485 : #include "sql_cast_impl_int.h"
486 : #undef TP2
487 : #undef TP1
488 :
489 : #ifdef HAVE_HGE
490 : #define TP1 hge
491 : #define TP2 flt
492 : #include "sql_cast_impl_int.h"
493 : #undef TP2
494 : #undef TP1
495 : #endif
496 :
497 : #define TP1 bte
498 : #define TP2 dbl
499 : #include "sql_cast_impl_int.h"
500 : #undef TP2
501 : #undef TP1
502 :
503 : #define TP1 sht
504 : #define TP2 dbl
505 : #include "sql_cast_impl_int.h"
506 : #undef TP2
507 : #undef TP1
508 :
509 : #define TP1 int
510 : #define TP2 dbl
511 : #include "sql_cast_impl_int.h"
512 : #undef TP2
513 : #undef TP1
514 :
515 : #define TP1 lng
516 : #define TP2 dbl
517 : #include "sql_cast_impl_int.h"
518 : #undef TP2
519 : #undef TP1
520 :
521 : #ifdef HAVE_HGE
522 : #define TP1 hge
523 : #define TP2 dbl
524 : #include "sql_cast_impl_int.h"
525 : #undef TP2
526 : #undef TP1
527 : #endif
528 :
529 : #define TP1 sht
530 : #define TP2 bte
531 : #include "sql_cast_impl_int.h"
532 : #undef TP2
533 : #undef TP1
534 :
535 : #define TP1 int
536 : #define TP2 bte
537 : #include "sql_cast_impl_int.h"
538 : #undef TP2
539 : #undef TP1
540 :
541 : #define TP1 lng
542 : #define TP2 bte
543 : #include "sql_cast_impl_int.h"
544 : #undef TP2
545 : #undef TP1
546 :
547 : #ifdef HAVE_HGE
548 : #define TP1 hge
549 : #define TP2 bte
550 : #include "sql_cast_impl_int.h"
551 : #undef TP2
552 : #undef TP1
553 : #endif
554 :
555 : #define TP1 int
556 : #define TP2 sht
557 : #include "sql_cast_impl_int.h"
558 : #undef TP2
559 : #undef TP1
560 :
561 : #define TP1 lng
562 : #define TP2 sht
563 : #include "sql_cast_impl_int.h"
564 : #undef TP2
565 : #undef TP1
566 :
567 : #ifdef HAVE_HGE
568 : #define TP1 hge
569 : #define TP2 sht
570 : #include "sql_cast_impl_int.h"
571 : #undef TP2
572 : #undef TP1
573 : #endif
574 :
575 : #define TP1 lng
576 : #define TP2 int
577 : #include "sql_cast_impl_int.h"
578 : #undef TP2
579 : #undef TP1
580 :
581 : #ifdef HAVE_HGE
582 : #define TP1 hge
583 : #define TP2 int
584 : #include "sql_cast_impl_int.h"
585 : #undef TP2
586 : #undef TP1
587 : #endif
588 :
589 : #ifdef HAVE_HGE
590 : #define TP1 hge
591 : #define TP2 lng
592 : #include "sql_cast_impl_int.h"
593 : #undef TP2
594 : #undef TP1
595 : #endif
|