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 | #define dec_round_body_nonil FUN(TYPE, dec_round_body_nonil) |
10 | #define dec_round_body FUN(TYPE, dec_round_body) |
11 | #define dec_round_wrap FUN(TYPE, dec_round_wrap) |
12 | #define bat_dec_round_wrap FUN(TYPE, bat_dec_round_wrap) |
13 | #define round_body_nonil FUN(TYPE, round_body_nonil) |
14 | #define round_body FUN(TYPE, round_body) |
15 | #define round_wrap FUN(TYPE, round_wrap) |
16 | #define bat_round_wrap FUN(TYPE, bat_round_wrap) |
17 | #define nil_2dec FUN(nil_2dec, TYPE) |
18 | #define str_2dec FUN(str_2dec, TYPE) |
19 | #define nil_2num FUN(nil_2num, TYPE) |
20 | #define str_2num FUN(str_2num, TYPE) |
21 | #define batnil_2dec FUN(batnil_2dec, TYPE) |
22 | #define batstr_2dec FUN(batstr_2dec, TYPE) |
23 | #define batnil_2num FUN(batnil_2num, TYPE) |
24 | #define batstr_2num FUN(batstr_2num, TYPE) |
25 | #define dec2second_interval FUN(TYPE, dec2second_interval) |
26 | |
27 | static inline TYPE |
28 | dec_round_body_nonil(TYPE v, TYPE r) |
29 | { |
30 | TYPE add = r >> 1; |
31 | |
32 | assert(!ISNIL(TYPE)(v)); |
33 | |
34 | if (v < 0) |
35 | add = -add; |
36 | v += add; |
37 | return v / r; |
38 | } |
39 | |
40 | static inline TYPE |
41 | dec_round_body(TYPE v, TYPE r) |
42 | { |
43 | /* shortcut nil */ |
44 | if (ISNIL(TYPE)(v)) { |
45 | return NIL(TYPE); |
46 | } else { |
47 | return dec_round_body_nonil(v, r); |
48 | } |
49 | } |
50 | |
51 | str |
52 | dec_round_wrap(TYPE *res, const TYPE *v, const TYPE *r) |
53 | { |
54 | /* basic sanity checks */ |
55 | assert(res && v && r); |
56 | |
57 | *res = dec_round_body(*v, *r); |
58 | return MAL_SUCCEED; |
59 | } |
60 | |
61 | str |
62 | bat_dec_round_wrap(bat *_res, const bat *_v, const TYPE *r) |
63 | { |
64 | BAT *res, *v; |
65 | TYPE *src, *dst; |
66 | BUN i, cnt; |
67 | int nonil; /* TRUE: we know there are no NIL (NULL) values */ |
68 | |
69 | /* basic sanity checks */ |
70 | assert(_res && _v && r); |
71 | |
72 | /* get argument BAT descriptor */ |
73 | if ((v = BATdescriptor(*_v)) == NULL) |
74 | throw(MAL, "round" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
75 | |
76 | /* more sanity checks */ |
77 | if (v->ttype != TPE(TYPE)) { |
78 | BBPunfix(v->batCacheid); |
79 | throw(MAL, "round" , SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail" ); |
80 | } |
81 | cnt = BATcount(v); |
82 | |
83 | /* allocate result BAT */ |
84 | res = COLnew(v->hseqbase, TPE(TYPE), cnt, TRANSIENT); |
85 | if (res == NULL) { |
86 | BBPunfix(v->batCacheid); |
87 | throw(MAL, "round" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
88 | } |
89 | |
90 | /* access columns as arrays */ |
91 | src = (TYPE *) Tloc(v, 0); |
92 | dst = (TYPE *) Tloc(res, 0); |
93 | |
94 | nonil = TRUE; |
95 | if (v->tnonil) { |
96 | for (i = 0; i < cnt; i++) |
97 | dst[i] = dec_round_body_nonil(src[i], *r); |
98 | } else { |
99 | for (i = 0; i < cnt; i++) { |
100 | if (ISNIL(TYPE)(src[i])) { |
101 | nonil = FALSE; |
102 | dst[i] = NIL(TYPE); |
103 | } else { |
104 | dst[i] = dec_round_body_nonil(src[i], *r); |
105 | } |
106 | } |
107 | } |
108 | |
109 | /* set result BAT properties */ |
110 | BATsetcount(res, cnt); |
111 | /* hard to predict correct tail properties in general */ |
112 | res->tnonil = nonil; |
113 | res->tnil = !nonil; |
114 | res->tseqbase = oid_nil; |
115 | res->tsorted = v->tsorted; |
116 | res->trevsorted = v->trevsorted; |
117 | BATkey(res, false); |
118 | |
119 | /* release argument BAT descriptors */ |
120 | BBPunfix(v->batCacheid); |
121 | |
122 | /* keep result */ |
123 | BBPkeepref(*_res = res->batCacheid); |
124 | |
125 | return MAL_SUCCEED; |
126 | } |
127 | |
128 | static inline TYPE |
129 | round_body_nonil(TYPE v, int d, int s, int r) |
130 | { |
131 | TYPE res = NIL(TYPE); |
132 | |
133 | assert(!ISNIL(TYPE)(v)); |
134 | |
135 | if (-r > d) { |
136 | res = 0; |
137 | } else if (r > 0 && r < s) { |
138 | int dff = s - r; |
139 | BIG rnd = scales[dff] >> 1; |
140 | BIG lres; |
141 | if (v > 0) |
142 | lres = ((v + rnd) / scales[dff]) * scales[dff]; |
143 | else |
144 | lres = ((v - rnd) / scales[dff]) * scales[dff]; |
145 | res = (TYPE) lres; |
146 | } else if (r <= 0 && -r + s > 0) { |
147 | int dff = -r + s; |
148 | BIG rnd = scales[dff] >> 1; |
149 | BIG lres; |
150 | if (v > 0) |
151 | lres = ((v + rnd) / scales[dff]) * scales[dff]; |
152 | else |
153 | lres = ((v - rnd) / scales[dff]) * scales[dff]; |
154 | res = (TYPE) lres; |
155 | } else { |
156 | res = v; |
157 | } |
158 | return res; |
159 | } |
160 | |
161 | static inline TYPE |
162 | round_body(TYPE v, int d, int s, int r) |
163 | { |
164 | /* shortcut nil */ |
165 | if (ISNIL(TYPE)(v)) { |
166 | return NIL(TYPE); |
167 | } else { |
168 | return round_body_nonil(v, d, s, r); |
169 | } |
170 | } |
171 | |
172 | str |
173 | round_wrap(TYPE *res, const TYPE *v, const int *d, const int *s, const bte *r) |
174 | { |
175 | /* basic sanity checks */ |
176 | assert(res && v && r && d && s); |
177 | |
178 | *res = round_body(*v, *d, *s, *r); |
179 | return MAL_SUCCEED; |
180 | } |
181 | |
182 | str |
183 | bat_round_wrap(bat *_res, const bat *_v, const int *d, const int *s, const bte *r) |
184 | { |
185 | BAT *res, *v; |
186 | TYPE *src, *dst; |
187 | BUN i, cnt; |
188 | bool nonil; /* TRUE: we know there are no NIL (NULL) values */ |
189 | |
190 | /* basic sanity checks */ |
191 | assert(_res && _v && r && d && s); |
192 | |
193 | /* get argument BAT descriptor */ |
194 | if ((v = BATdescriptor(*_v)) == NULL) |
195 | throw(MAL, "round" , SQLSTATE(HY002) RUNTIME_OBJECT_MISSING); |
196 | |
197 | /* more sanity checks */ |
198 | if (v->ttype != TPE(TYPE)) { |
199 | BBPunfix(v->batCacheid); |
200 | throw(MAL, "round" , SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail" ); |
201 | } |
202 | cnt = BATcount(v); |
203 | |
204 | /* allocate result BAT */ |
205 | res = COLnew(v->hseqbase, TPE(TYPE), cnt, TRANSIENT); |
206 | if (res == NULL) { |
207 | BBPunfix(v->batCacheid); |
208 | throw(MAL, "round" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
209 | } |
210 | |
211 | /* access columns as arrays */ |
212 | src = (TYPE *) Tloc(v, 0); |
213 | dst = (TYPE *) Tloc(res, 0); |
214 | |
215 | nonil = true; |
216 | if (v->tnonil) { |
217 | for (i = 0; i < cnt; i++) |
218 | dst[i] = round_body_nonil(src[i], *d, *s, *r); |
219 | } else { |
220 | for (i = 0; i < cnt; i++) { |
221 | if (ISNIL(TYPE)(src[i])) { |
222 | nonil = false; |
223 | dst[i] = NIL(TYPE); |
224 | } else { |
225 | dst[i] = round_body_nonil(src[i], *d, *s, *r); |
226 | } |
227 | } |
228 | } |
229 | |
230 | /* set result BAT properties */ |
231 | BATsetcount(res, cnt); |
232 | /* hard to predict correct tail properties in general */ |
233 | res->tnonil = nonil; |
234 | res->tnil = !nonil; |
235 | res->tseqbase = oid_nil; |
236 | res->tsorted = v->tsorted; |
237 | res->trevsorted = v->trevsorted; |
238 | BATkey(res, false); |
239 | |
240 | /* release argument BAT descriptors */ |
241 | BBPunfix(v->batCacheid); |
242 | |
243 | /* keep result */ |
244 | BBPkeepref(*_res = res->batCacheid); |
245 | |
246 | return MAL_SUCCEED; |
247 | } |
248 | |
249 | str |
250 | nil_2dec(TYPE *res, const void *val, const int *d, const int *sc) |
251 | { |
252 | (void) val; |
253 | (void) d; |
254 | (void) sc; |
255 | |
256 | *res = NIL(TYPE); |
257 | return MAL_SUCCEED; |
258 | } |
259 | |
260 | str |
261 | str_2dec(TYPE *res, const str *val, const int *d, const int *sc) |
262 | { |
263 | char *s; |
264 | char *dot, *end; |
265 | int digits; |
266 | int scale; |
267 | BIG value; |
268 | |
269 | s = *val; |
270 | if (GDK_STRNIL(s)) { |
271 | *res = NIL(TYPE); |
272 | return MAL_SUCCEED; |
273 | } |
274 | dot = strchr(s, '.'); |
275 | if (dot != NULL) { |
276 | s = strip_extra_zeros(s); |
277 | digits = _strlen(s) - 1; |
278 | scale = _strlen(dot + 1); |
279 | } else { |
280 | digits = _strlen(s); |
281 | scale = 0; |
282 | } |
283 | end = NULL; |
284 | value = 0; |
285 | |
286 | if (digits < 0) |
287 | throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)" , *val, *d, *sc); |
288 | if (*d < 0 || *d >= (int) (sizeof(scales) / sizeof(scales[0]))) |
289 | throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)" , *val, *d, *sc); |
290 | |
291 | value = decimal_from_str(s, &end); |
292 | if (*s == '+' || *s == '-') |
293 | digits--; |
294 | if (scale < *sc) { |
295 | /* the current scale is too small, increase it by adding 0's */ |
296 | int dff = *sc - scale; /* CANNOT be 0! */ |
297 | |
298 | value *= scales[dff]; |
299 | scale += dff; |
300 | digits += dff; |
301 | } else if (scale > *sc) { |
302 | /* the current scale is too big, decrease it by correctly rounding */ |
303 | /* we should round properly, and check for overflow (res >= 10^digits+scale) */ |
304 | int dff = scale - *sc; /* CANNOT be 0 */ |
305 | BIG rnd = scales[dff] >> 1; |
306 | |
307 | if (value > 0) |
308 | value += rnd; |
309 | else |
310 | value -= rnd; |
311 | value /= scales[dff]; |
312 | scale -= dff; |
313 | digits -= dff; |
314 | if (value >= scales[*d] || value <= -scales[*d]) { |
315 | throw(SQL, STRING(TYPE), SQLSTATE(42000) "Rounding of decimal (%s) doesn't fit format (%d.%d)" , *val, *d, *sc); |
316 | } |
317 | } |
318 | if (value <= -scales[*d] || value >= scales[*d] || *end) { |
319 | throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)" , *val, *d, *sc); |
320 | } |
321 | *res = (TYPE) value; |
322 | return MAL_SUCCEED; |
323 | } |
324 | |
325 | str |
326 | nil_2num(TYPE *res, const void *v, const int *len) |
327 | { |
328 | int zero = 0; |
329 | return nil_2dec(res, v, len, &zero); |
330 | } |
331 | |
332 | str |
333 | str_2num(TYPE *res, const str *v, const int *len) |
334 | { |
335 | int zero = 0; |
336 | return str_2dec(res, v, len, &zero); |
337 | } |
338 | |
339 | str |
340 | batnil_2dec(bat *res, const bat *bid, const int *d, const int *sc) |
341 | { |
342 | BAT *b, *dst; |
343 | BUN p, q; |
344 | |
345 | (void) d; |
346 | (void) sc; |
347 | if ((b = BATdescriptor(*bid)) == NULL) { |
348 | throw(SQL, "batcalc.nil_2dec_" STRING(TYPE), SQLSTATE(HY005) "Cannot access column descriptor" ); |
349 | } |
350 | dst = COLnew(b->hseqbase, TPE(TYPE), BATcount(b), TRANSIENT); |
351 | if (dst == NULL) { |
352 | BBPunfix(b->batCacheid); |
353 | throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
354 | } |
355 | const TYPE r = NIL(TYPE); |
356 | BATloop(b, p, q) { |
357 | if (BUNappend(dst, &r, false) != GDK_SUCCEED) { |
358 | BBPunfix(b->batCacheid); |
359 | BBPreclaim(dst); |
360 | throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
361 | } |
362 | } |
363 | BBPkeepref(*res = dst->batCacheid); |
364 | BBPunfix(b->batCacheid); |
365 | return MAL_SUCCEED; |
366 | } |
367 | |
368 | str |
369 | batstr_2dec(bat *res, const bat *bid, const int *d, const int *sc) |
370 | { |
371 | BAT *b, *dst; |
372 | BATiter bi; |
373 | BUN p, q; |
374 | char *msg = NULL; |
375 | |
376 | if ((b = BATdescriptor(*bid)) == NULL) { |
377 | throw(SQL, "batcalc.str_2dec_" STRING(TYPE), SQLSTATE(HY005) "Cannot access column descriptor" ); |
378 | } |
379 | bi = bat_iterator(b); |
380 | dst = COLnew(b->hseqbase, TPE(TYPE), BATcount(b), TRANSIENT); |
381 | if (dst == NULL) { |
382 | BBPunfix(b->batCacheid); |
383 | throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
384 | } |
385 | BATloop(b, p, q) { |
386 | str v = (str) BUNtvar(bi, p); |
387 | TYPE r; |
388 | msg = str_2dec(&r, &v, d, sc); |
389 | if (msg) { |
390 | BBPunfix(dst->batCacheid); |
391 | BBPunfix(b->batCacheid); |
392 | return msg; |
393 | } |
394 | if (BUNappend(dst, &r, false) != GDK_SUCCEED) { |
395 | BBPunfix(b->batCacheid); |
396 | BBPreclaim(dst); |
397 | throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
398 | } |
399 | } |
400 | BBPkeepref(*res = dst->batCacheid); |
401 | BBPunfix(b->batCacheid); |
402 | return msg; |
403 | } |
404 | |
405 | str |
406 | batnil_2num(bat *res, const bat *bid, const int *len) |
407 | { |
408 | int zero = 0; |
409 | return batnil_2dec(res, bid, len, &zero); |
410 | } |
411 | |
412 | str |
413 | batstr_2num(bat *res, const bat *bid, const int *len) |
414 | { |
415 | BAT *b, *dst; |
416 | BATiter bi; |
417 | BUN p, q; |
418 | char *msg = NULL; |
419 | |
420 | if ((b = BATdescriptor(*bid)) == NULL) { |
421 | throw(SQL, "batcalc.str_2num_" STRING(TYPE), SQLSTATE(HY005) "Cannot access column descriptor" ); |
422 | } |
423 | bi = bat_iterator(b); |
424 | dst = COLnew(b->hseqbase, TPE(TYPE), BATcount(b), TRANSIENT); |
425 | if (dst == NULL) { |
426 | BBPunfix(b->batCacheid); |
427 | throw(SQL, "sql.num_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
428 | } |
429 | BATloop(b, p, q) { |
430 | str v = (str) BUNtvar(bi, p); |
431 | TYPE r; |
432 | msg = str_2num(&r, &v, len); |
433 | if (msg) { |
434 | BBPunfix(dst->batCacheid); |
435 | BBPunfix(b->batCacheid); |
436 | return msg; |
437 | } |
438 | if (BUNappend(dst, &r, false) != GDK_SUCCEED) { |
439 | BBPunfix(b->batCacheid); |
440 | BBPreclaim(dst); |
441 | throw(SQL, "sql.num_" STRING(TYPE), SQLSTATE(HY001) MAL_MALLOC_FAIL); |
442 | } |
443 | } |
444 | BBPkeepref(*res = dst->batCacheid); |
445 | BBPunfix(b->batCacheid); |
446 | return msg; |
447 | } |
448 | |
449 | str |
450 | dec2second_interval(lng *res, const int *sc, const TYPE *dec, const int *ek, const int *sk) |
451 | { |
452 | BIG value = *dec; |
453 | |
454 | (void) ek; |
455 | (void) sk; |
456 | if (*sc < 3) { |
457 | int d = 3 - *sc; |
458 | value *= scales[d]; |
459 | } else if (*sc > 3) { |
460 | int d = *sc - 3; |
461 | lng rnd = scales[d] >> 1; |
462 | |
463 | value += rnd; |
464 | value /= scales[d]; |
465 | } |
466 | *res = value; |
467 | return MAL_SUCCEED; |
468 | } |
469 | |
470 | #undef dec_round_body_nonil |
471 | #undef dec_round_body |
472 | #undef dec_round_wrap |
473 | #undef bat_dec_round_wrap |
474 | #undef round_body_nonil |
475 | #undef round_body |
476 | #undef round_wrap |
477 | #undef bat_round_wrap |
478 | #undef nil_2dec |
479 | #undef str_2dec |
480 | #undef nil_2num |
481 | #undef str_2num |
482 | #undef batnil_2dec |
483 | #undef batstr_2dec |
484 | #undef batnil_2num |
485 | #undef batstr_2num |
486 | #undef dec2second_interval |
487 | |