LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_support.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 253 289 87.5 %
Date: 2021-10-13 02:24:04 Functions: 31 34 91.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             :  /* (c) M. Kersten
      10             :  */
      11             : #include "monetdb_config.h"
      12             : #include "opt_prelude.h"
      13             : #include "opt_support.h"
      14             : #include "mal_interpreter.h"
      15             : #include "mal_listing.h"
      16             : #include "mal_debugger.h"
      17             : #include "opt_multiplex.h"
      18             : #include "optimizer_private.h"
      19             : #include "manifold.h"
      20             : 
      21             : /* Some optimizers can/need only be applied once.
      22             :  * The optimizer trace at the end of the MAL block
      23             :  * can be used to check for this.
      24             :  */
      25             : int
      26      351365 : optimizerIsApplied(MalBlkPtr mb, const char *opt)
      27             : {
      28             :         InstrPtr p;
      29             :         int i;
      30    74420144 :         for( i = mb->stop; i < mb->ssize; i++){
      31    74068779 :                 p = getInstrPtr(mb,i);
      32    74068779 :                 if (p && getModuleId(p) == optimizerRef && p->token == REMsymbol && getFunctionId(p) == opt)
      33             :                         return 1;
      34             :         }
      35             :         return 0;
      36             : }
      37             : 
      38             : /*
      39             :  * Some optimizers are interdependent (e.g. mitosis ), which
      40             :  * requires inspection of the pipeline attached to a MAL block.
      41             :  */
      42             : int
      43      353093 : isOptimizerEnabled(MalBlkPtr mb, const char *opt)
      44             : {
      45             :         int i;
      46             :         InstrPtr q;
      47             : 
      48     8130775 :         for (i= mb->stop-1; i > 0; i--){
      49     8130775 :                 q= getInstrPtr(mb,i);
      50     8130775 :                 if ( q->token == ENDsymbol)
      51             :                         break;
      52     8033284 :                 if ( q->token != REMsymbol && getModuleId(q) == optimizerRef && getFunctionId(q) == opt)
      53             :                         return 1;
      54             :         }
      55             :         return 0;
      56             : }
      57             : 
      58             : /*
      59             :  * Find if an optimizer 'opt' has run before the instruction 'p'.
      60             :  */
      61             : int
      62     1059286 : isOptimizerUsed(MalBlkPtr mb, InstrPtr p, const char *opt)
      63             : {
      64             :         bool p_found = false;
      65             : 
      66    20861976 :         for (int i= mb->stop-1; i > 0; i--) {
      67    20861976 :                 InstrPtr q = getInstrPtr(mb,i);
      68             : 
      69    20861976 :                 p_found |= q == p; /* the optimizer to find must come before p */
      70    20861976 :                 if (q && q->token == ENDsymbol)
      71             :                         return 0;
      72    20858507 :                 if (p_found && q && q != p && getModuleId(q) == optimizerRef && getFunctionId(q) == opt)
      73             :                         return 1;
      74             :         }
      75             :         return 0;
      76             : }
      77             : 
      78             : /* Simple insertion statements do not require complex optimizer steps */
      79             : int
      80      706193 : isSimpleSQL(MalBlkPtr mb)
      81             : {
      82             :         int cnt = 0;
      83             : 
      84    33316899 :         for (int i = 0; i < mb->stop; i++) {
      85    33018488 :                 InstrPtr p = getInstrPtr(mb,i);
      86             : 
      87    33018488 :                 if (p && getModuleId(p) == sqlRef && getFunctionId(p) == appendRef)
      88     1009200 :                         cnt ++;
      89    33018488 :                 if (p && getModuleId(p) == sqlRef && getFunctionId(p) == setVariableRef)
      90             :                         return 1;
      91    33017680 :                 if (p && getModuleId(p) == sqlcatalogRef)
      92             :                         return 1;
      93             :         }
      94      298411 :         return cnt > 0.63 * mb->stop;
      95             : }
      96             : 
      97             : /* Hypothetical, optimizers may massage the plan in such a way
      98             :  * that multiple passes are needed.
      99             :  * However, the current SQL driven approach only expects a single
     100             :  * non-repeating pipeline of optimizer steps stored at the end of the MAL block.
     101             :  * A single scan forward over the MAL plan is assumed.
     102             :  */
     103             : str
     104      365888 : optimizeMALBlock(Client cntxt, MalBlkPtr mb)
     105             : {
     106             :         InstrPtr p;
     107             :         int pc, oldstop;
     108             :         str msg = MAL_SUCCEED;
     109             :         int cnt = 0;
     110             :         int actions = 0;
     111      365888 :         lng clk = GDKusec();
     112             : 
     113             :         /* assume the type and flow have been checked already */
     114             :         /* SQL functions intended to be inlined should not be optimized */
     115      365888 :         if ( mb->inlineProp)
     116             :                 return 0;
     117             : 
     118      365750 :         mb->optimize = 0;
     119      365750 :         if (mb->errors)
     120           0 :                 throw(MAL, "optimizer.MALoptimizer", SQLSTATE(42000) "Start with inconsistent MAL plan");
     121             : 
     122             :         // strong defense line, assure that MAL plan is initially correct
     123      365750 :         if( mb->errors == 0 && mb->stop > 1){
     124      365750 :                 resetMalTypes(mb, mb->stop);
     125      365750 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     126      365749 :                 if (!msg)
     127      365749 :                         msg = chkFlow(mb);
     128      365750 :                 if (!msg)
     129      365750 :                         msg = chkDeclarations(mb);
     130      365749 :                 if (msg)
     131             :                         return msg;
     132      365749 :                 if (mb->errors != MAL_SUCCEED){
     133             :                         msg = mb->errors;
     134           0 :                         mb->errors = MAL_SUCCEED;
     135           0 :                         return msg;
     136             :                 }
     137             :         }
     138             : 
     139      365749 :         oldstop = mb->stop;
     140    33403210 :         for (pc = 0; pc < mb->stop; pc++) {
     141    33037460 :                 p = getInstrPtr(mb, pc);
     142    33037460 :                 if (getModuleId(p) == optimizerRef && p->fcn && p->token != REMsymbol) {
     143    10522570 :                         actions++;
     144    10522570 :                         msg = (str) (*p->fcn) (cntxt, mb, 0, p);
     145    10522571 :                         if (msg) {
     146           0 :                                 str place = getExceptionPlace(msg);
     147             :                                 str nmsg = NULL;
     148           0 :                                 if (place){
     149           0 :                                         nmsg = createException(getExceptionType(msg), place, "%s", getExceptionMessageAndState(msg));
     150           0 :                                         GDKfree(place);
     151             :                                 }
     152             :                                 if (nmsg ) {
     153           0 :                                         freeException(msg);
     154             :                                         msg = nmsg;
     155             :                                 }
     156           0 :                                 goto wrapup;
     157             :                         }
     158    10522571 :                         if (cntxt->mode == FINISHCLIENT){
     159           0 :                                 mb->optimize = GDKusec() - clk;
     160           0 :                                 throw(MAL, "optimizeMALBlock", SQLSTATE(42000) "prematurely stopped client");
     161             :                         }
     162             :                         /* the MAL block may have changed */
     163    10522571 :                         pc += mb->stop - oldstop - 1;
     164             :                         oldstop = mb->stop;
     165             :                 }
     166             :         }
     167             : 
     168      365750 : wrapup:
     169             :         /* Keep the total time spent on optimizing the plan for inspection */
     170      365750 :         if(actions > 0 && msg == MAL_SUCCEED){
     171      356796 :                 mb->optimize = GDKusec() - clk;
     172      356796 :                 p = newStmt(mb, optimizerRef, totalRef);
     173      356796 :                 p->token = REMsymbol;
     174      356796 :                 p = pushInt(mb, p, actions);
     175      356796 :                 p = pushLng(mb, p, mb->optimize);
     176             :         }
     177      365750 :         if (cnt >= mb->stop)
     178           0 :                 throw(MAL, "optimizer.MALoptimizer", SQLSTATE(42000) OPTIMIZER_CYCLE);
     179             :         return msg;
     180             : }
     181             : 
     182             : /*
     183             :  * The default MAL optimizer includes a final call to
     184             :  * the multiplex expander.
     185             :  * We should take care of functions marked as 'inline',
     186             :  * because they should be kept in raw form.
     187             :  * Their optimization takes place after inlining.
     188             :  */
     189             : str
     190       11410 : MALoptimizer(Client c)
     191             : {
     192             :         str msg;
     193             : 
     194       11410 :         if ( c->curprg->def->inlineProp)
     195             :                 return MAL_SUCCEED;
     196             :         // only a signature statement can be skipped
     197       11410 :         if (c ->curprg->def->stop == 1)
     198             :                 return MAL_SUCCEED;
     199        9044 :         msg= optimizeMALBlock(c, c->curprg->def);
     200        9044 :         if( msg == MAL_SUCCEED)
     201        9044 :                 msg = OPTmultiplexSimple(c, c->curprg->def);
     202             :         return msg;
     203             : }
     204             : 
     205             : /* Only used by opt_commonTerms! */
     206      128670 : int hasSameSignature(MalBlkPtr mb, InstrPtr p, InstrPtr q){
     207             :         int i;
     208             : 
     209      128670 :         if( q->retc != p->retc || q->argc != p->argc)
     210             :                 return FALSE;
     211      592787 :         for( i=0; i < p->argc; i++)
     212      464117 :                 if (getArgType(mb,p,i) != getArgType(mb,q,i))
     213             :                         return FALSE;
     214             :         return TRUE;
     215             : }
     216             : 
     217             : /* Only used by opt_commonTerms! */
     218     3944850 : int hasSameArguments(MalBlkPtr mb, InstrPtr p, InstrPtr q)
     219             : {   int k;
     220             :         int (*cmp)(const void *, const void *);
     221             :         VarPtr w,u;
     222             : 
     223             :         (void) mb;
     224     3944850 :         if( p->retc != q->retc || p->argc != q->argc)
     225             :                 return FALSE;
     226             :         /* heuristic, because instructions are linked using last constant argument */
     227     7943617 :         for(k=p->argc-1; k >= p->retc; k--)
     228     7814947 :                 if( q->argv[k]!= p->argv[k]){
     229     3419626 :                         if( isVarConstant(mb,getArg(p,k)) &&
     230     1748757 :                                 isVarConstant(mb,getArg(q,k)) ) {
     231             :                                         w= getVar(mb,getArg(p,k));
     232             :                                         u= getVar(mb,getArg(q,k));
     233     1748613 :                                         cmp = ATOMcompare(w->value.vtype);
     234     3183814 :                                         if ( w->value.vtype == u->value.vtype &&
     235     1435201 :                                                 (*cmp)(VALptr(&w->value), VALptr(&u->value)) == 0)
     236          51 :                                                 continue;
     237             :                         }
     238     3419575 :                         return FALSE;
     239             :                 }
     240             :         return TRUE;
     241             : }
     242             : 
     243             : /*
     244             :  * If two instructions have elements in common in their target list,
     245             :  * it means a variable is re-initialized and should not be considered
     246             :  * an alias.
     247             :  */
     248             : int
     249      128670 : hasCommonResults(InstrPtr p, InstrPtr q)
     250             : {
     251             :         int k, l;
     252             : 
     253      258387 :         for (k = 0; k < p->retc; k++)
     254      262498 :                 for (l = 0; l < q->retc; l++)
     255      132781 :                         if (p->argv[k] == q->argv[l])
     256             :                                 return TRUE;
     257             :         return FALSE;
     258             : }
     259             : /*
     260             :  * Dependency between target variables and arguments can be
     261             :  * checked with isDependent().
     262             :  */
     263             : static int
     264      115986 : isDependent(InstrPtr p, InstrPtr q){
     265             :         int i,j;
     266      233021 :         for(i= 0; i<q->retc; i++)
     267      427853 :         for(j= p->retc; j<p->argc; j++)
     268      310818 :                 if( getArg(q,i)== getArg(p,j)) return TRUE;
     269             :         return FALSE;
     270             : }
     271             : /*
     272             :  * The safety property should be relatively easy to determine for
     273             :  * each MAL function. This calls for accessing the function MAL block
     274             :  * and to inspect the arguments of the signature.
     275             :  */
     276             : inline int
     277   114953535 : isUnsafeFunction(InstrPtr q)
     278             : {
     279             :         InstrPtr p;
     280             : 
     281   114953535 :         if (q->fcn == 0 || getFunctionId(q) == 0 || q->blk == NULL)
     282             :                 return FALSE;
     283   114265757 :         p= getInstrPtr(q->blk,0);
     284   114265757 :         if( p->retc== 0)
     285             :                 return TRUE;
     286   114265757 :         return q->blk->unsafeProp;
     287             : }
     288             : 
     289             : /*
     290             :  * Instructions are unsafe if one of the arguments is also mentioned
     291             :  * in the result list. Alternatively, the 'unsafe' property is set
     292             :  * for the function call itself.
     293             :  */
     294             : int
     295           0 : isUnsafeInstruction(InstrPtr q)
     296             : {
     297             :         int j, k;
     298             : 
     299           0 :         for (j = 0; j < q->retc; j++)
     300           0 :                 for (k = q->retc; k < q->argc; k++)
     301           0 :                         if (q->argv[k] == q->argv[j])
     302             :                                 return TRUE;
     303             :         return FALSE;
     304             : }
     305             : 
     306             : /*
     307             :  * Any instruction may block identification of a common
     308             :  * subexpression. It suffices to stumble upon an unsafe function
     309             :  * whose parameter lists has a non-empty intersection with the
     310             :  * targeted instruction.
     311             :  * To illustrate, consider the sequence
     312             :  * @example
     313             :  * L1 := f(A,B,C);
     314             :  * ...
     315             :  * G1 := g(D,E,F);
     316             :  * ...
     317             :  * l2:= f(A,B,C);
     318             :  * ...
     319             :  * L2:= h()
     320             :  * @end example
     321             :  *
     322             :  * The instruction G1:=g(D,E,F) is blocking if G1 is an alias
     323             :  * for @verb{ { }A,B,C@verb{ } }.
     324             :  * Alternatively, function g() may be unsafe and @verb{ { }D,E,F@verb{ } }
     325             :  * has a non-empty intersection with @verb{ { }A,B,C@verb{ } }.
     326             :  * An alias can only be used later on for readonly (and not be used for a function with side effects).
     327             :  */
     328             : int
     329      115986 : safetyBarrier(InstrPtr p, InstrPtr q)
     330             : {
     331             :         int i,j;
     332      115986 :         if( isDependent(q,p))
     333             :                 return TRUE;
     334      115986 :         if (isUnsafeFunction(q)) {
     335           0 :                 for (i = p->retc; i < p->argc; i++)
     336           0 :                         for (j = q->retc; j < q->argc; j++)
     337           0 :                                 if (p->argv[i] == q->argv[j]) {
     338             :                                         /* TODO check safety property of the argument */
     339             :                                         return TRUE;
     340             :                                 }
     341             :         }
     342             :         return FALSE;
     343             : }
     344             : 
     345             : inline int
     346   126899350 : isUpdateInstruction(InstrPtr p){
     347   126899350 :         if ( getModuleId(p) == sqlRef &&
     348    21222741 :            ( getFunctionId(p) == appendRef ||
     349    18713069 :                 getFunctionId(p) == updateRef ||
     350    18691537 :                 getFunctionId(p) == deleteRef ||
     351    18690955 :                 getFunctionId(p) == claimRef ||
     352    18624082 :                 getFunctionId(p) == growRef ||
     353    18623941 :                 getFunctionId(p) == clear_tableRef ||
     354    18623689 :                 getFunctionId(p) == setVariableRef))
     355             :                         return TRUE;
     356   124299932 :         if ( getModuleId(p) == batRef &&
     357    11083706 :            ( getFunctionId(p) == appendRef ||
     358     8454676 :                 getFunctionId(p) == replaceRef ||
     359     8004055 :                 getFunctionId(p) == deleteRef))
     360     3079695 :                         return TRUE;
     361             :         return FALSE;
     362             : }
     363             : 
     364             : int
     365   103844417 : hasSideEffects(MalBlkPtr mb, InstrPtr p, int strict)
     366             : {
     367   103844417 :         if( getFunctionId(p) == NULL) return FALSE;
     368             : 
     369             : /*
     370             :  * Void-returning operations have side-effects and
     371             :  * should be considered as such
     372             :  */
     373   102107772 :         if (p->retc == 0 || (p->retc == 1 && getArgType(mb,p,0) == TYPE_void))
     374             :                 return TRUE;
     375             : 
     376             : /*
     377             :  * Any function marked as unsafe can not be moved around without
     378             :  * affecting its behavior on the program. For example, because they
     379             :  * check for volatile resource levels.
     380             :  */
     381    97412525 :         if ( isUnsafeFunction(p))
     382             :                 return TRUE;
     383             : 
     384             :         /* update instructions have side effects, they can be marked as unsafe */
     385    96586045 :         if (isUpdateInstruction(p))
     386             :                 return TRUE;
     387             : 
     388    93790746 :         if ( (getModuleId(p) == batRef || getModuleId(p)==sqlRef) &&
     389    16746286 :                  (getFunctionId(p) == setAccessRef ||
     390    16746286 :                   getFunctionId(p) == setWriteModeRef ))
     391             :                 return TRUE;
     392             : 
     393    93790746 :         if (getModuleId(p) == malRef && getFunctionId(p) == multiplexRef)
     394             :                 return FALSE;
     395             : 
     396    93786720 :         if( getModuleId(p) == ioRef ||
     397    93786720 :                 getModuleId(p) == streamsRef ||
     398    93786720 :                 getModuleId(p) == bstreamRef ||
     399    93786720 :                 getModuleId(p) == mdbRef ||
     400    93786307 :                 getModuleId(p) == malRef ||
     401    93786307 :                 getModuleId(p) == remapRef ||
     402    93786307 :                 getModuleId(p) == optimizerRef ||
     403    57516697 :                 getModuleId(p) == lockRef ||
     404    57516697 :                 getModuleId(p) == semaRef ||
     405    57516697 :                 getModuleId(p) == alarmRef)
     406             :                 return TRUE;
     407             : 
     408    57516697 :         if( getModuleId(p) == pyapi3Ref ||
     409    57516697 :                 getModuleId(p) == pyapi3mapRef ||
     410    57516547 :                 getModuleId(p) == rapiRef ||
     411    57516394 :                 getModuleId(p) == capiRef)
     412             :                 return TRUE;
     413             : 
     414    57516297 :         if (getModuleId(p) == sqlcatalogRef)
     415             :                 return TRUE;
     416    57516297 :         if (getModuleId(p) == sqlRef){
     417    12587023 :                 if (getFunctionId(p) == tidRef) return FALSE;
     418    10783848 :                 if (getFunctionId(p) == deltaRef) return FALSE;
     419     8759107 :                 if (getFunctionId(p) == subdeltaRef) return FALSE;
     420     8522668 :                 if (getFunctionId(p) == projectdeltaRef) return FALSE;
     421     7657542 :                 if (getFunctionId(p) == bindRef) return FALSE;
     422      892343 :                 if (getFunctionId(p) == bindidxRef) return FALSE;
     423      862653 :                 if (getFunctionId(p) == binddbatRef) return FALSE;
     424      862653 :                 if (getFunctionId(p) == columnBindRef) return FALSE;
     425      862653 :                 if (getFunctionId(p) == copy_fromRef) return FALSE;
     426             :                 /* assertions are the end-point of a flow path */
     427      862653 :                 if (getFunctionId(p) == not_uniqueRef) return FALSE;
     428      862653 :                 if (getFunctionId(p) == zero_or_oneRef) return FALSE;
     429      862653 :                 if (getFunctionId(p) == mvcRef) return FALSE;
     430       44937 :                 if (getFunctionId(p) == singleRef) return FALSE;
     431       44937 :                 if (getFunctionId(p) == importColumnRef) return FALSE;
     432       44313 :                 return TRUE;
     433             :         }
     434    44929274 :         if( getModuleId(p) == mapiRef){
     435           0 :                 if( getFunctionId(p) == rpcRef)
     436             :                         return TRUE;
     437           0 :                 if( getFunctionId(p) == reconnectRef)
     438             :                         return TRUE;
     439           0 :                 if( getFunctionId(p) == disconnectRef)
     440             :                         return TRUE;
     441             :         }
     442    44929274 :         if (strict &&  getFunctionId(p) == newRef &&
     443      361229 :                 getModuleId(p) != groupRef )
     444             :                 return TRUE;
     445             : 
     446             :         if ( getModuleId(p) == sqlcatalogRef)
     447             :                 return TRUE;
     448    44568045 :         if ( getModuleId(p) == oltpRef)
     449             :                 return TRUE;
     450    44568045 :         if ( getModuleId(p) == wlrRef)
     451             :                 return TRUE;
     452    44568026 :         if ( getModuleId(p) == wlcRef)
     453             :                 return TRUE;
     454    44568000 :         if ( getModuleId(p) == remoteRef)
     455       28852 :                 return TRUE;
     456             :         return FALSE;
     457             : }
     458             : 
     459             : /* Void returning functions always have side-effects.
     460             :  */
     461             : int
     462    18544067 : mayhaveSideEffects(Client cntxt, MalBlkPtr mb, InstrPtr p, int strict)
     463             : {
     464             :         int tpe;
     465    18544067 :         tpe= getVarType(mb,getArg(p,0));
     466    18544067 :         if( tpe == TYPE_void)
     467             :                 return TRUE;
     468    18291780 :         if (getModuleId(p) != malRef || getFunctionId(p) != multiplexRef)
     469    18290527 :                 return hasSideEffects(mb, p, strict);
     470             :         //  a manifold instruction can also have side effects.
     471             :         //  for this to check we need the function signature, not its function address.
     472             :         //  The easy way out now is to consider all manifold instructions as potentially having side effects.
     473        1253 :         if ( getModuleId(p) == malRef && getFunctionId(p) == manifoldRef)
     474             :                 return TRUE;
     475        1253 :         if (MANIFOLDtypecheck(cntxt,mb,p,1) == NULL)
     476         443 :                 return TRUE;
     477             :         return FALSE;
     478             : }
     479             : 
     480             : /*
     481             :  * Side-effect free functions are crucial for several operators.
     482             :  */
     483             : int
     484         212 : isSideEffectFree(MalBlkPtr mb){
     485             :         int i;
     486        8766 :         for(i=1; i< mb->stop && getInstrPtr(mb,i)->token != ENDsymbol; i++){
     487        8631 :                 if( hasSideEffects(mb,getInstrPtr(mb,i), TRUE))
     488             :                         return FALSE;
     489             :         }
     490             :         return TRUE;
     491             : }
     492             : 
     493             : /*
     494             :  * Breaking up a MAL program into pieces for distributed processing requires
     495             :  * identification of (partial) blocking instructions. A conservative
     496             :  * definition can be used.
     497             :  */
     498             : inline int
     499           0 : isBlocking(InstrPtr p)
     500             : {
     501           0 :         if (blockStart(p) || blockExit(p) || blockCntrl(p))
     502             :                 return TRUE;
     503             : 
     504           0 :         if ( getFunctionId(p) == sortRef )
     505             :                 return TRUE;
     506             : 
     507           0 :         if( getModuleId(p) == aggrRef ||
     508           0 :                 getModuleId(p) == groupRef ||
     509           0 :                 getModuleId(p) == sqlcatalogRef )
     510           0 :                         return TRUE;
     511             :         return FALSE;
     512             : }
     513             : 
     514             : /*
     515             :  * Used in the merge table optimizer. It is built incrementally
     516             :  * and should be conservative.
     517             :  */
     518             : 
     519             : static int
     520      114232 : isOrderDepenent(InstrPtr p)
     521             : {
     522      114232 :         if( getModuleId(p) != batsqlRef)
     523             :                 return 0;
     524         202 :         if ( getFunctionId(p) == differenceRef ||
     525         202 :                 getFunctionId(p) == window_boundRef ||
     526         194 :                 getFunctionId(p) == row_numberRef ||
     527         186 :                 getFunctionId(p) == rankRef ||
     528         172 :                 getFunctionId(p) == dense_rankRef ||
     529         168 :                 getFunctionId(p) == percent_rankRef ||
     530         168 :                 getFunctionId(p) == cume_distRef ||
     531         168 :                 getFunctionId(p) == ntileRef ||
     532         168 :                 getFunctionId(p) == first_valueRef ||
     533         168 :                 getFunctionId(p) == last_valueRef ||
     534         168 :                 getFunctionId(p) == nth_valueRef ||
     535         168 :                 getFunctionId(p) == lagRef ||
     536         168 :                 getFunctionId(p) == leadRef)
     537          34 :                 return 1;
     538             :         return 0;
     539             : }
     540             : 
     541      849421 : inline int isMapOp(InstrPtr p){
     542      849421 :         if (isUnsafeFunction(p))
     543             :                 return 0;
     544     1670958 :         return  getModuleId(p) &&
     545      832833 :                 ((getModuleId(p) == malRef && getFunctionId(p) == multiplexRef) ||
     546           0 :                  (getModuleId(p) == malRef && getFunctionId(p) == manifoldRef) ||
     547      832793 :                  (getModuleId(p) == batcalcRef) ||
     548      809398 :                  (getModuleId(p) != batcalcRef && getModuleId(p) != batRef && strncmp(getModuleId(p), "bat", 3) == 0) ||
     549      832833 :                  (getModuleId(p) == mkeyRef)) && !isOrderDepenent(p) &&
     550       24585 :                  getModuleId(p) != batrapiRef &&
     551      862706 :                  getModuleId(p) != batpyapi3Ref &&
     552       24581 :                  getModuleId(p) != batcapiRef;
     553             : }
     554             : 
     555      208203 : inline int isMap2Op(InstrPtr p){
     556      208203 :         if (isUnsafeFunction(p))
     557             :                 return 0;
     558      416358 :         return  getModuleId(p) &&
     559      208179 :                 ((getModuleId(p) == malRef && getFunctionId(p) == multiplexRef) ||
     560           0 :                  (getModuleId(p) == malRef && getFunctionId(p) == manifoldRef) ||
     561      208128 :                  (getModuleId(p) == batcalcRef) ||
     562      124108 :                  (getModuleId(p) != batcalcRef && getModuleId(p) != batRef && strncmp(getModuleId(p), "bat", 3) == 0) ||
     563      208179 :                  (getModuleId(p) == mkeyRef)) && !isOrderDepenent(p) &&
     564       89613 :                  getModuleId(p) != batrapiRef &&
     565      297788 :                  getModuleId(p) != batpyapi3Ref &&
     566       89609 :                  getModuleId(p) != batcapiRef;
     567             : }
     568             : 
     569    14611510 : inline int isLikeOp(InstrPtr p){
     570    14611510 :         return  (getModuleId(p) == batalgebraRef &&
     571         141 :                 (getFunctionId(p) == likeRef ||
     572          19 :                  getFunctionId(p) == not_likeRef));
     573             : }
     574             : 
     575             : inline int
     576      239390 : isTopn(InstrPtr p)
     577             : {
     578      239390 :         return ((getModuleId(p) == algebraRef && getFunctionId(p) == firstnRef) ||
     579      239338 :                         isSlice(p));
     580             : }
     581             : 
     582             : inline int
     583    29418385 : isSlice(InstrPtr p)
     584             : {
     585    29418385 :         return (getModuleId(p) == algebraRef &&
     586     3635723 :            (getFunctionId(p) == subsliceRef || getFunctionId(p) == sliceRef));
     587             : }
     588             : 
     589             : int
     590    17991394 : isSample(InstrPtr p)
     591             : {
     592    17991394 :         return (getModuleId(p) == sampleRef && getFunctionId(p) == subuniformRef);
     593             : }
     594             : 
     595           0 : inline int isOrderby(InstrPtr p){
     596           0 :         return getModuleId(p) == algebraRef &&
     597           0 :                 getFunctionId(p) == sortRef;
     598             : }
     599             : 
     600             : inline int
     601     1649082 : isMatJoinOp(InstrPtr p)
     602             : {
     603     1649082 :         return (isSubJoin(p) || (getModuleId(p) == algebraRef &&
     604     1153835 :                                 (getFunctionId(p) == crossRef ||
     605     1148153 :                                  getFunctionId(p) == joinRef ||
     606     1148153 :                                  getFunctionId(p) == thetajoinRef ||
     607     1148153 :                                  getFunctionId(p) == bandjoinRef ||
     608     1148153 :                                  getFunctionId(p) == rangejoinRef)
     609             :                 ));
     610             : }
     611             : 
     612             : inline int
     613     1649083 : isMatLeftJoinOp(InstrPtr p)
     614             : {
     615     1649083 :         return (getModuleId(p) == algebraRef &&
     616     1228404 :                 getFunctionId(p) == leftjoinRef);
     617             : }
     618             : 
     619      167466 : inline int isDelta(InstrPtr p){
     620             :         return
     621      167466 :                         (getModuleId(p)== sqlRef && (
     622      150872 :                                 getFunctionId(p)== deltaRef ||
     623       48168 :                                 getFunctionId(p)== projectdeltaRef ||
     624       10307 :                                 getFunctionId(p)== subdeltaRef
     625             :                         )
     626             :                 );
     627             : }
     628             : 
     629       21735 : int isFragmentGroup2(InstrPtr p){
     630       21735 :         if (getModuleId(p) == batRef && getFunctionId(p) == replaceRef)
     631             :                         return TRUE;
     632             :         return
     633        9101 :                         (getModuleId(p)== algebraRef && (
     634          11 :                                 getFunctionId(p)== projectionRef
     635        9101 :                         )) ||
     636        8911 :                         (getModuleId(p)== batRef && (
     637        8911 :                                 getFunctionId(p)== mergecandRef ||
     638           0 :                                 getFunctionId(p)== intersectcandRef ||
     639           0 :                                 getFunctionId(p)== diffcandRef
     640             :                         )
     641             :                 );
     642             : }
     643             : 
     644    28366809 : inline int isSelect(InstrPtr p)
     645             : {
     646    28366809 :         const char *func = getFunctionId(p);
     647    28366809 :         size_t l = func?strlen(func):0;
     648             : 
     649    27440032 :         return (l >= 6 && strcmp(func+l-6,"select") == 0);
     650             : }
     651             : 
     652     1649082 : inline int isSubJoin(InstrPtr p)
     653             : {
     654     1649082 :         const char *func = getFunctionId(p);
     655     1649082 :         size_t l = func?strlen(func):0;
     656             : 
     657     1649080 :         return (l >= 4 && strcmp(func+l-4,"join") == 0);
     658             : }
     659             : 
     660    74222132 : inline int isMultiplex(InstrPtr p)
     661             : {
     662    74222132 :         return (malRef && (getModuleId(p) == malRef || getModuleId(p) == batmalRef) &&
     663      302530 :                 getFunctionId(p) == multiplexRef);
     664             : }
     665             : 
     666      118594 : int isFragmentGroup(InstrPtr p){
     667             :         return
     668      201633 :                         (getModuleId(p)== algebraRef && (
     669       83039 :                                 getFunctionId(p)== projectRef ||
     670       64710 :                                 getFunctionId(p)== selectNotNilRef
     671      100265 :                         ))  ||
     672      183304 :                         isSelect(p) ||
     673       35566 :                         (getModuleId(p)== batRef && (
     674       35387 :                                 getFunctionId(p)== mirrorRef
     675             :                         ));
     676             : }
     677             : 

Generated by: LCOV version 1.14