LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_instruction.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 494 660 74.8 %
Date: 2021-09-14 22:17:06 Functions: 48 57 84.2 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * (author)  Author M. Kersten
      11             :  * For documentation see website
      12             :  */
      13             : #include "monetdb_config.h"
      14             : #include "mal_instruction.h"
      15             : #include "mal_function.h"             /* for getPC() */
      16             : #include "mal_utils.h"
      17             : #include "mal_exception.h"
      18             : #include "mal_private.h"
      19             : 
      20             : /* to avoid memory fragmentation stmt and var blocks are allocated in chunks */
      21             : #define MALCHUNK 256
      22             : 
      23             : /* If we encounter an error it can be left behind in the MalBlk
      24             :  * for the upper layers to abandon the track
      25             :  */
      26             : void
      27           0 : addMalException(MalBlkPtr mb, str msg)
      28             : {
      29           0 :         if( msg == NULL)
      30             :                 return;
      31           0 :         if( mb->errors){
      32           0 :                 mb->errors = concatErrors(mb->errors, msg);
      33             :         } else {
      34           0 :                 mb->errors = dupError(msg);
      35             :         }
      36             : }
      37             : 
      38             : Symbol
      39     3493479 : newSymbol(const char *nme, int kind)
      40             : {
      41             :         Symbol cur;
      42             : 
      43     3493479 :         if (nme == NULL)
      44             :                 return NULL;
      45     3493479 :         cur = (Symbol) GDKzalloc(sizeof(SymRecord));
      46     3493479 :         if (cur == NULL)
      47             :                 return NULL;
      48     3493479 :         cur->name = putName(nme);
      49     3493479 :         if(cur->name == NULL) {
      50           0 :                 GDKfree(cur);
      51           0 :                 return NULL;
      52             :         }
      53     3493479 :         cur->kind = kind;
      54     3493479 :         cur->peer = NULL;
      55     6947278 :         cur->def = newMalBlk(kind == FUNCTIONsymbol? STMT_INCREMENT : 2);
      56     3493479 :         if (cur->def == NULL){
      57           0 :                 GDKfree(cur);
      58           0 :                 return NULL;
      59             :         }
      60             :         return cur;
      61             : }
      62             : 
      63             : void
      64     3467625 : freeSymbol(Symbol s)
      65             : {
      66     3467625 :         if (s == NULL)
      67             :                 return;
      68     3467625 :         if (s->def) {
      69     3467625 :                 freeMalBlk(s->def);
      70     3467625 :                 s->def = NULL;
      71             :         }
      72     3467625 :         GDKfree(s);
      73             : }
      74             : 
      75             : void
      76      142320 : freeSymbolList(Symbol s)
      77             : {
      78             :         Symbol t = s;
      79             : 
      80     3609628 :         while (s) {
      81     3467308 :                 t = s->peer;
      82     3467308 :                 s->peer = NULL;
      83     3467308 :                 freeSymbol(s);
      84             :                 s = t;
      85             :         }
      86      142320 : }
      87             : 
      88             : int
      89     5883794 : newMalBlkStmt(MalBlkPtr mb, int maxstmts)
      90             : {
      91             :         InstrPtr *p;
      92     5883794 :         maxstmts= maxstmts % MALCHUNK == 0 ? maxstmts : ((maxstmts / MALCHUNK) + 1) * MALCHUNK;
      93             : 
      94     5883794 :         p = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * maxstmts);
      95     5883797 :         if (p == NULL)
      96             :                 return -1;
      97     5883797 :         mb->stmt = p;
      98     5883797 :         mb->stop = 0;
      99     5883797 :         mb->ssize = maxstmts;
     100     5883797 :         return 0;
     101             : }
     102             : 
     103             : MalBlkPtr
     104     3497339 : newMalBlk(int elements)
     105             : {
     106             :         MalBlkPtr mb;
     107             :         VarRecord *v;
     108             : 
     109     3497339 :         mb = (MalBlkPtr) GDKmalloc(sizeof(MalBlkRecord));
     110     3497341 :         if (mb == NULL)
     111             :                 return NULL;
     112             : 
     113             :         /* each MAL instruction implies at least one variable
     114             :          * we reserve some extra for constants */
     115     3497341 :         elements= (elements + 8) %  MALCHUNK == 0 ? elements + 8: ((elements + 8)/MALCHUNK + 1) * MALCHUNK;
     116     3497341 :         v = (VarRecord *) GDKzalloc(sizeof(VarRecord) * elements );
     117     3497346 :         if (v == NULL) {
     118           0 :                 GDKfree(mb);
     119           0 :                 return NULL;
     120             :         }
     121     3497346 :         mb->var = v;
     122     3497346 :         mb->vtop = 0;
     123     3497346 :         mb->vid = 0;
     124     3497346 :         mb->vsize = elements;
     125     3497346 :         mb->help = NULL;
     126     3497346 :         mb->statichelp = NULL;
     127     3497346 :         mb->binding[0] = 0;
     128     3497346 :         mb->tag = 0;
     129     3497346 :         mb->workers = 0;
     130     3497346 :         mb->memory = 0;
     131     3497346 :         mb->errors = NULL;
     132     3497346 :         mb->alternative = NULL;
     133     3497346 :         mb->history = NULL;
     134     3497346 :         mb->keephistory = 0;
     135     3497346 :         mb->maxarg = MAXARG;         /* the minimum for each instruction */
     136     3497346 :         mb->inlineProp = 0;
     137     3497346 :         mb->unsafeProp = 0;
     138     3497346 :         mb->replica = NULL;
     139     3497346 :         mb->starttime = 0;
     140     3497346 :         mb->runtime = 0;
     141     3497346 :         mb->calls = 0;
     142     3497346 :         mb->optimize = 0;
     143     3497346 :         mb->stmt = NULL;
     144     3497346 :         if (newMalBlkStmt(mb, elements) < 0) {
     145           0 :                 GDKfree(mb->var);
     146           0 :                 GDKfree(mb->stmt);
     147           0 :                 GDKfree(mb);
     148           0 :                 return NULL;
     149             :         }
     150             :         return mb;
     151             : }
     152             : 
     153             : /* We only grow until the MAL block can be used */
     154             : static int growBlk(int elm)
     155             : {
     156      129823 :         return elm % MALCHUNK ==0 ? elm + MALCHUNK : elm;
     157             : }
     158             : 
     159             : int
     160      100927 : resizeMalBlk(MalBlkPtr mb, int elements)
     161             : {
     162             :         int i;
     163      100927 :         elements = elements  %  MALCHUNK == 0?  elements: (elements / MALCHUNK +1) * MALCHUNK;
     164             : 
     165      100927 :         if( elements > mb->ssize){
     166       92161 :                 InstrPtr *ostmt = mb->stmt;
     167       92161 :                 mb->stmt = (InstrPtr *) GDKrealloc(mb->stmt, elements * sizeof(InstrPtr));
     168       92161 :                 if ( mb->stmt ){
     169    23596970 :                         for ( i = mb->ssize; i < elements; i++)
     170    23504809 :                                 mb->stmt[i] = 0;
     171       92161 :                         mb->ssize = elements;
     172             :                 } else {
     173           0 :                         mb->stmt = ostmt;    /* reinstate old pointer */
     174           0 :                         mb->errors = createMalException(mb,0, TYPE,  SQLSTATE(HY013) MAL_MALLOC_FAIL);
     175           0 :                         return -1;
     176             :                 }
     177             :         }
     178             : 
     179             : 
     180      100927 :         if( elements > mb->vsize){
     181           0 :                 VarRecord *ovar = mb->var;
     182           0 :                 mb->var = (VarRecord*) GDKrealloc(mb->var, elements * sizeof (VarRecord));
     183           0 :                 if ( mb->var ){
     184           0 :                         memset( ((char*) mb->var) + sizeof(VarRecord) * mb->vsize, 0, (elements - mb->vsize) * sizeof(VarRecord));
     185           0 :                         mb->vsize = elements;
     186             :                 } else{
     187           0 :                         mb->var = ovar;
     188           0 :                         mb->errors = createMalException(mb,0, TYPE,  SQLSTATE(HY013) MAL_MALLOC_FAIL);
     189           0 :                         return -1;
     190             :                 }
     191             :         }
     192             :         return 0;
     193             : }
     194             : /* For a MAL session we have to keep the variables around
     195             :  * and only need to reset the instruction pointer
     196             :  */
     197             : void
     198      364743 : resetMalTypes(MalBlkPtr mb, int stop)
     199             : {
     200             :         int i;
     201             : 
     202    22648047 :         for(i=0; i<stop; i++)
     203    22283304 :                 mb->stmt[i] ->typechk = TYPE_UNKNOWN;
     204      364743 :         mb->stop = stop;
     205      364743 :         mb->errors = NULL;
     206      364743 : }
     207             : 
     208             : /* For SQL operations we have to cleanup variables and trim the space
     209             :  * A portion is retained for the next query */
     210             : void
     211      358037 : resetMalBlk(MalBlkPtr mb)
     212             : {
     213             :         int i;
     214             :         InstrPtr *new;
     215             :         VarRecord *vnew;
     216             : 
     217    14145429 :         for(i=MALCHUNK; i<mb->ssize; i++) {
     218    13787392 :                 freeInstruction(mb->stmt[i]);
     219    13787392 :                 mb->stmt[i] = NULL;
     220             :         }
     221      358037 :         if( mb->ssize != MALCHUNK){
     222       26545 :                 new = (InstrPtr*) GDKrealloc(mb->stmt, sizeof(InstrPtr) * MALCHUNK);
     223       26545 :                 if( new == NULL){
     224             :                         // the only place to return an error signal at this stage.
     225             :                         // The Client context should be passed around more deeply
     226           0 :                         mb->errors = createMalException(mb,0,TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     227           0 :                         return ;
     228             :                 }
     229       26545 :                 mb->stmt = new;
     230       26545 :                 mb->ssize = MALCHUNK;
     231             :         }
     232             :         /* Reuse the initial function statement */
     233      358037 :         mb->stop = 0;
     234             : 
     235    60071659 :         for(i=0; i< mb->vtop; i++){
     236    59713622 :                 if (isVarConstant(mb, i))
     237    14581194 :                         VALclear(&getVarConstant(mb,i));
     238             :         }
     239             : 
     240      358037 :         if(mb->vsize != MALCHUNK){
     241       34016 :                 vnew = (VarRecord*) GDKrealloc(mb->var, sizeof(VarRecord) * MALCHUNK);
     242       34016 :                 if (vnew == NULL) {
     243             :                         // the only place to return an error signal at this stage.
     244             :                         // The Client context should be passed around more deeply
     245           0 :                         mb->errors = createMalException(mb,0,TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     246           0 :                         return;
     247             :                 }
     248       34016 :                 mb->var = vnew;
     249       34016 :                 mb->vsize = MALCHUNK;
     250             :         }
     251      358037 :     mb->vtop = 0;
     252      358037 :     mb->vid = 0;
     253             : }
     254             : 
     255             : 
     256             : /* The freeMalBlk code is quite defensive. It is used to localize an
     257             :  * illegal re-use of a MAL blk. */
     258             : void
     259     3471684 : freeMalBlk(MalBlkPtr mb)
     260             : {
     261             :         int i;
     262             : 
     263   892270862 :         for (i = 0; i < mb->ssize; i++)
     264   888799172 :                 if (mb->stmt[i]) {
     265     3667046 :                         freeInstruction(mb->stmt[i]);
     266     3667052 :                         mb->stmt[i] = NULL;
     267             :                 }
     268     3471690 :         mb->stop = 0;
     269    16981746 :         for(i=0; i< mb->vtop; i++)
     270    13510056 :         if( isVarConstant(mb,i))
     271       65361 :                 VALclear(&getVarConstant(mb,i));
     272     3471690 :         mb->vtop = 0;
     273     3471690 :         mb->vid = 0;
     274     3471690 :         GDKfree(mb->stmt);
     275     3471691 :         mb->stmt = 0;
     276     3471691 :         GDKfree(mb->var);
     277     3471691 :         mb->var = 0;
     278             : 
     279     3471691 :         if (mb->history){
     280           0 :                 freeMalBlk(mb->history);
     281           0 :                 mb->history = NULL;
     282             :         }
     283     3471691 :         mb->binding[0] = 0;
     284     3471691 :         mb->tag = 0;
     285     3471691 :         mb->memory = 0;
     286     3471691 :         mb->workers = 0;
     287     3471691 :         if (mb->help && mb->statichelp != mb->help)
     288          20 :                 GDKfree(mb->help);
     289     3471691 :         mb->help = 0;
     290     3471691 :         mb->statichelp = 0;
     291     3471691 :         mb->inlineProp = 0;
     292     3471691 :         mb->unsafeProp = 0;
     293     3471691 :         freeException(mb->errors);
     294     3471689 :         GDKfree(mb);
     295     3471691 : }
     296             : 
     297             : /* The routine below should assure that all referenced structures are
     298             :  * private. The copying is memory conservative. */
     299             : MalBlkPtr
     300         198 : copyMalBlk(MalBlkPtr old)
     301             : {
     302             :         MalBlkPtr mb;
     303             :         int i;
     304             : 
     305         198 :         mb = (MalBlkPtr) GDKzalloc(sizeof(MalBlkRecord));
     306         198 :         if (mb == NULL)
     307             :                 return NULL;
     308         198 :         mb->alternative = old->alternative;
     309         198 :         mb->history = NULL;
     310         198 :         mb->keephistory = old->keephistory;
     311             : 
     312         198 :         mb->var = (VarRecord *) GDKzalloc(sizeof(VarRecord) * old->vsize);
     313         198 :         if (mb->var == NULL) {
     314           0 :                 GDKfree(mb);
     315           0 :                 return NULL;
     316             :         }
     317             : 
     318         198 :         mb->vsize = old->vsize;
     319         198 :         mb->vtop = old->vtop;
     320         198 :         mb->vid = old->vid;
     321             : 
     322             :         // copy all variable records
     323       14396 :         for (i = 0; i < old->vtop; i++) {
     324       14198 :                 mb->var[i]=  old->var[i];
     325       14198 :                 if (!VALcopy(&(mb->var[i].value), &(old->var[i].value))) {
     326           0 :                         while (--i >= 0)
     327           0 :                                 VALclear(&mb->var[i].value);
     328           0 :                         GDKfree(mb->var);
     329           0 :                         GDKfree(mb);
     330           0 :                         return NULL;
     331             :                 }
     332             :         }
     333             : 
     334         198 :         mb->stmt = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * old->ssize);
     335             : 
     336         198 :         if (mb->stmt == NULL) {
     337           0 :                 for (i = 0; i < old->vtop; i++)
     338           0 :                         VALclear(&mb->var[i].value);
     339           0 :                 GDKfree(mb->var);
     340           0 :                 GDKfree(mb);
     341           0 :                 return NULL;
     342             :         }
     343             : 
     344         198 :         mb->stop = old->stop;
     345         198 :         mb->ssize = old->ssize;
     346         198 :         assert(old->stop < old->ssize);
     347       13324 :         for (i = 0; i < old->stop; i++) {
     348       13126 :                 mb->stmt[i] = copyInstruction(old->stmt[i]);
     349       13126 :                 if(!mb->stmt[i]) {
     350           0 :                         while (--i >= 0){
     351           0 :                                 freeInstruction(mb->stmt[i]);
     352           0 :                                 mb->stmt[i]= NULL;
     353             :                         }
     354           0 :                         for (i = 0; i < old->vtop; i++)
     355           0 :                                 VALclear(&mb->var[i].value);
     356           0 :                         GDKfree(mb->var);
     357           0 :                         GDKfree(mb->stmt);
     358           0 :                         GDKfree(mb);
     359           0 :                         return NULL;
     360             :                 }
     361             :         }
     362         198 :         mb->help = old->help ? GDKstrdup(old->help) : NULL;
     363         198 :         if (old->help && !mb->help) {
     364           0 :                 for (i = 0; i < old->stop; i++){
     365           0 :                         freeInstruction(mb->stmt[i]);
     366           0 :                         mb->stmt[i]= NULL;
     367             :                 }
     368           0 :                 for (i = 0; i < old->vtop; i++)
     369           0 :                         VALclear(&mb->var[i].value);
     370           0 :                 GDKfree(mb->var);
     371           0 :                 GDKfree(mb->stmt);
     372           0 :                 GDKfree(mb);
     373           0 :                 return NULL;
     374             :         }
     375         198 :         strcpy_len(mb->binding,  old->binding, sizeof(mb->binding));
     376         198 :         mb->errors = old->errors? GDKstrdup(old->errors):0;
     377         198 :         mb->tag = old->tag;
     378         198 :         mb->runtime = old->runtime;
     379         198 :         mb->calls = old->calls;
     380         198 :         mb->optimize = old->optimize;
     381         198 :         mb->replica = old->replica;
     382         198 :         mb->maxarg = old->maxarg;
     383         198 :         mb->inlineProp = old->inlineProp;
     384         198 :         mb->unsafeProp = old->unsafeProp;
     385         198 :         return mb;
     386             : }
     387             : 
     388             : void
     389    10751127 : addtoMalBlkHistory(MalBlkPtr mb)
     390             : {
     391             :         MalBlkPtr cpy, h;
     392    10751127 :         if (mb->keephistory) {
     393           0 :                 cpy = copyMalBlk(mb);
     394           0 :                 if (cpy == NULL)
     395             :                         return;                         /* ignore history */
     396           0 :                 cpy->history = NULL;
     397           0 :                 if (mb->history == NULL)
     398           0 :                         mb->history = cpy;
     399             :                 else {
     400           0 :                         for (h = mb; h->history; h = h->history)
     401             :                                 ;
     402           0 :                         h->history = cpy;
     403             :                 }
     404             :         }
     405             : }
     406             : 
     407             : void
     408           0 : removeMalBlkHistory(MalBlkPtr mb)
     409             : {
     410           0 :         if(mb->history){
     411           0 :                 removeMalBlkHistory(mb->history);
     412           0 :                 freeMalBlk(mb->history);
     413           0 :                 mb->history = NULL;
     414             :         }
     415           0 : }
     416             : 
     417             : MalBlkPtr
     418           0 : getMalBlkHistory(MalBlkPtr mb, int idx)
     419             : {
     420             :         MalBlkPtr h = mb;
     421             : 
     422           0 :         while (h && idx-- >= 0)
     423           0 :                 h = h->history;
     424           0 :         return h ? h : mb;
     425             : }
     426             : 
     427             : // Localize the plan using the optimizer name
     428             : MalBlkPtr
     429           0 : getMalBlkOptimized(MalBlkPtr mb, const char *name)
     430             : {
     431           0 :         MalBlkPtr h = mb->history;
     432             :         InstrPtr p;
     433             :         int i= 0;
     434           0 :         char buf[IDLENGTH]= {0}, *n;
     435             :         size_t nlen;
     436             : 
     437           0 :         if( name == 0)
     438             :                 return mb;
     439             : 
     440           0 :         nlen = strlen(name);
     441           0 :         if (nlen >= sizeof(buf)) {
     442           0 :                 mb->errors = createMalException(mb,0, TYPE, "Optimizer name is too large");
     443           0 :                 return NULL;
     444             :         }
     445           0 :         memcpy(buf, name, nlen + 1);
     446           0 :         n = strchr(buf,']');
     447           0 :         if( n) *n = 0;
     448             : 
     449           0 :         while (h ){
     450           0 :                 for( i = 1; i< h->stop; i++){
     451           0 :                         p = getInstrPtr(h,i);
     452           0 :                         if( p->token == REMsymbol && strstr(getVarConstant(h, getArg(p,0)).val.sval, buf)  )
     453           0 :                                 return h;
     454             :                 }
     455           0 :                 h = h->history;
     456             :         }
     457             :         return 0;
     458             : }
     459             : 
     460             : /* The MAL records should be managed from a pool to
     461             :  * avoid repeated alloc/free and reduce probability of
     462             :  * memory fragmentation. (todo)
     463             :  * The complicating factor is their variable size,
     464             :  * which leads to growing records as a result of pushArguments
     465             :  * Allocation of an instruction should always succeed.
     466             :  */
     467             : InstrPtr
     468    23479251 : newInstructionArgs(MalBlkPtr mb, const char *modnme, const char *fcnnme, int args)
     469             : {
     470             :         InstrPtr p = NULL;
     471             : 
     472             :         (void) mb;
     473             : 
     474    23479251 :         p = GDKzalloc(args * sizeof(p->argv[0]) + offsetof(InstrRecord, argv));
     475    23479250 :         if (p == NULL) {
     476             :                 /* We are facing an hard problem.
     477             :                  * The upper layers of the code base assume that this routine will always produce a structure.
     478             :                  * Furthermore, failure to allocate such a small data structure indicates we are in serious trouble.
     479             :                  * The only way out is declare it a fatal error, terminate the system to avoid crashes in all kind of places.
     480             :                  */
     481           0 :                 GDKerror(SQLSTATE(HY013) MAL_MALLOC_FAIL);
     482           0 :                 mal_exit(1);
     483             :         }
     484    23479250 :         p->maxarg = args;
     485    23479250 :         p->typechk = TYPE_UNKNOWN;
     486    23479250 :         setModuleId(p, modnme);
     487    23479250 :         setFunctionId(p, fcnnme);
     488    23479250 :         p->argc = 1;
     489    23479250 :         p->retc = 1;
     490    23479250 :         p->argv[0] = -1;                     /* watch out for direct use in variable table */
     491             :         /* Flow of control instructions are always marked as an assignment
     492             :          * with modifier */
     493    23479250 :         p->token = ASSIGNsymbol;
     494    23479250 :         return p;
     495             : }
     496             : 
     497             : InstrPtr
     498     5830343 : newInstruction(MalBlkPtr mb, const char *modnme, const char *fcnnme)
     499             : {
     500     5830343 :         return newInstructionArgs(mb, modnme, fcnnme, MAXARG);
     501             : }
     502             : 
     503             : /* Moving instructions around calls for care, because all dependent
     504             :  * information should also be updated. */
     505             : static void
     506    39980029 : oldmoveInstruction(InstrPtr new, InstrPtr p)
     507             : {
     508             :         int space;
     509             : 
     510    39980029 :         space = offsetof(InstrRecord, argv) + p->maxarg * sizeof(p->argv[0]);
     511    39980029 :         memcpy((char *) new, (char *) p, space);
     512    39980029 :         setFunctionId(new, getFunctionId(p));
     513    39980029 :         setModuleId(new, getModuleId(p));
     514    39980029 :         new->typechk = TYPE_UNKNOWN;
     515    39980029 : }
     516             : 
     517             : /* Copying an instruction is space conservative. */
     518             : InstrPtr
     519    39980012 : copyInstructionArgs(InstrPtr p, int args)
     520             : {
     521    39980012 :         if (p->maxarg > args)
     522             :                 args = p->maxarg;
     523    39980012 :         InstrPtr new = (InstrPtr) GDKmalloc(offsetof(InstrRecord, argv) + args * sizeof(p->argv[0]));
     524    39980031 :         if(new == NULL)
     525             :                 return new;
     526    39980031 :         oldmoveInstruction(new, p);
     527    39980019 :         new->maxarg = args;
     528    39980019 :         if (args > p->maxarg)
     529     3310231 :                 memset(new->argv + p->maxarg, 0, (args - p->maxarg) * sizeof(new->argv[0]));
     530             :         return new;
     531             : }
     532             : 
     533             : InstrPtr
     534    31194331 : copyInstruction(InstrPtr p)
     535             : {
     536    31194331 :         return copyInstructionArgs(p, p->maxarg);
     537             : }
     538             : 
     539             : void
     540      505727 : clrFunction(InstrPtr p)
     541             : {
     542      505727 :         p->token = ASSIGNsymbol;
     543      505727 :         p->fcn = 0;
     544      505727 :         p->blk = 0;
     545      505727 :         p->typechk = TYPE_UNKNOWN;
     546      505727 :         setModuleId(p, NULL);
     547      505727 :         setFunctionId(p, NULL);
     548      505727 : }
     549             : 
     550             : void
     551           0 : clrInstruction(InstrPtr p)
     552             : {
     553           0 :         clrFunction(p);
     554           0 :         memset((char *) p, 0, offsetof(InstrRecord, argv) + p->maxarg * sizeof(p->argv[0]));
     555           0 : }
     556             : 
     557             : void
     558    68127720 : freeInstruction(InstrPtr p)
     559             : {
     560    68127720 :         GDKfree(p);
     561    68127736 : }
     562             : 
     563             : /* Query optimizers walk their way through a MAL program block. They
     564             :  * require some primitives to move instructions around and to remove
     565             :  * superflous instructions. The removal is based on the assumption
     566             :  * that indeed the instruction belonged to the block. */
     567             : void
     568           3 : removeInstruction(MalBlkPtr mb, InstrPtr p)
     569             : {
     570             :         int i;
     571             : 
     572           9 :         for (i = 0; i < mb->stop - 1; i++)
     573           9 :                 if (mb->stmt[i] == p)
     574             :                         break;
     575             : 
     576           3 :         if (i == mb->stop)
     577             :                 return;
     578             : 
     579           8 :         for (; i < mb->stop - 1; i++)
     580           5 :                 mb->stmt[i] = mb->stmt[i + 1];
     581           3 :         mb->stmt[i] = 0;
     582           3 :         mb->stop--;
     583           3 :         assert(i == mb->stop);
     584             : 
     585             :         /* move statement after stop */
     586           3 :         mb->stmt[i] = p;
     587             : }
     588             : 
     589             : void
     590           0 : removeInstructionBlock(MalBlkPtr mb, int pc, int cnt)
     591             : {
     592             :         int i;
     593             :         InstrPtr p;
     594             : 
     595           0 :         for (i = pc; i < pc + cnt; i++) {
     596           0 :                 p = getInstrPtr(mb, i);
     597           0 :                 freeInstruction(p);
     598           0 :                 mb->stmt[i]= NULL;
     599             :         }
     600             : 
     601           0 :         for (i = pc; i < mb->stop - cnt; i++)
     602           0 :                 mb->stmt[i] = mb->stmt[i + cnt];
     603             : 
     604           0 :         mb->stop -= cnt;
     605             :         for (; i < mb->stop; i++)
     606             :                 mb->stmt[i] = 0;
     607           0 : }
     608             : 
     609             : void
     610           0 : moveInstruction(MalBlkPtr mb, int pc, int target)
     611             : {
     612             :         InstrPtr p;
     613             :         int i;
     614             : 
     615           0 :         p = getInstrPtr(mb, pc);
     616           0 :         if (pc > target) {
     617           0 :                 for (i = pc; i > target; i--)
     618           0 :                         mb->stmt[i] = mb->stmt[i - 1];
     619           0 :                 mb->stmt[i] = p;
     620             :         } else {
     621           0 :                 for (i = target; i > pc; i--)
     622           0 :                         mb->stmt[i] = mb->stmt[i - 1];
     623           0 :                 mb->stmt[i] = p;
     624             :         }
     625           0 : }
     626             : 
     627             : /* Beware that the first argument of a signature is reserved for the
     628             :  * function return type , which should be equal to the destination
     629             :  * variable type.
     630             :  */
     631             : 
     632             : int
     633      490697 : findVariable(MalBlkPtr mb, const char *name)
     634             : {
     635             :         int i;
     636             : 
     637      490697 :         if (name == NULL)
     638             :                 return -1;
     639     1414132 :         for (i = mb->vtop - 1; i >= 0; i--)
     640     1403472 :                 if (idcmp(name, getVarName(mb, i)) == 0)
     641      480037 :                         return i;
     642             :         return -1;
     643             : }
     644             : 
     645             : /* The second version of findVariable assumes you have not yet
     646             :  * allocated a private structure. This is particularly useful during
     647             :  * parsing, because most variables are already defined. This way we
     648             :  * safe GDKmalloc/GDKfree. */
     649             : int
     650      128902 : findVariableLength(MalBlkPtr mb, const char *name, int len)
     651             : {
     652             :         int i;
     653             : 
     654      622716 :         for (i = mb->vtop - 1; i >= 0; i--) {
     655      559201 :                 const char *s = mb->var[i].name;
     656             : 
     657      559201 :                 if (s && strncmp(name, s, len) == 0 && s[len] == 0)
     658       65387 :                         return i;
     659             :         }
     660             :         return -1;
     661             : }
     662             : 
     663             : /* Note that getType also checks for type names directly. They have
     664             :  * preference over variable names. */
     665             : malType
     666           0 : getType(MalBlkPtr mb, const char *nme)
     667             : {
     668             :         int i;
     669             : 
     670           0 :         i = findVariable(mb, nme);
     671           0 :         if (i < 0)
     672           0 :                 return getAtomIndex(nme, strlen(nme), TYPE_any);
     673           0 :         return getVarType(mb, i);
     674             : }
     675             : 
     676             : str
     677         182 : getArgDefault(MalBlkPtr mb, InstrPtr p, int idx)
     678             : {
     679         182 :         ValPtr v = &getVarConstant(mb, getArg(p, idx));
     680             : 
     681         182 :         if (v->vtype == TYPE_str)
     682         182 :                 return v->val.sval;
     683             :         return NULL;
     684             : }
     685             : 
     686             : /* All variables are implicitly declared upon their first assignment.
     687             :  *
     688             :  * Lexical constants require some care. They typically appear as
     689             :  * arguments in operator/function calls. To simplify program analysis
     690             :  * later on, we stick to the situation that function/operator
     691             :  * arguments are always references to by variables.
     692             :  *
     693             :  * Reserved words
     694             :  * Although MAL has been designed as a minimal language, several
     695             :  * identifiers are not eligible as variables. The encoding below is
     696             :  * geared at simple and speed. */
     697             : #if 0
     698             : int
     699             : isReserved(str nme)
     700             : {
     701             :         switch (*nme) {
     702             :         case 'A':
     703             :         case 'a':
     704             :                 if (idcmp("atom", nme) == 0)
     705             :                         return 1;
     706             :                 break;
     707             :         case 'B':
     708             :         case 'b':
     709             :                 if (idcmp("barrier", nme) == 0)
     710             :                         return 1;
     711             :                 break;
     712             :         case 'C':
     713             :         case 'c':
     714             :                 if (idcmp("command", nme) == 0)
     715             :                         return 1;
     716             :                 break;
     717             :         case 'E':
     718             :         case 'e':
     719             :                 if (idcmp("exit", nme) == 0)
     720             :                         return 1;
     721             :                 if (idcmp("end", nme) == 0)
     722             :                         return 1;
     723             :                 break;
     724             :         case 'F':
     725             :         case 'f':
     726             :                 if (idcmp("false", nme) == 0)
     727             :                         return 1;
     728             :                 if (idcmp("function", nme) == 0)
     729             :                         return 1;
     730             :                 if (idcmp("factory", nme) == 0)
     731             :                         return 1;
     732             :                 break;
     733             :         case 'I':
     734             :         case 'i':
     735             :                 if (idcmp("include", nme) == 0)
     736             :                         return 1;
     737             :                 break;
     738             :         case 'M':
     739             :         case 'm':
     740             :                 if (idcmp("module", nme) == 0)
     741             :                         return 1;
     742             :                 if (idcmp("macro", nme) == 0)
     743             :                         return 1;
     744             :                 break;
     745             :         case 'O':
     746             :         case 'o':
     747             :                 if (idcmp("orcam", nme) == 0)
     748             :                         return 1;
     749             :                 break;
     750             :         case 'P':
     751             :         case 'p':
     752             :                 if (idcmp("pattern", nme) == 0)
     753             :                         return 1;
     754             :                 break;
     755             :         case 'T':
     756             :         case 't':
     757             :                 if (idcmp("thread", nme) == 0)
     758             :                         return 1;
     759             :                 if (idcmp("true", nme) == 0)
     760             :                         return 1;
     761             :                 break;
     762             :         }
     763             :         return 0;
     764             : }
     765             : #endif
     766             : 
     767             : /* Beware, the symbol table structure assumes that it is relatively
     768             :  * cheap to perform a linear search to a variable or constant. */
     769             : static int
     770    72978970 : makeVarSpace(MalBlkPtr mb)
     771             : {
     772    72978970 :         if (mb->vtop >= mb->vsize) {
     773             :                 VarRecord *new;
     774             :                 int s = growBlk(mb->vsize);
     775             : 
     776      129650 :                 new = (VarRecord*) GDKrealloc(mb->var, s * sizeof(VarRecord));
     777      129650 :                 if (new == NULL) {
     778             :                         // the only place to return an error signal at this stage.
     779             :                         // The Client context should be passed around more deeply
     780           0 :                         mb->errors = createMalException(mb,0,TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
     781           0 :                         return -1;
     782             :                 }
     783      129650 :                 memset( ((char*) new) + mb->vsize * sizeof(VarRecord), 0, (s- mb->vsize) * sizeof(VarRecord));
     784      129650 :                 mb->vsize = s;
     785      129650 :                 mb->var = new;
     786             :         }
     787             :         return 0;
     788             : }
     789             : 
     790             : /* create and initialize a variable record*/
     791             : void
     792    72978967 : setVariableType(MalBlkPtr mb, const int n, malType type)
     793             : {
     794    72978967 :         assert( n >= 0 && n <mb->vtop);
     795    72978967 :         setVarType(mb, n, type);
     796    72978967 :         setRowCnt(mb,n,0);
     797    72978967 :         clrVarFixed(mb, n);
     798    72978967 :         clrVarUsed(mb, n);
     799    72978967 :         clrVarInit(mb, n);
     800    72978967 :         clrVarDisabled(mb, n);
     801    72978967 :         clrVarConstant(mb, n);
     802    72978967 :         clrVarCleanup(mb, n);
     803    72978967 : }
     804             : 
     805             : 
     806             : char *
     807     1822162 : getVarName(MalBlkPtr mb, int idx)
     808             : {
     809     1822162 :         char *s = mb->var[idx].name;
     810     1822162 :         if( getVarKind(mb,idx) == 0)
     811           0 :                 setVarKind(mb,idx, REFMARKER);
     812             : 
     813     1822162 :         if( *s &&  s[1] != '_' && (s[0] != 'X' && s[0] != 'C'))
     814             :                 return s;
     815     1304460 :         if ( *s == 0)
     816      582469 :                 (void) snprintf(s, IDLENGTH,"%c_%d", getVarKind(mb, idx), mb->vid++);
     817             :         return s;
     818             : }
     819             : 
     820             : int
     821    72978972 : newVariable(MalBlkPtr mb, const char *name, size_t len, malType type)
     822             : {
     823             :         int n;
     824             :         int kind = REFMARKER;
     825             : 
     826    72978972 :         if( len >= IDLENGTH){
     827           4 :                 mb->errors = createMalException(mb,0,TYPE, "newVariable: id too long");
     828           4 :                 return -1;
     829             :         }
     830    72978968 :         if (makeVarSpace(mb)) {
     831           0 :                 assert(0);
     832             :                 /* no space for a new variable */
     833             :                 return -1;
     834             :         }
     835    72978971 :         n = mb->vtop;
     836    72978971 :         if( name == 0 || len == 0){
     837    72877109 :                 mb->var[n].name[0] = 0;
     838             :         } else {
     839             :                 /* avoid calling strcpy_len since we're not interested in the
     840             :                  * source length, and that may be very large */
     841      101862 :                 char *nme = mb->var[n].name;
     842      588351 :                 for (size_t i = 0; i < len; i++)
     843      486489 :                         nme[i] = name[i];
     844      101862 :                 nme[len] = 0;
     845      101862 :                 kind = nme[0];
     846             :         }
     847             : 
     848    72978971 :         mb->vtop++;
     849    72978971 :         setVarKind(mb, n, kind);
     850    72978971 :         setVariableType(mb, n, type);
     851    72978978 :         return n;
     852             : }
     853             : 
     854             : /* Simplified cloning. */
     855             : int
     856    10497651 : cloneVariable(MalBlkPtr tm, MalBlkPtr mb, int x)
     857             : {
     858             :         int res;
     859    10497651 :         if (isVarConstant(mb, x))
     860           0 :                 res = cpyConstant(tm, getVar(mb, x));
     861             :         else {
     862    10497651 :                 res = newTmpVariable(tm, getVarType(mb, x));
     863    10497652 :                 if( *mb->var[x].name)
     864           0 :                         strcpy(tm->var[x].name, mb->var[x].name);
     865             :                 //res = newVariable(tm, getVarName(mb, x), strlen(getVarName(mb,x)), getVarType(mb, x));
     866             :         }
     867    10497651 :         if (res < 0)
     868             :                 return res;
     869    10497651 :         if (isVarFixed(mb, x))
     870    10497652 :                 setVarFixed(tm, res);
     871    10497651 :         if (isVarUsed(mb, x))
     872           0 :                 setVarUsed(tm, res);
     873    10497651 :         if (isVarInit(mb, x))
     874    10497652 :                 setVarInit(tm, res);
     875    10497651 :         if (isVarDisabled(mb, x))
     876           0 :                 setVarDisabled(tm, res);
     877    10497651 :         if (isVarCleanup(mb, x))
     878    10497652 :                 setVarCleanup(tm, res);
     879    10497651 :         getVarSTC(tm,x) = getVarSTC(mb,x);
     880    10497651 :         setVarKind(tm,x, getVarKind(mb,x));
     881    10497651 :         return res;
     882             : }
     883             : 
     884             : int
     885    72877105 : newTmpVariable(MalBlkPtr mb, malType type)
     886             : {
     887    72877105 :         return newVariable(mb,0,0,type);
     888             : }
     889             : 
     890             : int
     891         283 : newTypeVariable(MalBlkPtr mb, malType type)
     892             : {
     893             :         int n, i;
     894        1343 :         for (i = 0; i < mb->vtop; i++)
     895        1103 :                 if (isVarTypedef(mb, i) && getVarType(mb, i) == type)
     896             :                         break;
     897             : 
     898         283 :         if( i < mb->vtop )
     899             :                 return i;
     900         240 :         n = newTmpVariable(mb, type);
     901         240 :         setVarTypedef(mb, n);
     902         240 :         return n;
     903             : }
     904             : 
     905             : void
     906       18304 : clearVariable(MalBlkPtr mb, int varid)
     907             : {
     908             :         VarPtr v;
     909             : 
     910       18304 :         v = getVar(mb, varid);
     911       18304 :         if (isVarConstant(mb, varid) || isVarDisabled(mb, varid))
     912        4647 :                 VALclear(&v->value);
     913       18304 :         v->type = 0;
     914       18304 :         v->constant= 0;
     915       18304 :         v->typevar= 0;
     916       18304 :         v->fixedtype= 0;
     917       18304 :         v->cleanup= 0;
     918       18304 :         v->initialized= 0;
     919       18304 :         v->used= 0;
     920       18304 :         v->rowcnt = 0;
     921       18304 :         v->eolife = 0;
     922       18304 :         v->stc = 0;
     923       18304 : }
     924             : 
     925             : void
     926          82 : freeVariable(MalBlkPtr mb, int varid)
     927             : {
     928          82 :         clearVariable(mb, varid);
     929          82 : }
     930             : 
     931             : /* A special action is to reduce the variable space by removing all
     932             :  * that do not contribute.
     933             :  * All temporary variables are renamed in the process to trim the varid.
     934             :  */
     935             : void
     936           3 : trimMalVariables_(MalBlkPtr mb, MalStkPtr glb)
     937             : {
     938             :         int *alias, cnt = 0, i, j;
     939             :         InstrPtr q;
     940             : 
     941           3 :         if( mb->vtop == 0)
     942             :                 return;
     943           3 :         alias = (int *) GDKzalloc(mb->vtop * sizeof(int));
     944           3 :         if (alias == NULL)
     945             :                 return;                                 /* forget it if we run out of memory */
     946             : 
     947             :         /* build the alias table */
     948         677 :         for (i = 0; i < mb->vtop; i++) {
     949         674 :                 if ( isVarUsed(mb,i) == 0) {
     950          82 :                         if (glb && i < glb->stktop && isVarConstant(mb, i))
     951           0 :                                 VALclear(&glb->stk[i]);
     952          82 :                         freeVariable(mb, i);
     953          82 :                         continue;
     954             :                 }
     955         592 :                 if (i > cnt) {
     956             :                         /* remap temporary variables */
     957         532 :                         VarRecord t = mb->var[cnt];
     958         532 :                         mb->var[cnt] = mb->var[i];
     959         532 :                         mb->var[i] = t;
     960             :                 }
     961             : 
     962             :                 /* valgrind finds a leak when we move these variable record
     963             :                  * pointers around. */
     964         592 :                 alias[i] = cnt;
     965         592 :                 if (glb && i < glb->stktop && i != cnt) {
     966           0 :                         glb->stk[cnt] = glb->stk[i];
     967           0 :                         VALempty(&glb->stk[i]);
     968             :                 }
     969         592 :                 cnt++;
     970             :         }
     971             : 
     972             :         /* remap all variable references to their new position. */
     973           3 :         if (cnt < mb->vtop) {
     974         387 :                 for (i = 0; i < mb->stop; i++) {
     975         384 :                         q = getInstrPtr(mb, i);
     976        2279 :                         for (j = 0; j < q->argc; j++){
     977        1895 :                                 getArg(q, j) = alias[getArg(q, j)];
     978             :                         }
     979             :                 }
     980             :         }
     981             :         /* rename the temporary variable */
     982           3 :         mb->vid = 0;
     983             : /* Obsolete, name generation is postponed until needed
     984             :         for( i =0; i< cnt; i++)
     985             :         if( isTmpVar(mb,i))
     986             :                 (void) snprintf(getVarName(mb,i), IDLENGTH,"%c_%d", getVarKind(mb,i), mb->vid++);
     987             : */
     988             : 
     989           3 :         GDKfree(alias);
     990           3 :         mb->vtop = cnt;
     991             : }
     992             : 
     993             : void
     994           3 : trimMalVariables(MalBlkPtr mb, MalStkPtr stk)
     995             : {
     996             :         int i, j;
     997             :         InstrPtr q;
     998             : 
     999             :         /* reset the use bit for all non-signature arguments */
    1000         677 :         for (i = 0; i < mb->vtop; i++)
    1001         674 :                 clrVarUsed(mb,i);
    1002             :         /* build the use table */
    1003         387 :         for (i = 0; i < mb->stop; i++) {
    1004         384 :                 q = getInstrPtr(mb, i);
    1005             : 
    1006        2279 :                 for (j = 0; j < q->argc; j++)
    1007        1895 :                         setVarUsed(mb,getArg(q,j));
    1008             :         }
    1009           3 :         trimMalVariables_(mb, stk);
    1010           3 : }
    1011             : 
    1012             : /* MAL constants
    1013             :  * Constants are stored in the symbol table and referenced by a
    1014             :  * variable identifier. This means that per MAL instruction, we may
    1015             :  * end up with MAXARG entries in the symbol table. This may lead to
    1016             :  * long searches for variables. An optimization strategy deployed in
    1017             :  * the current implementation is to look around for a similar
    1018             :  * (constant) definition and to reuse its identifier. This avoids an
    1019             :  * exploding symbol table with a lot of temporary variables (as in
    1020             :  * tst400cHuge)
    1021             :  *
    1022             :  * But then the question becomes how far to search? Searching through
    1023             :  * all variables is only useful when the list remains short or when
    1024             :  * the constant-variable-name is easily derivable from its literal
    1025             :  * value and a hash-based index leads you quickly to it.
    1026             :  *
    1027             :  * For the time being, we use a MAL system parameter, MAL_VAR_WINDOW,
    1028             :  * to indicate the number of symbol table entries to consider. Setting
    1029             :  * it to >= MAXARG will at least capture repeated use of a constant
    1030             :  * within a single function call or repeated use within a small block
    1031             :  * of code.
    1032             :  *
    1033             :  * The final step is to prepare a GDK value record, from which the
    1034             :  * internal representation can be obtained during MAL interpretation.
    1035             :  *
    1036             :  * The constant values are linked together to improve searching
    1037             :  * them. This start of the constant list is kept in the MalBlk.
    1038             :  *
    1039             :  * Conversion of a constant to another type is limited to well-known
    1040             :  * coercion rules. Errors are reported and the nil value is set. */
    1041             : 
    1042             : /* Converts the constant in vr to the MAL type type.  Conversion is
    1043             :  * done in the vr struct. */
    1044             : str
    1045      334145 : convertConstant(int type, ValPtr vr)
    1046             : {
    1047      334145 :         if( type > GDKatomcnt )
    1048           0 :                 throw(SYNTAX, "convertConstant", "type index out of bound");
    1049      334145 :         if (vr->vtype == type)
    1050             :                 return MAL_SUCCEED;
    1051      334068 :         if (type == TYPE_bat || isaBatType(type)) {
    1052             :                 /* BAT variables can only be set to nil */
    1053         409 :                 if( vr->vtype != TYPE_void)
    1054           0 :                         throw(SYNTAX, "convertConstant", "BAT conversion error");
    1055         409 :                 VALclear(vr);
    1056         409 :                 vr->vtype = type;
    1057         409 :                 vr->val.bval = bat_nil;
    1058         409 :                 return MAL_SUCCEED;
    1059             :         }
    1060      333659 :         if (type == TYPE_ptr) {
    1061             :                 /* all coercions should be avoided to protect against memory probing */
    1062          32 :                 if (vr->vtype == TYPE_void) {
    1063          32 :                         VALclear(vr);
    1064          32 :                         vr->vtype = type;
    1065          32 :                         vr->val.pval = NULL;
    1066          32 :                         return MAL_SUCCEED;
    1067             :                 }
    1068             :                 if (vr->vtype != type)
    1069           0 :                         throw(SYNTAX, "convertConstant", "pointer conversion error");
    1070             :                 return MAL_SUCCEED;
    1071             :         }
    1072      333627 :         if (type == TYPE_any) {
    1073             : #ifndef DEBUG_MAL_INSTR
    1074             :                 assert(0);
    1075             : #endif
    1076           0 :                 throw(SYNTAX, "convertConstant", "missing type");
    1077             :         }
    1078      333627 :         if (VALconvert(type, vr) == NULL) {
    1079           1 :                 if (vr->vtype == TYPE_str)
    1080           0 :                         throw(SYNTAX, "convertConstant", "parse error in '%s'", vr->val.sval);
    1081           1 :                 throw(SYNTAX, "convertConstant", "coercion failed");
    1082             :         }
    1083             :         return MAL_SUCCEED;
    1084             : }
    1085             : 
    1086             : int
    1087    40169250 : fndConstant(MalBlkPtr mb, const ValRecord *cst, int depth)
    1088             : {
    1089             :         int i, k;
    1090             :         const void *p;
    1091             : 
    1092             :         /* pointers never match */
    1093    40169250 :         if (ATOMstorage(cst->vtype) == TYPE_ptr)
    1094             :                 return -1;
    1095             : 
    1096    40051499 :         p = VALptr(cst);
    1097    40051499 :         k = mb->vtop - depth;
    1098             :         if (k < 0)
    1099             :                 k = 0;
    1100   463727980 :         for (i=k; i < mb->vtop - 1; i++){
    1101   447697213 :                 VarPtr v = getVar(mb, i);
    1102   447697213 :                 if (v->constant){
    1103   151784819 :                         if (v && v->type == cst->vtype && v->value.len == cst->len && ATOMcmp(cst->vtype, VALptr(&v->value), p) == 0)
    1104    24020719 :                                 return i;
    1105             :                 }
    1106             :         }
    1107             :         return -1;
    1108             : }
    1109             : 
    1110             : int
    1111        2229 : cpyConstant(MalBlkPtr mb, VarPtr vr)
    1112             : {
    1113             :         int i;
    1114             :         ValRecord cst;
    1115             : 
    1116        2229 :         if (VALcopy(&cst, &vr->value) == NULL)
    1117             :                 return -1;
    1118             : 
    1119        2229 :         i = defConstant(mb, vr->type, &cst);
    1120             :         if( i<0)
    1121             :                 return -1;
    1122             :         return i;
    1123             : }
    1124             : 
    1125             : int
    1126    35357874 : defConstant(MalBlkPtr mb, int type, ValPtr cst)
    1127             : {
    1128             :         int k;
    1129             :         str msg;
    1130             : 
    1131    35357874 :         if (isaBatType(type)){
    1132        1534 :                  if( cst->vtype == TYPE_void) {
    1133        1533 :                         cst->vtype = TYPE_bat;
    1134        1533 :                         cst->val.bval = bat_nil;
    1135             :                 } else {
    1136           1 :                         mb->errors = createMalException(mb, 0, TYPE, "BAT coercion error");
    1137           1 :                         return -1;
    1138             :                 }
    1139    35356340 :         } else if (cst->vtype != type && !isPolyType(type)) {
    1140             :                 int otype = cst->vtype;
    1141        2721 :                 assert(type != TYPE_any);       /* help Coverity */
    1142        2721 :                 msg = convertConstant(getBatType(type), cst);
    1143        2721 :                 if (msg) {
    1144             :                         str ft, tt;
    1145             : 
    1146             :                         /* free old value */
    1147           1 :                         ft = getTypeName(otype);
    1148           1 :                         tt = getTypeName(type);
    1149           1 :                         mb->errors = createMalException(mb, 0, TYPE, "constant coercion error from %s to %s", ft, tt);
    1150           1 :                         GDKfree(ft);
    1151           1 :                         GDKfree(tt);
    1152           1 :                         freeException(msg);
    1153           1 :                         VALclear(cst);  // it could contain allocated space
    1154           1 :                         return -1;
    1155             :                 } else {
    1156        2720 :                         assert(cst->vtype == type);
    1157             :                 }
    1158             :         }
    1159    35357872 :         k = fndConstant(mb, cst, MAL_VAR_WINDOW);
    1160    35357923 :         if (k >= 0) {
    1161             :                 /* protect against leaks coming from constant reuse */
    1162    20702230 :                 if (ATOMextern(type) && cst->val.pval)
    1163      937760 :                         VALclear(cst);
    1164    20702230 :                 return k;
    1165             :         }
    1166    14655693 :         k = newTmpVariable(mb, type);
    1167    14655696 :         setVarConstant(mb, k);
    1168    14655696 :         setVarFixed(mb, k);
    1169    14655696 :         if (type >= 0 && type < GDKatomcnt && ATOMextern(type))
    1170     3708828 :                 setVarCleanup(mb, k);
    1171             :         else
    1172    10946868 :                 clrVarCleanup(mb, k);
    1173             :         /* if cst is external, we give its allocated buffer away, so clear
    1174             :          * it to avoid confusion */
    1175    14655696 :         getVarConstant(mb, k) = *cst;
    1176    14655696 :         VALempty(cst);
    1177    14655696 :         return k;
    1178             : }
    1179             : 
    1180             : /* Argument handling
    1181             :  * The number of arguments for procedures is currently
    1182             :  * limited. Furthermore, we should assure that no variable is
    1183             :  * referenced before being assigned. Failure to obey should mark the
    1184             :  * instruction as type-error. */
    1185             : 
    1186             : static InstrPtr
    1187         699 : extendInstruction(MalBlkPtr mb, InstrPtr p)
    1188             : {
    1189             :         InstrPtr pn = p;
    1190             : 
    1191         699 :         if (p->argc == p->maxarg) {
    1192         699 :                 int space = p->maxarg * sizeof(p->argv[0]) + offsetof(InstrRecord, argv);
    1193         699 :                 pn = (InstrPtr) GDKrealloc(p,space + MAXARG * sizeof(p->argv[0]));
    1194             : 
    1195         699 :                 if (pn == NULL) {
    1196             :                         /* In the exceptional case we can not allocate more space
    1197             :                          * then we show an exception, mark the block as erroneous
    1198             :                          * and leave the instruction as is.
    1199             :                         */
    1200           0 :                         mb->errors = createMalException(mb,0, TYPE, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1201           0 :                         return p;
    1202             :                 }
    1203         699 :                 memset( ((char*)pn) + space, 0, MAXARG * sizeof(pn->argv[0]));
    1204         699 :                 pn->maxarg += MAXARG;
    1205             :         }
    1206             :         return pn;
    1207             : }
    1208             : 
    1209             : InstrPtr
    1210    69972559 : pushArgument(MalBlkPtr mb, InstrPtr p, int varid)
    1211             : {
    1212             :         InstrPtr pn;
    1213             : 
    1214    69972559 :         if (p == NULL)
    1215             :                 return NULL;
    1216    69972559 :         if (varid < 0) {
    1217             :                 /* leave everything as is in this exceptional programming error */
    1218           0 :                 mb->errors = createMalException(mb, 0, TYPE,"improper variable id");
    1219           0 :                 return p;
    1220             :         }
    1221    69972559 :         if (p->argc == p->maxarg) {
    1222         699 :                 pn = extendInstruction(mb, p);
    1223             : 
    1224             :                 /* if the instruction is already stored in the MAL block
    1225             :                  * it should be replaced by an extended version.
    1226             :                  */
    1227         699 :                 if (p != pn) {
    1228         678 :                         for (int i = mb->stop - 1; i >= 0; i--) {
    1229         633 :                                 if (mb->stmt[i] == p) {
    1230         588 :                                         mb->stmt[i] =  pn;
    1231         588 :                                         break;
    1232             :                                 }
    1233             :                         }
    1234             :                 }
    1235             :                 p = pn;
    1236         699 :                 if (mb->errors)
    1237             :                         return p;
    1238             :         }
    1239             :         /* protect against the case that the instruction is malloced
    1240             :          * in isolation */
    1241    69972559 :         if( mb->maxarg < p->maxarg)
    1242       20090 :                 mb->maxarg= p->maxarg;
    1243    69972559 :         p->argv[p->argc++] = varid;
    1244    69972559 :         return p;
    1245             : }
    1246             : 
    1247             : 
    1248             : /* the next version assumes that we have allocated an isolated instruction
    1249             :  * using newInstruction. As long as it is not stored in the MAL block
    1250             :  * we can simpy extend it with arguments
    1251             :  */
    1252             : InstrPtr
    1253   113670423 : addArgument(MalBlkPtr mb, InstrPtr p, int varid)
    1254             : {
    1255             :         InstrPtr pn = p;
    1256             : 
    1257   113670423 :         if (p == NULL)
    1258             :                 return NULL;
    1259   113670423 :         if (varid < 0) {
    1260             :                 /* leave everything as is in this exceptional programming error */
    1261           0 :                 mb->errors = createMalException(mb, 0, TYPE,"improper variable id");
    1262           0 :                 return p;
    1263             :         }
    1264             : 
    1265   113670423 :         if (p->argc == p->maxarg) {
    1266           0 :                 pn = extendInstruction(mb, p);
    1267             : #ifndef NDEBUG
    1268           0 :                if (p != pn) {
    1269           0 :                        for (int i = mb->stop - 1; i >= 0; i--)
    1270           0 :                                assert(mb->stmt[i] != p);
    1271             :                }
    1272             : #endif
    1273             :                 p = pn;
    1274           0 :                 if (mb->errors)
    1275             :                         return p;
    1276             :         }
    1277             :         /* protect against the case that the instruction is malloced in isolation */
    1278   113670423 :         if( mb->maxarg < p->maxarg)
    1279        2162 :                 mb->maxarg= p->maxarg;
    1280             : 
    1281   113670423 :         p->argv[p->argc++] = varid;
    1282   113670423 :         return p;
    1283             : }
    1284             : 
    1285             : InstrPtr
    1286     4430018 : setArgument(MalBlkPtr mb, InstrPtr p, int idx, int varid)
    1287             : {
    1288             :         int i;
    1289             : 
    1290     4430018 :         if (p == NULL)
    1291             :                 return NULL;
    1292     4430018 :         p = pushArgument(mb, p, varid); /* make space */
    1293     4430018 :         if (p == NULL)
    1294             :                 return NULL;
    1295     4453248 :         for (i = p->argc - 1; i > idx; i--)
    1296       23230 :                 getArg(p, i) = getArg(p, i - 1);
    1297     4430018 :         getArg(p, i) = varid;
    1298     4430018 :         return p;
    1299             : }
    1300             : 
    1301             : InstrPtr
    1302     4430354 : pushReturn(MalBlkPtr mb, InstrPtr p, int varid)
    1303             : {
    1304     4430354 :         if (p->retc == 1 && p->argv[0] == -1) {
    1305         336 :                 p->argv[0] = varid;
    1306         336 :                 return p;
    1307             :         }
    1308     4430018 :         if ((p = setArgument(mb, p, p->retc, varid)) == NULL)
    1309             :                 return NULL;
    1310     4430018 :         p->retc++;
    1311     4430018 :         return p;
    1312             : }
    1313             : 
    1314             : /* Store the information of a destination variable in the signature
    1315             :  * structure of each instruction. This code is largely equivalent to
    1316             :  * pushArgument, but it is more efficient in searching and collecting
    1317             :  * the information.
    1318             :  * TODO */
    1319             : /* swallows name argument */
    1320             : InstrPtr
    1321        3544 : pushArgumentId(MalBlkPtr mb, InstrPtr p, const char *name)
    1322             : {
    1323             :         int v;
    1324             : 
    1325        3544 :         if (p == NULL)
    1326             :                 return NULL;
    1327        3544 :         v = findVariable(mb, name);
    1328        3544 :         if (v < 0) {
    1329         382 :                 size_t namelen = strlen(name);
    1330         382 :                 if ((v = newVariable(mb, name, namelen, getAtomIndex(name, namelen, TYPE_any))) < 0) {
    1331             :                         /* set the MAL block to erroneous and simply return without doing anything */
    1332             :                         /* mb->errors already set */
    1333             :                         return p;
    1334             :                 }
    1335             :         }
    1336        3540 :         return pushArgument(mb, p, v);
    1337             : }
    1338             : 
    1339             : /* The alternative is to remove arguments from an instruction
    1340             :  * record. This is typically part of instruction constructions. */
    1341             : void
    1342      218432 : delArgument(InstrPtr p, int idx)
    1343             : {
    1344             :         int i;
    1345             : 
    1346     1154543 :         for (i = idx; i < p->argc - 1; i++)
    1347      936111 :                 p->argv[i] = p->argv[i + 1];
    1348      218432 :         p->argc--;
    1349      218432 :         if (idx < p->retc)
    1350      218186 :                 p->retc--;
    1351      218432 : }
    1352             : 
    1353             : void
    1354       28661 : setArgType(MalBlkPtr mb, InstrPtr p, int i, int tpe)
    1355             : {
    1356       28661 :         assert(p->argv[i] < mb->vsize);
    1357       28661 :         setVarType(mb,getArg(p, i),tpe);
    1358       28661 : }
    1359             : 
    1360             : void
    1361         174 : setReturnArgument(InstrPtr p, int i)
    1362             : {
    1363         174 :         setDestVar(p, i);
    1364         174 : }
    1365             : 
    1366             : malType
    1367           0 : destinationType(MalBlkPtr mb, InstrPtr p)
    1368             : {
    1369           0 :         if (p->argc > 0)
    1370           0 :                 return getVarType(mb, getDestVar(p));
    1371             :         return TYPE_any;
    1372             : }
    1373             : 
    1374             : /* For polymorphic instructions we should keep around the maximal
    1375             :  * index to later allocate sufficient space for type resolutions maps.
    1376             :  * Beware, that we should only consider the instruction polymorphic if
    1377             :  * it has a positive index or belongs to the signature.
    1378             :  * BATs can only have a polymorphic type at the tail.
    1379             :  */
    1380             : inline void
    1381      566479 : setPolymorphic(InstrPtr p, int tpe, int force)
    1382             : {
    1383             :         int c1 = 0, c2 = 0;
    1384             : 
    1385      566479 :         if (force == FALSE && tpe == TYPE_any)
    1386             :                 return;
    1387      566479 :         if (isaBatType(tpe))
    1388             :                 c1= TYPE_oid;
    1389      566479 :         if (getTypeIndex(tpe) > 0)
    1390             :                 c2 = getTypeIndex(tpe);
    1391      566438 :         else if (getBatType(tpe) == TYPE_any)
    1392             :                 c2 = 1;
    1393      566479 :         c1 = c1 > c2 ? c1 : c2;
    1394      566479 :         if (c1 > 0 && c1 >= p->polymorphic)
    1395      354329 :                 p->polymorphic = c1 + 1;
    1396             : }
    1397             : 
    1398             : /* Instructions are simply appended to a MAL block. It should always succeed.
    1399             :  * The assumption is to push it when you are completely done with its preparation.
    1400             :  */
    1401             : 
    1402             : void
    1403   265787783 : pushInstruction(MalBlkPtr mb, InstrPtr p)
    1404             : {
    1405             :         int i;
    1406             :         int extra;
    1407             :         InstrPtr q;
    1408             : 
    1409   265787783 :         if (p == NULL)
    1410             :                 return;
    1411             : 
    1412   265787783 :         extra = mb->vsize - mb->vtop; // the extra variables already known
    1413   265787783 :         if (mb->stop + 1 >= mb->ssize) {
    1414       92334 :                 if( resizeMalBlk(mb, growBlk(mb->ssize + extra)) ){
    1415             :                         /* perhaps we can continue with a smaller increment.
    1416             :                          * But the block remains marked as faulty.
    1417             :                          */
    1418           0 :                         if( resizeMalBlk(mb,mb->ssize + 1)){
    1419             :                                 /* we are now left with the situation that the new instruction is dangling .
    1420             :                                  * The hack is to take an instruction out of the block that is likely not referenced independently
    1421             :                                  * The last resort is to take the first, which should always be there
    1422             :                                  * This assumes that no references are kept elsewhere to the statement
    1423             :                                  */
    1424           0 :                                 for( i = 1; i < mb->stop; i++){
    1425           0 :                                         q= getInstrPtr(mb,i);
    1426           0 :                                         if( q->token == REMsymbol){
    1427           0 :                                                 freeInstruction(q);
    1428           0 :                                                 mb->stmt[i] = p;
    1429           0 :                                                 return;
    1430             :                                         }
    1431             :                                 }
    1432           0 :                                 freeInstruction(getInstrPtr(mb,0));
    1433           0 :                                 mb->stmt[0] = p;
    1434           0 :                                 return;
    1435             :                         }
    1436             :                 }
    1437             :         }
    1438   265787783 :         if (mb->stmt[mb->stop])
    1439       11281 :                 freeInstruction(mb->stmt[mb->stop]);
    1440   265787803 :         p->pc = mb->stop;
    1441   265787803 :         mb->stmt[mb->stop++] = p;
    1442             : }

Generated by: LCOV version 1.14