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 | |
35 | str |
36 | VLTgenerator_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 | |
92 | static str |
93 | VLTgenerator_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 | |
182 | str |
183 | VLTgenerator_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 | */ |
205 | static InstrPtr |
206 | findGeneratorDefinition(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 | |
294 | str |
295 | VLTgenerator_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 | |
537 | str 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 | |
670 | wrapup: |
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 | |
710 | str 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 | |
839 | str 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 | |
1004 | str 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 | |