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 : #define dec_round_body FUN(TYPE, dec_round_body)
14 : #define dec_round_wrap FUN(TYPE, dec_round_wrap)
15 : #define bat_dec_round_wrap FUN(TYPE, bat_dec_round_wrap)
16 : #define bat_dec_round_wrap_cst FUN(TYPE, bat_dec_round_wrap_cst)
17 : #define bat_dec_round_wrap_nocst FUN(TYPE, bat_dec_round_wrap_nocst)
18 : #define round_body FUN(TYPE, round_body)
19 : #define round_wrap FUN(TYPE, round_wrap)
20 : #define bat_round_wrap FUN(TYPE, bat_round_wrap)
21 : #define bat_round_wrap_cst FUN(TYPE, bat_round_wrap_cst)
22 : #define bat_round_wrap_nocst FUN(TYPE, bat_round_wrap_nocst)
23 : #define nil_2dec FUN(nil_2dec, TYPE)
24 : #define str_2dec_body FUN(str_2dec_body, TYPE)
25 : #define str_2dec FUN(str_2dec, TYPE)
26 : #define batnil_2dec FUN(batnil_2dec, TYPE)
27 : #define batstr_2dec FUN(batstr_2dec, TYPE)
28 : #define dec2second_interval FUN(TYPE, dec2second_interval)
29 : #define batdec2second_interval FUN(TYPE, batdec2second_interval)
30 :
31 : static inline TYPE
32 21 : dec_round_body(TYPE v, TYPE r)
33 : {
34 21 : TYPE add = r >> 1;
35 :
36 21 : assert(!ISNIL(TYPE)(v));
37 :
38 21 : if (v < 0)
39 4 : add = -add;
40 21 : v += add;
41 21 : return v / r;
42 : }
43 :
44 : str
45 12 : dec_round_wrap(TYPE *res, const TYPE *v, const TYPE *r)
46 : {
47 : /* basic sanity checks */
48 12 : assert(res && v && r);
49 :
50 12 : if (ISNIL(TYPE)(*r))
51 0 : throw(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
52 12 : if (*r <= 0)
53 0 : throw(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
54 :
55 12 : *res = ISNIL(TYPE)(*v) ? NIL(TYPE) : dec_round_body(*v, *r);
56 12 : return MAL_SUCCEED;
57 : }
58 :
59 : str
60 1 : bat_dec_round_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
61 : {
62 1 : BAT *bn = NULL, *b = NULL, *bs = NULL;
63 1 : TYPE *restrict src, *restrict dst, x, r = *(TYPE *)getArgReference(stk, pci, 2);
64 1 : str msg = MAL_SUCCEED;
65 1 : bool nils = false, btsorted = false, btrevsorted = false;
66 1 : struct canditer ci1 = {0};
67 1 : oid off1;
68 1 : bat *res = getArgReference_bat(stk, pci, 0), *bid = getArgReference_bat(stk, pci, 1),
69 1 : *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
70 1 : BATiter bi;
71 :
72 1 : (void) cntxt;
73 1 : (void) mb;
74 1 : if (ISNIL(TYPE)(r)) {
75 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
76 0 : goto bailout;
77 : }
78 1 : if (r <= 0) {
79 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
80 0 : goto bailout;
81 : }
82 1 : if (!(b = BATdescriptor(*bid))) {
83 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
84 0 : goto bailout;
85 : }
86 1 : if (b->ttype != TPE(TYPE)) {
87 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail");
88 0 : goto bailout;
89 : }
90 1 : if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
91 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
92 0 : goto bailout;
93 : }
94 1 : canditer_init(&ci1, b, bs);
95 1 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
96 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
97 0 : goto bailout;
98 : }
99 :
100 1 : off1 = b->hseqbase;
101 1 : bi = bat_iterator(b);
102 1 : src = (TYPE *) bi.base;
103 1 : dst = (TYPE *) Tloc(bn, 0);
104 1 : if (ci1.tpe == cand_dense) {
105 10 : for (BUN i = 0; i < ci1.ncand; i++) {
106 9 : oid p1 = (canditer_next_dense(&ci1) - off1);
107 9 : x = src[p1];
108 :
109 9 : if (ISNIL(TYPE)(x)) {
110 0 : dst[i] = NIL(TYPE);
111 0 : nils = true;
112 : } else {
113 9 : dst[i] = dec_round_body(x, r);
114 : }
115 : }
116 : } else {
117 0 : for (BUN i = 0; i < ci1.ncand; i++) {
118 0 : oid p1 = (canditer_next(&ci1) - off1);
119 0 : x = src[p1];
120 :
121 0 : if (ISNIL(TYPE)(x)) {
122 0 : dst[i] = NIL(TYPE);
123 0 : nils = true;
124 : } else {
125 0 : dst[i] = dec_round_body(x, r);
126 : }
127 : }
128 : }
129 1 : btsorted = bi.sorted;
130 1 : btrevsorted = bi.revsorted;
131 1 : bat_iterator_end(&bi);
132 1 : bailout:
133 1 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, btsorted, btrevsorted);
134 1 : unfix_inputs(2, b, bs);
135 1 : return msg;
136 : }
137 :
138 : str
139 0 : bat_dec_round_wrap_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
140 : {
141 0 : BAT *bn = NULL, *b = NULL, *bs = NULL;
142 0 : TYPE *restrict src, *restrict dst, x = *(TYPE *)getArgReference(stk, pci, 1), r;
143 0 : str msg = MAL_SUCCEED;
144 0 : bool nils = false;
145 0 : struct canditer ci1 = {0};
146 0 : oid off1;
147 0 : bat *res = getArgReference_bat(stk, pci, 0), *bid = getArgReference_bat(stk, pci, 2),
148 0 : *sid1 = pci->argc == 4 ? getArgReference_bat(stk, pci, 3) : NULL;
149 0 : BATiter bi;
150 :
151 0 : (void) cntxt;
152 0 : (void) mb;
153 0 : if (!(b = BATdescriptor(*bid))) {
154 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
155 0 : goto bailout;
156 : }
157 0 : if (b->ttype != TPE(TYPE)) {
158 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail");
159 0 : goto bailout;
160 : }
161 0 : if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
162 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
163 0 : goto bailout;
164 : }
165 0 : canditer_init(&ci1, b, bs);
166 0 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
167 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
168 0 : goto bailout;
169 : }
170 :
171 0 : off1 = b->hseqbase;
172 0 : bi = bat_iterator(b);
173 0 : src = (TYPE *) bi.base;
174 0 : dst = (TYPE *) Tloc(bn, 0);
175 0 : if (ci1.tpe == cand_dense) {
176 0 : for (BUN i = 0; i < ci1.ncand; i++) {
177 0 : oid p1 = (canditer_next_dense(&ci1) - off1);
178 0 : r = src[p1];
179 :
180 0 : if (ISNIL(TYPE)(r)) {
181 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
182 0 : goto bailout1;
183 0 : } else if (r <= 0) {
184 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
185 0 : goto bailout1;
186 0 : } else if (ISNIL(TYPE)(x)) {
187 0 : dst[i] = NIL(TYPE);
188 0 : nils = true;
189 : } else {
190 0 : dst[i] = dec_round_body(x, r);
191 : }
192 : }
193 : } else {
194 0 : for (BUN i = 0; i < ci1.ncand; i++) {
195 0 : oid p1 = (canditer_next(&ci1) - off1);
196 0 : r = src[p1];
197 :
198 0 : if (ISNIL(TYPE)(r)) {
199 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
200 0 : goto bailout1;
201 0 : } else if (r <= 0) {
202 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
203 0 : goto bailout1;
204 0 : } else if (ISNIL(TYPE)(x)) {
205 0 : dst[i] = NIL(TYPE);
206 0 : nils = true;
207 : } else {
208 0 : dst[i] = dec_round_body(x, r);
209 : }
210 : }
211 : }
212 0 : bailout1:
213 0 : bat_iterator_end(&bi);
214 :
215 0 : bailout:
216 0 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, false, false/* don't propagate here*/);
217 0 : unfix_inputs(2, b, bs);
218 0 : return msg;
219 : }
220 :
221 : str
222 0 : bat_dec_round_wrap_nocst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
223 : {
224 0 : BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
225 0 : TYPE *src1, *src2, *restrict dst, x, rr;
226 0 : str msg = MAL_SUCCEED;
227 0 : bool nils = false;
228 0 : struct canditer ci1 = {0}, ci2 = {0};
229 0 : oid off1, off2;
230 0 : bat *res = getArgReference_bat(stk, pci, 0), *l = getArgReference_bat(stk, pci, 1),
231 0 : *r = getArgReference_bat(stk, pci, 2),
232 0 : *sid1 = pci->argc == 5 ? getArgReference_bat(stk, pci, 3) : NULL,
233 0 : *sid2 = pci->argc == 5 ? getArgReference_bat(stk, pci, 4) : NULL;
234 0 : BATiter lefti, righti;
235 :
236 0 : (void) cntxt;
237 0 : (void) mb;
238 0 : if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
239 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
240 0 : goto bailout;
241 : }
242 0 : if (left->ttype != TPE(TYPE) || right->ttype != TPE(TYPE)) {
243 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Arguments must have a " STRING(TYPE) " tail");
244 0 : goto bailout;
245 : }
246 0 : if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
247 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
248 0 : goto bailout;
249 : }
250 0 : canditer_init(&ci1, left, lefts);
251 0 : canditer_init(&ci2, right, rights);
252 0 : if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
253 0 : msg = createException(MAL, "round", ILLEGAL_ARGUMENT " Requires bats of identical size");
254 0 : goto bailout;
255 : }
256 0 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
257 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
258 0 : goto bailout;
259 : }
260 :
261 0 : off1 = left->hseqbase;
262 0 : off2 = right->hseqbase;
263 0 : lefti = bat_iterator(left);
264 0 : righti = bat_iterator(right);
265 0 : src1 = (TYPE *) lefti.base;
266 0 : src2 = (TYPE *) righti.base;
267 0 : dst = (TYPE *) Tloc(bn, 0);
268 0 : if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
269 0 : for (BUN i = 0; i < ci1.ncand; i++) {
270 0 : oid p1 = (canditer_next_dense(&ci1) - off1), p2 = (canditer_next_dense(&ci2) - off2);
271 0 : x = src1[p1];
272 0 : rr = src2[p2];
273 :
274 0 : if (ISNIL(TYPE)(rr)) {
275 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
276 0 : goto bailout1;
277 0 : } else if (rr <= 0) {
278 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
279 0 : goto bailout1;
280 0 : } else if (ISNIL(TYPE)(x)) {
281 0 : dst[i] = NIL(TYPE);
282 0 : nils = true;
283 : } else {
284 0 : dst[i] = dec_round_body(x, rr);
285 : }
286 : }
287 : } else {
288 0 : for (BUN i = 0; i < ci1.ncand; i++) {
289 0 : oid p1 = (canditer_next(&ci1) - off1), p2 = (canditer_next(&ci2) - off2);
290 0 : x = src1[p1];
291 0 : rr = src2[p2];
292 :
293 0 : if (ISNIL(TYPE)(rr)) {
294 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function cannot be null");
295 0 : goto bailout1;
296 0 : } else if (rr <= 0) {
297 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 to round function must be positive");
298 0 : goto bailout1;
299 0 : } else if (ISNIL(TYPE)(x)) {
300 0 : dst[i] = NIL(TYPE);
301 0 : nils = true;
302 : } else {
303 0 : dst[i] = dec_round_body(x, rr);
304 : }
305 : }
306 : }
307 0 : bailout1:
308 0 : bat_iterator_end(&lefti);
309 0 : bat_iterator_end(&righti);
310 :
311 0 : bailout:
312 0 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, false, false/* don't propagate here*/);
313 0 : unfix_inputs(4, left, lefts, right, rights);
314 0 : return msg;
315 : }
316 :
317 : static inline TYPE
318 18692 : round_body(TYPE v, int d, int s, int r)
319 : {
320 18692 : TYPE res = NIL(TYPE);
321 :
322 18692 : assert(!ISNIL(TYPE)(v));
323 :
324 18692 : if (r > 0 && r < s) {
325 17817 : int dff = s - r;
326 17817 : BIG rnd = scales[dff] >> 1;
327 17817 : BIG lres;
328 17817 : if (v > 0)
329 17817 : lres = ((v + rnd) / scales[dff]) * scales[dff];
330 : else
331 0 : lres = ((v - rnd) / scales[dff]) * scales[dff];
332 7 : res = (TYPE) lres;
333 875 : } else if (r <= 0 && -r > -s) {
334 25 : int dff = -r + s;
335 25 : if (dff > d) {
336 : res = 0;
337 : } else {
338 21 : BIG rnd = scales[dff] >> 1;
339 21 : BIG lres;
340 21 : if (v > 0)
341 13 : lres = ((v + rnd) / scales[dff]) * scales[dff];
342 : else
343 8 : lres = ((v - rnd) / scales[dff]) * scales[dff];
344 11 : res = (TYPE) lres;
345 : }
346 : } else {
347 : res = v;
348 : }
349 18692 : return res;
350 : }
351 :
352 : str
353 17 : round_wrap(TYPE *res, const TYPE *v, const bte *r, const int *d, const int *s)
354 : {
355 : /* basic sanity checks */
356 17 : assert(res && v && r && d && s);
357 :
358 17 : *res = (ISNIL(TYPE)(*v) || is_bte_nil(*r)) ? NIL(TYPE) : round_body(*v, *d, *s, *r);
359 17 : return MAL_SUCCEED;
360 : }
361 :
362 : str
363 28 : bat_round_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
364 : {
365 28 : BAT *bn = NULL, *b = NULL, *bs = NULL;
366 28 : TYPE *restrict src, *restrict dst, x;
367 28 : bte r = *getArgReference_bte(stk, pci, 2);
368 84 : int d = *getArgReference_int(stk, pci, pci->argc == 6 ? 4 : 3), s = *getArgReference_int(stk, pci, pci->argc == 6 ? 5 : 4);
369 28 : str msg = MAL_SUCCEED;
370 28 : bool nils = false, btsorted = false, btrevsorted = false;
371 28 : struct canditer ci1 = {0};
372 28 : oid off1;
373 28 : bat *res = getArgReference_bat(stk, pci, 0), *bid = getArgReference_bat(stk, pci, 1),
374 28 : *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 3) : NULL;
375 28 : BATiter bi;
376 :
377 28 : (void) cntxt;
378 28 : (void) mb;
379 28 : if (!(b = BATdescriptor(*bid))) {
380 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
381 0 : goto bailout;
382 : }
383 28 : if (b->ttype != TPE(TYPE)) {
384 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail");
385 0 : goto bailout;
386 : }
387 28 : if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
388 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
389 0 : goto bailout;
390 : }
391 28 : canditer_init(&ci1, b, bs);
392 28 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
393 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
394 0 : goto bailout;
395 : }
396 :
397 28 : off1 = b->hseqbase;
398 28 : bi = bat_iterator(b);
399 28 : src = (TYPE *) bi.base;
400 28 : dst = (TYPE *) Tloc(bn, 0);
401 28 : if (ci1.tpe == cand_dense) {
402 18688 : for (BUN i = 0; i < ci1.ncand; i++) {
403 18660 : oid p1 = (canditer_next_dense(&ci1) - off1);
404 18660 : x = src[p1];
405 :
406 18660 : if (ISNIL(TYPE)(x) || is_bte_nil(r)) {
407 4 : dst[i] = NIL(TYPE);
408 4 : nils = true;
409 : } else {
410 18656 : dst[i] = round_body(x, d, s, r);
411 : }
412 : }
413 : } else {
414 0 : for (BUN i = 0; i < ci1.ncand; i++) {
415 0 : oid p1 = (canditer_next(&ci1) - off1);
416 0 : x = src[p1];
417 :
418 0 : if (ISNIL(TYPE)(x) || is_bte_nil(r)) {
419 0 : dst[i] = NIL(TYPE);
420 0 : nils = true;
421 : } else {
422 0 : dst[i] = round_body(x, d, s, r);
423 : }
424 : }
425 : }
426 28 : btsorted = bi.sorted;
427 28 : btrevsorted = bi.revsorted;
428 28 : bat_iterator_end(&bi);
429 :
430 28 : bailout:
431 28 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, btsorted, btrevsorted);
432 28 : unfix_inputs(2, b, bs);
433 28 : return msg;
434 : }
435 :
436 : str
437 8 : bat_round_wrap_cst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
438 : {
439 8 : BAT *bn = NULL, *b = NULL, *bs = NULL;
440 8 : TYPE *restrict dst, x = *(TYPE *)getArgReference(stk, pci, 1);
441 8 : bte *restrict src, r;
442 22 : int d = *getArgReference_int(stk, pci, pci->argc == 6 ? 4 : 3), s = *getArgReference_int(stk, pci, pci->argc == 6 ? 5 : 4);
443 8 : str msg = MAL_SUCCEED;
444 8 : bool nils = false;
445 8 : struct canditer ci1 = {0};
446 8 : oid off1;
447 8 : bat *res = getArgReference_bat(stk, pci, 0), *bid = getArgReference_bat(stk, pci, 2),
448 8 : *sid1 = pci->argc == 6 ? getArgReference_bat(stk, pci, 3) : NULL;
449 8 : BATiter bi;
450 :
451 8 : (void) cntxt;
452 8 : (void) mb;
453 8 : if (!(b = BATdescriptor(*bid))) {
454 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
455 0 : goto bailout;
456 : }
457 8 : if (b->ttype != TYPE_bte) {
458 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 must have a bte tail");
459 0 : goto bailout;
460 : }
461 8 : if (sid1 && !is_bat_nil(*sid1) && !(bs = BATdescriptor(*sid1))) {
462 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
463 0 : goto bailout;
464 : }
465 8 : canditer_init(&ci1, b, bs);
466 8 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
467 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
468 0 : goto bailout;
469 : }
470 :
471 8 : off1 = b->hseqbase;
472 8 : bi = bat_iterator(b);
473 8 : src = (bte *) bi.base;
474 8 : dst = (TYPE *) Tloc(bn, 0);
475 8 : if (ci1.tpe == cand_dense) {
476 26 : for (BUN i = 0; i < ci1.ncand; i++) {
477 18 : oid p1 = (canditer_next_dense(&ci1) - off1);
478 18 : r = src[p1];
479 :
480 18 : if (ISNIL(TYPE)(x) || is_bte_nil(r)) {
481 0 : dst[i] = NIL(TYPE);
482 0 : nils = true;
483 : } else {
484 18 : dst[i] = round_body(x, d, s, r);
485 : }
486 : }
487 : } else {
488 0 : for (BUN i = 0; i < ci1.ncand; i++) {
489 0 : oid p1 = (canditer_next(&ci1) - off1);
490 0 : r = src[p1];
491 :
492 0 : if (ISNIL(TYPE)(x) || is_bte_nil(r)) {
493 0 : dst[i] = NIL(TYPE);
494 0 : nils = true;
495 : } else {
496 0 : dst[i] = round_body(x, d, s, r);
497 : }
498 : }
499 : }
500 8 : bat_iterator_end(&bi);
501 :
502 8 : bailout:
503 8 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, false, false/* don't propagate here*/);
504 8 : unfix_inputs(2, b, bs);
505 8 : return msg;
506 : }
507 :
508 : str
509 1 : bat_round_wrap_nocst(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
510 : {
511 1 : BAT *bn = NULL, *left = NULL, *lefts = NULL, *right = NULL, *rights = NULL;
512 1 : TYPE *restrict dst, *src1, x;
513 1 : bte *src2, rr;
514 3 : int d = *getArgReference_int(stk, pci, pci->argc == 7 ? 5 : 3), s = *getArgReference_int(stk, pci, pci->argc == 7 ? 6 : 4);
515 1 : str msg = MAL_SUCCEED;
516 1 : bool nils = false;
517 1 : struct canditer ci1 = {0}, ci2 = {0};
518 1 : oid off1, off2;
519 1 : bat *res = getArgReference_bat(stk, pci, 0), *l = getArgReference_bat(stk, pci, 1),
520 1 : *r = getArgReference_bat(stk, pci, 2),
521 1 : *sid1 = pci->argc == 7 ? getArgReference_bat(stk, pci, 3) : NULL,
522 1 : *sid2 = pci->argc == 7 ? getArgReference_bat(stk, pci, 4) : NULL;
523 1 : BATiter lefti, righti;
524 :
525 1 : (void) cntxt;
526 1 : (void) mb;
527 1 : if (!(left = BATdescriptor(*l)) || !(right = BATdescriptor(*r))) {
528 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
529 0 : goto bailout;
530 : }
531 1 : if (left->ttype != TPE(TYPE)) {
532 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 1 must have a " STRING(TYPE) " tail");
533 0 : goto bailout;
534 : }
535 1 : if (right->ttype != TYPE_bte) {
536 0 : msg = createException(MAL, "round", SQLSTATE(42000) "Argument 2 must have a bte tail");
537 0 : goto bailout;
538 : }
539 1 : if ((sid1 && !is_bat_nil(*sid1) && !(lefts = BATdescriptor(*sid1))) || (sid2 && !is_bat_nil(*sid2) && !(rights = BATdescriptor(*sid2)))) {
540 0 : msg = createException(MAL, "round", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
541 0 : goto bailout;
542 : }
543 1 : canditer_init(&ci1, left, lefts);
544 1 : canditer_init(&ci2, right, rights);
545 1 : if (ci2.ncand != ci1.ncand || ci1.hseq != ci2.hseq) {
546 0 : msg = createException(MAL, "round", ILLEGAL_ARGUMENT " Requires bats of identical size");
547 0 : goto bailout;
548 : }
549 1 : if (!(bn = COLnew(ci1.hseq, TPE(TYPE), ci1.ncand, TRANSIENT))) {
550 0 : msg = createException(MAL, "round", SQLSTATE(HY013) MAL_MALLOC_FAIL);
551 0 : goto bailout;
552 : }
553 :
554 1 : off1 = left->hseqbase;
555 1 : off2 = right->hseqbase;
556 1 : lefti = bat_iterator(left);
557 1 : righti = bat_iterator(right);
558 1 : src1 = (TYPE *) lefti.base;
559 1 : src2 = (bte *) righti.base;
560 1 : dst = (TYPE *) Tloc(bn, 0);
561 1 : if (ci1.tpe == cand_dense && ci2.tpe == cand_dense) {
562 2 : for (BUN i = 0; i < ci1.ncand; i++) {
563 1 : oid p1 = (canditer_next_dense(&ci1) - off1), p2 = (canditer_next_dense(&ci2) - off2);
564 1 : x = src1[p1];
565 1 : rr = src2[p2];
566 :
567 1 : if (ISNIL(TYPE)(x) || is_bte_nil(rr)) {
568 0 : dst[i] = NIL(TYPE);
569 0 : nils = true;
570 : } else {
571 1 : dst[i] = round_body(x, d, s, rr);
572 : }
573 : }
574 : } else {
575 0 : for (BUN i = 0; i < ci1.ncand; i++) {
576 0 : oid p1 = (canditer_next(&ci1) - off1), p2 = (canditer_next(&ci2) - off2);
577 0 : x = src1[p1];
578 0 : rr = src2[p2];
579 :
580 0 : if (ISNIL(TYPE)(x) || is_bte_nil(rr)) {
581 0 : dst[i] = NIL(TYPE);
582 0 : nils = true;
583 : } else {
584 0 : dst[i] = round_body(x, d, s, rr);
585 : }
586 : }
587 : }
588 1 : bat_iterator_end(&lefti);
589 1 : bat_iterator_end(&righti);
590 :
591 1 : bailout:
592 1 : finalize_ouput_copy_sorted_property(res, bn, msg, nils, ci1.ncand, false, false/* don't propagate here*/);
593 1 : unfix_inputs(4, left, lefts, right, rights);
594 1 : return msg;
595 : }
596 :
597 : str
598 0 : nil_2dec(TYPE *res, const void *val, const int *d, const int *sc)
599 : {
600 0 : (void) val;
601 0 : (void) d;
602 0 : (void) sc;
603 :
604 0 : *res = NIL(TYPE);
605 0 : return MAL_SUCCEED;
606 : }
607 :
608 : static inline str
609 674 : str_2dec_body(TYPE *res, const char *val, const int d, const int sc)
610 : {
611 674 : const char *s = val;
612 674 : int digits;
613 674 : int scale;
614 674 : BIG value;
615 :
616 674 : if (d < 0 || d >= (int) (sizeof(scales) / sizeof(scales[0])))
617 0 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)", s, d, sc);
618 :
619 674 : int has_errors;
620 674 : value = 0;
621 :
622 : // s = strip_extra_zeros(s);
623 :
624 674 : value = decimal_from_str(s, &digits, &scale, &has_errors);
625 674 : if (has_errors)
626 77 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)", s, d, sc);
627 :
628 : // handle situations where the de facto scale is different from the formal scale.
629 597 : if (scale < sc) {
630 : /* the current scale is too small, increase it by adding 0's */
631 414 : int dff = sc - scale; /* CANNOT be 0! */
632 414 : if (dff >= MAX_SCALE)
633 0 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Rounding of decimal (%s) doesn't fit format (%d.%d)", s, d, sc);
634 :
635 414 : value *= scales[dff];
636 414 : scale += dff;
637 414 : digits += dff;
638 183 : } else if (scale > sc) {
639 : /* the current scale is too big, decrease it by correctly rounding */
640 : /* we should round properly, and check for overflow (res >= 10^digits+scale) */
641 121 : int dff = scale - sc; /* CANNOT be 0 */
642 :
643 121 : if (dff >= MAX_SCALE)
644 0 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Rounding of decimal (%s) doesn't fit format (%d.%d)", s, d, sc);
645 :
646 121 : BIG rnd = scales[dff] >> 1;
647 :
648 121 : if (value > 0)
649 84 : value += rnd;
650 : else
651 37 : value -= rnd;
652 121 : value /= scales[dff];
653 121 : scale -= dff;
654 121 : digits -= dff;
655 121 : if (value >= scales[d] || value <= -scales[d])
656 14 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Rounding of decimal (%s) doesn't fit format (%d.%d)", s, d, sc);
657 : }
658 583 : if (value <= -scales[d] || value >= scales[d])
659 2 : throw(SQL, STRING(TYPE), SQLSTATE(42000) "Decimal (%s) doesn't have format (%d.%d)", s, d, sc);
660 581 : *res = (TYPE) value;
661 581 : return MAL_SUCCEED;
662 : }
663 :
664 : str
665 579 : str_2dec(TYPE *res, const str *val, const int *d, const int *sc)
666 : {
667 579 : str v = *val;
668 :
669 579 : if (strNil(v)) {
670 0 : *res = NIL(TYPE);
671 0 : return MAL_SUCCEED;
672 : } else {
673 579 : return str_2dec_body(res, v, *d, *sc);
674 : }
675 : }
676 :
677 : str
678 0 : batnil_2dec(bat *res, const bat *bid, const int *d, const int *sc)
679 : {
680 0 : BAT *b, *dst;
681 0 : BUN p, q;
682 :
683 0 : (void) d;
684 0 : (void) sc;
685 0 : if ((b = BATdescriptor(*bid)) == NULL) {
686 0 : throw(SQL, "batcalc.nil_2dec_" STRING(TYPE), SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
687 : }
688 0 : dst = COLnew(b->hseqbase, TPE(TYPE), BATcount(b), TRANSIENT);
689 0 : if (dst == NULL) {
690 0 : BBPunfix(b->batCacheid);
691 0 : throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY013) MAL_MALLOC_FAIL);
692 : }
693 0 : const TYPE r = NIL(TYPE);
694 0 : BATloop(b, p, q) {
695 0 : if (BUNappend(dst, &r, false) != GDK_SUCCEED) {
696 0 : BBPunfix(b->batCacheid);
697 0 : BBPreclaim(dst);
698 0 : throw(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY013) MAL_MALLOC_FAIL);
699 : }
700 : }
701 0 : *res = dst->batCacheid;
702 0 : BBPkeepref(dst);
703 0 : BBPunfix(b->batCacheid);
704 0 : return MAL_SUCCEED;
705 : }
706 :
707 : str
708 47 : batstr_2dec(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
709 : {
710 47 : str msg = MAL_SUCCEED;
711 47 : int d = *getArgReference_int(stk, pci, pci->argc == 5 ? 3 : 2), sk = *getArgReference_int(stk, pci, pci->argc == 5 ? 4 : 3);
712 47 : BAT *b = NULL, *s = NULL, *res = NULL;
713 47 : bat *r = getArgReference_bat(stk, pci, 0), *sid = pci->argc == 5 ? getArgReference_bat(stk, pci, 2) : NULL;
714 47 : BATiter bi;
715 47 : oid off;
716 47 : struct canditer ci = {0};
717 47 : TYPE *restrict ret;
718 47 : bool nils = false;
719 :
720 47 : (void) cntxt;
721 47 : (void) mb;
722 47 : if (!(b = BATdescriptor(*getArgReference_bat(stk, pci, 1)))) {
723 0 : msg = createException(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
724 0 : goto bailout;
725 : }
726 47 : bi = bat_iterator(b);
727 47 : if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
728 0 : msg = createException(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
729 0 : goto bailout1;
730 : }
731 47 : off = b->hseqbase;
732 47 : canditer_init(&ci, b, s);
733 47 : if (!(res = COLnew(ci.hseq, TPE(TYPE), ci.ncand, TRANSIENT))) {
734 0 : msg = createException(SQL, "sql.dec_" STRING(TYPE), SQLSTATE(HY013) MAL_MALLOC_FAIL);
735 0 : goto bailout1;
736 : }
737 47 : ret = (TYPE*) Tloc(res, 0);
738 :
739 47 : if (ci.tpe == cand_dense) {
740 141 : for (BUN i = 0; i < ci.ncand; i++) {
741 95 : oid p = (canditer_next_dense(&ci) - off);
742 95 : const char *next = BUNtail(bi, p);
743 :
744 95 : if (strNil(next)) {
745 0 : ret[i] = NIL(TYPE);
746 0 : nils = true;
747 95 : } else if ((msg = str_2dec_body(&(ret[i]), next, d, sk)))
748 1 : goto bailout1;
749 : }
750 : } else {
751 0 : for (BUN i = 0; i < ci.ncand; i++) {
752 0 : oid p = (canditer_next(&ci) - off);
753 0 : const char *next = BUNtail(bi, p);
754 :
755 0 : if (strNil(next)) {
756 0 : ret[i] = NIL(TYPE);
757 0 : nils = true;
758 0 : } else if ((msg = str_2dec_body(&(ret[i]), next, d, sk)))
759 0 : goto bailout1;
760 : }
761 : }
762 0 : bailout1:
763 47 : bat_iterator_end(&bi);
764 :
765 47 : bailout:
766 47 : finalize_ouput_copy_sorted_property(r, res, msg, nils, ci.ncand, false, false/* don't propagate here*/);
767 47 : unfix_inputs(2, b, s);
768 47 : return msg;
769 : }
770 :
771 : str
772 0 : dec2second_interval(lng *res, const int *sc, const TYPE *dec, const int *ek, const int *sk)
773 : {
774 0 : BIG value = *dec;
775 0 : int scale = *sc;
776 :
777 0 : if (is_int_nil(scale))
778 0 : throw(SQL, "calc.dec2second_interval", SQLSTATE(42000) "Scale cannot be NULL");
779 0 : if (scale < 0 || (size_t) scale >= sizeof(scales) / sizeof(scales[0]))
780 0 : throw(SQL, "calc.dec2second_interval", SQLSTATE(42000) "Scale out of bounds");
781 :
782 0 : (void) ek;
783 0 : (void) sk;
784 0 : if (ISNIL(TYPE)(*dec)) {
785 0 : value = lng_nil;
786 0 : } else if (scale < 3) {
787 0 : int d = 3 - scale;
788 0 : value *= scales[d];
789 0 : } else if (scale > 3) {
790 0 : int d = scale - 3;
791 0 : lng rnd = scales[d] >> 1;
792 :
793 0 : value += rnd;
794 0 : value /= scales[d];
795 : }
796 0 : *res = value;
797 0 : return MAL_SUCCEED;
798 : }
799 :
800 : str
801 0 : batdec2second_interval(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
802 : {
803 0 : str msg = MAL_SUCCEED;
804 0 : int sc = *getArgReference_int(stk, pci, 1);
805 0 : BAT *b = NULL, *s = NULL, *res = NULL;
806 0 : bat *r = getArgReference_bat(stk, pci, 0), *sid = pci->argc == 6 ? getArgReference_bat(stk, pci, 3) : NULL;
807 0 : oid off;
808 0 : struct canditer ci = {0};
809 0 : TYPE *restrict src;
810 0 : BIG *restrict ret, multiplier = 1, divider = 1, offset = 0;
811 0 : bool nils = false;
812 0 : BATiter bi;
813 :
814 0 : (void) cntxt;
815 0 : (void) mb;
816 0 : if (is_int_nil(sc)) {
817 0 : msg = createException(SQL, "batcalc.batdec2second_interval", SQLSTATE(42000) "Scale cannot be NULL");
818 0 : goto bailout;
819 : }
820 0 : if (sc < 0 || (size_t) sc >= sizeof(scales) / sizeof(scales[0])) {
821 0 : msg = createException(SQL, "batcalc.batdec2second_interval", SQLSTATE(42000) "Scale out of bounds");
822 0 : goto bailout;
823 : }
824 0 : if (!(b = BATdescriptor(*getArgReference_bat(stk, pci, 2)))) {
825 0 : msg = createException(SQL, "batcalc.batdec2second_interval", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
826 0 : goto bailout;
827 : }
828 0 : if (sid && !is_bat_nil(*sid) && (s = BATdescriptor(*sid)) == NULL) {
829 0 : msg = createException(SQL, "batcalc.batdec2second_interval", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
830 0 : goto bailout;
831 : }
832 0 : off = b->hseqbase;
833 0 : canditer_init(&ci, b, s);
834 0 : if (!(res = COLnew(ci.hseq, TYPE_lng, ci.ncand, TRANSIENT))) {
835 0 : msg = createException(SQL, "batcalc.batdec2second_interval", SQLSTATE(HY013) MAL_MALLOC_FAIL);
836 0 : goto bailout;
837 : }
838 0 : bi = bat_iterator(b);
839 0 : src = bi.base;
840 0 : ret = Tloc(res, 0);
841 :
842 0 : if (sc < 3) {
843 0 : int d = 3 - sc;
844 0 : multiplier = scales[d];
845 0 : } else if (sc > 3) {
846 0 : int d = sc - 3;
847 0 : lng rnd = scales[d] >> 1;
848 :
849 0 : offset = rnd;
850 0 : divider = scales[d];
851 : }
852 :
853 : /* the cast from decimal to interval is now deactivated. So adding the canditer_next_dense case is not worth */
854 0 : if (sc < 3) {
855 0 : for (BUN i = 0 ; i < ci.ncand ; i++) {
856 0 : oid p = (canditer_next(&ci) - off);
857 0 : if (ISNIL(TYPE)(src[p])) {
858 0 : ret[i] = lng_nil;
859 0 : nils = true;
860 : } else {
861 0 : BIG next = (BIG) src[p];
862 0 : next *= multiplier;
863 0 : ret[i] = next;
864 : }
865 : }
866 0 : } else if (sc > 3) {
867 0 : for (BUN i = 0 ; i < ci.ncand ; i++) {
868 0 : oid p = (canditer_next(&ci) - off);
869 0 : if (ISNIL(TYPE)(src[p])) {
870 0 : ret[i] = lng_nil;
871 0 : nils = true;
872 : } else {
873 0 : BIG next = (BIG) src[p];
874 0 : next += offset;
875 0 : next /= divider;
876 0 : ret[i] = next;
877 : }
878 : }
879 : } else {
880 0 : for (BUN i = 0 ; i < ci.ncand ; i++) {
881 0 : oid p = (canditer_next(&ci) - off);
882 0 : if (ISNIL(TYPE)(src[p])) {
883 0 : ret[i] = lng_nil;
884 0 : nils = true;
885 : } else {
886 0 : ret[i] = (BIG) src[p];
887 : }
888 : }
889 : }
890 0 : bat_iterator_end(&bi);
891 :
892 0 : bailout:
893 0 : finalize_ouput_copy_sorted_property(r, res, msg, nils, ci.ncand, false, false/* don't propagate here*/);
894 0 : unfix_inputs(2, b, s);
895 0 : return msg;
896 : }
897 :
898 : #undef dec_round_body
899 : #undef dec_round_wrap
900 : #undef bat_dec_round_wrap
901 : #undef bat_dec_round_wrap_cst
902 : #undef bat_dec_round_wrap_nocst
903 : #undef round_body
904 : #undef round_wrap
905 : #undef bat_round_wrap
906 : #undef bat_round_wrap_cst
907 : #undef bat_round_wrap_nocst
908 : #undef nil_2dec
909 : #undef str_2dec_body
910 : #undef str_2dec
911 : #undef batnil_2dec
912 : #undef batstr_2dec
913 : #undef dec2second_interval
914 : #undef batdec2second_interval
|