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 * (c) Martin Kersten, Sjoerd Mullender
11 * Series generating module for integer, decimal, real, double and timestamps.
12 */
13
14#include "monetdb_config.h"
15#include "opt_prelude.h"
16#include "algebra.h"
17#include "generator.h"
18#include "mtime.h"
19#include <math.h>
20
21
22#define IDENTITY(x) (x)
23
24/*
25 * The noop simply means that we keep the properties for the generator object.
26 */
27#define VLTnoop(TPE) \
28 do { \
29 TPE s; \
30 s = pci->argc == 3 ? 1: *getArgReference_##TPE(stk,pci, 3); \
31 zeroerror = (s == 0); \
32 nullerr = is_##TPE##_nil(s); \
33 } while (0)
34
35str
36VLTgenerator_noop(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
37{
38 int nullerr= 0, zeroerror=0, tpe;
39 (void) cntxt;
40
41 switch( tpe = getArgType(mb,pci,1)){
42 case TYPE_bte: VLTnoop(bte); break;
43 case TYPE_sht: VLTnoop(sht); break;
44 case TYPE_int: VLTnoop(int); break;
45 case TYPE_lng: VLTnoop(lng); break;
46#ifdef HAVE_HGE
47 case TYPE_hge: VLTnoop(hge); break;
48#endif
49 case TYPE_flt: VLTnoop(flt); break;
50 case TYPE_dbl: VLTnoop(dbl); break;
51 default:
52 if (tpe == TYPE_timestamp){
53 /* with timestamp, step is of SQL type "interval seconds",
54 * i.e., MAL / C type "lng" */
55 VLTnoop(lng);
56 } else throw(MAL,"generator.noop", SQLSTATE(42000) "unknown data type %d", getArgType(mb,pci,1));
57 }
58 if( zeroerror)
59 throw(MAL,"generator.noop", SQLSTATE(42000) "Zero step size not allowed");
60 if( nullerr)
61 throw(MAL,"generator.noop", SQLSTATE(42000) "Null step size not allowed");
62 return MAL_SUCCEED;
63}
64
65/*
66 * The base line consists of materializing the generator iterator value
67 */
68#define VLTmaterialize(TPE) \
69 do { \
70 TPE *v, f, l, s; \
71 f = *getArgReference_##TPE(stk, pci, 1); \
72 l = *getArgReference_##TPE(stk, pci, 2); \
73 if ( pci->argc == 3) \
74 s = f<l? (TPE) 1: (TPE)-1; \
75 else s = *getArgReference_##TPE(stk,pci, 3); \
76 if (s == 0 || (s > 0 && f > l) || (s < 0 && f < l) || is_##TPE##_nil(f) || is_##TPE##_nil(l)) \
77 throw(MAL, "generator.table", \
78 SQLSTATE(42000) "Illegal generator range"); \
79 n = (BUN) ((l - f) / s); \
80 if ((TPE) (n * s + f) != l) \
81 n++; \
82 bn = COLnew(0, TYPE_##TPE, n, TRANSIENT); \
83 if (bn == NULL) \
84 throw(MAL, "generator.table", SQLSTATE(HY001) MAL_MALLOC_FAIL); \
85 v = (TPE*) Tloc(bn, 0); \
86 for (c = 0; c < n; c++) \
87 *v++ = (TPE) (f + c * s); \
88 bn->tsorted = s > 0 || n <= 1; \
89 bn->trevsorted = s < 0 || n <= 1; \
90 } while (0)
91
92static str
93VLTgenerator_table_(BAT **result, Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
94{
95 BUN c, n;
96 BAT *bn;
97 int tpe;
98 (void) cntxt;
99
100 *result = NULL;
101 tpe = getArgType(mb, pci, 1);
102 switch (tpe) {
103 case TYPE_bte:
104 VLTmaterialize(bte);
105 break;
106 case TYPE_sht:
107 VLTmaterialize(sht);
108 break;
109 case TYPE_int:
110 VLTmaterialize(int);
111 break;
112 case TYPE_lng:
113 VLTmaterialize(lng);
114 break;
115#ifdef HAVE_HGE
116 case TYPE_hge:
117 VLTmaterialize(hge);
118 break;
119#endif
120 case TYPE_flt:
121 VLTmaterialize(flt);
122 break;
123 case TYPE_dbl:
124 VLTmaterialize(dbl);
125 break;
126 default:
127 if (tpe == TYPE_timestamp) {
128 timestamp *v,f,l;
129 lng s;
130 ValRecord ret;
131 if (VARcalccmp(&ret, &stk->stk[pci->argv[1]],
132 &stk->stk[pci->argv[2]]) != GDK_SUCCEED)
133 throw(MAL, "generator.table",
134 SQLSTATE(42000) "Illegal generator expression range");
135 f = *getArgReference_TYPE(stk, pci, 1, timestamp);
136 l = *getArgReference_TYPE(stk, pci, 2, timestamp);
137 if ( pci->argc == 3)
138 throw(MAL,"generator.table", SQLSTATE(42000) "Timestamp step missing");
139 s = *getArgReference_lng(stk, pci, 3);
140 if (s == 0 ||
141 (s > 0 && ret.val.btval > 0) ||
142 (s < 0 && ret.val.btval < 0) ||
143 is_timestamp_nil(f) || is_timestamp_nil(l))
144 throw(MAL, "generator.table",
145 SQLSTATE(42000) "Illegal generator range");
146 /* casting one value to lng causes the whole
147 * computation to be done as lng, reducing the
148 * risk of overflow */
149 s *= 1000; /* msec -> usec */
150 n = (BUN) (timestamp_diff(l, f) / s);
151 bn = COLnew(0, TYPE_timestamp, n + 1, TRANSIENT);
152 if (bn == NULL)
153 throw(MAL, "generator.table", SQLSTATE(HY001) MAL_MALLOC_FAIL);
154 v = (timestamp *) Tloc(bn, 0);
155 for (c = 0; c < n; c++) {
156 *v++ = f;
157 f = timestamp_add_usec(f, s);
158 if (is_timestamp_nil(f)) {
159 BBPreclaim(bn);
160 throw(MAL, "generator.table", SQLSTATE(22003) "overflow in calculation");
161 }
162 }
163 if (f != l) {
164 *v++ = f;
165 n++;
166 }
167 bn->tsorted = s > 0 || n <= 1;
168 bn->trevsorted = s < 0 || n <= 1;
169 } else {
170 throw(MAL, "generator.table", SQLSTATE(42000) "Unsupported type");
171 }
172 break;
173 }
174 BATsetcount(bn, c);
175 bn->tkey = true;
176 bn->tnil = false;
177 bn->tnonil = true;
178 *result = bn;
179 return MAL_SUCCEED;
180}
181
182str
183VLTgenerator_table(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
184{
185 str msg;
186 BAT *bn = NULL;
187
188 if ((msg = VLTgenerator_noop(cntxt, mb, stk, pci)) != MAL_SUCCEED)
189 return msg;
190
191 msg = VLTgenerator_table_(&bn, cntxt, mb, stk, pci);
192 if( msg == MAL_SUCCEED){
193 *getArgReference_bat(stk, pci, 0) = bn->batCacheid;
194 BBPkeepref(bn->batCacheid);
195 }
196 return msg;
197}
198
199/*
200 * Selection over the generator table does not require a materialization of the table
201 * An optimizer can replace the subselect directly into a generator specific one.
202 * The target to look for is generator.series(A1,A2,A3)
203 * We need the generator parameters, which are injected to replace the target column
204 */
205static InstrPtr
206findGeneratorDefinition(MalBlkPtr mb, InstrPtr pci, int target)
207{
208 InstrPtr q, p = NULL;
209 int i;
210
211 for (i = 1; i < mb->stop; i++) {
212 q = getInstrPtr(mb, i);
213 if (q->argv[0] == target && getModuleId(q) == generatorRef && (getFunctionId(q) == parametersRef || getFunctionId(q) == seriesRef))
214 p = q;
215 if (q == pci)
216 return p;
217 }
218 return p;
219}
220
221#define calculate_range(TPE, TPE2) \
222 do { \
223 TPE f, l, s, low, hgh; \
224 \
225 f = * getArgReference_##TPE(stk, p, 1); \
226 l = * getArgReference_##TPE(stk, p, 2); \
227 if ( p->argc == 3) \
228 s = f<l? (TPE) 1: (TPE)-1; \
229 else s = * getArgReference_##TPE(stk, p, 3); \
230 if (s == 0 || (s > 0 && f > l) || (s < 0 && f < l) || is_##TPE##_nil(f) || is_##TPE##_nil(l)) \
231 throw(MAL, "generator.select", \
232 SQLSTATE(42000) "Illegal generator range"); \
233 n = (BUN) (((TPE2) l - (TPE2) f) / (TPE2) s); \
234 if ((TPE)(n * s + f) != l) \
235 n++; \
236 \
237 low = * getArgReference_##TPE(stk, pci, i); \
238 hgh = * getArgReference_##TPE(stk, pci, i + 1); \
239 \
240 if (!is_##TPE##_nil(low) && low == hgh) \
241 hi = li; \
242 if (is_##TPE##_nil(low) && is_##TPE##_nil(hgh)) { \
243 if (li && hi && !anti) { \
244 /* match NILs (of which there aren't */ \
245 /* any) */ \
246 o1 = o2 = 0; \
247 } else { \
248 /* match all non-NIL values, */ \
249 /* i.e. everything */ \
250 o1 = 0; \
251 o2 = (oid) n; \
252 } \
253 } else if (s > 0) { \
254 if (is_##TPE##_nil(low) || low < f) \
255 o1 = 0; \
256 else { \
257 o1 = (oid) (((TPE2) low - (TPE2) f) / (TPE2) s); \
258 if ((TPE) (f + o1 * s) < low || \
259 (!li && (TPE) (f + o1 * s) == low)) \
260 o1++; \
261 } \
262 if (is_##TPE##_nil(hgh)) \
263 o2 = (oid) n; \
264 else if (hgh < f) \
265 o2 = 0; \
266 else { \
267 o2 = (oid) (((TPE2) hgh - (TPE2) f) / (TPE2) s); \
268 if ((hi && (TPE) (f + o2 * s) == hgh) || \
269 (TPE) (f + o2 * s) < hgh) \
270 o2++; \
271 } \
272 } else { \
273 if (is_##TPE##_nil(low)) \
274 o2 = (oid) n; \
275 else if (low > f) \
276 o2 = 0; \
277 else { \
278 o2 = (oid) (((TPE2) low - (TPE2) f) / (TPE2) s); \
279 if ((li && (TPE) (f + o2 * s) == low) || \
280 (TPE) (f + o2 * s) > low) \
281 o2++; \
282 } \
283 if (is_##TPE##_nil(hgh) || hgh > f) \
284 o1 = 0; \
285 else { \
286 o1 = (oid) (((TPE2) hgh - (TPE2) f) / (TPE2) s); \
287 if ((!hi && (TPE) (f + o1 * s) == hgh) || \
288 (TPE) (f + o1 * s) > hgh) \
289 o1++; \
290 } \
291 } \
292 } while (0)
293
294str
295VLTgenerator_subselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
296{
297 bit li, hi, anti;
298 int i;
299 oid o1, o2;
300 BUN n = 0;
301 BAT *bn, *cand = NULL;
302 struct canditer ci = (struct canditer) {.tpe = cand_dense};
303 InstrPtr p;
304 int tpe;
305
306 (void) cntxt;
307 p = findGeneratorDefinition(mb, pci, pci->argv[1]);
308 if (p == NULL)
309 throw(MAL, "generator.select",
310 SQLSTATE(42000) "Could not locate definition for object");
311
312 if (pci->argc == 8) { /* candidate list included */
313 bat candid = *getArgReference_bat(stk, pci, 2);
314 if (candid) {
315 cand = BATdescriptor(candid);
316 if (cand == NULL)
317 throw(MAL, "generator.select",
318 SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
319 canditer_init(&ci, NULL, cand);
320 }
321 i = 3;
322 } else
323 i = 2;
324
325 li = * getArgReference_bit(stk, pci, i + 2);
326 hi = * getArgReference_bit(stk, pci, i + 3);
327 anti = * getArgReference_bit(stk, pci, i + 4);
328
329 switch ( tpe = getArgType(mb, pci, i)) {
330 case TYPE_bte: calculate_range(bte, sht); break;
331 case TYPE_sht: calculate_range(sht, int); break;
332 case TYPE_int: calculate_range(int, lng); break;
333#ifndef HAVE_HGE
334 case TYPE_lng: calculate_range(lng, lng); break;
335#else
336 case TYPE_lng: calculate_range(lng, hge); break;
337 case TYPE_hge: calculate_range(hge, hge); break;
338#endif
339 case TYPE_flt: calculate_range(flt, dbl); break;
340 case TYPE_dbl: calculate_range(dbl, dbl); break;
341 default:
342 if( tpe == TYPE_timestamp){
343 timestamp tsf,tsl;
344 timestamp tlow,thgh;
345 lng tss;
346 oid *ol;
347
348 tsf = *getArgReference_TYPE(stk, p, 1, timestamp);
349 tsl = *getArgReference_TYPE(stk, p, 2, timestamp);
350 if ( p->argc == 3)
351 throw(MAL,"generator.table", SQLSTATE(42000) "Timestamp step missing");
352 tss = *getArgReference_lng(stk, p, 3);
353 if ( tss == 0 ||
354 is_timestamp_nil(tsf) || is_timestamp_nil(tsl) ||
355 (tss > 0 && tsf > tsl ) ||
356 (tss < 0 && tsf < tsl )
357 )
358 throw(MAL, "generator.select", SQLSTATE(42000) "Illegal generator range");
359
360 tlow = *getArgReference_TYPE(stk,pci,i, timestamp);
361 thgh = *getArgReference_TYPE(stk,pci,i+1, timestamp);
362
363 if (!is_timestamp_nil(tlow) && tlow == thgh)
364 hi = li;
365 if( hi && !is_timestamp_nil(thgh)) {
366 thgh = timestamp_add_usec(thgh, 1);
367 if (is_timestamp_nil(thgh))
368 throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation");
369 }
370 if( !li && !is_timestamp_nil(tlow)) {
371 tlow = timestamp_add_usec(tlow, 1);
372 if (is_timestamp_nil(tlow))
373 throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation");
374 }
375
376 /* casting one value to lng causes the whole
377 * computation to be done as lng, reducing the
378 * risk of overflow */
379 tss *= 1000; /* msec -> usec */
380 o2 = (BUN) (timestamp_diff(tsl, tsf) / tss);
381 bn = COLnew(0, TYPE_oid, o2 + 1, TRANSIENT);
382 if (bn == NULL)
383 throw(MAL, "generator.select", SQLSTATE(HY001) MAL_MALLOC_FAIL);
384
385 // simply enumerate the sequence and filter it by predicate and candidate list
386 ol = (oid *) Tloc(bn, 0);
387 for (o1=0; o1 <= o2; o1++) {
388 if(((is_timestamp_nil(tlow) || tsf >= tlow) &&
389 (is_timestamp_nil(thgh) || tsf < thgh)) != anti ){
390 /* could be improved when no candidate list is available into a void/void BAT */
391 if( cand == NULL || canditer_search(&ci, o1, false) != BUN_NONE) {
392 *ol++ = o1;
393 n++;
394 }
395 }
396 tsf = timestamp_add_usec(tsf, tss);
397 if (is_timestamp_nil(tsf)) {
398 BBPreclaim(bn);
399 throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation");
400 }
401 }
402 BATsetcount(bn, (BUN) n);
403 bn->tsorted = true;
404 bn->trevsorted = BATcount(bn) <= 1;
405 bn->tkey = true;
406 bn->tnil = false;
407 bn->tnonil = true;
408 * getArgReference_bat(stk, pci, 0) = bn->batCacheid;
409 BBPkeepref(bn->batCacheid);
410 return MAL_SUCCEED;
411 } else
412 throw(MAL, "generator.select", SQLSTATE(42000) "Unsupported type in select");
413 }
414 if (o1 > (oid) n)
415 o1 = (oid) n;
416 if (o2 > (oid) n)
417 o2 = (oid) n;
418 assert(o1 <= o2);
419 assert(o2 - o1 <= (oid) n);
420 if (anti && o1 == o2) {
421 o1 = 0;
422 o2 = (oid) n;
423 anti = 0;
424 }
425 if (cand) {
426 o1 = canditer_search(&ci, o1, true);
427 o2 = canditer_search(&ci, o2, true);
428 if (anti) {
429 bn = canditer_slice2(&ci, 0, o1, o2, ci.ncand);
430 } else {
431 bn = canditer_slice(&ci, o1, o2);
432 }
433 BBPunfix(cand->batCacheid);
434 if (bn == NULL)
435 throw(MAL, "generator.select",
436 SQLSTATE(HY001) MAL_MALLOC_FAIL);
437 } else {
438 if (anti) {
439 oid o;
440 oid *op;
441
442 bn = COLnew(0, TYPE_oid, n - (o2 - o1), TRANSIENT);
443 if (bn == NULL)
444 throw(MAL, "generator.select",
445 SQLSTATE(HY001) MAL_MALLOC_FAIL);
446 BATsetcount(bn, n - (o2 - o1));
447 op = (oid *) Tloc(bn, 0);
448 for (o = 0; o < o1; o++)
449 *op++ = o;
450 for (o = o2; o < (oid) n; o++)
451 *op++ = o;
452 bn->tnil = false;
453 bn->tnonil = true;
454 bn->tsorted = true;
455 bn->trevsorted = BATcount(bn) <= 1;
456 bn->tkey = true;
457 } else {
458 bn = BATdense(0, o1, (BUN) (o2 - o1));
459 if (bn == NULL)
460 throw(MAL, "generator.select",
461 SQLSTATE(HY001) MAL_MALLOC_FAIL);
462 }
463 }
464 * getArgReference_bat(stk, pci, 0) = bn->batCacheid;
465 BBPkeepref(bn->batCacheid);
466 return MAL_SUCCEED;
467}
468
469#define PREVVALUEbte(x) ((x) - 1)
470#define PREVVALUEsht(x) ((x) - 1)
471#define PREVVALUEint(x) ((x) - 1)
472#define PREVVALUElng(x) ((x) - 1)
473#ifdef HAVE_HGE
474#define PREVVALUEhge(x) ((x) - 1)
475#endif
476#define PREVVALUEoid(x) ((x) - 1)
477#define PREVVALUEflt(x) nextafterf((x), -GDK_flt_max)
478#define PREVVALUEdbl(x) nextafter((x), -GDK_dbl_max)
479
480#define NEXTVALUEbte(x) ((x) + 1)
481#define NEXTVALUEsht(x) ((x) + 1)
482#define NEXTVALUEint(x) ((x) + 1)
483#define NEXTVALUElng(x) ((x) + 1)
484#ifdef HAVE_HGE
485#define NEXTVALUEhge(x) ((x) + 1)
486#endif
487#define NEXTVALUEoid(x) ((x) + 1)
488#define NEXTVALUEflt(x) nextafterf((x), GDK_flt_max)
489#define NEXTVALUEdbl(x) nextafter((x), GDK_dbl_max)
490
491#define HGE_ABS(a) (((a) < 0) ? -(a) : (a))
492
493#define VLTthetasubselect(TPE,ABS) \
494 do { \
495 TPE f,l,s, low, hgh; \
496 BUN j; oid *v; \
497 f = *getArgReference_##TPE(stk,p, 1); \
498 l = *getArgReference_##TPE(stk,p, 2); \
499 if ( p->argc == 3) \
500 s = f<l? (TPE) 1: (TPE)-1; \
501 else s = *getArgReference_##TPE(stk,p, 3); \
502 if( s == 0 || (f<l && s < 0) || (f>l && s> 0)) \
503 throw(MAL,"generator.thetaselect", SQLSTATE(42000) "Illegal range"); \
504 cap = (BUN)(ABS(l-f)/ABS(s)); \
505 bn = COLnew(0, TYPE_oid, cap, TRANSIENT); \
506 if( bn == NULL) \
507 throw(MAL,"generator.thetaselect", SQLSTATE(HY001) MAL_MALLOC_FAIL); \
508 low= hgh = TPE##_nil; \
509 v = (oid*) Tloc(bn,0); \
510 if ( strcmp(oper,"<") == 0){ \
511 hgh= *getArgReference_##TPE(stk,pci,idx); \
512 hgh = PREVVALUE##TPE(hgh); \
513 } else if ( strcmp(oper,"<=") == 0){ \
514 hgh= *getArgReference_##TPE(stk,pci,idx); \
515 } else if ( strcmp(oper,">") == 0){ \
516 low= *getArgReference_##TPE(stk,pci,idx); \
517 low = NEXTVALUE##TPE(low); \
518 } else if ( strcmp(oper,">=") == 0){ \
519 low= *getArgReference_##TPE(stk,pci,idx); \
520 } else if ( strcmp(oper,"!=") == 0 || strcmp(oper, "<>") == 0){ \
521 hgh= low= *getArgReference_##TPE(stk,pci,idx); \
522 anti = 1; \
523 } else if ( strcmp(oper,"==") == 0 || strcmp(oper, "=") == 0){ \
524 hgh= low= *getArgReference_##TPE(stk,pci,idx); \
525 } else \
526 throw(MAL,"generator.thetaselect", SQLSTATE(42000) "Unknown operator"); \
527 for(j=0;j<cap;j++, f+=s, o++) \
528 if( ((is_##TPE##_nil(low) || f >= low) && (is_##TPE##_nil(hgh) || f <= hgh)) != anti){ \
529 if(cand == NULL || canditer_search(&ci, o, false) != BUN_NONE) { \
530 *v++ = o; \
531 c++; \
532 } \
533 } \
534 } while (0)
535
536
537str VLTgenerator_thetasubselect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
538{
539 int idx, c= 0, anti =0,tpe;
540 bat cndid =0;
541 BAT *cand = 0, *bn = NULL;
542 struct canditer ci = (struct canditer) {.tpe = cand_dense};
543 BUN cap,j;
544 oid o = 0;
545 InstrPtr p;
546 str oper, msg= MAL_SUCCEED;
547
548 (void) cntxt;
549 p = findGeneratorDefinition(mb,pci,pci->argv[1]);
550 if( p == NULL)
551 throw(MAL,"generator.thetaselect",SQLSTATE(42000) "Could not locate definition for object");
552
553 if( pci->argc == 5){ // candidate list included
554 cndid = *getArgReference_bat(stk,pci, 2);
555 if( !is_bat_nil(cndid)){
556 cand = BATdescriptor(cndid);
557 if( cand == NULL)
558 throw(MAL,"generator.select", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
559 canditer_init(&ci, NULL, cand);
560 }
561 idx = 3;
562 } else idx = 2;
563 oper= *getArgReference_str(stk,pci,idx+1);
564
565 // check the step direction
566
567 switch( tpe =getArgType(mb,pci,idx)){
568 case TYPE_bte: VLTthetasubselect(bte,abs);break;
569 case TYPE_sht: VLTthetasubselect(sht,abs);break;
570 case TYPE_int: VLTthetasubselect(int,abs);break;
571 case TYPE_lng: VLTthetasubselect(lng,llabs);break;
572#ifdef HAVE_HGE
573 case TYPE_hge: VLTthetasubselect(hge,HGE_ABS);break;
574#endif
575 case TYPE_flt: VLTthetasubselect(flt,fabsf);break;
576 case TYPE_dbl: VLTthetasubselect(dbl,fabs);break;
577 break;
578 default:
579 if ( tpe == TYPE_timestamp){
580 timestamp f,l, val, low, hgh;
581 lng s;
582 oid *v;
583
584 f = *getArgReference_TYPE(stk,p, 1, timestamp);
585 l = *getArgReference_TYPE(stk,p, 2, timestamp);
586 if ( p->argc == 3) {
587 if (cand)
588 BBPunfix(cand->batCacheid);
589 throw(MAL,"generator.table", SQLSTATE(42000) "Timestamp step missing");
590 }
591 s = *getArgReference_lng(stk,p, 3);
592 if ( s == 0 ||
593 (s > 0 && f > l) ||
594 (s < 0 && f < l)
595 ) {
596 if (cand)
597 BBPunfix(cand->batCacheid);
598 throw(MAL, "generator.select", SQLSTATE(42000) "Illegal generator range");
599 }
600
601 hgh = low = timestamp_nil;
602 if ( strcmp(oper,"<") == 0){
603 hgh= *getArgReference_TYPE(stk,pci,idx, timestamp);
604 hgh = timestamp_add_usec(hgh, -1);
605 if (is_timestamp_nil(hgh)) {
606 if (cand)
607 BBPunfix(cand->batCacheid);
608 throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation");
609 }
610 } else
611 if ( strcmp(oper,"<=") == 0){
612 hgh= *getArgReference_TYPE(stk,pci,idx, timestamp) ;
613 } else
614 if ( strcmp(oper,">") == 0){
615 low= *getArgReference_TYPE(stk,pci,idx, timestamp);
616 low = timestamp_add_usec(low, 1);
617 if (is_timestamp_nil(low)) {
618 if (cand)
619 BBPunfix(cand->batCacheid);
620 throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation");
621 }
622 } else
623 if ( strcmp(oper,">=") == 0){
624 low= *getArgReference_TYPE(stk,pci,idx, timestamp);
625 } else
626 if ( strcmp(oper,"!=") == 0 || strcmp(oper, "<>") == 0){
627 hgh= low= *getArgReference_TYPE(stk,pci,idx, timestamp);
628 anti = 1;
629 } else
630 if ( strcmp(oper,"==") == 0 || strcmp(oper, "=") == 0){
631 hgh= low= *getArgReference_TYPE(stk,pci,idx, timestamp);
632 } else {
633 if (cand)
634 BBPunfix(cand->batCacheid);
635 throw(MAL,"generator.thetaselect", SQLSTATE(42000) "Unknown operator");
636 }
637
638 s *= 1000; /* msec -> usec */
639 cap = (BUN) (timestamp_diff(l, f) / s);
640 bn = COLnew(0, TYPE_oid, cap, TRANSIENT);
641 if( bn == NULL) {
642 if (cand)
643 BBPunfix(cand->batCacheid);
644 throw(MAL,"generator.thetaselect", SQLSTATE(HY001) MAL_MALLOC_FAIL);
645 }
646 v = (oid*) Tloc(bn,0);
647
648 val = f;
649 for(j = 0; j< cap; j++, o++){
650 if (((is_timestamp_nil(low) || val >= low) &&
651 (is_timestamp_nil(hgh) || val <= hgh)) != anti){
652 if(cand == NULL || canditer_search(&ci, o, false) != BUN_NONE){
653 *v++ = o;
654 c++;
655 }
656 }
657 val = timestamp_add_usec(val, s);
658 if (is_timestamp_nil(val)) {
659 msg = createException(MAL, "generator.thetaselect", SQLSTATE(22003) "overflow in calculation");
660 goto wrapup;
661 }
662 }
663 } else {
664 if (cand)
665 BBPunfix(cand->batCacheid);
666 throw(MAL,"generator.thetaselect", SQLSTATE(42000) "Illegal generator arguments");
667 }
668 }
669
670wrapup:
671 if( cndid)
672 BBPunfix(cndid);
673 if( bn){
674 bn->tsorted = true;
675 bn->trevsorted = false;
676 bn->tkey = true;
677 bn->tnil = false;
678 bn->tnonil = true;
679 BATsetcount(bn,c);
680 BBPkeepref(*getArgReference_bat(stk,pci,0)= bn->batCacheid);
681 }
682 return msg;
683}
684
685#define VLTprojection(TPE) {\
686 TPE f,l,s, val;\
687 TPE *v;\
688 f = *getArgReference_##TPE(stk,p, 1);\
689 l = *getArgReference_##TPE(stk,p, 2);\
690 if ( p->argc == 3) \
691 s = f<l? (TPE) 1: (TPE)-1;\
692 else s = * getArgReference_##TPE(stk, p, 3); \
693 if ( s == 0 || (f> l && s>0) || (f<l && s < 0))\
694 throw(MAL,"generator.projection", SQLSTATE(42000) "Illegal range");\
695 bn = COLnew(0, TYPE_##TPE, cnt, TRANSIENT);\
696 if( bn == NULL){\
697 BBPunfix(bid);\
698 throw(MAL,"generator.projection", SQLSTATE(HY001) MAL_MALLOC_FAIL);\
699 }\
700 v = (TPE*) Tloc(bn,0);\
701 for(; cnt-- > 0; ol ? *ol++ : o++){\
702 val = f + ((TPE) ( b->ttype == TYPE_void?o:*ol)) * s;\
703 if ( (s > 0 && (val < f || val >= l)) || (s < 0 && (val <= l || val > f))) \
704 continue;\
705 *v++ = val;\
706 c++;\
707 }\
708}
709
710str VLTgenerator_projection(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
711{
712 int c= 0, tpe;
713 bat bid = 0, *ret;
714 BAT *b, *bn = NULL;
715 BUN cnt;
716 oid *ol =0, o= 0;
717 InstrPtr p;
718 str msg;
719
720 (void) cntxt;
721 p = findGeneratorDefinition(mb,pci,pci->argv[2]);
722
723 ret = getArgReference_bat(stk,pci,0);
724 b = BATdescriptor(bid = *getArgReference_bat(stk,pci,1));
725 if( b == NULL)
726 throw(MAL,"generator.projection", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
727
728 // if it does not exist we should fall back to the ordinary projection to try
729 // it might have been materialized already
730 if( p == NULL){
731 bn = BATdescriptor( *getArgReference_bat(stk,pci,2));
732 if( bn == NULL) {
733 BBPunfix(b->batCacheid);
734 throw(MAL,"generator.projection", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
735 }
736 msg = ALGprojection(ret, &b->batCacheid, &bn->batCacheid);
737 BBPunfix(b->batCacheid);
738 BBPunfix(bn->batCacheid);
739 return msg;
740 }
741
742 cnt = BATcount(b);
743 if ( b->ttype == TYPE_void)
744 o = b->tseqbase;
745 else
746 ol = (oid*) Tloc(b,0);
747
748 /* the actual code to perform a projection over generators */
749 switch( tpe = getArgType(mb,p,1)){
750 case TYPE_bte: VLTprojection(bte); break;
751 case TYPE_sht: VLTprojection(sht); break;
752 case TYPE_int: VLTprojection(int); break;
753 case TYPE_lng: VLTprojection(lng); break;
754#ifdef HAVE_HGE
755 case TYPE_hge: VLTprojection(hge); break;
756#endif
757 case TYPE_flt: VLTprojection(flt); break;
758 case TYPE_dbl: VLTprojection(dbl); break;
759 default:
760 if ( tpe == TYPE_timestamp){
761 timestamp f,l, val;
762 lng s,t;
763 timestamp *v;
764 f = *getArgReference_TYPE(stk,p, 1, timestamp);
765 l = *getArgReference_TYPE(stk,p, 2, timestamp);
766 if ( p->argc == 3) {
767 BBPunfix(b->batCacheid);
768 throw(MAL,"generator.table", SQLSTATE(42000) "Timestamp step missing");
769 }
770 s = *getArgReference_lng(stk,p, 3);
771 if ( s == 0 ||
772 (s< 0 && f < l) ||
773 (s> 0 && l < f) ) {
774 BBPunfix(b->batCacheid);
775 throw(MAL,"generator.projection", SQLSTATE(42000) "Illegal range");
776 }
777
778 s *= 1000; /* msec -> usec */
779 bn = COLnew(0, TYPE_timestamp, cnt, TRANSIENT);
780 if( bn == NULL){
781 BBPunfix(bid);
782 throw(MAL,"generator.projection", SQLSTATE(HY001) MAL_MALLOC_FAIL);
783 }
784
785 v = (timestamp*) Tloc(bn,0);
786
787 for(; cnt-- > 0; ol ? *ol++ : o++){
788 t = ((lng) ( b->ttype == TYPE_void?o:*ol)) * s;
789 val = timestamp_add_usec(f, t);
790 if (is_timestamp_nil(val))
791 throw(MAL, "generator.projection", SQLSTATE(22003) "overflow in calculation");
792
793 if ( is_timestamp_nil(val))
794 continue;
795 if (s > 0 && (val < f || val >= l) )
796 continue;
797 if (s < 0 && (val <= l || val > f) )
798 continue;
799 *v++ = val;
800 c++;
801 }
802 }
803 }
804
805 /* adminstrative wrapup of the projection */
806 BBPunfix(bid);
807 if( bn){
808 bn->tsorted = bn->trevsorted = false;
809 bn->tkey = false;
810 bn->tnil = false;
811 bn->tnonil = false;
812 BATsetcount(bn,c);
813 BBPkeepref(*getArgReference_bat(stk,pci,0)= bn->batCacheid);
814 }
815 return MAL_SUCCEED;
816}
817
818/* The operands of a join operation can either be defined on a generator */
819#define VLTjoin(TPE, ABS) \
820 { TPE f,l,s; TPE *v; BUN w;\
821 f = *getArgReference_##TPE(stk,p, 1);\
822 l = *getArgReference_##TPE(stk,p, 2);\
823 if ( p->argc == 3) \
824 s = f<l? (TPE) 1: (TPE)-1;\
825 else s = * getArgReference_##TPE(stk, p, 3); \
826 incr = s > 0;\
827 v = (TPE*) Tloc(b,0);\
828 if ( s == 0 || (f> l && s>0) || (f<l && s < 0))\
829 throw(MAL,"generator.join", SQLSTATE(42000) "Illegal range");\
830 for( ; cnt >0; cnt--,o++,v++){\
831 w = (BUN) (ABS(*v -f)/ABS(s));\
832 if ( f + (TPE)(w * s) == *v ){\
833 *ol++ = (oid) w;\
834 *or++ = o;\
835 c++;\
836 }\
837 } }\
838
839str VLTgenerator_join(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
840{
841 BAT *b, *bl = NULL, *br = NULL, *bln = NULL, *brn= NULL;
842 BUN cnt,c =0;
843 oid o= 0, *ol, *or;
844 int tpe, incr=0, materialized = 0;
845 InstrPtr p = NULL, q = NULL;
846 str msg = MAL_SUCCEED;
847
848 (void) cntxt;
849 // we assume at most one of the arguments to refer to the generator
850 p = findGeneratorDefinition(mb,pci,pci->argv[2]);
851 q = findGeneratorDefinition(mb,pci,pci->argv[3]);
852
853 if (p == NULL && q == NULL) {
854 bit zero = 0;
855 return ALGjoin(getArgReference_bat(stk, pci, 0),
856 getArgReference_bat(stk, pci, 1),
857 getArgReference_bat(stk, pci, 2),
858 getArgReference_bat(stk, pci, 3),
859 NULL, /* left candidate */
860 NULL, /* right candidate */
861 &zero, /* nil_matches */
862 NULL); /* estimate */
863 }
864
865 if( p == NULL){
866 bl = BATdescriptor(*getArgReference_bat(stk,pci,2));
867 if( bl == NULL)
868 throw(MAL,"generator.join", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
869 }
870 if ( q == NULL){
871 /* p != NULL, hence bl == NULL */
872 br = BATdescriptor(*getArgReference_bat(stk,pci,3));
873 if( br == NULL)
874 throw(MAL,"generator.join", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
875 }
876
877 // in case of both generators || getModuleId(q) == generatorRef)materialize the 'smallest' one first
878 // or implement more knowledge, postponed
879 if (p && q ){
880 msg = VLTgenerator_table_(&bl, cntxt, mb, stk, p);
881 if( msg || bl == NULL )
882 throw(MAL,"generator.join",SQLSTATE(42000) "Join over generator pairs not supported");
883 else
884 p = NULL;
885 materialized =1;
886 }
887
888 // switch roles to have a single target bat[:oid,:any] designated
889 // by b and reference instruction p for the generator
890 b = q? bl : br;
891 p = q? q : p;
892 cnt = BATcount(b);
893 tpe = b->ttype;
894 o= b->hseqbase;
895
896 bln = COLnew(0,TYPE_oid, cnt, TRANSIENT);
897 brn = COLnew(0,TYPE_oid, cnt, TRANSIENT);
898 if( bln == NULL || brn == NULL){
899 if(bln) BBPunfix(bln->batCacheid);
900 if(brn) BBPunfix(brn->batCacheid);
901 if(bl) BBPunfix(bl->batCacheid);
902 if(br) BBPunfix(br->batCacheid);
903 throw(MAL,"generator.join", SQLSTATE(HY001) MAL_MALLOC_FAIL);
904 }
905 ol = (oid*) Tloc(bln,0);
906 or = (oid*) Tloc(brn,0);
907
908 /* The actual join code for generators be injected here */
909 switch(tpe){
910 case TYPE_bte: VLTjoin(bte,abs); break;
911 case TYPE_sht: VLTjoin(sht,abs); break;
912 case TYPE_int: VLTjoin(int,abs); break;
913 case TYPE_lng: VLTjoin(lng,llabs); break;
914#ifdef HAVE_HGE
915 case TYPE_hge: VLTjoin(hge,HGE_ABS); break;
916#endif
917 case TYPE_flt: VLTjoin(flt,fabsf); break;
918 case TYPE_dbl: VLTjoin(dbl,fabs); break;
919 default:
920 if( tpe == TYPE_timestamp){
921 // it is easier to produce the timestamp series
922 // then to estimate the possible index
923 }
924 throw(MAL,"generator.join", SQLSTATE(42000) "Illegal type");
925 }
926
927 bln->tsorted = bln->trevsorted = false;
928 bln->tkey = false;
929 bln->tnil = false;
930 bln->tnonil = false;
931 BATsetcount(bln,c);
932 bln->tsorted = incr || c <= 1;
933 bln->trevsorted = !incr || c <= 1;
934
935 brn->tsorted = brn->trevsorted = false;
936 brn->tkey = false;
937 brn->tnil = false;
938 brn->tnonil = false;
939 BATsetcount(brn,c);
940 brn->tsorted = incr || c <= 1;
941 brn->trevsorted = !incr || c <= 1;
942 if( q){
943 BBPkeepref(*getArgReference_bat(stk,pci,0)= brn->batCacheid);
944 BBPkeepref(*getArgReference_bat(stk,pci,1)= bln->batCacheid);
945 } else {
946 BBPkeepref(*getArgReference_bat(stk,pci,0)= bln->batCacheid);
947 BBPkeepref(*getArgReference_bat(stk,pci,1)= brn->batCacheid);
948 }
949 if ( materialized){
950 BBPreclaim(bl);
951 bl = 0;
952 }
953 if(bl) BBPunfix(bl->batCacheid);
954 if(br) BBPunfix(br->batCacheid);
955 return msg;
956}
957
958#define VLTrangeExpand() \
959{ limit+= cnt * (limit/(done?done:1)+1);\
960 if (BATextend(bln, limit) != GDK_SUCCEED) { \
961 BBPunfix(blow->batCacheid);\
962 BBPunfix(bhgh->batCacheid);\
963 BBPunfix(bln->batCacheid);\
964 BBPunfix(brn->batCacheid);\
965 throw(MAL,"generator.rangejoin", SQLSTATE(HY001) MAL_MALLOC_FAIL);\
966 }\
967 if (BATextend(brn, limit) != GDK_SUCCEED) { \
968 BBPunfix(blow->batCacheid);\
969 BBPunfix(bhgh->batCacheid);\
970 BBPunfix(bln->batCacheid);\
971 BBPunfix(brn->batCacheid);\
972 throw(MAL,"generator.rangejoin", SQLSTATE(HY001) MAL_MALLOC_FAIL);\
973 }\
974 ol = (oid*) Tloc(bln,0) + c;\
975 or = (oid*) Tloc(brn,0) + c;\
976}
977
978/* The operands of a join operation can either be defined on a generator */
979#define VLTrangejoin(TPE, ABS, FLOOR) \
980{ TPE f,f1,l,s; TPE *vlow,*vhgh; BUN w;\
981 f = *getArgReference_##TPE(stk,p, 1);\
982 l = *getArgReference_##TPE(stk,p, 2);\
983 if ( p->argc == 3) \
984 s = f<l? (TPE) 1: (TPE)-1;\
985 else s = * getArgReference_##TPE(stk, p, 3); \
986 incr = s > 0;\
987 if ( s == 0 || (f> l && s>0) || (f<l && s < 0))\
988 throw(MAL,"generator.rangejoin", SQLSTATE(42000) "Illegal range");\
989 vlow = (TPE*) Tloc(blow,0);\
990 vhgh = (TPE*) Tloc(bhgh,0);\
991 for( ; cnt >0; cnt--, done++, o++,vlow++,vhgh++){\
992 f1 = f + FLOOR(ABS(*vlow-f)/ABS(s)) * s;\
993 if ( f1 < *vlow ) f1+= s;\
994 w = (BUN) FLOOR(ABS(f1-f)/ABS(s));\
995 for( ; (f1 > *vlow || (li && f1 == *vlow)) && (f1 < *vhgh || (ri && f1 == *vhgh)); f1 += s, w++){\
996 if(c == limit)\
997 VLTrangeExpand();\
998 *ol++ = (oid) w;\
999 *or++ = o;\
1000 c++;\
1001 }\
1002} }
1003
1004str VLTgenerator_rangejoin(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
1005{
1006 BAT *blow = NULL, *bhgh = NULL, *bln = NULL, *brn= NULL;
1007 bit li,ri;
1008 BUN limit, cnt, done=0, c =0;
1009 oid o= 0, *ol, *or;
1010 int tpe, incr=0;
1011 InstrPtr p = NULL;
1012 str msg = MAL_SUCCEED;
1013
1014 (void) cntxt;
1015 // the left join argument should be a generator
1016 p = findGeneratorDefinition(mb,pci,pci->argv[2]);
1017 if( p == NULL)
1018 throw(MAL,"generator.rangejoin",SQLSTATE(42000) "Invalid arguments");
1019
1020 blow = BATdescriptor(*getArgReference_bat(stk,pci,3));
1021 if( blow == NULL)
1022 throw(MAL,"generator.rangejoin", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1023
1024 bhgh = BATdescriptor(*getArgReference_bat(stk,pci,4));
1025 if( bhgh == NULL){
1026 BBPunfix(blow->batCacheid);
1027 throw(MAL,"generator.rangejoin", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
1028 }
1029 li = *getArgReference_bit(stk,pci,5);
1030 ri = *getArgReference_bit(stk,pci,6);
1031
1032 cnt = BATcount(blow);
1033 limit = 2 * cnt; //top off result before expansion
1034 tpe = blow->ttype;
1035 o= blow->hseqbase;
1036
1037 bln = COLnew(0,TYPE_oid, limit, TRANSIENT);
1038 brn = COLnew(0,TYPE_oid, limit, TRANSIENT);
1039 if( bln == NULL || brn == NULL){
1040 if(bln) BBPunfix(bln->batCacheid);
1041 if(brn) BBPunfix(brn->batCacheid);
1042 if(blow) BBPunfix(blow->batCacheid);
1043 if(bhgh) BBPunfix(bhgh->batCacheid);
1044 throw(MAL,"generator.rangejoin", SQLSTATE(HY001) MAL_MALLOC_FAIL);
1045 }
1046 ol = (oid*) Tloc(bln,0);
1047 or = (oid*) Tloc(brn,0);
1048
1049 /* The actual join code for generators be injected here */
1050 switch(tpe){
1051 case TYPE_bte: VLTrangejoin(bte,abs,IDENTITY); break;
1052 case TYPE_sht: VLTrangejoin(sht,abs,IDENTITY); break;
1053 case TYPE_int: VLTrangejoin(int,abs,IDENTITY); break;
1054 case TYPE_lng: VLTrangejoin(lng,llabs,IDENTITY); break;
1055#ifdef HAVE_HGE
1056 case TYPE_hge: VLTrangejoin(hge,HGE_ABS,IDENTITY); break;
1057#endif
1058 case TYPE_flt: VLTrangejoin(flt,fabsf,floorf); break;
1059 case TYPE_dbl: VLTrangejoin(dbl,fabs,floor); break;
1060 default:
1061 if( tpe == TYPE_timestamp){
1062 // it is easier to produce the timestamp series
1063 // then to estimate the possible index
1064 }
1065 throw(MAL,"generator.rangejoin","Illegal type");
1066 }
1067
1068 bln->tsorted = bln->trevsorted = false;
1069 bln->tkey = false;
1070 bln->tnil = false;
1071 bln->tnonil = false;
1072 BATsetcount(bln,c);
1073 bln->tsorted = incr || c <= 1;
1074 bln->trevsorted = !incr || c <= 1;
1075
1076 brn->tsorted = brn->trevsorted = false;
1077 brn->tkey = false;
1078 brn->tnil = false;
1079 brn->tnonil = false;
1080 BATsetcount(brn,c);
1081 brn->tsorted = incr || c <= 1;
1082 brn->trevsorted = !incr || c <= 1;
1083 BBPkeepref(*getArgReference_bat(stk,pci,0)= bln->batCacheid);
1084 BBPkeepref(*getArgReference_bat(stk,pci,1)= brn->batCacheid);
1085 return msg;
1086}
1087