LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_remap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 212 343 61.8 %
Date: 2024-10-04 20:04:04 Functions: 4 5 80.0 %

          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      157290 : OPTremapDirect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int idx,
      41             :                            Module scope)
      42             : {
      43      157290 :         str mod, fcn;
      44      157290 :         char buf[1024];
      45      157290 :         int i, retc = pci->retc;
      46      157290 :         InstrPtr p;
      47      157290 :         const char *bufName, *fcnName;
      48             : 
      49      157290 :         (void) cntxt;
      50      157290 :         (void) stk;
      51      157290 :         int plus_one = getArgType(mb, pci, pci->retc) == TYPE_lng ? 1 : 0;
      52      157290 :         mod = VALget(&getVar(mb, getArg(pci, retc + 0 + plus_one))->value);
      53      157290 :         fcn = VALget(&getVar(mb, getArg(pci, retc + 1 + plus_one))->value);
      54             : 
      55      157290 :         if (strncmp(mod, "bat", 3) == 0)
      56           0 :                 mod += 3;
      57             : 
      58             : 
      59      157290 :         snprintf(buf, 1024, "bat%s", mod);
      60      157290 :         bufName = putName(buf);
      61      157290 :         fcnName = putName(fcn);
      62      157290 :         if (bufName == NULL || fcnName == NULL)
      63             :                 return 0;
      64             : 
      65      157290 :         p = newInstructionArgs(mb, bufName, fcnName, pci->argc + 2);
      66      157290 :         if (p == NULL)
      67             :                 return 0;
      68             : 
      69      314634 :         for (i = 0; i < pci->retc; i++)
      70      157344 :                 if (i < 1)
      71      157290 :                         getArg(p, i) = getArg(pci, i);
      72             :                 else
      73          54 :                         p = pushReturn(mb, p, getArg(pci, i));
      74      157290 :         p->retc = p->argc = pci->retc;
      75             : 
      76             : 
      77      157290 :         if (plus_one) {
      78         101 :                 p = pushArgument(mb, p, getArg(pci, pci->retc));     // cardinality argument
      79             :         }
      80             : 
      81      506190 :         for (i = pci->retc + 2 + plus_one; i < pci->argc; i++)
      82      348900 :                 p = pushArgument(mb, p, getArg(pci, i));
      83      157290 :         if (p->retc == 1 &&
      84      157270 :                 ((bufName == batcalcRef
      85      134837 :                   && (fcnName == mulRef
      86      121572 :                           || fcnName == divRef
      87      120291 :                           || fcnName == plusRef
      88       86520 :                           || fcnName == minusRef
      89       74693 :                           || fcnName == modRef))
      90       97012 :                  || bufName == batmtimeRef
      91       96598 :                  || bufName == batstrRef)) {
      92       63441 :                 if (p->argc == 3 &&
      93             :                         /* these two filter out unary batcalc.- with a candidate list */
      94       44430 :                         getBatType(getArgType(mb, p, 1)) != TYPE_oid
      95       44430 :                         && (getBatType(getArgType(mb, p, 2)) != TYPE_oid
      96       43949 :                                 && !(isVarConstant(mb, getArg(p, 2))
      97          11 :                                          && isaBatType(getArgType(mb, p, 2) )))) {
      98             :                         /* add candidate lists */
      99       43940 :                         if (isaBatType(getArgType(mb, p, 1)))
     100       43719 :                                 p = pushNilBat(mb, p);
     101       43940 :                         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      157290 :         typeChecker(scope, mb, p, idx, TRUE);
     108      157289 :         if (!p->typeresolved) {
     109        1258 :                 freeInstruction(p);
     110        1258 :                 return 0;
     111             :         }
     112      156031 :         pushInstruction(mb, p);
     113      156031 :         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        1258 : OPTremapSwitched(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     396             :                                  int idx, Module scope)
     397             : {
     398        1258 :         char *fcn;
     399        1258 :         int r, i;
     400        1258 :         (void) stk;
     401        1258 :         (void) scope;
     402             : 
     403        1258 :         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        1258 :         fcn = VALget(&getVar(mb, getArg(pci, 2))->value);
     409       10064 :         for (i = 0; OperatorMap[i].src; i++)
     410        7548 :                 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      566262 : OPTremapImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     436             : {
     437      566262 :         InstrPtr *old, p;
     438      566262 :         int i, limit, slimit, actions = 0;
     439      566262 :         Module scope = cntxt->usermodule;
     440      566262 :         str msg = MAL_SUCCEED;
     441             : 
     442    25869490 :         for (i = 0; i < mb->stop; i++) {
     443    25322916 :                 p = getInstrPtr(mb, i);
     444    25322916 :                 if (isMultiplex(p)
     445    25303228 :                         || (p->argc == 4 && getModuleId(p) == aggrRef
     446           0 :                                 && getFunctionId(p) == avgRef)) {
     447             :                         break;
     448             :                 }
     449             :         }
     450      566253 :         if (i == mb->stop) {
     451      546574 :                 goto wrapup;
     452             :         }
     453             : 
     454       19679 :         old = mb->stmt;
     455       19679 :         limit = mb->stop;
     456       19679 :         slimit = mb->ssize;
     457       19679 :         if (newMalBlkStmt(mb, mb->ssize) < 0)
     458           0 :                 throw(MAL, "optimizer.remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     459             : 
     460     3488219 :         for (i = 0; i < limit; i++) {
     461     3468541 :                 p = old[i];
     462     3468541 :                 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      157552 :                         int plus_one = getArgType(mb, p, p->retc) == TYPE_lng ? 1 : 0;
     470      157552 :                         str mod = VALget(&getVar(mb, getArg(p, p->retc + 0 + plus_one))-> value);
     471      157552 :                         str fcn = VALget(&getVar(mb, getArg(p, p->retc + 1 + plus_one))-> value);
     472             :                         //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
     473      157552 :                         Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
     474             : 
     475      157552 :                         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      157290 :                         } else if (OPTremapDirect(cntxt, mb, stk, p, i, scope)
     481        1258 :                                            || OPTremapSwitched(cntxt, mb, stk, p, i, scope)) {
     482      156031 :                                 freeInstruction(p);
     483      156031 :                                 actions++;
     484             :                         } else {
     485        1258 :                                 pushInstruction(mb, p);
     486             :                         }
     487     3310989 :                 } 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     3310989 :                         pushInstruction(mb, p);
     574             :                 }
     575             :         }
     576     2696820 :         for (; i < slimit; i++)
     577     2677141 :                 if (old[i])
     578           0 :                         pushInstruction(mb, old[i]);
     579       19679 :         GDKfree(old);
     580             : 
     581             :         /* Defense line against incorrect plans */
     582       19679 :         if (msg == MAL_SUCCEED && actions > 0) {
     583       19326 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     584       19326 :                 if (!msg)
     585       19326 :                         msg = chkFlow(mb);
     586       19326 :                 if (!msg)
     587       19326 :                         msg = chkDeclarations(mb);
     588             :         }
     589         353 :   wrapup:
     590             :         /* keep actions taken as a fake argument */
     591      566253 :         (void) pushInt(mb, pci, actions);
     592      566253 :         return msg;
     593             : }

Generated by: LCOV version 1.14