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
13static InstrPtr
14PushArgument(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
25static InstrPtr
26PushNil(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
38static InstrPtr
39ReplaceWithNil(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
50typedef struct subselect_t {
51 int nr;
52 int tid[MAX_TABLES];
53 int subselect[MAX_TABLES];
54} subselect_t;
55
56static int
57subselect_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
77static int
78subselect_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
90static int
91subselect_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
103static int
104lastbat_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 */
118static int
119no_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
131str
132OPTpushselectImplementation(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 }
698wrapup:
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