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 : #include "monetdb_config.h"
14 : #include "opt_pushselect.h"
15 : #include "mal_interpreter.h" /* for showErrors() */
16 :
17 : static InstrPtr
18 81512 : PushArgument(MalBlkPtr mb, InstrPtr p, int arg, int pos)
19 : {
20 81512 : int i;
21 :
22 81512 : p = pushArgument(mb, p, arg); /* push at end */
23 81512 : if (mb->errors == NULL) {
24 326048 : for (i = p->argc - 1; i > pos; i--)
25 244536 : getArg(p, i) = getArg(p, i - 1);
26 81512 : getArg(p, pos) = arg;
27 : }
28 81512 : return p;
29 : }
30 :
31 : static InstrPtr
32 29994 : ReplaceWithNil(MalBlkPtr mb, InstrPtr p, int pos, int tpe)
33 : {
34 29994 : p = pushNil(mb, p, tpe); /* push at end */
35 29994 : getArg(p, pos) = getArg(p, p->argc - 1);
36 29994 : p->argc--;
37 29994 : return p;
38 : }
39 :
40 :
41 : #define MAX_TABLES 64
42 :
43 : typedef struct subselect_t {
44 : int nr;
45 : int tid[MAX_TABLES];
46 : int subselect[MAX_TABLES];
47 : } subselect_t;
48 :
49 : static int
50 6192 : subselect_add(subselect_t *subselects, int tid, int subselect)
51 : {
52 6192 : int i;
53 :
54 6429 : for (i = 0; i < subselects->nr; i++) {
55 579 : if (subselects->tid[i] == tid) {
56 342 : if (subselects->subselect[i] == subselect)
57 : return i;
58 : else
59 342 : return -1;
60 : }
61 : }
62 5850 : if (i >= MAX_TABLES)
63 : return -1;
64 5850 : subselects->nr++;
65 5850 : subselects->tid[i] = tid;
66 5850 : subselects->subselect[i] = subselect;
67 5850 : return i;
68 : }
69 :
70 : static int
71 34503587 : lastbat_arg(MalBlkPtr mb, InstrPtr p)
72 : {
73 34503587 : int i = 0;
74 42617301 : for (i = p->retc; i < p->argc; i++) {
75 19587780 : int type = getArgType(mb, p, i);
76 19587780 : if (!isaBatType(type) && type != TYPE_bat)
77 : break;
78 : }
79 34503587 : if (i < p->argc)
80 11474060 : return i - 1;
81 : return 0;
82 : }
83 :
84 : /* check for updates inbetween assignment to variables newv and oldv */
85 : static int
86 : no_updates(InstrPtr *old, int *vars, int oldv, int newv)
87 : {
88 : while (newv > oldv) {
89 : InstrPtr q = old[vars[newv]];
90 :
91 : if (isUpdateInstruction(q))
92 : return 0;
93 : newv = getArg(q, 1);
94 : }
95 : return 1;
96 : }
97 :
98 : #define isIntersect(p) (getModuleId(p) == algebraRef && getFunctionId(p) == intersectRef)
99 :
100 : str
101 467667 : OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
102 : InstrPtr pci)
103 : {
104 467667 : int i, j, limit, slimit, actions = 0, *vars, *nvars = NULL,
105 467667 : *slices = NULL, push_down_delta = 0, nr_topn = 0, nr_likes = 0,
106 467667 : no_mito = 0;
107 467667 : bool *rslices = NULL, *oclean = NULL;
108 467667 : InstrPtr p, *old = NULL;
109 467667 : subselect_t subselects;
110 467667 : str msg = MAL_SUCCEED;
111 :
112 467667 : subselects = (subselect_t) { 0 };
113 467667 : if (mb->errors)
114 0 : throw(MAL, "optimizer.pushselect", "%s", mb->errors);
115 :
116 467667 : no_mito = !isOptimizerEnabled(mb, mitosisRef);
117 467666 : (void) stk;
118 467666 : vars = (int *) GDKzalloc(sizeof(int) * mb->vtop);
119 467667 : if (vars == NULL)
120 0 : throw(MAL, "optimizer.pushselect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
121 :
122 467667 : limit = mb->stop;
123 467667 : slimit = mb->ssize;
124 467667 : old = mb->stmt;
125 :
126 : /* check for bailout conditions */
127 18115621 : for (i = 1; mb->errors == NULL && i < limit; i++) {
128 17660674 : int lastbat;
129 17660674 : p = old[i];
130 :
131 35217344 : for (j = 0; j < p->retc; j++) {
132 17556670 : int res = getArg(p, j);
133 17556670 : vars[res] = i;
134 : }
135 :
136 17660674 : if (getModuleId(p) == algebraRef
137 1444876 : && ((!no_mito && getFunctionId(p) == intersectRef)
138 1443416 : || getFunctionId(p) == differenceRef)) {
139 12361 : GDKfree(vars);
140 12361 : goto wrapup;
141 : }
142 :
143 17648313 : if (isSlice(p))
144 16619 : nr_topn++;
145 :
146 17648343 : if (isLikeOp(p))
147 126 : nr_likes++;
148 :
149 17648227 : if (no_mito && isIntersect(p))
150 5 : push_down_delta++;
151 :
152 17648227 : if ((getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef)
153 17511553 : || (no_mito && getModuleId(p) == matRef
154 0 : && getFunctionId(p) == packRef && p->argc == (p->retc + 2)))
155 136674 : push_down_delta++;
156 :
157 17648227 : if ( /* DISABLES CODE */ (0) && getModuleId(p) == sqlRef && getFunctionId(p) == tidRef) { /* rewrite equal table ids */
158 : int sname = getArg(p, 2), tname = getArg(p, 3), s;
159 :
160 : for (s = 0; s < subselects.nr; s++) {
161 : InstrPtr q = old[vars[subselects.tid[s]]];
162 : int Qsname = getArg(q, 2), Qtname = getArg(q, 3);
163 :
164 : if (no_updates(old, vars, getArg(q, 1), getArg(p, 1))
165 : && ((sname == Qsname && tname == Qtname)
166 : || ( /* DISABLES CODE */ (0)
167 : && strcmp(getVarConstant(mb, sname).val.sval,
168 : getVarConstant(mb, Qsname).val.sval) == 0
169 : &&
170 : strcmp(getVarConstant(mb, tname).val.sval,
171 : getVarConstant(mb,
172 : Qtname).val.sval) == 0))) {
173 : clrFunction(p);
174 : p->retc = 1;
175 : p->argc = 2;
176 : getArg(p, 1) = getArg(q, 0);
177 : break;
178 : }
179 : }
180 : }
181 17648227 : lastbat = lastbat_arg(mb, p);
182 17648227 : if (isSelect(p) && p->retc == 1 &&
183 568663 : /* no cand list */ getArgType(mb, p,
184 : lastbat) != newBatType(TYPE_oid)) {
185 460522 : int i1 = getArg(p, 1), tid = 0;
186 460522 : InstrPtr q = old[vars[i1]];
187 :
188 : /* find the table ids */
189 460522 : while (!tid) {
190 481668 : if (getModuleId(q) == algebraRef
191 21179 : && getFunctionId(q) == projectionRef) {
192 19079 : int i1 = getArg(q, 1);
193 19079 : InstrPtr s = old[vars[i1]];
194 :
195 19079 : if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef)
196 19079 : tid = getArg(q, 1);
197 19079 : if (s->argc == 2 && s->retc == 1) {
198 0 : int i1 = getArg(s, 1);
199 0 : InstrPtr s = old[vars[i1]];
200 0 : if (getModuleId(s) == sqlRef
201 0 : && getFunctionId(s) == tidRef)
202 460525 : tid = getArg(q, 1);
203 : }
204 : break;
205 462589 : } else if (isMapOp(q) && q->retc == 1 && q->argc >= 2
206 21180 : && isaBatType(getArgType(mb, q, 1))) {
207 21056 : int i1 = getArg(q, 1);
208 21056 : q = old[vars[i1]];
209 441534 : } else if (isMapOp(q) && q->retc == 1 && q->argc >= 3
210 124 : && isaBatType(getArgType(mb, q, 2))) {
211 90 : int i2 = getArg(q, 2);
212 90 : q = old[vars[i2]];
213 : } else {
214 : break;
215 : }
216 : }
217 460525 : if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) {
218 342 : GDKfree(vars);
219 342 : goto wrapup;
220 : }
221 : }
222 : /* left hand side */
223 17647954 : if ((ATOMIC_GET(&GDKdebug) & PUSHCANDMASK) && isMatJoinOp(p)
224 0 : && p->retc == 2) {
225 0 : int i1 = getArg(p, 2), tid = 0;
226 0 : InstrPtr q = old[vars[i1]];
227 :
228 : /* find the table ids */
229 0 : while (!tid) {
230 0 : if (getModuleId(q) == algebraRef
231 0 : && getFunctionId(q) == projectionRef) {
232 0 : int i1 = getArg(q, 1);
233 0 : InstrPtr s = old[vars[i1]];
234 :
235 0 : if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef)
236 : tid = getArg(q, 1);
237 : break;
238 0 : } else if (isMapOp(q) && q->argc >= 2
239 0 : && isaBatType(getArgType(mb, q, 1))) {
240 0 : int i1 = getArg(q, 1);
241 0 : q = old[vars[i1]];
242 0 : } else if (isMapOp(q) && q->argc >= 3
243 0 : && isaBatType(getArgType(mb, q, 2))) {
244 0 : int i2 = getArg(q, 2);
245 0 : q = old[vars[i2]];
246 : } else {
247 : break;
248 : }
249 : }
250 0 : if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) {
251 0 : GDKfree(vars);
252 0 : goto wrapup;
253 : }
254 : }
255 : /* right hand side */
256 17647954 : if ((ATOMIC_GET(&GDKdebug) & PUSHCANDMASK) && isMatJoinOp(p)
257 0 : && p->retc == 2) {
258 0 : int i1 = getArg(p, 3), tid = 0;
259 0 : InstrPtr q = old[vars[i1]];
260 :
261 : /* find the table ids */
262 0 : while (!tid) {
263 0 : if (getModuleId(q) == algebraRef
264 0 : && getFunctionId(q) == projectionRef) {
265 0 : int i1 = getArg(q, 1);
266 0 : InstrPtr s = old[vars[i1]];
267 :
268 0 : if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef)
269 : tid = getArg(q, 1);
270 : break;
271 0 : } else if (isMapOp(q) && q->argc >= 2
272 0 : && isaBatType(getArgType(mb, q, 1))) {
273 0 : int i1 = getArg(q, 1);
274 0 : q = old[vars[i1]];
275 0 : } else if (isMapOp(q) && q->argc >= 3
276 0 : && isaBatType(getArgType(mb, q, 2))) {
277 0 : int i2 = getArg(q, 2);
278 0 : q = old[vars[i2]];
279 : } else {
280 : break;
281 : }
282 : }
283 0 : if (tid && subselect_add(&subselects, tid, getArg(p, 1)) < 0) {
284 0 : GDKfree(vars);
285 0 : goto wrapup;
286 : }
287 : }
288 : }
289 :
290 454947 : if (nr_likes || subselects.nr) {
291 4962 : if (newMalBlkStmt(mb, mb->ssize) < 0) {
292 0 : GDKfree(vars);
293 0 : goto wrapup;
294 : }
295 :
296 4962 : pushInstruction(mb, old[0]);
297 :
298 269992 : for (i = 1; mb->errors == NULL && i < limit; i++) {
299 260068 : p = old[i];
300 :
301 : /* rewrite batalgebra.like + [theta]select -> likeselect */
302 260068 : if (getModuleId(p) == algebraRef && p->retc == 1
303 14471 : && (getFunctionId(p) == selectRef
304 13643 : || getFunctionId(p) == thetaselectRef)) {
305 6813 : int var = getArg(p, 1);
306 6813 : InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */
307 :
308 6813 : if (isLikeOp(q) && !isaBatType(getArgType(mb, q, 2)) && isVarConstant(mb, getArg(q, 2)) && /* pattern is a value */
309 9 : isVarConstant(mb, getArg(q, 3)) && /* escape is a value */
310 9 : isVarConstant(mb, getArg(q, 4)) && /* isensitive flag is a value */
311 9 : getArg(q, 0) == getArg(p,
312 : 1)
313 : /* the output variable from batalgebra.like is the input one for [theta]select */
314 : ) {
315 9 : int has_cand = (getArgType(mb, p, 2) == newBatType(TYPE_oid)),
316 9 : offset = 0, anti = (getFunctionId(q)[0] == 'n');
317 9 : bit ignore_case = *(bit *) getVarValue(mb, getArg(q, 4)),
318 9 : selectok = TRUE;
319 :
320 : /* TODO at the moment we cannot convert if the select statement has NULL semantics
321 : we can convert it into VAL is NULL or PATTERN is NULL or ESCAPE is NULL
322 : */
323 9 : if (getFunctionId(p) == selectRef
324 2 : && isVarConstant(mb, getArg(p, 2 + has_cand))
325 2 : && isVarConstant(mb, getArg(p, 3 + has_cand))
326 2 : && isVarConstant(mb, getArg(p, 4 + has_cand))
327 2 : && isVarConstant(mb, getArg(p, 5 + has_cand))
328 2 : && isVarConstant(mb, getArg(p, 6 + has_cand))
329 4 : && (p->argc < (has_cand ? 9 : 8)
330 0 : || isVarConstant(mb, getArg(p, 7 + has_cand)))) {
331 2 : bit low = *(bit *) getVarValue(mb,
332 : getArg(p, 2 + has_cand)),
333 2 : high = *(bit *) getVarValue(mb,
334 : getArg(p, 3 + has_cand));
335 2 : bit li = *(bit *) getVarValue(mb,
336 : getArg(p, 4 + has_cand)),
337 2 : hi = *(bit *) getVarValue(mb,
338 : getArg(p, 5 + has_cand));
339 2 : bit santi = *(bit *) getVarValue(mb,
340 : getArg(p, 6 + has_cand));
341 2 : bit sunknown = (p->argc == (has_cand ? 9 : 8)) ? 0 : *(bit *) getVarValue(mb, getArg(p, 7 + has_cand));
342 :
343 : /* semantic or not symmetric cases, it cannot be converted */
344 2 : if (is_bit_nil(low) || is_bit_nil(li)
345 0 : || is_bit_nil(santi) || low != high || li != hi
346 0 : || sunknown)
347 2 : selectok = FALSE;
348 :
349 : /* there are no negative candidate lists so on = false situations swap anti flag */
350 2 : if (low == 0)
351 0 : anti = !anti;
352 2 : if (li == 0)
353 0 : anti = !anti;
354 2 : if (santi)
355 0 : anti = !anti;
356 7 : } else if (getFunctionId(p) == thetaselectRef
357 7 : && isVarConstant(mb, getArg(p, 3))
358 6 : && isVarConstant(mb, getArg(p, 4))) {
359 6 : bit truth_value = *(bit *) getVarValue(mb, getArg(p, 3));
360 6 : str comparison = (str) getVarValue(mb, getArg(p, 4));
361 :
362 : /* there are no negative candidate lists so on = false situations swap anti flag */
363 6 : if (truth_value == 0)
364 2 : anti = !anti;
365 4 : else if (is_bit_nil(truth_value))
366 0 : selectok = FALSE;
367 6 : if (strcmp(comparison, "<>") == 0)
368 0 : anti = !anti;
369 6 : else if (strcmp(comparison, "==") != 0)
370 : selectok = FALSE;
371 : } else {
372 : selectok = FALSE;
373 : }
374 :
375 8 : if (selectok) {
376 6 : InstrPtr r = newInstruction(mb, algebraRef, likeselectRef);
377 6 : if (r == NULL) {
378 0 : msg = createException(MAL, "optimizer.pushselect",
379 : SQLSTATE(HY013)
380 : MAL_MALLOC_FAIL);
381 0 : break;
382 : }
383 6 : getArg(r, 0) = getArg(p, 0);
384 6 : r = pushArgument(mb, r, getArg(q, 1));
385 6 : if (has_cand) {
386 5 : r = pushArgument(mb, r, getArg(p, 2));
387 5 : offset = 1;
388 1 : } else if (isaBatType(getArgType(mb, q, 1))) { /* likeselect calls have a candidate parameter */
389 1 : r = pushNil(mb, r, TYPE_bat);
390 1 : offset = 1;
391 : }
392 24 : for (int a = 2; a < q->argc; a++)
393 18 : r = pushArgument(mb, r, getArg(q, a));
394 6 : if (r->argc < (4 + offset))
395 0 : r = pushStr(mb, r,
396 0 : (str) getVarValue(mb, getArg(q, 3)));
397 6 : if (r->argc < (5 + offset))
398 0 : r = pushBit(mb, r, ignore_case);
399 6 : if (r->argc < (6 + offset))
400 6 : r = pushBit(mb, r, anti);
401 6 : freeInstruction(p);
402 6 : p = r;
403 6 : actions++;
404 : }
405 : }
406 : }
407 :
408 : /* inject table ids into subselect
409 : * s = subselect(c, C1..) => subselect(c, t, C1..)
410 : */
411 260068 : pushInstruction(mb, p);
412 : }
413 4962 : for (; i < limit; i++)
414 0 : if (old[i])
415 0 : pushInstruction(mb, old[i]);
416 1019038 : for (; i < slimit; i++)
417 1014076 : if (old[i])
418 0 : freeInstruction(old[i]);
419 4962 : GDKfree(old);
420 4962 : if (msg != MAL_SUCCEED || !push_down_delta) {
421 4895 : GDKfree(vars);
422 4895 : goto wrapup;
423 : }
424 : }
425 :
426 : /* now push selects through delta's */
427 450052 : limit = mb->stop;
428 450052 : slimit = mb->ssize;
429 450052 : old = mb->stmt;
430 :
431 450052 : nvars = (int *) GDKzalloc(sizeof(int) * mb->vtop);
432 450069 : slices = (int *) GDKzalloc(sizeof(int) * mb->vtop);
433 450066 : rslices = (bool *) GDKzalloc(sizeof(bool) * mb->vtop);
434 450069 : oclean = (bool *) GDKzalloc(sizeof(bool) * mb->vtop);
435 450068 : if (!nvars || !slices || !rslices || !oclean
436 450067 : || newMalBlkStmt(mb,
437 450068 : mb->stop + (5 * push_down_delta) + (2 * nr_topn)) <
438 : 0) {
439 0 : mb->stmt = old;
440 0 : GDKfree(vars);
441 0 : GDKfree(nvars);
442 0 : GDKfree(slices);
443 0 : GDKfree(rslices);
444 0 : GDKfree(oclean);
445 0 : goto wrapup;
446 : }
447 450067 : pushInstruction(mb, old[0]);
448 :
449 17757547 : for (i = 1; mb->errors == NULL && i < limit; i++) {
450 16857425 : int lastbat;
451 16857425 : p = old[i];
452 :
453 33534986 : for (j = 0; j < p->retc; j++) {
454 16677561 : int res = getArg(p, j);
455 16677561 : vars[res] = i;
456 : }
457 :
458 : /* push subslice under projectdelta */
459 16857425 : if (isSlice(p) && p->retc == 1) {
460 16493 : int var = getArg(p, 1);
461 16493 : InstrPtr q = old[vars[var]];
462 16493 : if (q && getModuleId(q) == sqlRef
463 12 : && getFunctionId(q) == projectdeltaRef) {
464 0 : InstrPtr r = copyInstruction(p);
465 0 : InstrPtr s = copyInstruction(q);
466 0 : if (r == NULL || s == NULL) {
467 0 : freeInstruction(r);
468 0 : freeInstruction(s);
469 0 : msg = createException(MAL, "optimizer.pushselect",
470 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
471 0 : break;
472 : }
473 :
474 0 : rslices[getArg(q, 0)] = true; /* mark projectdelta as rewriten */
475 0 : rslices[getArg(p, 0)] = true; /* mark slice as rewriten */
476 :
477 : /* slice the candidates */
478 0 : setFunctionId(r, sliceRef);
479 0 : nvars[getArg(p, 0)] = getArg(r, 0) = newTmpVariable(mb, getArgType(mb, r, 0));
480 0 : slices[getArg(q, 1)] = getArg(p, 0);
481 :
482 0 : setVarCList(mb, getArg(r, 0));
483 0 : getArg(r, 1) = getArg(s, 1);
484 0 : pushInstruction(mb, r);
485 :
486 0 : nvars[getArg(q, 0)] = getArg(s, 0) = newTmpVariable(mb, getArgType(mb, s, 0));
487 0 : getArg(s, 1) = getArg(r, 0); /* use result of slice */
488 0 : pushInstruction(mb, s);
489 0 : oclean[i] = true;
490 0 : actions++;
491 0 : continue;
492 : }
493 : }
494 : /* Leftfetchjoins involving rewriten sliced candidates ids need to be flattend
495 : * l = projection(t, c); => l = c;
496 : * and
497 : * l = projection(s, ntids); => l = s;
498 : */
499 16841889 : else if (getModuleId(p) == algebraRef
500 1211185 : && getFunctionId(p) == projectionRef) {
501 1053453 : int var = getArg(p, 1);
502 1053453 : InstrPtr r = old[vars[var]], q;
503 :
504 1053453 : if (r && isSlice(r) && rslices[var] && getArg(r, 0) == getArg(p, 1)) {
505 0 : int col = getArg(p, 2);
506 :
507 0 : if (!rslices[col]) { /* was the deltaproject rewriten (sliced) */
508 0 : InstrPtr s = old[vars[col]], u = NULL;
509 :
510 0 : if (s && getModuleId(s) == algebraRef
511 0 : && getFunctionId(s) == projectRef) {
512 0 : col = getArg(s, 1);
513 0 : u = s;
514 0 : s = old[vars[col]];
515 : }
516 0 : if (s && getModuleId(s) == sqlRef
517 0 : && getFunctionId(s) == projectdeltaRef) {
518 0 : InstrPtr t = copyInstruction(s);
519 0 : if (t == NULL) {
520 0 : msg = createException(MAL, "optimizer.pushselect",
521 : SQLSTATE(HY013)
522 : MAL_MALLOC_FAIL);
523 0 : break;
524 : }
525 :
526 0 : getArg(t, 1) = nvars[getArg(r, 0)]; /* use result of slice */
527 0 : rslices[col] = true;
528 0 : nvars[getArg(s, 0)] = getArg(t, 0) = newTmpVariable(mb, getArgType(mb, t, 0));
529 0 : pushInstruction(mb, t);
530 0 : if (u) { /* add again */
531 0 : if ((t = copyInstruction(u)) == NULL) {
532 0 : msg = createException(MAL,
533 : "optimizer.pushselect",
534 : SQLSTATE(HY013)
535 : MAL_MALLOC_FAIL);
536 0 : break;
537 : }
538 0 : getArg(t, 1) = nvars[getArg(t, 1)];
539 0 : pushInstruction(mb, t);
540 : }
541 : }
542 : }
543 0 : q = newAssignment(mb);
544 0 : if (q == NULL) {
545 0 : msg = createException(MAL, "optimizer.pushselect",
546 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
547 0 : break;
548 : }
549 0 : getArg(q, 0) = getArg(p, 0);
550 0 : q = pushArgument(mb, q, getArg(p, 2));
551 0 : if (nvars[getArg(p, 2)] > 0)
552 0 : getArg(q, 1) = nvars[getArg(p, 2)];
553 0 : oclean[i] = true;
554 0 : actions++;
555 0 : pushInstruction(mb, q);
556 0 : continue;
557 : }
558 15788436 : } else if (p->argc >= 2 && slices[getArg(p, 1)] != 0) {
559 : /* use new slice candidate list */
560 0 : assert(slices[getArg(p, 1)] == nvars[getArg(p, 1)]);
561 0 : getArg(p, 1) = slices[getArg(p, 1)];
562 : }
563 : /* remap */
564 37588370 : for (j = p->retc; j < p->argc; j++) {
565 20729965 : int var = getArg(p, j);
566 20729965 : if (nvars[var] > 0) {
567 0 : getArg(p, j) = nvars[var];
568 : }
569 : }
570 :
571 : /* c = delta(b, uid, uvl)
572 : * s = select(c, C1..)
573 : *
574 : * nc = select(b, C1..)
575 : * nu = select(uvl, C1..)
576 : * s = subdelta(nc, uid, nu);
577 : *
578 : * doesn't handle Xselect(x, .. z, C1.. cases) ie multicolumn selects
579 : *
580 : * also handle (if no_mito)
581 : * c = pack(b, ins)
582 : * s = select(c, C1..)
583 : */
584 16858405 : lastbat = lastbat_arg(mb, p);
585 16858405 : if (isSelect(p) && p->retc == 1 && lastbat == 2) {
586 68947 : int var = getArg(p, 1);
587 68947 : InstrPtr q = old[vars[var]];
588 :
589 68947 : if (q && q->token == ASSIGNsymbol) {
590 32353 : var = getArg(q, 1);
591 32353 : q = old[vars[var]];
592 : }
593 68947 : if (no_mito && q && getModuleId(q) == matRef
594 0 : && getFunctionId(q) == packRef && q->argc == (q->retc + 2)) {
595 0 : InstrPtr r = copyInstruction(p);
596 0 : InstrPtr t = copyInstruction(p);
597 :
598 0 : if (r == NULL || t == NULL) {
599 0 : freeInstruction(r);
600 0 : freeInstruction(t);
601 0 : msg = createException(MAL, "optimizer.pushselect",
602 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
603 0 : break;
604 : }
605 0 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
606 0 : setVarCList(mb, getArg(r, 0));
607 0 : getArg(r, 1) = getArg(q, 1); /* column */
608 0 : r->typechk = TYPE_UNKNOWN;
609 0 : pushInstruction(mb, r);
610 0 : getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
611 0 : setVarCList(mb, getArg(t, 0));
612 0 : getArg(t, 1) = getArg(q, 2); /* inserts */
613 0 : pushInstruction(mb, t);
614 :
615 0 : InstrPtr u = copyInstruction(q); /* pack result */
616 0 : if (u == NULL) {
617 0 : msg = createException(MAL, "optimizer.pushselect",
618 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
619 0 : break;
620 : }
621 0 : getArg(u, 0) = getArg(p, 0);
622 0 : getArg(u, 1) = getArg(r, 0);
623 0 : getArg(u, 2) = getArg(t, 0);
624 0 : u->typechk = TYPE_UNKNOWN;
625 0 : pushInstruction(mb, u);
626 0 : oclean[i] = true;
627 0 : continue;
628 68947 : } else if (q && getModuleId(q) == sqlRef
629 63265 : && getFunctionId(q) == deltaRef) {
630 29994 : InstrPtr r = copyInstruction(p);
631 29994 : InstrPtr s = copyInstruction(p);
632 29994 : InstrPtr u = copyInstruction(q);
633 :
634 29994 : if (r == NULL || s == NULL || u == NULL) {
635 0 : freeInstruction(r);
636 0 : freeInstruction(s);
637 0 : freeInstruction(u);
638 0 : msg = createException(MAL, "optimizer.pushselect",
639 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
640 0 : break;
641 : }
642 29994 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
643 29994 : setVarCList(mb, getArg(r, 0));
644 29994 : getArg(r, 1) = getArg(q, 1); /* column */
645 29994 : r->typechk = TYPE_UNKNOWN;
646 29994 : pushInstruction(mb, r);
647 29994 : getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
648 29994 : setVarCList(mb, getArg(s, 0));
649 29994 : getArg(s, 1) = getArg(q, 3); /* updates */
650 29994 : s = ReplaceWithNil(mb, s, 2, TYPE_bat); /* no candidate list */
651 29994 : setArgType(mb, s, 2, newBatType(TYPE_oid));
652 : /* make sure to resolve again */
653 29994 : s->token = ASSIGNsymbol;
654 29994 : s->typechk = TYPE_UNKNOWN;
655 29994 : s->fcn = NULL;
656 29994 : s->blk = NULL;
657 29994 : pushInstruction(mb, s);
658 :
659 29994 : setFunctionId(u, subdeltaRef);
660 29994 : getArg(u, 0) = getArg(p, 0);
661 29994 : getArg(u, 1) = getArg(r, 0);
662 29994 : getArg(u, 2) = getArg(p, 2); /* pre-cands */
663 29994 : getArg(u, 3) = getArg(q, 2); /* update ids */
664 29994 : u = pushArgument(mb, u, getArg(s, 0)); /* selected updated values ids */
665 29994 : u->token = ASSIGNsymbol;
666 29994 : u->typechk = TYPE_UNKNOWN;
667 29994 : u->fcn = NULL;
668 29994 : u->blk = NULL;
669 29994 : pushInstruction(mb, u);
670 29994 : oclean[i] = true;
671 29994 : continue;
672 : }
673 16788675 : } else if (getModuleId(p) == algebraRef
674 1158725 : && getFunctionId(p) == projectionRef) {
675 1053456 : int id = getArg(p, 1);
676 1053456 : InstrPtr s = old[vars[id]];
677 1053456 : int var = getArg(p, 2);
678 1053456 : InstrPtr q = old[vars[var]];
679 :
680 1053456 : if (no_mito && getModuleId(q) == matRef
681 0 : && getFunctionId(q) == packRef && q->argc == 3
682 0 : && getModuleId(s) == matRef && getFunctionId(s) == packRef
683 0 : && s->argc == 3) {
684 0 : InstrPtr r = copyInstruction(p);
685 0 : InstrPtr t = copyInstruction(p);
686 :
687 0 : if (r == NULL || t == NULL) {
688 0 : freeInstruction(r);
689 0 : freeInstruction(t);
690 0 : msg = createException(MAL, "optimizer.pushselect",
691 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
692 0 : break;
693 : }
694 0 : getArg(r, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
695 0 : setVarCList(mb, getArg(r, 0));
696 0 : getArg(r, 1) = getArg(s, 1);
697 0 : getArg(r, 2) = getArg(q, 1); /* column */
698 0 : r->typechk = TYPE_UNKNOWN;
699 0 : pushInstruction(mb, r);
700 0 : getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
701 0 : setVarCList(mb, getArg(t, 0));
702 0 : getArg(t, 1) = getArg(s, 2);
703 0 : getArg(t, 2) = getArg(q, 2); /* inserts */
704 0 : pushInstruction(mb, t);
705 :
706 0 : InstrPtr u = copyInstruction(q); /* pack result */
707 0 : if (u == NULL) {
708 0 : msg = createException(MAL, "optimizer.pushselect",
709 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
710 0 : break;
711 : }
712 0 : getArg(u, 0) = getArg(p, 0);
713 0 : getArg(u, 1) = getArg(r, 0);
714 0 : getArg(u, 2) = getArg(t, 0);
715 0 : u->typechk = TYPE_UNKNOWN;
716 0 : pushInstruction(mb, u);
717 0 : oclean[i] = true;
718 0 : continue;
719 1053456 : } else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef
720 81512 : && q->argc == 4) {
721 81512 : q = copyInstruction(q);
722 81512 : if (q == NULL) {
723 0 : msg = createException(MAL, "optimizer.pushselect",
724 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
725 0 : break;
726 : }
727 81512 : setFunctionId(q, projectdeltaRef);
728 81512 : getArg(q, 0) = getArg(p, 0);
729 81512 : q = PushArgument(mb, q, getArg(p, 1), 1);
730 81512 : p = q;
731 81512 : oclean[i] = true;
732 81512 : actions++;
733 : }
734 15735219 : } else if (isIntersect(p) && p->retc == 1 && lastbat == 4) {
735 : /* l = delta(b, uid, uvl)
736 : * s = intersect(l, r, li, ..)
737 : *
738 : * nc = intersect(b, r, li..)
739 : * nu = intersect(uvl, r, ..)
740 : * s = subdelta(nc, li, uid, nu);
741 : */
742 5 : int var = getArg(p, 1);
743 5 : InstrPtr q = old[vars[var]];
744 :
745 5 : if (q && q->token == ASSIGNsymbol) {
746 0 : var = getArg(q, 1);
747 0 : q = old[vars[var]];
748 : }
749 5 : if (q && getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) {
750 0 : InstrPtr r = copyInstruction(p);
751 0 : InstrPtr s = copyInstruction(p);
752 0 : InstrPtr u = copyInstruction(q);
753 :
754 0 : if (r == NULL || s == NULL || u == NULL) {
755 0 : freeInstruction(r);
756 0 : freeInstruction(s);
757 0 : freeInstruction(u);
758 0 : msg = createException(MAL, "optimizer.pushselect",
759 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
760 0 : break;
761 : }
762 0 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
763 0 : setVarCList(mb, getArg(r, 0));
764 0 : getArg(r, 1) = getArg(q, 1); /* column */
765 0 : r->typechk = TYPE_UNKNOWN;
766 0 : pushInstruction(mb, r);
767 0 : getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
768 0 : setVarCList(mb, getArg(s, 0));
769 0 : getArg(s, 1) = getArg(q, 3); /* updates */
770 0 : s = ReplaceWithNil(mb, s, 3, TYPE_bat); /* no candidate list */
771 0 : setArgType(mb, s, 3, newBatType(TYPE_oid));
772 : /* make sure to resolve again */
773 0 : s->token = ASSIGNsymbol;
774 0 : s->typechk = TYPE_UNKNOWN;
775 0 : s->fcn = NULL;
776 0 : s->blk = NULL;
777 0 : pushInstruction(mb, s);
778 :
779 0 : setFunctionId(u, subdeltaRef);
780 0 : getArg(u, 0) = getArg(p, 0);
781 0 : getArg(u, 1) = getArg(r, 0);
782 0 : getArg(u, 2) = getArg(p, 3); /* pre-cands */
783 0 : getArg(u, 3) = getArg(q, 2); /* update ids */
784 : //getArg(u, 4) = getArg(s,0);
785 0 : p = pushArgument(mb, u, getArg(s, 0)); /* push at end */
786 : /* make sure to resolve again */
787 0 : u->token = ASSIGNsymbol;
788 0 : u->typechk = TYPE_UNKNOWN;
789 0 : u->fcn = NULL;
790 0 : u->blk = NULL;
791 0 : pushInstruction(mb, u);
792 0 : oclean[i] = true;
793 0 : continue;
794 : }
795 : }
796 16827628 : assert(p == old[i] || oclean[i]);
797 16827628 : pushInstruction(mb, p);
798 : }
799 17309778 : for (j = 1; j < i; j++)
800 16859710 : if (old[j] && oclean[j])
801 111506 : freeInstruction(old[j]);
802 100818554 : for (; i < slimit; i++)
803 100368493 : if (old[i])
804 0 : pushInstruction(mb, old[i]);
805 450061 : GDKfree(vars);
806 450069 : GDKfree(nvars);
807 450068 : GDKfree(slices);
808 450069 : GDKfree(rslices);
809 450068 : GDKfree(oclean);
810 450068 : GDKfree(old);
811 :
812 : /* Defense line against incorrect plans */
813 450067 : if (msg == MAL_SUCCEED && actions > 0) {
814 19989 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
815 19989 : if (msg == MAL_SUCCEED)
816 19989 : msg = chkFlow(mb);
817 19989 : if (msg == MAL_SUCCEED)
818 19989 : msg = chkDeclarations(mb);
819 : }
820 430078 : wrapup:
821 : /* keep actions taken as a fake argument */
822 467665 : (void) pushInt(mb, pci, actions);
823 467665 : return msg;
824 : }
|