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 | #include "monetdb_config.h" |
10 | #include "opt_pushselect.h" |
11 | #include "mal_interpreter.h" /* for showErrors() */ |
12 | |
13 | static InstrPtr |
14 | PushArgument(MalBlkPtr mb, InstrPtr p, int arg, int pos) |
15 | { |
16 | int i; |
17 | |
18 | p = pushArgument(mb, p, arg); /* push at end */ |
19 | for (i = p->argc-1; i > pos; i--) |
20 | getArg(p, i) = getArg(p, i-1); |
21 | getArg(p, pos) = arg; |
22 | return p; |
23 | } |
24 | |
25 | static InstrPtr |
26 | PushNil(MalBlkPtr mb, InstrPtr p, int pos, int tpe) |
27 | { |
28 | int i, arg; |
29 | |
30 | p = pushNil(mb, p, tpe); /* push at end */ |
31 | arg = getArg(p, p->argc-1); |
32 | for (i = p->argc-1; i > pos; i--) |
33 | getArg(p, i) = getArg(p, i-1); |
34 | getArg(p, pos) = arg; |
35 | return p; |
36 | } |
37 | |
38 | static InstrPtr |
39 | ReplaceWithNil(MalBlkPtr mb, InstrPtr p, int pos, int tpe) |
40 | { |
41 | p = pushNil(mb, p, tpe); /* push at end */ |
42 | getArg(p, pos) = getArg(p, p->argc-1); |
43 | p->argc--; |
44 | return p; |
45 | } |
46 | |
47 | |
48 | #define MAX_TABLES 64 |
49 | |
50 | typedef struct subselect_t { |
51 | int nr; |
52 | int tid[MAX_TABLES]; |
53 | int subselect[MAX_TABLES]; |
54 | } subselect_t; |
55 | |
56 | static int |
57 | subselect_add( subselect_t *subselects, int tid, int subselect ) |
58 | { |
59 | int i; |
60 | |
61 | for (i = 0; i<subselects->nr; i++) { |
62 | if (subselects->tid[i] == tid) { |
63 | if (subselects->subselect[i] == subselect) |
64 | return i; |
65 | else |
66 | return -1; |
67 | } |
68 | } |
69 | if (i >= MAX_TABLES) |
70 | return -1; |
71 | subselects->nr++; |
72 | subselects->tid[i] = tid; |
73 | subselects->subselect[i] = subselect; |
74 | return i; |
75 | } |
76 | |
77 | static int |
78 | subselect_find_tids( subselect_t *subselects, int subselect) |
79 | { |
80 | int i; |
81 | |
82 | for (i = 0; i<subselects->nr; i++) { |
83 | if (subselects->subselect[i] == subselect) { |
84 | return subselects->tid[i]; |
85 | } |
86 | } |
87 | return -1; |
88 | } |
89 | |
90 | static int |
91 | subselect_find_subselect( subselect_t *subselects, int tid) |
92 | { |
93 | int i; |
94 | |
95 | for (i = 0; i<subselects->nr; i++) { |
96 | if (subselects->tid[i] == tid) { |
97 | return subselects->subselect[i]; |
98 | } |
99 | } |
100 | return -1; |
101 | } |
102 | |
103 | static int |
104 | lastbat_arg(MalBlkPtr mb, InstrPtr p) |
105 | { |
106 | int i = 0; |
107 | for (i=p->retc; i<p->argc; i++) { |
108 | int type = getArgType(mb, p, i); |
109 | if (!isaBatType(type) && type != TYPE_bat) |
110 | break; |
111 | } |
112 | if (i < p->argc) |
113 | return i-1; |
114 | return 0; |
115 | } |
116 | |
117 | /* check for updates inbetween assignment to variables newv and oldv */ |
118 | static int |
119 | no_updates(InstrPtr *old, int *vars, int oldv, int newv) |
120 | { |
121 | while(newv > oldv) { |
122 | InstrPtr q = old[vars[newv]]; |
123 | |
124 | if (isUpdateInstruction(q)) |
125 | return 0; |
126 | newv = getArg(q, 1); |
127 | } |
128 | return 1; |
129 | } |
130 | |
131 | str |
132 | OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) |
133 | { |
134 | int i, j, limit, slimit, actions=0, *vars, *nvars = NULL, *slices = NULL, push_down_delta = 0, nr_topn = 0, nr_likes = 0; |
135 | char *rslices = NULL, *oclean = NULL; |
136 | InstrPtr p, *old; |
137 | subselect_t subselects; |
138 | char buf[256]; |
139 | lng usec = GDKusec(); |
140 | |
141 | subselects = (subselect_t) {0}; |
142 | if( mb->errors) |
143 | return MAL_SUCCEED; |
144 | |
145 | (void) stk; |
146 | (void) pci; |
147 | vars= (int*) GDKzalloc(sizeof(int)* mb->vtop); |
148 | if( vars == NULL) |
149 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
150 | |
151 | limit = mb->stop; |
152 | slimit= mb->ssize; |
153 | old = mb->stmt; |
154 | |
155 | /* check for bailout conditions */ |
156 | for (i = 1; i < limit; i++) { |
157 | int lastbat; |
158 | p = old[i]; |
159 | |
160 | for (j = 0; j<p->retc; j++) { |
161 | int res = getArg(p, j); |
162 | vars[res] = i; |
163 | } |
164 | |
165 | if (getModuleId(p) == algebraRef && |
166 | (getFunctionId(p) == intersectRef || |
167 | getFunctionId(p) == differenceRef)) { |
168 | GDKfree(vars); |
169 | goto wrapup; |
170 | } |
171 | |
172 | if (isSlice(p)) |
173 | nr_topn++; |
174 | |
175 | if (isLikeOp(p)) |
176 | nr_likes++; |
177 | |
178 | if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef) |
179 | push_down_delta++; |
180 | |
181 | if (/* DISABLES CODE */ (0) && getModuleId(p) == sqlRef && getFunctionId(p) == tidRef) { /* rewrite equal table ids */ |
182 | int sname = getArg(p, 2), tname = getArg(p, 3), s; |
183 | |
184 | for (s = 0; s < subselects.nr; s++) { |
185 | InstrPtr q = old[vars[subselects.tid[s]]]; |
186 | int Qsname = getArg(q, 2), Qtname = getArg(q, 3); |
187 | |
188 | if (no_updates(old, vars, getArg(q,1), getArg(p,1)) && |
189 | ((sname == Qsname && tname == Qtname) || |
190 | (/* DISABLES CODE */ (0) && strcmp(getVarConstant(mb, sname).val.sval, getVarConstant(mb, Qsname).val.sval) == 0 && |
191 | strcmp(getVarConstant(mb, tname).val.sval, getVarConstant(mb, Qtname).val.sval) == 0))) { |
192 | clrFunction(p); |
193 | p->retc = 1; |
194 | p->argc = 2; |
195 | getArg(p, 1) = getArg(q, 0); |
196 | break; |
197 | } |
198 | } |
199 | } |
200 | lastbat = lastbat_arg(mb, p); |
201 | if (isSelect(p) && p->retc == 1 && |
202 | /* no cand list */ getArgType(mb, p, lastbat) != newBatType(TYPE_oid)) { |
203 | int i1 = getArg(p, 1), tid = 0; |
204 | InstrPtr q = old[vars[i1]]; |
205 | |
206 | /* find the table ids */ |
207 | while(!tid) { |
208 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
209 | int i1 = getArg(q, 1); |
210 | InstrPtr s = old[vars[i1]]; |
211 | |
212 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
213 | tid = getArg(q, 1); |
214 | if (s->argc == 2 && s->retc == 1) { |
215 | int i1 = getArg(s, 1); |
216 | InstrPtr s = old[vars[i1]]; |
217 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
218 | tid = getArg(q, 1); |
219 | } |
220 | break; |
221 | } else if (isMapOp(q) && q->retc == 1 && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
222 | int i1 = getArg(q, 1); |
223 | q = old[vars[i1]]; |
224 | } else if (isMapOp(q) && q->retc == 1 && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
225 | int i2 = getArg(q, 2); |
226 | q = old[vars[i2]]; |
227 | } else { |
228 | break; |
229 | } |
230 | } |
231 | if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { |
232 | GDKfree(vars); |
233 | goto wrapup; |
234 | } |
235 | } |
236 | /* left hand side */ |
237 | if ( (GDKdebug & (1<<15)) && |
238 | isMatJoinOp(p) && p->retc == 2) { |
239 | int i1 = getArg(p, 2), tid = 0; |
240 | InstrPtr q = old[vars[i1]]; |
241 | |
242 | /* find the table ids */ |
243 | while(!tid) { |
244 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
245 | int i1 = getArg(q, 1); |
246 | InstrPtr s = old[vars[i1]]; |
247 | |
248 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
249 | tid = getArg(q, 1); |
250 | break; |
251 | } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
252 | int i1 = getArg(q, 1); |
253 | q = old[vars[i1]]; |
254 | } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
255 | int i2 = getArg(q, 2); |
256 | q = old[vars[i2]]; |
257 | } else { |
258 | break; |
259 | } |
260 | } |
261 | if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) { |
262 | GDKfree(vars); |
263 | goto wrapup; |
264 | } |
265 | } |
266 | /* right hand side */ |
267 | if ( (GDKdebug & (1<<15)) && |
268 | isMatJoinOp(p) && p->retc == 2) { |
269 | int i1 = getArg(p, 3), tid = 0; |
270 | InstrPtr q = old[vars[i1]]; |
271 | |
272 | /* find the table ids */ |
273 | while(!tid) { |
274 | if (getModuleId(q) == algebraRef && getFunctionId(q) == projectionRef) { |
275 | int i1 = getArg(q, 1); |
276 | InstrPtr s = old[vars[i1]]; |
277 | |
278 | if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef) |
279 | tid = getArg(q, 1); |
280 | break; |
281 | } else if (isMapOp(q) && q->argc >= 2 && isaBatType(getArgType(mb, q, 1))) { |
282 | int i1 = getArg(q, 1); |
283 | q = old[vars[i1]]; |
284 | } else if (isMapOp(q) && q->argc >= 3 && isaBatType(getArgType(mb, q, 2))) { |
285 | int i2 = getArg(q, 2); |
286 | q = old[vars[i2]]; |
287 | } else { |
288 | break; |
289 | } |
290 | } |
291 | if (tid && subselect_add(&subselects, tid, getArg(p, 1)) < 0) { |
292 | GDKfree(vars); |
293 | goto wrapup; |
294 | } |
295 | } |
296 | } |
297 | |
298 | if ((!subselects.nr && !nr_topn && !nr_likes) || newMalBlkStmt(mb, mb->ssize) <0 ) { |
299 | GDKfree(vars); |
300 | goto wrapup; |
301 | } |
302 | pushInstruction(mb,old[0]); |
303 | |
304 | for (i = 1; i < limit; i++) { |
305 | p = old[i]; |
306 | |
307 | /* rewrite batalgebra.like + select -> likeselect */ |
308 | if (getModuleId(p) == algebraRef && p->retc == 1 && getFunctionId(p) == selectRef) { |
309 | int var = getArg(p, 1); |
310 | InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ |
311 | |
312 | if (isLikeOp(q)) { /* TODO check if getArg(p, 3) value == TRUE */ |
313 | InstrPtr r = newInstruction(mb, algebraRef, likeselectRef); |
314 | int has_cand = (getArgType(mb, p, 2) == newBatType(TYPE_oid)); |
315 | int a, anti = (getFunctionId(q)[0] == 'n'), ignore_case = (getFunctionId(q)[anti?4:0] == 'i'); |
316 | |
317 | getArg(r,0) = getArg(p,0); |
318 | r = pushArgument(mb, r, getArg(q, 1)); |
319 | if (has_cand) |
320 | r = pushArgument(mb, r, getArg(p, 2)); |
321 | for(a = 2; a<q->argc; a++) |
322 | r = pushArgument(mb, r, getArg(q, a)); |
323 | if (r->argc < (4+has_cand)) |
324 | r = pushStr(mb, r, "" ); /* default esc */ |
325 | if (r->argc < (5+has_cand)) |
326 | r = pushBit(mb, r, ignore_case); |
327 | if (r->argc < (6+has_cand)) |
328 | r = pushBit(mb, r, anti); |
329 | freeInstruction(p); |
330 | p = r; |
331 | actions++; |
332 | } |
333 | } |
334 | |
335 | /* inject table ids into subselect |
336 | * s = subselect(c, C1..) => subselect(c, t, C1..) |
337 | */ |
338 | if (isSelect(p) && p->retc == 1) { |
339 | int tid = 0; |
340 | |
341 | if ((tid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { |
342 | int lastbat = lastbat_arg(mb, p); |
343 | if (getArgType(mb, p, lastbat) == TYPE_bat) /* empty candidate list bat_nil */ |
344 | getArg(p, lastbat) = tid; |
345 | else |
346 | p = PushArgument(mb, p, tid, lastbat+1); |
347 | /* make sure to resolve again */ |
348 | p->token = ASSIGNsymbol; |
349 | p->typechk = TYPE_UNKNOWN; |
350 | p->fcn = NULL; |
351 | p->blk = NULL; |
352 | actions++; |
353 | } |
354 | } |
355 | else if ( (GDKdebug & (1<<15)) && |
356 | isMatJoinOp(p) && p->retc == 2 |
357 | ) { |
358 | int ltid = 0, rtid = 0, done = 0; |
359 | int range = 0; |
360 | |
361 | if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0 && |
362 | (rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { |
363 | p = PushArgument(mb, p, ltid, 4+range); |
364 | p = PushArgument(mb, p, rtid, 5+range); |
365 | done = 1; |
366 | } else if ((ltid = subselect_find_tids(&subselects, getArg(p, 0))) >= 0) { |
367 | p = PushArgument(mb, p, ltid, 4+range); |
368 | p = PushNil(mb, p, 5+range, TYPE_bat); |
369 | done = 1; |
370 | } else if ((rtid = subselect_find_tids(&subselects, getArg(p, 1))) >= 0) { |
371 | p = PushNil(mb, p, 4+range, TYPE_bat); |
372 | p = PushArgument(mb, p, rtid, 5+range); |
373 | done = 1; |
374 | } |
375 | if (done) { |
376 | p = pushBit(mb, p, FALSE); /* do not match nils */ |
377 | p = pushNil(mb, p, TYPE_lng); /* no estimate */ |
378 | |
379 | /* make sure to resolve again */ |
380 | p->token = ASSIGNsymbol; |
381 | p->typechk = TYPE_UNKNOWN; |
382 | p->fcn = NULL; |
383 | p->blk = NULL; |
384 | actions++; |
385 | } |
386 | } |
387 | /* Leftfetchjoins involving rewriten table ids need to be flattend |
388 | * l = projection(t, c); => l = c; |
389 | * and |
390 | * l = projection(s, ntids); => l = s; |
391 | */ |
392 | else if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) { |
393 | int var = getArg(p, 1); |
394 | |
395 | if (subselect_find_subselect(&subselects, var) > 0) { |
396 | InstrPtr q = newAssignment(mb); |
397 | |
398 | getArg(q, 0) = getArg(p, 0); |
399 | (void) pushArgument(mb, q, getArg(p, 2)); |
400 | actions++; |
401 | freeInstruction(p); |
402 | continue; |
403 | } else { /* deletes/updates use table ids */ |
404 | int var = getArg(p, 2); |
405 | InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */ |
406 | |
407 | if (q->token == ASSIGNsymbol) { |
408 | var = getArg(q, 1); |
409 | q = mb->stmt[vars[var]]; |
410 | } |
411 | if (subselect_find_subselect(&subselects, var) > 0) { |
412 | InstrPtr qq = newAssignment(mb); |
413 | /* TODO: check result */ |
414 | |
415 | getArg(qq, 0) = getArg(p, 0); |
416 | (void) pushArgument(mb, qq, getArg(p, 1)); |
417 | actions++; |
418 | freeInstruction(p); |
419 | continue; |
420 | } |
421 | /* c = sql.delta(b,uid,uval,ins); |
422 | * l = projection(x, c); |
423 | * into |
424 | * l = sql.projectdelta(x,b,uid,uval,ins); |
425 | */ |
426 | else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef && q->argc == 5) { |
427 | q = copyInstruction(q); |
428 | if( q == NULL){ |
429 | for (; i<limit; i++) |
430 | if (old[i]) |
431 | pushInstruction(mb,old[i]); |
432 | GDKfree(slices); |
433 | GDKfree(rslices); |
434 | GDKfree(old); |
435 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
436 | } |
437 | |
438 | setFunctionId(q, projectdeltaRef); |
439 | getArg(q, 0) = getArg(p, 0); |
440 | q = PushArgument(mb, q, getArg(p, 1), 1); |
441 | freeInstruction(p); |
442 | p = q; |
443 | actions++; |
444 | } |
445 | } |
446 | } |
447 | pushInstruction(mb,p); |
448 | } |
449 | for (; i<limit; i++) |
450 | if (old[i]) |
451 | pushInstruction(mb,old[i]); |
452 | for (; i<slimit; i++) |
453 | if (old[i]) |
454 | freeInstruction(old[i]); |
455 | GDKfree(old); |
456 | if (!push_down_delta) { |
457 | GDKfree(vars); |
458 | goto wrapup; |
459 | } |
460 | |
461 | /* now push selects through delta's */ |
462 | limit = mb->stop; |
463 | slimit= mb->ssize; |
464 | old = mb->stmt; |
465 | |
466 | nvars = (int*) GDKzalloc(sizeof(int)* mb->vtop); |
467 | slices = (int*) GDKzalloc(sizeof(int)* mb->vtop); |
468 | rslices = (char*) GDKzalloc(sizeof(char)* mb->vtop); |
469 | oclean = (char*) GDKzalloc(sizeof(char)* mb->vtop); |
470 | if (!nvars || !slices || !rslices || !oclean || newMalBlkStmt(mb, mb->stop+(5*push_down_delta)) <0 ) { |
471 | mb->stmt = old; |
472 | GDKfree(vars); |
473 | GDKfree(nvars); |
474 | GDKfree(slices); |
475 | GDKfree(rslices); |
476 | GDKfree(oclean); |
477 | goto wrapup; |
478 | } |
479 | pushInstruction(mb,old[0]); |
480 | |
481 | for (i = 1; i < limit; i++) { |
482 | int lastbat; |
483 | p = old[i]; |
484 | |
485 | for (j = 0; j<p->retc; j++) { |
486 | int res = getArg(p, j); |
487 | vars[res] = i; |
488 | } |
489 | |
490 | /* push subslice under projectdelta */ |
491 | if (isSlice(p) && p->retc == 1) { |
492 | int var = getArg(p, 1); |
493 | InstrPtr q = old[vars[var]]; |
494 | if (q && getModuleId(q) == sqlRef && getFunctionId(q) == projectdeltaRef) { |
495 | InstrPtr r = copyInstruction(p); |
496 | InstrPtr s = copyInstruction(q); |
497 | |
498 | rslices[getArg(q,0)] = 1; /* mark projectdelta as rewriten */ |
499 | rslices[getArg(p,0)] = 1; /* mark slice as rewriten */ |
500 | |
501 | if (r == NULL || s == NULL){ |
502 | GDKfree(vars); |
503 | GDKfree(nvars); |
504 | GDKfree(slices); |
505 | GDKfree(rslices); |
506 | GDKfree(oclean); |
507 | GDKfree(old); |
508 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
509 | } |
510 | |
511 | /* slice the candidates */ |
512 | setFunctionId(r, sliceRef); |
513 | nvars[getArg(p,0)] = getArg(r, 0) = |
514 | newTmpVariable(mb, getArgType(mb, r, 0)); |
515 | slices[getArg(q, 1)] = getArg(p, 0); |
516 | |
517 | setVarCList(mb,getArg(r,0)); |
518 | getArg(r, 1) = getArg(s, 1); |
519 | pushInstruction(mb,r); |
520 | |
521 | nvars[getArg(q,0)] = getArg(s, 0) = |
522 | newTmpVariable(mb, getArgType(mb, s, 0)); |
523 | getArg(s, 1) = getArg(r, 0); /* use result of slice */ |
524 | pushInstruction(mb, s); |
525 | oclean[i] = 1; |
526 | actions++; |
527 | continue; |
528 | } |
529 | } |
530 | /* Leftfetchjoins involving rewriten sliced candidates ids need to be flattend |
531 | * l = projection(t, c); => l = c; |
532 | * and |
533 | * l = projection(s, ntids); => l = s; |
534 | */ |
535 | else if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) { |
536 | int var = getArg(p, 1); |
537 | InstrPtr r = old[vars[var]], q; |
538 | |
539 | if (r && isSlice(r) && rslices[var] && getArg(r, 0) == getArg(p, 1)) { |
540 | int col = getArg(p, 2); |
541 | |
542 | if (!rslices[col]) { /* was the deltaproject rewriten (sliced) */ |
543 | InstrPtr s = old[vars[col]], u = NULL; |
544 | |
545 | if (s && getModuleId(s) == algebraRef && getFunctionId(s) == projectRef) { |
546 | col = getArg(s, 1); |
547 | u = s; |
548 | s = old[vars[col]]; |
549 | } |
550 | if (s && getModuleId(s) == sqlRef && getFunctionId(s) == projectdeltaRef) { |
551 | InstrPtr t = copyInstruction(s); |
552 | if (t == NULL){ |
553 | GDKfree(vars); |
554 | GDKfree(nvars); |
555 | GDKfree(slices); |
556 | GDKfree(rslices); |
557 | GDKfree(oclean); |
558 | GDKfree(old); |
559 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
560 | } |
561 | |
562 | getArg(t, 1) = nvars[getArg(r, 0)]; /* use result of slice */ |
563 | rslices[col] = 1; |
564 | nvars[getArg(s,0)] = getArg(t, 0) = |
565 | newTmpVariable(mb, getArgType(mb, t, 0)); |
566 | pushInstruction(mb, t); |
567 | if (u) { /* add again */ |
568 | if((t = copyInstruction(u)) == NULL) { |
569 | GDKfree(vars); |
570 | GDKfree(nvars); |
571 | GDKfree(slices); |
572 | GDKfree(rslices); |
573 | GDKfree(oclean); |
574 | GDKfree(old); |
575 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
576 | } |
577 | getArg(t, 1) = nvars[getArg(t,1)]; |
578 | pushInstruction(mb, t); |
579 | } |
580 | } |
581 | } |
582 | q = newAssignment(mb); |
583 | getArg(q, 0) = getArg(p, 0); |
584 | (void) pushArgument(mb, q, getArg(p, 2)); |
585 | if (nvars[getArg(p, 2)] > 0) |
586 | getArg(q, 1) = nvars[getArg(p, 2)]; |
587 | oclean[i] = 1; |
588 | actions++; |
589 | continue; |
590 | } |
591 | } else if (p->argc >= 2 && slices[getArg(p, 1)] != 0) { |
592 | /* use new slice candidate list */ |
593 | assert(slices[getArg(p,1)] == nvars[getArg(p,1)]); |
594 | getArg(p, 1) = slices[getArg(p, 1)]; |
595 | } |
596 | /* remap */ |
597 | for (j = p->retc; j<p->argc; j++) { |
598 | int var = getArg(p, j); |
599 | if (nvars[var] > 0) { |
600 | getArg(p, j) = nvars[var]; |
601 | } |
602 | } |
603 | |
604 | /* c = delta(b, uid, uvl, ins) |
605 | * s = select(c, C1..) |
606 | * |
607 | * nc = select(b, C1..) |
608 | * ni = select(ins, C1..) |
609 | * nu = select(uvl, C1..) |
610 | * s = subdelta(nc, uid, nu, ni); |
611 | * |
612 | * doesn't handle Xselect(x, .. z, C1.. cases) ie multicolumn selects |
613 | */ |
614 | lastbat = lastbat_arg(mb, p); |
615 | if (isSelect(p) && p->retc == 1 && lastbat == 2) { |
616 | int var = getArg(p, 1); |
617 | InstrPtr q = old[vars[var]]; |
618 | |
619 | if (q && q->token == ASSIGNsymbol) { |
620 | var = getArg(q, 1); |
621 | q = old[vars[var]]; |
622 | } |
623 | if (q && getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) { |
624 | InstrPtr r = copyInstruction(p); |
625 | InstrPtr s = copyInstruction(p); |
626 | InstrPtr t = copyInstruction(p); |
627 | InstrPtr u = copyInstruction(q); |
628 | |
629 | if( r == NULL || s == NULL || t== NULL ||u == NULL){ |
630 | freeInstruction(r); |
631 | freeInstruction(s); |
632 | freeInstruction(t); |
633 | freeInstruction(u); |
634 | GDKfree(vars); |
635 | GDKfree(nvars); |
636 | GDKfree(slices); |
637 | GDKfree(rslices); |
638 | GDKfree(oclean); |
639 | GDKfree(old); |
640 | throw(MAL,"optimizer.pushselect" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
641 | } |
642 | getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
643 | setVarCList(mb,getArg(r,0)); |
644 | getArg(r, 1) = getArg(q, 1); /* column */ |
645 | r->typechk = TYPE_UNKNOWN; |
646 | pushInstruction(mb,r); |
647 | getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
648 | setVarCList(mb,getArg(s,0)); |
649 | getArg(s, 1) = getArg(q, 3); /* updates */ |
650 | s = ReplaceWithNil(mb, s, 2, TYPE_bat); /* no candidate list */ |
651 | setArgType(mb, s, 2, newBatType(TYPE_oid)); |
652 | /* make sure to resolve again */ |
653 | s->token = ASSIGNsymbol; |
654 | s->typechk = TYPE_UNKNOWN; |
655 | s->fcn = NULL; |
656 | s->blk = NULL; |
657 | pushInstruction(mb,s); |
658 | getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid)); |
659 | setVarCList(mb,getArg(t,0)); |
660 | getArg(t, 1) = getArg(q, 4); /* inserts */ |
661 | pushInstruction(mb,t); |
662 | |
663 | setFunctionId(u, subdeltaRef); |
664 | getArg(u, 0) = getArg(p,0); |
665 | getArg(u, 1) = getArg(r,0); |
666 | getArg(u, 2) = getArg(p,2); /* pre-cands */ |
667 | getArg(u, 3) = getArg(q,2); /* update ids */ |
668 | getArg(u, 4) = getArg(s,0); |
669 | u = pushArgument(mb, u, getArg(t,0)); |
670 | u->typechk = TYPE_UNKNOWN; |
671 | pushInstruction(mb,u); |
672 | oclean[i] = 1; |
673 | continue; |
674 | } |
675 | } |
676 | pushInstruction(mb,p); |
677 | } |
678 | for (j=1; j<i; j++) |
679 | if (old[j] && oclean[j]) |
680 | freeInstruction(old[j]); |
681 | for (; i<limit; i++) |
682 | if (old[i]) |
683 | freeInstruction(old[i]); |
684 | //pushInstruction(mb,old[i]); |
685 | GDKfree(vars); |
686 | GDKfree(nvars); |
687 | GDKfree(slices); |
688 | GDKfree(rslices); |
689 | GDKfree(oclean); |
690 | GDKfree(old); |
691 | |
692 | /* Defense line against incorrect plans */ |
693 | if( actions > 0){ |
694 | chkTypes(cntxt->usermodule, mb, FALSE); |
695 | chkFlow(mb); |
696 | chkDeclarations(mb); |
697 | } |
698 | wrapup: |
699 | /* keep all actions taken as a post block comment */ |
700 | usec = GDKusec()- usec; |
701 | snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec" ,"pushselect" ,actions, usec); |
702 | newComment(mb,buf); |
703 | if( actions >= 0) |
704 | addtoMalBlkHistory(mb); |
705 | |
706 | if( OPTdebug & OPTpushselect){ |
707 | fprintf(stderr, "#PUSHSELECT optimizer exit\n" ); |
708 | fprintFunction(stderr, mb, 0, LIST_MAL_ALL); |
709 | } |
710 | return MAL_SUCCEED; |
711 | } |
712 | |