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
27static inline TYPE
28dec_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
40static inline TYPE
41dec_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
51str
52dec_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
61str
62bat_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
128static inline TYPE
129round_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
161static inline TYPE
162round_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
172str
173round_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
182str
183bat_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
249str
250nil_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
260str
261str_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
325str
326nil_2num(TYPE *res, const void *v, const int *len)
327{
328 int zero = 0;
329 return nil_2dec(res, v, len, &zero);
330}
331
332str
333str_2num(TYPE *res, const str *v, const int *len)
334{
335 int zero = 0;
336 return str_2dec(res, v, len, &zero);
337}
338
339str
340batnil_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
368str
369batstr_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
405str
406batnil_2num(bat *res, const bat *bid, const int *len)
407{
408 int zero = 0;
409 return batnil_2dec(res, bid, len, &zero);
410}
411
412str
413batstr_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
449str
450dec2second_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