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 : /*
14 : * The first attempt of the multiplex optimizer is to locate
15 : * a properly typed multi-plexed implementation.
16 : * The policy is to search for bat<mod>.<fcn> before going
17 : * into the iterator code generation.
18 : */
19 : #include "monetdb_config.h"
20 : #include "opt_remap.h"
21 : #include "opt_inline.h"
22 : #include "opt_multiplex.h"
23 :
24 : static InstrPtr
25 0 : pushNilAt(MalBlkPtr mb, InstrPtr p, int pos)
26 : {
27 0 : int i;
28 :
29 0 : p = pushNilBat(mb, p); /* push at end */
30 0 : if (mb->errors == NULL) {
31 0 : int arg = getArg(p, p->argc - 1);
32 0 : for (i = p->argc - 1; i > pos; i--)
33 0 : getArg(p, i) = getArg(p, i - 1);
34 0 : getArg(p, pos) = arg;
35 : }
36 0 : return p;
37 : }
38 :
39 : static int
40 154382 : OPTremapDirect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int idx,
41 : Module scope)
42 : {
43 154382 : str mod, fcn;
44 154382 : char buf[1024];
45 154382 : int i, retc = pci->retc;
46 154382 : InstrPtr p;
47 154382 : const char *bufName, *fcnName;
48 :
49 154382 : (void) cntxt;
50 154382 : (void) stk;
51 154382 : int plus_one = getArgType(mb, pci, pci->retc) == TYPE_lng ? 1 : 0;
52 154382 : mod = VALget(&getVar(mb, getArg(pci, retc + 0 + plus_one))->value);
53 154382 : fcn = VALget(&getVar(mb, getArg(pci, retc + 1 + plus_one))->value);
54 :
55 154382 : if (strncmp(mod, "bat", 3) == 0)
56 0 : mod += 3;
57 :
58 :
59 154382 : snprintf(buf, 1024, "bat%s", mod);
60 154382 : bufName = putName(buf);
61 154382 : fcnName = putName(fcn);
62 154382 : if (bufName == NULL || fcnName == NULL)
63 : return 0;
64 :
65 154382 : p = newInstructionArgs(mb, bufName, fcnName, pci->argc + 2);
66 154382 : if (p == NULL)
67 : return 0;
68 :
69 308818 : for (i = 0; i < pci->retc; i++)
70 154436 : if (i < 1)
71 154382 : getArg(p, i) = getArg(pci, i);
72 : else
73 54 : p = pushReturn(mb, p, getArg(pci, i));
74 154382 : p->retc = p->argc = pci->retc;
75 :
76 :
77 154382 : if (plus_one) {
78 101 : p = pushArgument(mb, p, getArg(pci, pci->retc)); // cardinality argument
79 : }
80 :
81 497450 : for (i = pci->retc + 2 + plus_one; i < pci->argc; i++)
82 343068 : p = pushArgument(mb, p, getArg(pci, i));
83 154382 : if (p->retc == 1 &&
84 154362 : ((bufName == batcalcRef
85 131835 : && (fcnName == mulRef
86 118570 : || fcnName == divRef
87 117289 : || fcnName == plusRef
88 83546 : || fcnName == minusRef
89 71719 : || fcnName == modRef))
90 94129 : || bufName == batmtimeRef
91 93715 : || bufName == batstrRef)) {
92 63417 : if (p->argc == 3 &&
93 : /* these two filter out unary batcalc.- with a candidate list */
94 44433 : getBatType(getArgType(mb, p, 1)) != TYPE_oid
95 44433 : && (getBatType(getArgType(mb, p, 2)) != TYPE_oid
96 43952 : && !(isVarConstant(mb, getArg(p, 2))
97 11 : && isaBatType(getArgType(mb, p, 2) )))) {
98 : /* add candidate lists */
99 43943 : if (isaBatType(getArgType(mb, p, 1)))
100 43722 : p = pushNilBat(mb, p);
101 43943 : if (isaBatType(getArgType(mb, p, 2)))
102 24649 : p = pushNilBat(mb, p);
103 : }
104 : }
105 :
106 : /* now see if we can resolve the instruction */
107 154382 : typeChecker(scope, mb, p, idx, TRUE);
108 154382 : if (!p->typeresolved) {
109 1287 : freeInstruction(p);
110 1287 : return 0;
111 : }
112 153095 : pushInstruction(mb, p);
113 153095 : return 1;
114 : }
115 :
116 : /*
117 : * Multiplex inline functions should be done with care.
118 : * The approach taken is to make a temporary copy of the function to be inlined.
119 : * To change all the statements to reflect the new situation
120 : * and, if no error occurs, replaces the target instruction
121 : * with this new block.
122 : *
123 : * By the time we get here, we know that function is
124 : * side-effect free.
125 : *
126 : * The multiplex upgrade is targeted at all function
127 : * arguments whose actual is a BAT and its formal
128 : * is a scalar.
129 : * This seems sufficient for the SQL generated PSM code,
130 : * but does in general not hold.
131 : * For example,
132 : *
133 : * function foo(b:int,c:bat[:oid,:int])
134 : * ... d:= batcalc.+(b,c)
135 : * and
136 : * multiplex("user","foo",ba:bat[:oid,:int],ca:bat[:oid,:int])
137 : * upgrades the first argument. The naive upgrade of
138 : * the statement that would fail. The code below catches
139 : * most of them by simple prepending "bat" to the MAL function
140 : * name and leave it to the type resolver to generate the
141 : * error.
142 : *
143 : * The process terminates as soon as we
144 : * find an instruction that does not have a multiplex
145 : * counterpart.
146 : */
147 : static int
148 262 : OPTmultiplexInline(Client cntxt, MalBlkPtr mb, InstrPtr p, int pc)
149 : {
150 262 : MalBlkPtr mq;
151 262 : InstrPtr q = NULL, sig;
152 262 : char buf[1024];
153 262 : int i, j, k, m;
154 262 : int refbat = 0, retc = p->retc;
155 262 : bit *upgrade;
156 262 : str msg;
157 :
158 :
159 262 : str mod = VALget(&getVar(mb, getArg(p, retc + 0))->value);
160 262 : str fcn = VALget(&getVar(mb, getArg(p, retc + 1))->value);
161 : //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
162 262 : Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
163 :
164 262 : if (s == NULL || !isSideEffectFree(s->def)
165 215 : || getInstrPtr(s->def, 0)->retc != p->retc) {
166 47 : return 0;
167 : }
168 : /*
169 : * Determine the variables to be upgraded and adjust their type
170 : */
171 215 : if ((mq = copyMalBlk(s->def)) == NULL) {
172 : return 0;
173 : }
174 215 : sig = getInstrPtr(mq, 0);
175 :
176 215 : upgrade = (bit *) GDKzalloc(sizeof(bit) * mq->vtop);
177 215 : if (upgrade == NULL) {
178 0 : freeMalBlk(mq);
179 0 : return 0;
180 : }
181 :
182 215 : setVarType(mq, 0, newBatType(getArgType(mb, p, 0)));
183 215 : clrVarFixed(mq, getArg(getInstrPtr(mq, 0), 0)); /* for typing */
184 215 : upgrade[getArg(getInstrPtr(mq, 0), 0)] = TRUE;
185 :
186 544 : for (i = 3; i < p->argc; i++) {
187 329 : if (!isaBatType(getArgType(mq, sig, i - 2))
188 329 : && isaBatType(getArgType(mb, p, i))) {
189 :
190 319 : if (getBatType(getArgType(mb, p, i)) != getArgType(mq, sig, i - 2)) {
191 0 : goto terminateMX;
192 : }
193 :
194 319 : setVarType(mq, i - 2, newBatType(getArgType(mb, p, i)));
195 319 : upgrade[getArg(sig, i - 2)] = TRUE;
196 319 : refbat = getArg(sig, i - 2);
197 : }
198 : }
199 : /*
200 : * The next step is to check each instruction of the
201 : * to-be-inlined function for arguments that require
202 : * an upgrade and resolve it afterwards.
203 : */
204 257572 : for (i = 1; i < mq->stop; i++) {
205 257572 : int fnd = 0;
206 :
207 257572 : q = getInstrPtr(mq, i);
208 257572 : if (q->token == ENDsymbol)
209 : break;
210 603359 : for (j = 0; j < q->argc && !fnd; j++)
211 346002 : if (upgrade[getArg(q, j)]) {
212 355572 : for (k = 0; k < q->retc; k++) {
213 177786 : setVarType(mq, getArg(q, j),
214 : newBatType(getArgType(mq, q, j)));
215 : /* for typing */
216 177786 : clrVarFixed(mq, getArg(q, k));
217 177786 : if (!upgrade[getArg(q, k)]) {
218 1821 : upgrade[getArg(q, k)] = TRUE;
219 : /* lets restart */
220 1821 : i = 0;
221 : }
222 : }
223 : fnd = 1;
224 : }
225 : /* nil:type -> nil:bat[:oid,:type] */
226 257357 : if (!getModuleId(q) && q->token == ASSIGNsymbol && q->argc == 2
227 115751 : && isVarConstant(mq, getArg(q, 1)) && upgrade[getArg(q, 0)]
228 851 : && getArgType(mq, q, 0) == TYPE_void
229 0 : && !isaBatType(getArgType(mq, q, 1))) {
230 : /* handle nil assignment */
231 0 : if (ATOMcmp(getArgGDKType(mq, q, 1),
232 : VALptr(&getVar(mq, getArg(q, 1))->value),
233 : ATOMnilptr(getArgType(mq, q, 1))) == 0) {
234 0 : ValRecord cst;
235 0 : int tpe = getArgType(mq, q, 1);
236 :
237 0 : cst.vtype = tpe;
238 0 : cst.bat = true;
239 0 : cst.val.bval = bat_nil;
240 0 : cst.len = 0;
241 0 : tpe = newBatType(tpe);
242 0 : setVarType(mq, getArg(q, 0), tpe);
243 0 : m = defConstant(mq, tpe, &cst);
244 0 : if (m >= 0) {
245 0 : getArg(q, 1) = m;
246 0 : setVarType(mq, getArg(q, 1), tpe);
247 : }
248 : } else {
249 : /* handle constant tail setting */
250 0 : int tpe = newBatType(getArgType(mq, q, 1));
251 :
252 0 : setVarType(mq, getArg(q, 0), tpe);
253 0 : setModuleId(q, algebraRef);
254 0 : setFunctionId(q, projectRef);
255 0 : q = pushArgument(mb, q, getArg(q, 1));
256 0 : mq->stmt[i] = q;
257 0 : getArg(q, 1) = refbat;
258 : }
259 : }
260 : }
261 :
262 : /* now upgrade the statements */
263 2870 : for (i = 1; i < mq->stop; i++) {
264 2870 : q = getInstrPtr(mq, i);
265 2870 : if (q->token == ENDsymbol)
266 : break;
267 6022 : for (j = 0; j < q->argc; j++)
268 4246 : if (upgrade[getArg(q, j)]) {
269 1976 : if (blockStart(q) || q->barrier == REDOsymbol
270 1972 : || q->barrier == LEAVEsymbol)
271 4 : goto terminateMX;
272 1972 : if (getModuleId(q)) {
273 868 : snprintf(buf, 1024, "bat%s", getModuleId(q));
274 868 : setModuleId(q, putName(buf));
275 868 : q->typeresolved = false;
276 868 : if (q->retc == 1 &&
277 868 : ((getModuleId(q) == batcalcRef
278 587 : && ( getFunctionId(q) == mulRef
279 564 : || getFunctionId(q) == divRef
280 563 : || getFunctionId(q) == plusRef
281 39 : || getFunctionId(q) == minusRef
282 31 : || getFunctionId(q) == modRef
283 31 : || (q->argc > 3 && (
284 4 : getFunctionId(q) == intRef
285 4 : || getFunctionId(q) == lngRef
286 4 : || getFunctionId(q) == hgeRef))
287 : ))
288 312 : || getModuleId(q) == batmtimeRef
289 311 : || getModuleId(q) == batstrRef)) {
290 818 : if (q->argc == 3 &&
291 : /* these two filter out unary batcalc.- with a candidate list */
292 556 : getBatType(getArgType(mq, q, 1)) != TYPE_oid
293 556 : && getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
294 : /* add candidate lists */
295 556 : if (isaBatType(getArgType(mq, q, 1)))
296 382 : q = pushNilBat(mq, q);
297 556 : if (isaBatType(getArgType(mq, q, 2)))
298 286 : q = pushNilBat(mq, q);
299 262 : } else if (q->argc == 4
300 261 : && getBatType(getArgType(mq, q, 3)) == TYPE_bit
301 : /* these two filter out unary
302 : * batcalc.- with a candidate
303 : * list */
304 0 : && getBatType(getArgType(mq, q, 1)) != TYPE_oid
305 0 : && getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
306 0 : int a = getArg(q, 3);
307 0 : q->argc--;
308 : /* add candidate lists */
309 0 : if (isaBatType(getArgType(mq, q, 1)))
310 0 : q = pushNilBat(mq, q);
311 0 : if (isaBatType(getArgType(mq, q, 2)))
312 0 : q = pushNilBat(mq, q);
313 0 : q = pushArgument(mq, q, a);
314 262 : } else if (q->argc == 5 && getModuleId(q) == batcalcRef) { /* decimal casts */
315 0 : int pos = 3;
316 0 : if (isaBatType(getArgType(mq, q, 1)))
317 0 : q = pushNilAt(mq, q, pos++);
318 0 : if (isaBatType(getArgType(mq, q, 2)))
319 0 : q = pushNilAt(mq, q, pos);
320 : }
321 : }
322 :
323 : /* now see if we can resolve the instruction */
324 868 : typeChecker(cntxt->usermodule, mq, q, i, TRUE);
325 868 : if (!q->typeresolved)
326 3 : goto terminateMX;
327 : break;
328 : }
329 : /* handle simple upgraded assignments as well */
330 1104 : if (q->token == ASSIGNsymbol && q->argc == 2
331 1104 : && !(isaBatType(getArgType(mq, q, 1)))) {
332 14 : setModuleId(q, algebraRef);
333 14 : setFunctionId(q, projectRef);
334 14 : q = pushArgument(mq, q, getArg(q, 1));
335 14 : mq->stmt[i] = q;
336 14 : getArg(q, 1) = refbat;
337 :
338 14 : q->typeresolved = false;
339 14 : typeChecker(cntxt->usermodule, mq, q, i, TRUE);
340 14 : if (!q->typeresolved)
341 0 : goto terminateMX;
342 : break;
343 : }
344 : }
345 : }
346 :
347 :
348 208 : if (mq->errors) {
349 0 : terminateMX:
350 :
351 7 : freeMalBlk(mq);
352 7 : GDKfree(upgrade);
353 :
354 : /* ugh ugh, fallback to non inline, but optimized code */
355 7 : msg = OPTmultiplexSimple(cntxt, s->def);
356 7 : if (msg)
357 0 : freeException(msg);
358 7 : if (s->kind == FUNCTIONsymbol)
359 7 : s->def->inlineProp = 0;
360 7 : return 0;
361 : }
362 : /*
363 : * We have successfully constructed a variant
364 : * of the to-be-inlined function. Put it in place
365 : * of the original multiplex.
366 : * But first, shift the arguments of the multiplex.
367 : */
368 208 : delArgument(p, 2);
369 208 : delArgument(p, 1);
370 208 : inlineMALblock(mb, pc, mq);
371 :
372 208 : freeMalBlk(mq);
373 208 : GDKfree(upgrade);
374 208 : return 1;
375 : }
376 :
377 : /*
378 : * The comparison multiplex operations with a constant head may be supported
379 : * by reverse of the operation.
380 : */
381 : static const struct {
382 : const char *src, *dst;
383 : const int len;
384 : } OperatorMap[] = {
385 : {"<", ">", 1},
386 : {">", "<", 1},
387 : {">=", "<=", 2},
388 : {"<=", ">=", 2},
389 : {"==", "==", 2},
390 : {"!=", "!=", 2},
391 : {0, 0, 0}
392 : };
393 :
394 : static int
395 1287 : OPTremapSwitched(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
396 : int idx, Module scope)
397 : {
398 1287 : char *fcn;
399 1287 : int r, i;
400 1287 : (void) stk;
401 1287 : (void) scope;
402 :
403 1287 : if (!isMultiplex(pci) && getArgType(mb, pci, pci->retc) != TYPE_lng
404 12 : && !isVarConstant(mb, getArg(pci, 1))
405 12 : && !isVarConstant(mb, getArg(pci, 2))
406 0 : && !isVarConstant(mb, getArg(pci, 4)) && pci->argc != 5)
407 : return 0;
408 1287 : fcn = VALget(&getVar(mb, getArg(pci, 2))->value);
409 10296 : for (i = 0; OperatorMap[i].src; i++)
410 7722 : if (strcmp(fcn, OperatorMap[i].src) == 0) {
411 : /* found a candidate for a switch */
412 0 : getVarConstant(mb, getArg(pci, 2)).val.sval = (char *) putNameLen(OperatorMap[i].dst, OperatorMap[i].len);
413 0 : getVarConstant(mb, getArg(pci, 2)).len = OperatorMap[i].len;
414 0 : r = getArg(pci, 3);
415 0 : getArg(pci, 3) = getArg(pci, 4);
416 0 : getArg(pci, 4) = r;
417 0 : r = OPTremapDirect(cntxt, mb, stk, pci, idx, scope);
418 :
419 : /* always restore the allocated function name */
420 0 : getVarConstant(mb, getArg(pci, 2)).val.sval = fcn;
421 0 : getVarConstant(mb, getArg(pci, 2)).len = strlen(fcn);
422 :
423 0 : if (r)
424 : return 1;
425 :
426 : /* restore the arguments */
427 0 : r = getArg(pci, 3);
428 0 : getArg(pci, 3) = getArg(pci, 4);
429 0 : getArg(pci, 4) = r;
430 : }
431 : return 0;
432 : }
433 :
434 : str
435 554477 : OPTremapImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
436 : {
437 554477 : InstrPtr *old, p;
438 554477 : int i, limit, slimit, actions = 0;
439 554477 : Module scope = cntxt->usermodule;
440 554477 : str msg = MAL_SUCCEED;
441 :
442 25241331 : for (i = 0; i < mb->stop; i++) {
443 24706615 : p = getInstrPtr(mb, i);
444 24706615 : if (isMultiplex(p)
445 24686854 : || (p->argc == 4 && getModuleId(p) == aggrRef
446 0 : && getFunctionId(p) == avgRef)) {
447 : break;
448 : }
449 : }
450 554472 : if (i == mb->stop) {
451 534716 : goto wrapup;
452 : }
453 :
454 19756 : old = mb->stmt;
455 19756 : limit = mb->stop;
456 19756 : slimit = mb->ssize;
457 19756 : if (newMalBlkStmt(mb, mb->ssize) < 0)
458 0 : throw(MAL, "optimizer.remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
459 :
460 3495575 : for (i = 0; i < limit; i++) {
461 3475819 : p = old[i];
462 3475819 : if (isUnion(p)) {
463 : /*
464 : * The next step considered is to handle inlined functions.
465 : * It means we have already skipped the most obvious ones,
466 : * such as the calculator functions. It is particularly
467 : * geared at handling the PSM code.
468 : */
469 154644 : int plus_one = getArgType(mb, p, p->retc) == TYPE_lng ? 1 : 0;
470 154644 : str mod = VALget(&getVar(mb, getArg(p, p->retc + 0 + plus_one))-> value);
471 154644 : str fcn = VALget(&getVar(mb, getArg(p, p->retc + 1 + plus_one))-> value);
472 : //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
473 154644 : Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
474 :
475 154644 : if (s && s->kind == FUNCTIONsymbol && s->def->inlineProp) {
476 262 : pushInstruction(mb, p);
477 262 : if (OPTmultiplexInline(cntxt, mb, p, mb->stop - 1)) {
478 208 : actions++;
479 : }
480 154382 : } else if (OPTremapDirect(cntxt, mb, stk, p, i, scope)
481 1287 : || OPTremapSwitched(cntxt, mb, stk, p, i, scope)) {
482 153095 : freeInstruction(p);
483 153095 : actions++;
484 : } else {
485 1287 : pushInstruction(mb, p);
486 : }
487 3321175 : } else if (p->argc == 4 && getModuleId(p) == aggrRef
488 0 : && getFunctionId(p) == avgRef) {
489 : /* group aggr.avg -> aggr.sum/aggr.count */
490 0 : InstrPtr sum, avg, t, iszero;
491 0 : InstrPtr cnt;
492 0 : sum = copyInstruction(p);
493 0 : if (sum == NULL) {
494 0 : msg = createException(MAL, "optimizer.remap",
495 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
496 0 : break;
497 : }
498 0 : cnt = copyInstruction(p);
499 0 : if (cnt == NULL) {
500 0 : freeInstruction(sum);
501 0 : msg = createException(MAL, "optimizer.remap",
502 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
503 0 : break;
504 : }
505 0 : setFunctionId(sum, sumRef);
506 0 : setFunctionId(cnt, countRef);
507 0 : getArg(sum, 0) = newTmpVariable(mb, getArgType(mb, p, 1));
508 0 : getArg(cnt, 0) = newTmpVariable(mb, newBatType(TYPE_lng));
509 0 : pushInstruction(mb, sum);
510 0 : pushInstruction(mb, cnt);
511 :
512 0 : t = newInstruction(mb, batcalcRef, eqRef);
513 0 : if (t == NULL) {
514 0 : msg = createException(MAL, "optimizer.remap",
515 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
516 0 : break;
517 : }
518 0 : getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_bit));
519 0 : t = pushArgument(mb, t, getDestVar(cnt));
520 0 : t = pushLng(mb, t, 0);
521 0 : pushInstruction(mb, t);
522 0 : iszero = t;
523 :
524 0 : t = newInstruction(mb, batcalcRef, dblRef);
525 0 : if (t == NULL) {
526 0 : msg = createException(MAL, "optimizer.remap",
527 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
528 0 : break;
529 : }
530 0 : getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
531 0 : t = pushArgument(mb, t, getDestVar(sum));
532 0 : pushInstruction(mb, t);
533 0 : sum = t;
534 :
535 0 : t = newInstruction(mb, batcalcRef, ifthenelseRef);
536 0 : if (t == NULL) {
537 0 : msg = createException(MAL, "optimizer.remap",
538 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
539 0 : break;
540 : }
541 0 : getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
542 0 : t = pushArgument(mb, t, getDestVar(iszero));
543 0 : t = pushNil(mb, t, TYPE_dbl);
544 0 : t = pushArgument(mb, t, getDestVar(sum));
545 0 : pushInstruction(mb, t);
546 0 : sum = t;
547 :
548 0 : t = newInstruction(mb, batcalcRef, dblRef);
549 0 : if (t == NULL) {
550 0 : msg = createException(MAL, "optimizer.remap",
551 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
552 0 : break;
553 : }
554 0 : getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
555 0 : t = pushArgument(mb, t, getDestVar(cnt));
556 0 : pushInstruction(mb, t);
557 0 : cnt = t;
558 :
559 0 : avg = newInstruction(mb, batcalcRef, divRef);
560 0 : if (avg == NULL) {
561 0 : msg = createException(MAL, "optimizer.remap",
562 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
563 0 : break;
564 : }
565 0 : getArg(avg, 0) = getArg(p, 0);
566 0 : avg = pushArgument(mb, avg, getDestVar(sum));
567 0 : avg = pushArgument(mb, avg, getDestVar(cnt));
568 0 : avg = pushNilBat(mb, avg);
569 0 : avg = pushNilBat(mb, avg);
570 0 : freeInstruction(p);
571 0 : pushInstruction(mb, avg);
572 : } else {
573 3321175 : pushInstruction(mb, p);
574 : }
575 : }
576 2710599 : for (; i < slimit; i++)
577 2690843 : if (old[i])
578 0 : pushInstruction(mb, old[i]);
579 19756 : GDKfree(old);
580 :
581 : /* Defense line against incorrect plans */
582 19756 : if (msg == MAL_SUCCEED && actions > 0) {
583 19395 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
584 19395 : if (!msg)
585 19395 : msg = chkFlow(mb);
586 19395 : if (!msg)
587 19395 : msg = chkDeclarations(mb);
588 : }
589 361 : wrapup:
590 : /* keep actions taken as a fake argument */
591 554472 : (void) pushInt(mb, pci, actions);
592 554472 : return msg;
593 : }
|