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

Generated by: LCOV version 1.14