LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_remap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 205 324 63.3 %
Date: 2024-04-25 23:25:41 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      148022 : OPTremapDirect(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int idx,
      26             :                            Module scope)
      27             : {
      28      148022 :         str mod, fcn;
      29      148022 :         char buf[1024];
      30      148022 :         int i, retc = pci->retc;
      31      148022 :         InstrPtr p;
      32      148022 :         const char *bufName, *fcnName;
      33             : 
      34      148022 :         (void) cntxt;
      35      148022 :         (void) stk;
      36      148022 :         int plus_one = getArgType(mb, pci, pci->retc) == TYPE_lng ? 1 : 0;
      37      148022 :         mod = VALget(&getVar(mb, getArg(pci, retc + 0 + plus_one))->value);
      38      148022 :         fcn = VALget(&getVar(mb, getArg(pci, retc + 1 + plus_one))->value);
      39             : 
      40      148022 :         if (strncmp(mod, "bat", 3) == 0)
      41           0 :                 mod += 3;
      42             : 
      43             : 
      44      148022 :         snprintf(buf, 1024, "bat%s", mod);
      45      148022 :         bufName = putName(buf);
      46      148022 :         fcnName = putName(fcn);
      47      148022 :         if (bufName == NULL || fcnName == NULL)
      48             :                 return 0;
      49             : 
      50      148022 :         p = newInstructionArgs(mb, bufName, fcnName, pci->argc + 2);
      51      148022 :         if (p == NULL)
      52             :                 return 0;
      53             : 
      54      296086 :         for (i = 0; i < pci->retc; i++)
      55      148064 :                 if (i < 1)
      56      148022 :                         getArg(p, i) = getArg(pci, i);
      57             :                 else
      58          42 :                         p = pushReturn(mb, p, getArg(pci, i));
      59      148022 :         p->retc = p->argc = pci->retc;
      60             : 
      61             : 
      62             : 
      63      148022 :         if (plus_one) {
      64         101 :                 p = pushArgument(mb, p, getArg(pci, pci->retc));     // cardinality argument
      65             :         }
      66             : 
      67      476572 :         for (i = pci->retc + 2 + plus_one; i < pci->argc; i++)
      68      328550 :                 p = pushArgument(mb, p, getArg(pci, i));
      69      148022 :         if (p->retc == 1 &&
      70      148014 :                 ((bufName == batcalcRef
      71      127707 :                   && (fcnName == mulRef
      72      114488 :                           || fcnName == divRef
      73      113206 :                           || fcnName == plusRef
      74       80076 :                           || fcnName == minusRef
      75       68242 :                           || fcnName == modRef))
      76       88447 :                  || bufName == batmtimeRef
      77       88050 :                  || bufName == batstrRef)) {
      78       62603 :                 if (p->argc == 3 &&
      79             :                         /* these two filter out unary batcalc.- with a candidate list */
      80       43946 :                         getBatType(getArgType(mb, p, 1)) != TYPE_oid
      81       43946 :                         && (getBatType(getArgType(mb, p, 2)) != TYPE_oid
      82       43754 :                                 && !(isVarConstant(mb, getArg(p, 2))
      83          11 :                                          && isaBatType(getArgType(mb, p, 2) )))) {
      84             :                         /* add candidate lists */
      85       43745 :                         if (isaBatType(getArgType(mb, p, 1)))
      86       43535 :                                 p = pushNilBat(mb, p);
      87       43745 :                         if (isaBatType(getArgType(mb, p, 2)))
      88       24482 :                                 p = pushNilBat(mb, p);
      89             :                 }
      90             :         }
      91             : 
      92             :         /* now see if we can resolve the instruction */
      93      148022 :         typeChecker(scope, mb, p, idx, TRUE);
      94      148022 :         if (!p->typeresolved) {
      95         731 :                 freeInstruction(p);
      96         731 :                 return 0;
      97             :         }
      98      147291 :         pushInstruction(mb, p);
      99      147291 :         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         260 : OPTmultiplexInline(Client cntxt, MalBlkPtr mb, InstrPtr p, int pc)
     135             : {
     136         260 :         MalBlkPtr mq;
     137         260 :         InstrPtr q = NULL, sig;
     138         260 :         char buf[1024];
     139         260 :         int i, j, k, m;
     140         260 :         int refbat = 0, retc = p->retc;
     141         260 :         bit *upgrade;
     142         260 :         str msg;
     143             : 
     144             : 
     145         260 :         str mod = VALget(&getVar(mb, getArg(p, retc + 0))->value);
     146         260 :         str fcn = VALget(&getVar(mb, getArg(p, retc + 1))->value);
     147             :         //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
     148         260 :         Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
     149             : 
     150         260 :         if (s == NULL || !isSideEffectFree(s->def)
     151         212 :                 || getInstrPtr(s->def, 0)->retc != p->retc) {
     152          48 :                 return 0;
     153             :         }
     154             :         /*
     155             :          * Determine the variables to be upgraded and adjust their type
     156             :          */
     157         212 :         if ((mq = copyMalBlk(s->def)) == NULL) {
     158             :                 return 0;
     159             :         }
     160         212 :         sig = getInstrPtr(mq, 0);
     161             : 
     162         212 :         upgrade = (bit *) GDKzalloc(sizeof(bit) * mq->vtop);
     163         212 :         if (upgrade == NULL) {
     164           0 :                 freeMalBlk(mq);
     165           0 :                 return 0;
     166             :         }
     167             : 
     168         212 :         setVarType(mq, 0, newBatType(getArgType(mb, p, 0)));
     169         212 :         clrVarFixed(mq, getArg(getInstrPtr(mq, 0), 0)); /* for typing */
     170         212 :         upgrade[getArg(getInstrPtr(mq, 0), 0)] = TRUE;
     171             : 
     172         538 :         for (i = 3; i < p->argc; i++) {
     173         326 :                 if (!isaBatType(getArgType(mq, sig, i - 2))
     174         326 :                         && isaBatType(getArgType(mb, p, i))) {
     175             : 
     176         316 :                         if (getBatType(getArgType(mb, p, i)) != getArgType(mq, sig, i - 2)) {
     177           0 :                                 goto terminateMX;
     178             :                         }
     179             : 
     180         316 :                         setVarType(mq, i - 2, newBatType(getArgType(mb, p, i)));
     181         316 :                         upgrade[getArg(sig, i - 2)] = TRUE;
     182         316 :                         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      257445 :         for (i = 1; i < mq->stop; i++) {
     191      257445 :                 int fnd = 0;
     192             : 
     193      257445 :                 q = getInstrPtr(mq, i);
     194      257445 :                 if (q->token == ENDsymbol)
     195             :                         break;
     196      603062 :                 for (j = 0; j < q->argc && !fnd; j++)
     197      345829 :                         if (upgrade[getArg(q, j)]) {
     198      355426 :                                 for (k = 0; k < q->retc; k++) {
     199      177713 :                                         setVarType(mq, getArg(q, j),
     200             :                                                            newBatType(getArgType(mq, q, j)));
     201             :                                         /* for typing */
     202      177713 :                                         clrVarFixed(mq, getArg(q, k));
     203      177713 :                                         if (!upgrade[getArg(q, k)]) {
     204        1807 :                                                 upgrade[getArg(q, k)] = TRUE;
     205             :                                                 /* lets restart */
     206        1807 :                                                 i = 0;
     207             :                                         }
     208             :                                 }
     209             :                                 fnd = 1;
     210             :                         }
     211             :                 /* nil:type -> nil:bat[:oid,:type] */
     212      257233 :                 if (!getModuleId(q) && q->token == ASSIGNsymbol && q->argc == 2
     213      115688 :                         && isVarConstant(mq, getArg(q, 1)) && upgrade[getArg(q, 0)]
     214         851 :                         && 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 = getArgType(mq, q, 1);
     222             : 
     223           0 :                                 cst.vtype = tpe;
     224           0 :                                 cst.bat = true;
     225           0 :                                 cst.val.bval = bat_nil;
     226           0 :                                 cst.len = 0;
     227           0 :                                 tpe = newBatType(tpe);
     228           0 :                                 setVarType(mq, getArg(q, 0), tpe);
     229           0 :                                 m = defConstant(mq, tpe, &cst);
     230           0 :                                 if (m >= 0) {
     231           0 :                                         getArg(q, 1) = m;
     232           0 :                                         setVarType(mq, getArg(q, 1), tpe);
     233             :                                 }
     234             :                         } else {
     235             :                                 /* handle constant tail setting */
     236           0 :                                 int tpe = newBatType(getArgType(mq, q, 1));
     237             : 
     238           0 :                                 setVarType(mq, getArg(q, 0), tpe);
     239           0 :                                 setModuleId(q, algebraRef);
     240           0 :                                 setFunctionId(q, projectRef);
     241           0 :                                 q = pushArgument(mb, q, getArg(q, 1));
     242           0 :                                 mq->stmt[i] = q;
     243           0 :                                 getArg(q, 1) = refbat;
     244             :                         }
     245             :                 }
     246             :         }
     247             : 
     248             :         /* now upgrade the statements */
     249        2849 :         for (i = 1; i < mq->stop; i++) {
     250        2849 :                 q = getInstrPtr(mq, i);
     251        2849 :                 if (q->token == ENDsymbol)
     252             :                         break;
     253        5976 :                 for (j = 0; j < q->argc; j++)
     254        4215 :                         if (upgrade[getArg(q, j)]) {
     255        1960 :                                 if (blockStart(q) || q->barrier == REDOsymbol
     256        1956 :                                         || q->barrier == LEAVEsymbol)
     257           4 :                                         goto terminateMX;
     258        1956 :                                 if (getModuleId(q)) {
     259         864 :                                         snprintf(buf, 1024, "bat%s", getModuleId(q));
     260         864 :                                         setModuleId(q, putName(buf));
     261         864 :                                         q->typeresolved = false;
     262         864 :                                         if (q->retc == 1 &&
     263         864 :                                                 ((getModuleId(q) == batcalcRef
     264         585 :                                                   && (getFunctionId(q) == mulRef
     265         562 :                                                           || getFunctionId(q) == divRef
     266         561 :                                                           || getFunctionId(q) == plusRef
     267          39 :                                                           || getFunctionId(q) == minusRef
     268          31 :                                                           || getFunctionId(q) == modRef))
     269         310 :                                                  || getModuleId(q) == batmtimeRef
     270         309 :                                                  || getModuleId(q) == batstrRef)) {
     271         815 :                                                 if (q->argc == 3 &&
     272             :                                                         /* these two filter out unary batcalc.- with a candidate list */
     273         554 :                                                         getBatType(getArgType(mq, q, 1)) != TYPE_oid
     274         554 :                                                         && getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
     275             :                                                         /* add candidate lists */
     276         554 :                                                         if (isaBatType(getArgType(mq, q, 1)))
     277         381 :                                                                 q = pushNilBat(mq, q);
     278         554 :                                                         if (isaBatType(getArgType(mq, q, 2)))
     279         285 :                                                                 q = pushNilBat(mq, q);
     280         261 :                                                 } else if (q->argc == 4
     281         260 :                                                                    && getBatType(getArgType(mq, q, 3)) == TYPE_bit
     282             :                                                                    /* these two filter out unary
     283             :                                                                     * batcalc.- with a candidate
     284             :                                                                     * list */
     285           0 :                                                                    && getBatType(getArgType(mq, q, 1)) != TYPE_oid
     286           0 :                                                                    && getBatType(getArgType(mq, q, 2)) != TYPE_oid) {
     287           0 :                                                         int a = getArg(q, 3);
     288           0 :                                                         q->argc--;
     289             :                                                         /* add candidate lists */
     290           0 :                                                         if (isaBatType(getArgType(mq, q, 1)))
     291           0 :                                                                 q = pushNilBat(mq, q);
     292           0 :                                                         if (isaBatType(getArgType(mq, q, 2)))
     293           0 :                                                                 q = pushNilBat(mq, q);
     294           0 :                                                         q = pushArgument(mq, q, a);
     295             :                                                 }
     296             :                                         }
     297             : 
     298             :                                         /* now see if we can resolve the instruction */
     299         864 :                                         typeChecker(cntxt->usermodule, mq, q, i, TRUE);
     300         864 :                                         if (!q->typeresolved)
     301           2 :                                                 goto terminateMX;
     302             :                                         break;
     303             :                                 }
     304             :                                 /* handle simple upgraded assignments as well */
     305        1092 :                                 if (q->token == ASSIGNsymbol && q->argc == 2
     306        1092 :                                         && !(isaBatType(getArgType(mq, q, 1)))) {
     307          14 :                                         setModuleId(q, algebraRef);
     308          14 :                                         setFunctionId(q, projectRef);
     309          14 :                                         q = pushArgument(mq, q, getArg(q, 1));
     310          14 :                                         mq->stmt[i] = q;
     311          14 :                                         getArg(q, 1) = refbat;
     312             : 
     313          14 :                                         q->typeresolved = false;
     314          14 :                                         typeChecker(cntxt->usermodule, mq, q, i, TRUE);
     315          14 :                                         if (!q->typeresolved)
     316           0 :                                                 goto terminateMX;
     317             :                                         break;
     318             :                                 }
     319             :                         }
     320             :         }
     321             : 
     322             : 
     323         206 :         if (mq->errors) {
     324           0 :   terminateMX:
     325             : 
     326           6 :                 freeMalBlk(mq);
     327           6 :                 GDKfree(upgrade);
     328             : 
     329             :                 /* ugh ugh, fallback to non inline, but optimized code */
     330           6 :                 msg = OPTmultiplexSimple(cntxt, s->def);
     331           6 :                 if (msg)
     332           0 :                         freeException(msg);
     333           6 :                 if (s->kind == FUNCTIONsymbol)
     334           6 :                         s->def->inlineProp = 0;
     335           6 :                 return 0;
     336             :         }
     337             :         /*
     338             :          * We have successfully constructed a variant
     339             :          * of the to-be-inlined function. Put it in place
     340             :          * of the original multiplex.
     341             :          * But first, shift the arguments of the multiplex.
     342             :          */
     343         206 :         delArgument(p, 2);
     344         206 :         delArgument(p, 1);
     345         206 :         inlineMALblock(mb, pc, mq);
     346             : 
     347         206 :         freeMalBlk(mq);
     348         206 :         GDKfree(upgrade);
     349         206 :         return 1;
     350             : }
     351             : 
     352             : /*
     353             :  * The comparison multiplex operations with a constant head may be supported
     354             :  * by reverse of the operation.
     355             :  */
     356             : static const struct {
     357             :         const char *src, *dst;
     358             :         const int len;
     359             : } OperatorMap[] = {
     360             :         {"<", ">", 1},
     361             :         {">", "<", 1},
     362             :         {">=", "<=", 2},
     363             :         {"<=", ">=", 2},
     364             :         {"==", "==", 2},
     365             :         {"!=", "!=", 2},
     366             :         {0, 0, 0}
     367             : };
     368             : 
     369             : static int
     370         731 : OPTremapSwitched(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     371             :                                  int idx, Module scope)
     372             : {
     373         731 :         char *fcn;
     374         731 :         int r, i;
     375         731 :         (void) stk;
     376         731 :         (void) scope;
     377             : 
     378         731 :         if (!isMultiplex(pci) && getArgType(mb, pci, pci->retc) != TYPE_lng
     379           0 :                 && !isVarConstant(mb, getArg(pci, 1))
     380           0 :                 && !isVarConstant(mb, getArg(pci, 2))
     381           0 :                 && !isVarConstant(mb, getArg(pci, 4)) && pci->argc != 5)
     382             :                 return 0;
     383         731 :         fcn = VALget(&getVar(mb, getArg(pci, 2))->value);
     384        5848 :         for (i = 0; OperatorMap[i].src; i++)
     385        4386 :                 if (strcmp(fcn, OperatorMap[i].src) == 0) {
     386             :                         /* found a candidate for a switch */
     387           0 :                         getVarConstant(mb, getArg(pci, 2)).val.sval = (char *) putNameLen(OperatorMap[i].dst, OperatorMap[i].len);
     388           0 :                         getVarConstant(mb, getArg(pci, 2)).len = OperatorMap[i].len;
     389           0 :                         r = getArg(pci, 3);
     390           0 :                         getArg(pci, 3) = getArg(pci, 4);
     391           0 :                         getArg(pci, 4) = r;
     392           0 :                         r = OPTremapDirect(cntxt, mb, stk, pci, idx, scope);
     393             : 
     394             :                         /* always restore the allocated function name */
     395           0 :                         getVarConstant(mb, getArg(pci, 2)).val.sval = fcn;
     396           0 :                         getVarConstant(mb, getArg(pci, 2)).len = strlen(fcn);
     397             : 
     398           0 :                         if (r)
     399             :                                 return 1;
     400             : 
     401             :                         /* restore the arguments */
     402           0 :                         r = getArg(pci, 3);
     403           0 :                         getArg(pci, 3) = getArg(pci, 4);
     404           0 :                         getArg(pci, 4) = r;
     405             :                 }
     406             :         return 0;
     407             : }
     408             : 
     409             : str
     410      558613 : OPTremapImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     411             : {
     412      558613 :         InstrPtr *old, p;
     413      558613 :         int i, limit, slimit, actions = 0;
     414      558613 :         Module scope = cntxt->usermodule;
     415      558613 :         str msg = MAL_SUCCEED;
     416             : 
     417    25424128 :         for (i = 0; i < mb->stop; i++) {
     418    24884261 :                 p = getInstrPtr(mb, i);
     419    24884261 :                 if (isMultiplex(p)
     420    24865515 :                         || (p->argc == 4 && getModuleId(p) == aggrRef
     421           0 :                                 && getFunctionId(p) == avgRef)) {
     422             :                         break;
     423             :                 }
     424             :         }
     425      558604 :         if (i == mb->stop) {
     426      539867 :                 goto wrapup;
     427             :         }
     428             : 
     429       18737 :         old = mb->stmt;
     430       18737 :         limit = mb->stop;
     431       18737 :         slimit = mb->ssize;
     432       18737 :         if (newMalBlkStmt(mb, mb->ssize) < 0)
     433           0 :                 throw(MAL, "optmizer.remap", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     434             : 
     435     3308547 :         for (i = 0; i < limit; i++) {
     436     3289810 :                 p = old[i];
     437     3289810 :                 if (isMultiplex(p)) {
     438             :                         /*
     439             :                          * The next step considered is to handle inlined functions.
     440             :                          * It means we have already skipped the most obvious ones,
     441             :                          * such as the calculator functions. It is particularly
     442             :                          * geared at handling the PSM code.
     443             :                          */
     444      148282 :                         int plus_one = getArgType(mb, p, p->retc) == TYPE_lng ? 1 : 0;
     445      148282 :                         str mod = VALget(&getVar(mb, getArg(p, p->retc + 0 + plus_one))-> value);
     446      148282 :                         str fcn = VALget(&getVar(mb, getArg(p, p->retc + 1 + plus_one))-> value);
     447             :                         //Symbol s = findSymbol(cntxt->usermodule, mod,fcn);
     448      148282 :                         Symbol s = findSymbolInModule(getModule(putName(mod)), putName(fcn));
     449             : 
     450      148282 :                         if (s && s->kind == FUNCTIONsymbol && s->def->inlineProp) {
     451         260 :                                 pushInstruction(mb, p);
     452         260 :                                 if (OPTmultiplexInline(cntxt, mb, p, mb->stop - 1)) {
     453         206 :                                         actions++;
     454             :                                 }
     455      148022 :                         } else if (OPTremapDirect(cntxt, mb, stk, p, i, scope)
     456         731 :                                            || OPTremapSwitched(cntxt, mb, stk, p, i, scope)) {
     457      147291 :                                 freeInstruction(p);
     458      147291 :                                 actions++;
     459             :                         } else {
     460         731 :                                 pushInstruction(mb, p);
     461             :                         }
     462     3141528 :                 } else if (p->argc == 4 && getModuleId(p) == aggrRef
     463           0 :                                    && getFunctionId(p) == avgRef) {
     464             :                         /* group aggr.avg -> aggr.sum/aggr.count */
     465           0 :                         InstrPtr sum, avg, t, iszero;
     466           0 :                         InstrPtr cnt;
     467           0 :                         sum = copyInstruction(p);
     468           0 :                         if (sum == NULL) {
     469           0 :                                 msg = createException(MAL, "optimizer.remap",
     470             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     471           0 :                                 break;
     472             :                         }
     473           0 :                         cnt = copyInstruction(p);
     474           0 :                         if (cnt == NULL) {
     475           0 :                                 freeInstruction(sum);
     476           0 :                                 msg = createException(MAL, "optimizer.remap",
     477             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     478           0 :                                 break;
     479             :                         }
     480           0 :                         setFunctionId(sum, sumRef);
     481           0 :                         setFunctionId(cnt, countRef);
     482           0 :                         getArg(sum, 0) = newTmpVariable(mb, getArgType(mb, p, 1));
     483           0 :                         getArg(cnt, 0) = newTmpVariable(mb, newBatType(TYPE_lng));
     484           0 :                         pushInstruction(mb, sum);
     485           0 :                         pushInstruction(mb, cnt);
     486             : 
     487           0 :                         t = newInstruction(mb, batcalcRef, eqRef);
     488           0 :                         if (t == NULL) {
     489           0 :                                 msg = createException(MAL, "optimizer.remap",
     490             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     491           0 :                                 break;
     492             :                         }
     493           0 :                         getArg(t, 0) = newTmpVariable(mb, newBatType(TYPE_bit));
     494           0 :                         t = pushArgument(mb, t, getDestVar(cnt));
     495           0 :                         t = pushLng(mb, t, 0);
     496           0 :                         pushInstruction(mb, t);
     497           0 :                         iszero = t;
     498             : 
     499           0 :                         t = newInstruction(mb, batcalcRef, dblRef);
     500           0 :                         if (t == NULL) {
     501           0 :                                 msg = createException(MAL, "optimizer.remap",
     502             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     503           0 :                                 break;
     504             :                         }
     505           0 :                         getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
     506           0 :                         t = pushArgument(mb, t, getDestVar(sum));
     507           0 :                         pushInstruction(mb, t);
     508           0 :                         sum = t;
     509             : 
     510           0 :                         t = newInstruction(mb, batcalcRef, ifthenelseRef);
     511           0 :                         if (t == NULL) {
     512           0 :                                 msg = createException(MAL, "optimizer.remap",
     513             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     514           0 :                                 break;
     515             :                         }
     516           0 :                         getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
     517           0 :                         t = pushArgument(mb, t, getDestVar(iszero));
     518           0 :                         t = pushNil(mb, t, TYPE_dbl);
     519           0 :                         t = pushArgument(mb, t, getDestVar(sum));
     520           0 :                         pushInstruction(mb, t);
     521           0 :                         sum = t;
     522             : 
     523           0 :                         t = newInstruction(mb, batcalcRef, dblRef);
     524           0 :                         if (t == NULL) {
     525           0 :                                 msg = createException(MAL, "optimizer.remap",
     526             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     527           0 :                                 break;
     528             :                         }
     529           0 :                         getArg(t, 0) = newTmpVariable(mb, getArgType(mb, p, 0));
     530           0 :                         t = pushArgument(mb, t, getDestVar(cnt));
     531           0 :                         pushInstruction(mb, t);
     532           0 :                         cnt = t;
     533             : 
     534           0 :                         avg = newInstruction(mb, batcalcRef, divRef);
     535           0 :                         if (avg == NULL) {
     536           0 :                                 msg = createException(MAL, "optimizer.remap",
     537             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     538           0 :                                 break;
     539             :                         }
     540           0 :                         getArg(avg, 0) = getArg(p, 0);
     541           0 :                         avg = pushArgument(mb, avg, getDestVar(sum));
     542           0 :                         avg = pushArgument(mb, avg, getDestVar(cnt));
     543           0 :                         avg = pushNilBat(mb, avg);
     544           0 :                         avg = pushNilBat(mb, avg);
     545           0 :                         freeInstruction(p);
     546           0 :                         pushInstruction(mb, avg);
     547             :                 } else {
     548     3141528 :                         pushInstruction(mb, p);
     549             :                 }
     550             :         }
     551     2593777 :         for (; i < slimit; i++)
     552     2575040 :                 if (old[i])
     553           0 :                         pushInstruction(mb, old[i]);
     554       18737 :         GDKfree(old);
     555             : 
     556             :         /* Defense line against incorrect plans */
     557       18737 :         if (msg == MAL_SUCCEED && actions > 0) {
     558       18391 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     559       18391 :                 if (!msg)
     560       18391 :                         msg = chkFlow(mb);
     561       18391 :                 if (!msg)
     562       18391 :                         msg = chkDeclarations(mb);
     563             :         }
     564         346 :   wrapup:
     565             :         /* keep actions taken as a fake argument */
     566      558604 :         (void) pushInt(mb, pci, actions);
     567      558604 :         return msg;
     568             : }

Generated by: LCOV version 1.14