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 82394 : PushArgument(MalBlkPtr mb, InstrPtr p, int arg, int pos)
19 : {
20 82394 : int i;
21 :
22 82394 : p = pushArgument(mb, p, arg); /* push at end */
23 82394 : if (mb->errors == NULL) {
24 329576 : for (i = p->argc - 1; i > pos; i--)
25 247182 : getArg(p, i) = getArg(p, i - 1);
26 82394 : getArg(p, pos) = arg;
27 : }
28 82394 : return p;
29 : }
30 :
31 : static InstrPtr
32 31494 : ReplaceWithNil(MalBlkPtr mb, InstrPtr p, int pos)
33 : {
34 31494 : p = pushNilBat(mb, p); /* push at end */
35 31494 : getArg(p, pos) = getArg(p, p->argc - 1);
36 31494 : p->argc--;
37 31494 : 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 6794 : subselect_add(subselect_t *subselects, int tid, int subselect)
51 : {
52 6794 : int i;
53 :
54 7026 : for (i = 0; i < subselects->nr; i++) {
55 543 : if (subselects->tid[i] == tid) {
56 311 : if (subselects->subselect[i] == subselect)
57 : return i;
58 : else
59 311 : return -1;
60 : }
61 : }
62 6483 : if (i >= MAX_TABLES)
63 : return -1;
64 6483 : subselects->nr++;
65 6483 : subselects->tid[i] = tid;
66 6483 : subselects->subselect[i] = subselect;
67 6483 : return i;
68 : }
69 :
70 : static int
71 35477939 : lastbat_arg(MalBlkPtr mb, InstrPtr p)
72 : {
73 35477939 : int i = 0;
74 43778750 : for (i = p->retc; i < p->argc; i++) {
75 20029563 : int type = getArgType(mb, p, i);
76 20029563 : if (!isaBatType(type))
77 : break;
78 : }
79 35477939 : if (i < p->argc)
80 11728753 : return i - 1;
81 : return 0;
82 : }
83 :
84 : /* check for updates in between 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 483983 : OPTpushselectImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
102 : InstrPtr pci)
103 : {
104 483983 : int i, j, limit, slimit, actions = 0, *vars, *nvars = NULL,
105 483983 : *slices = NULL, push_down_delta = 0, nr_topn = 0, nr_likes = 0,
106 483983 : no_mito = 0;
107 483983 : bool *rslices = NULL, *oclean = NULL;
108 483983 : InstrPtr p, *old = NULL;
109 483983 : subselect_t subselects;
110 483983 : str msg = MAL_SUCCEED;
111 :
112 483983 : subselects = (subselect_t) { 0 };
113 483983 : if (mb->errors)
114 0 : throw(MAL, "optimizer.pushselect", "%s", mb->errors);
115 :
116 483983 : no_mito = !isOptimizerEnabled(mb, mitosisRef);
117 483982 : (void) stk;
118 483982 : vars = (int *) GDKzalloc(sizeof(int) * mb->vtop);
119 483983 : if (vars == NULL)
120 0 : throw(MAL, "optimizer.pushselect", SQLSTATE(HY013) MAL_MALLOC_FAIL);
121 :
122 483983 : limit = mb->stop;
123 483983 : slimit = mb->ssize;
124 483983 : old = mb->stmt;
125 :
126 : /* check for bailout conditions */
127 18674245 : for (i = 1; mb->errors == NULL && i < limit; i++) {
128 18204462 : int lastbat;
129 18204462 : p = old[i];
130 :
131 36311474 : for (j = 0; j < p->retc; j++) {
132 18107012 : int res = getArg(p, j);
133 18107012 : vars[res] = i;
134 : }
135 :
136 18204462 : if (getModuleId(p) == algebraRef
137 1500577 : && ((!no_mito && getFunctionId(p) == intersectRef)
138 1498520 : || getFunctionId(p) == differenceRef)) {
139 13870 : GDKfree(vars);
140 13870 : goto wrapup;
141 : }
142 :
143 18190592 : if (isSlice(p))
144 16524 : nr_topn++;
145 :
146 18190526 : if (isLikeOp(p))
147 318 : nr_likes++;
148 :
149 18190465 : if (no_mito && isIntersect(p))
150 8 : push_down_delta++;
151 :
152 18190465 : if ((getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef)
153 18034930 : || (no_mito && getModuleId(p) == matRef
154 14 : && getFunctionId(p) == packRef && p->argc == (p->retc + 2)))
155 155535 : push_down_delta++;
156 :
157 18190465 : 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 18190465 : lastbat = lastbat_arg(mb, p);
182 18190465 : if (isSelect(p) && p->retc == 1 &&
183 590934 : /* no cand list */ getArgType(mb, p,
184 : lastbat) != newBatType(TYPE_oid)) {
185 479709 : int i1 = getArg(p, 1), tid = 0;
186 479709 : InstrPtr q = old[vars[i1]];
187 :
188 : /* find the table ids */
189 479709 : while (!tid) {
190 498712 : if (getModuleId(q) == algebraRef
191 23673 : && getFunctionId(q) == projectionRef) {
192 20614 : int i1 = getArg(q, 1);
193 20614 : InstrPtr s = old[vars[i1]];
194 :
195 20614 : if (getModuleId(s) == sqlRef && getFunctionId(s) == tidRef)
196 20614 : tid = getArg(q, 1);
197 20614 : 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 479719 : tid = getArg(q, 1);
203 : }
204 : break;
205 478098 : } else if (isMapOp(q) && q->retc == 1 && q->argc >= 2
206 19074 : && isaBatType(getArgType(mb, q, 1))) {
207 18915 : int i1 = getArg(q, 1);
208 18915 : q = old[vars[i1]];
209 459193 : } else if (isMapOp(q) && q->retc == 1 && q->argc >= 3
210 159 : && isaBatType(getArgType(mb, q, 2))) {
211 88 : int i2 = getArg(q, 2);
212 88 : q = old[vars[i2]];
213 : } else {
214 : break;
215 : }
216 : }
217 479719 : if (tid && subselect_add(&subselects, tid, getArg(p, 0)) < 0) {
218 311 : GDKfree(vars);
219 311 : goto wrapup;
220 : }
221 : }
222 : /* left hand side */
223 18190262 : 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 18190262 : 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 469783 : if (nr_likes || subselects.nr) {
291 5699 : if (newMalBlkStmt(mb, mb->ssize) < 0) {
292 0 : GDKfree(vars);
293 0 : goto wrapup;
294 : }
295 :
296 5701 : pushInstruction(mb, old[0]);
297 :
298 304192 : for (i = 1; mb->errors == NULL && i < limit; i++) {
299 292793 : p = old[i];
300 :
301 : /* rewrite batalgebra.like + [theta]select -> likeselect */
302 292793 : if (getModuleId(p) == algebraRef && p->retc == 1
303 15111 : && (getFunctionId(p) == selectRef
304 14217 : || getFunctionId(p) == thetaselectRef)) {
305 7381 : int var = getArg(p, 1);
306 7381 : InstrPtr q = mb->stmt[vars[var]]; /* BEWARE: the optimizer may not add or remove statements ! */
307 :
308 7381 : 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 7 : && isVarConstant(mb, getArg(p, 4))) {
359 7 : bit truth_value = *(bit *) getVarValue(mb, getArg(p, 3));
360 7 : str comparison = (str) getVarValue(mb, getArg(p, 4));
361 :
362 : /* there are no negative candidate lists so on = false situations swap anti flag */
363 7 : if (truth_value == 0)
364 2 : anti = !anti;
365 5 : else if (is_bit_nil(truth_value))
366 0 : selectok = FALSE;
367 7 : if (strcmp(comparison, "<>") == 0)
368 0 : anti = !anti;
369 7 : else if (strcmp(comparison, "==") != 0)
370 : selectok = FALSE;
371 : } else {
372 : selectok = FALSE;
373 : }
374 :
375 9 : if (selectok) {
376 7 : InstrPtr r = newInstruction(mb, algebraRef, likeselectRef);
377 7 : if (r == NULL) {
378 0 : msg = createException(MAL, "optimizer.pushselect",
379 : SQLSTATE(HY013)
380 : MAL_MALLOC_FAIL);
381 0 : break;
382 : }
383 7 : getArg(r, 0) = getArg(p, 0);
384 7 : r = pushArgument(mb, r, getArg(q, 1));
385 7 : if (has_cand) {
386 6 : r = pushArgument(mb, r, getArg(p, 2));
387 6 : offset = 1;
388 1 : } else if (isaBatType(getArgType(mb, q, 1))) { /* likeselect calls have a candidate parameter */
389 1 : r = pushNilBat(mb, r);
390 1 : offset = 1;
391 : }
392 28 : for (int a = 2; a < q->argc; a++)
393 21 : r = pushArgument(mb, r, getArg(q, a));
394 7 : if (r->argc < (4 + offset))
395 0 : r = pushStr(mb, r,
396 0 : (str) getVarValue(mb, getArg(q, 3)));
397 7 : if (r->argc < (5 + offset))
398 0 : r = pushBit(mb, r, ignore_case);
399 7 : if (r->argc < (6 + offset))
400 7 : r = pushBit(mb, r, anti);
401 7 : freeInstruction(p);
402 7 : p = r;
403 7 : actions++;
404 : }
405 : }
406 : }
407 :
408 : /* inject table ids into subselect
409 : * s = subselect(c, C1..) => subselect(c, t, C1..)
410 : */
411 292793 : pushInstruction(mb, p);
412 : }
413 5698 : for (; i < limit; i++)
414 0 : if (old[i])
415 0 : pushInstruction(mb, old[i]);
416 1166754 : for (; i < slimit; i++)
417 1161054 : if (old[i])
418 0 : freeInstruction(old[i]);
419 5700 : GDKfree(old);
420 5701 : if (msg != MAL_SUCCEED || !push_down_delta) {
421 5681 : GDKfree(vars);
422 5681 : goto wrapup;
423 : }
424 : }
425 :
426 : /* now push selects through delta's */
427 464104 : limit = mb->stop;
428 464104 : slimit = mb->ssize;
429 464104 : old = mb->stmt;
430 :
431 464104 : nvars = (int *) GDKzalloc(sizeof(int) * mb->vtop);
432 464119 : slices = (int *) GDKzalloc(sizeof(int) * mb->vtop);
433 464120 : rslices = (bool *) GDKzalloc(sizeof(bool) * mb->vtop);
434 464121 : oclean = (bool *) GDKzalloc(sizeof(bool) * mb->vtop);
435 928241 : if (!nvars || !slices || !rslices || !oclean ||
436 464120 : newMalBlkStmt(mb, mb->stop + (5 * push_down_delta) + (2 * nr_topn)) < 0) {
437 0 : mb->stmt = old;
438 0 : GDKfree(vars);
439 0 : GDKfree(nvars);
440 0 : GDKfree(slices);
441 0 : GDKfree(rslices);
442 0 : GDKfree(oclean);
443 0 : goto wrapup;
444 : }
445 464121 : pushInstruction(mb, old[0]);
446 :
447 18218709 : for (i = 1; mb->errors == NULL && i < limit; i++) {
448 17290475 : int lastbat;
449 17290475 : p = old[i];
450 :
451 34388305 : for (j = 0; j < p->retc; j++) {
452 17097830 : int res = getArg(p, j);
453 17097830 : vars[res] = i;
454 : }
455 :
456 : /* push subslice under projectdelta */
457 17290475 : if (isSlice(p) && p->retc == 1) {
458 16368 : int var = getArg(p, 1);
459 16368 : InstrPtr q = old[vars[var]];
460 16368 : if (q && getModuleId(q) == sqlRef
461 11 : && getFunctionId(q) == projectdeltaRef) {
462 0 : InstrPtr r = copyInstruction(p);
463 0 : InstrPtr s = copyInstruction(q);
464 0 : if (r == NULL || s == NULL) {
465 0 : freeInstruction(r);
466 0 : freeInstruction(s);
467 0 : msg = createException(MAL, "optimizer.pushselect",
468 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
469 0 : break;
470 : }
471 :
472 0 : rslices[getArg(q, 0)] = true; /* mark projectdelta as rewritten */
473 0 : rslices[getArg(p, 0)] = true; /* mark slice as rewritten */
474 :
475 : /* slice the candidates */
476 0 : setFunctionId(r, sliceRef);
477 0 : nvars[getArg(p, 0)] = getArg(r, 0) = newTmpVariable(mb, getArgType(mb, r, 0));
478 0 : slices[getArg(q, 1)] = getArg(p, 0);
479 :
480 0 : setVarCList(mb, getArg(r, 0));
481 0 : getArg(r, 1) = getArg(s, 1);
482 0 : pushInstruction(mb, r);
483 :
484 0 : nvars[getArg(q, 0)] = getArg(s, 0) = newTmpVariable(mb, getArgType(mb, s, 0));
485 0 : getArg(s, 1) = getArg(r, 0); /* use result of slice */
486 0 : pushInstruction(mb, s);
487 0 : oclean[i] = true;
488 0 : actions++;
489 0 : continue;
490 : }
491 : }
492 : /* Leftfetchjoins involving rewritten sliced candidates ids need to be flattened
493 : * l = projection(t, c); => l = c;
494 : * and
495 : * l = projection(s, ntids); => l = s;
496 : */
497 17274980 : else if (getModuleId(p) == algebraRef
498 1234080 : && getFunctionId(p) == projectionRef) {
499 1066363 : int var = getArg(p, 1);
500 1066363 : InstrPtr r = old[vars[var]], q;
501 :
502 1066363 : if (r && isSlice(r) && rslices[var] && getArg(r, 0) == getArg(p, 1)) {
503 0 : int col = getArg(p, 2);
504 :
505 0 : if (!rslices[col]) { /* was the deltaproject rewritten (sliced) */
506 0 : InstrPtr s = old[vars[col]], u = NULL;
507 :
508 0 : if (s && getModuleId(s) == algebraRef
509 0 : && getFunctionId(s) == projectRef) {
510 0 : col = getArg(s, 1);
511 0 : u = s;
512 0 : s = old[vars[col]];
513 : }
514 0 : if (s && getModuleId(s) == sqlRef
515 0 : && getFunctionId(s) == projectdeltaRef) {
516 0 : InstrPtr t = copyInstruction(s);
517 0 : if (t == NULL) {
518 0 : msg = createException(MAL, "optimizer.pushselect",
519 : SQLSTATE(HY013)
520 : MAL_MALLOC_FAIL);
521 0 : break;
522 : }
523 :
524 0 : getArg(t, 1) = nvars[getArg(r, 0)]; /* use result of slice */
525 0 : rslices[col] = true;
526 0 : nvars[getArg(s, 0)] = getArg(t, 0) = newTmpVariable(mb, getArgType(mb, t, 0));
527 0 : pushInstruction(mb, t);
528 0 : if (u) { /* add again */
529 0 : if ((t = copyInstruction(u)) == NULL) {
530 0 : msg = createException(MAL,
531 : "optimizer.pushselect",
532 : SQLSTATE(HY013)
533 : MAL_MALLOC_FAIL);
534 0 : break;
535 : }
536 0 : getArg(t, 1) = nvars[getArg(t, 1)];
537 0 : pushInstruction(mb, t);
538 : }
539 : }
540 : }
541 0 : q = newAssignment(mb);
542 0 : if (q == NULL) {
543 0 : msg = createException(MAL, "optimizer.pushselect",
544 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
545 0 : break;
546 : }
547 0 : getArg(q, 0) = getArg(p, 0);
548 0 : q = pushArgument(mb, q, getArg(p, 2));
549 0 : if (nvars[getArg(p, 2)] > 0)
550 0 : getArg(q, 1) = nvars[getArg(p, 2)];
551 0 : oclean[i] = true;
552 0 : actions++;
553 0 : pushInstruction(mb, q);
554 0 : continue;
555 : }
556 16208617 : } else if (p->argc >= 2 && slices[getArg(p, 1)] != 0) {
557 : /* use new slice candidate list */
558 0 : assert(slices[getArg(p, 1)] == nvars[getArg(p, 1)]);
559 0 : getArg(p, 1) = slices[getArg(p, 1)];
560 : }
561 : /* remap */
562 38142023 : for (j = p->retc; j < p->argc; j++) {
563 20850660 : int var = getArg(p, j);
564 20850660 : if (nvars[var] > 0) {
565 0 : getArg(p, j) = nvars[var];
566 : }
567 : }
568 :
569 : /* c = delta(b, uid, uvl)
570 : * s = select(c, C1..)
571 : *
572 : * nc = select(b, C1..)
573 : * nu = select(uvl, C1..)
574 : * s = subdelta(nc, uid, nu);
575 : *
576 : * doesn't handle Xselect(x, .. z, C1.. cases) ie multicolumn selects
577 : *
578 : * also handle (if no_mito)
579 : * c = pack(b, ins)
580 : * s = select(c, C1..)
581 : */
582 17291363 : lastbat = lastbat_arg(mb, p);
583 17291363 : if (isSelect(p) && p->retc == 1 && lastbat == 2) {
584 71499 : int var = getArg(p, 1);
585 71499 : InstrPtr q = old[vars[var]];
586 :
587 71499 : if (q && q->token == ASSIGNsymbol) {
588 32084 : var = getArg(q, 1);
589 32084 : q = old[vars[var]];
590 : }
591 71499 : if (no_mito && q && getModuleId(q) == matRef
592 0 : && getFunctionId(q) == packRef && q->argc == (q->retc + 2)) {
593 0 : InstrPtr r = copyInstruction(p);
594 0 : InstrPtr t = copyInstruction(p);
595 :
596 0 : if (r == NULL || t == NULL) {
597 0 : freeInstruction(r);
598 0 : freeInstruction(t);
599 0 : msg = createException(MAL, "optimizer.pushselect",
600 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
601 0 : break;
602 : }
603 0 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
604 0 : setVarCList(mb, getArg(r, 0));
605 0 : getArg(r, 1) = getArg(q, 1); /* column */
606 0 : r->typeresolved = false;
607 0 : pushInstruction(mb, r);
608 0 : getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
609 0 : setVarCList(mb, getArg(t, 0));
610 0 : getArg(t, 1) = getArg(q, 2); /* inserts */
611 0 : pushInstruction(mb, t);
612 :
613 0 : InstrPtr u = copyInstruction(q); /* pack result */
614 0 : if (u == NULL) {
615 0 : msg = createException(MAL, "optimizer.pushselect",
616 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
617 0 : break;
618 : }
619 0 : getArg(u, 0) = getArg(p, 0);
620 0 : getArg(u, 1) = getArg(r, 0);
621 0 : getArg(u, 2) = getArg(t, 0);
622 0 : u->typeresolved = false;
623 0 : pushInstruction(mb, u);
624 0 : oclean[i] = true;
625 0 : continue;
626 71499 : } else if (q && getModuleId(q) == sqlRef
627 64359 : && getFunctionId(q) == deltaRef) {
628 31494 : InstrPtr r = copyInstruction(p);
629 31494 : InstrPtr s = copyInstruction(p);
630 31494 : InstrPtr u = copyInstruction(q);
631 :
632 31494 : if (r == NULL || s == NULL || u == NULL) {
633 0 : freeInstruction(r);
634 0 : freeInstruction(s);
635 0 : freeInstruction(u);
636 0 : msg = createException(MAL, "optimizer.pushselect",
637 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
638 0 : break;
639 : }
640 31494 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
641 31494 : setVarCList(mb, getArg(r, 0));
642 31494 : getArg(r, 1) = getArg(q, 1); /* column */
643 31494 : r->typeresolved = false;
644 31494 : pushInstruction(mb, r);
645 31494 : getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
646 31494 : setVarCList(mb, getArg(s, 0));
647 31494 : getArg(s, 1) = getArg(q, 3); /* updates */
648 31494 : s = ReplaceWithNil(mb, s, 2); /* no candidate list */
649 31494 : setArgType(mb, s, 2, newBatType(TYPE_oid));
650 : /* make sure to resolve again */
651 31494 : s->token = ASSIGNsymbol;
652 31494 : s->typeresolved = false;
653 31494 : s->fcn = NULL;
654 31494 : s->blk = NULL;
655 31494 : pushInstruction(mb, s);
656 :
657 31494 : setFunctionId(u, subdeltaRef);
658 31494 : getArg(u, 0) = getArg(p, 0);
659 31494 : getArg(u, 1) = getArg(r, 0);
660 31494 : getArg(u, 2) = getArg(p, 2); /* pre-cands */
661 31494 : getArg(u, 3) = getArg(q, 2); /* update ids */
662 31494 : u = pushArgument(mb, u, getArg(s, 0)); /* selected updated values ids */
663 31494 : u->token = ASSIGNsymbol;
664 31494 : u->typeresolved = false;
665 31494 : u->fcn = NULL;
666 31494 : u->blk = NULL;
667 31494 : pushInstruction(mb, u);
668 31494 : oclean[i] = true;
669 31494 : continue;
670 : }
671 17219013 : } else if (getModuleId(p) == algebraRef
672 1178953 : && getFunctionId(p) == projectionRef) {
673 1066370 : int id = getArg(p, 1);
674 1066370 : InstrPtr s = old[vars[id]];
675 1066370 : int var = getArg(p, 2);
676 1066370 : InstrPtr q = old[vars[var]];
677 :
678 1066370 : if (no_mito && getModuleId(q) == matRef
679 2 : && getFunctionId(q) == packRef && q->argc == 3
680 0 : && getModuleId(s) == matRef && getFunctionId(s) == packRef
681 0 : && s->argc == 3) {
682 0 : InstrPtr r = copyInstruction(p);
683 0 : InstrPtr t = copyInstruction(p);
684 :
685 0 : if (r == NULL || t == NULL) {
686 0 : freeInstruction(r);
687 0 : freeInstruction(t);
688 0 : msg = createException(MAL, "optimizer.pushselect",
689 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
690 0 : break;
691 : }
692 0 : getArg(r, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
693 0 : setVarCList(mb, getArg(r, 0));
694 0 : getArg(r, 1) = getArg(s, 1);
695 0 : getArg(r, 2) = getArg(q, 1); /* column */
696 0 : r->typeresolved = false;
697 0 : pushInstruction(mb, r);
698 0 : getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
699 0 : setVarCList(mb, getArg(t, 0));
700 0 : getArg(t, 1) = getArg(s, 2);
701 0 : getArg(t, 2) = getArg(q, 2); /* inserts */
702 0 : pushInstruction(mb, t);
703 :
704 0 : InstrPtr u = copyInstruction(q); /* pack result */
705 0 : if (u == NULL) {
706 0 : msg = createException(MAL, "optimizer.pushselect",
707 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
708 0 : break;
709 : }
710 0 : getArg(u, 0) = getArg(p, 0);
711 0 : getArg(u, 1) = getArg(r, 0);
712 0 : getArg(u, 2) = getArg(t, 0);
713 0 : u->typeresolved = false;
714 0 : pushInstruction(mb, u);
715 0 : oclean[i] = true;
716 0 : continue;
717 1066370 : } else if (getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef
718 82394 : && q->argc == 4) {
719 82394 : q = copyInstruction(q);
720 82394 : if (q == NULL) {
721 0 : msg = createException(MAL, "optimizer.pushselect",
722 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
723 0 : break;
724 : }
725 82394 : setFunctionId(q, projectdeltaRef);
726 82394 : getArg(q, 0) = getArg(p, 0);
727 82394 : q = PushArgument(mb, q, getArg(p, 1), 1);
728 82394 : p = q;
729 82394 : oclean[i] = true;
730 82394 : actions++;
731 : }
732 16152643 : } else if (isIntersect(p) && p->retc == 1 && lastbat == 4) {
733 : /* l = delta(b, uid, uvl)
734 : * s = intersect(l, r, li, ..)
735 : *
736 : * nc = intersect(b, r, li..)
737 : * nu = intersect(uvl, r, ..)
738 : * s = subdelta(nc, li, uid, nu);
739 : */
740 8 : int var = getArg(p, 1);
741 8 : InstrPtr q = old[vars[var]];
742 :
743 8 : if (q && q->token == ASSIGNsymbol) {
744 0 : var = getArg(q, 1);
745 0 : q = old[vars[var]];
746 : }
747 8 : if (q && getModuleId(q) == sqlRef && getFunctionId(q) == deltaRef) {
748 0 : InstrPtr r = copyInstruction(p);
749 0 : InstrPtr s = copyInstruction(p);
750 0 : InstrPtr u = copyInstruction(q);
751 :
752 0 : if (r == NULL || s == NULL || u == NULL) {
753 0 : freeInstruction(r);
754 0 : freeInstruction(s);
755 0 : freeInstruction(u);
756 0 : msg = createException(MAL, "optimizer.pushselect",
757 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
758 0 : break;
759 : }
760 0 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
761 0 : setVarCList(mb, getArg(r, 0));
762 0 : getArg(r, 1) = getArg(q, 1); /* column */
763 0 : r->typeresolved = false;
764 0 : pushInstruction(mb, r);
765 0 : getArg(s, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
766 0 : setVarCList(mb, getArg(s, 0));
767 0 : getArg(s, 1) = getArg(q, 3); /* updates */
768 0 : s = ReplaceWithNil(mb, s, 3); /* no candidate list */
769 0 : setArgType(mb, s, 3, newBatType(TYPE_oid));
770 : /* make sure to resolve again */
771 0 : s->token = ASSIGNsymbol;
772 0 : s->typeresolved = false;
773 0 : s->fcn = NULL;
774 0 : s->blk = NULL;
775 0 : pushInstruction(mb, s);
776 :
777 0 : setFunctionId(u, subdeltaRef);
778 0 : getArg(u, 0) = getArg(p, 0);
779 0 : getArg(u, 1) = getArg(r, 0);
780 0 : getArg(u, 2) = getArg(p, 3); /* pre-cands */
781 0 : getArg(u, 3) = getArg(q, 2); /* update ids */
782 : //getArg(u, 4) = getArg(s,0);
783 0 : p = pushArgument(mb, u, getArg(s, 0)); /* push at end */
784 : /* make sure to resolve again */
785 0 : u->token = ASSIGNsymbol;
786 0 : u->typeresolved = false;
787 0 : u->fcn = NULL;
788 0 : u->blk = NULL;
789 0 : pushInstruction(mb, u);
790 0 : oclean[i] = true;
791 0 : continue;
792 : }
793 : }
794 17259018 : assert(p == old[i] || oclean[i]);
795 17259018 : pushInstruction(mb, p);
796 : }
797 17756316 : for (j = 1; j < i; j++)
798 17292207 : if (old[j] && oclean[j])
799 113888 : freeInstruction(old[j]);
800 103974592 : for (; i < slimit; i++)
801 103510473 : if (old[i])
802 0 : pushInstruction(mb, old[i]);
803 464119 : GDKfree(vars);
804 464121 : GDKfree(nvars);
805 464121 : GDKfree(slices);
806 464120 : GDKfree(rslices);
807 464121 : GDKfree(oclean);
808 464121 : GDKfree(old);
809 :
810 : /* Defense line against incorrect plans */
811 464121 : if (msg == MAL_SUCCEED && actions > 0) {
812 21460 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
813 21460 : if (msg == MAL_SUCCEED)
814 21460 : msg = chkFlow(mb);
815 21460 : if (msg == MAL_SUCCEED)
816 21460 : msg = chkDeclarations(mb);
817 : }
818 442661 : wrapup:
819 : /* keep actions taken as a fake argument */
820 483983 : (void) pushInt(mb, pci, actions);
821 483983 : return msg;
822 : }
|