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