LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_evaluate.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 153 164 93.3 %
Date: 2024-04-25 20:03:45 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "opt_evaluate.h"
      15             : #include "opt_aliases.h"
      16             : 
      17             : static bool
      18    20433167 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
      19             : {
      20    20433167 :         int i;
      21    20433167 :         (void) cntxt;
      22             : 
      23    20433167 :         if (p->token != ASSIGNsymbol
      24    20432050 :                 && getModuleId(p) != calcRef
      25    20290429 :                 && getModuleId(p) != strRef
      26    20289976 :                 && getModuleId(p) != mtimeRef
      27    20289488 :                 && getModuleId(p) != mmathRef)
      28             :                 return false;
      29      143920 :         if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
      30             :                 return false;
      31             : 
      32      342029 :         for (i = p->retc; i < p->argc; i++)
      33      236517 :                 if (isVarConstant(mb, getArg(p, i)) == FALSE)
      34             :                         return false;
      35      210979 :         for (i = 0; i < p->retc; i++) {
      36      105512 :                 if (isaBatType(getArgType(mb, p, i)))
      37             :                         return false;
      38      105512 :                 if (mb->unsafeProp)
      39             :                         return false;
      40             :         }
      41             :         return true;
      42             : }
      43             : 
      44             : static bool
      45         141 : OPTsimpleflow(MalBlkPtr mb, int pc)
      46             : {
      47         141 :         int i, block = 0;
      48         141 :         bool simple = true;
      49         141 :         InstrPtr p;
      50             : 
      51         633 :         for (i = pc; i < mb->stop; i++) {
      52         633 :                 p = getInstrPtr(mb, i);
      53         633 :                 if (blockStart(p))
      54         152 :                         block++;
      55         633 :                 if (blockExit(p))
      56         152 :                         block--;
      57         633 :                 if (blockCntrl(p))
      58          26 :                         simple = false;
      59         633 :                 if (block == 0) {
      60         141 :                         return simple;
      61             :                 }
      62             :         }
      63             :         return false;
      64             : }
      65             : 
      66             : /* barrier blocks can only be dropped when they are fully excluded.  */
      67             : static str
      68         307 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
      69             : {
      70             :         /* catch and remove constant bounded blocks */
      71         307 :         int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
      72         307 :         InstrPtr p;
      73         307 :         str msg = MAL_SUCCEED;
      74             : 
      75         617 :         while (multipass--) {
      76             :                 block = -1;
      77             :                 skip = 0;
      78             :                 j = 0;
      79       25265 :                 for (i = 0; i < mb->stop; i++) {
      80       24955 :                         p = mb->stmt[i];
      81       24955 :                         if (blockExit(p) && block == getArg(p, 0)) {
      82         313 :                                 block = -1;
      83         313 :                                 skip = 0;
      84         313 :                                 freeInstruction(p);
      85         313 :                                 mb->stmt[i] = 0;
      86         313 :                                 continue;
      87             :                         }
      88       24642 :                         if (p->argc == 2 && blockStart(p) && block < 0
      89         435 :                                 && isVarConstant(mb, getArg(p, 1))
      90         339 :                                 && getArgType(mb, p, 1) == TYPE_bit) {
      91         339 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
      92         185 :                                         block = getArg(p, 0);
      93         185 :                                         skip++;
      94         185 :                                         action++;
      95             :                                 }
      96             :                                 // Try to remove the barrier statement itself (when true).
      97         339 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
      98         141 :                                         && OPTsimpleflow(mb, i)) {
      99         128 :                                         block = getArg(p, 0);
     100         128 :                                         skip = 0;
     101         128 :                                         action++;
     102         128 :                                         freeInstruction(p);
     103         128 :                                         mb->stmt[i] = 0;
     104         128 :                                         continue;
     105             :                                 }
     106       24303 :                         } else if (p->argc == 2 && blockStart(p) && block >= 0 && skip == 0
     107           7 :                                            && isVarConstant(mb, getArg(p, 1))
     108           7 :                                            && getArgType(mb, p, 1) == TYPE_bit && multipass == 0)
     109       24514 :                                 multipass++;
     110       24514 :                         if (skip) {
     111         548 :                                 freeInstruction(p);
     112         548 :                                 mb->stmt[i] = 0;
     113             :                         } else
     114       23966 :                                 mb->stmt[j++] = p;
     115             :                 }
     116         310 :                 mb->stop = j;
     117        1299 :                 for (; j < i; j++)
     118         989 :                         mb->stmt[j] = NULL;
     119             :         }
     120         307 :         if (action)
     121         112 :                 msg = chkTypes(cntxt->usermodule, mb, TRUE);
     122         307 :         return msg;
     123             : }
     124             : 
     125             : str
     126      467675 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     127             :                                                   InstrPtr pci)
     128             : {
     129      467675 :         InstrPtr p;
     130      467675 :         int i, k, limit, *alias = 0, barrier;
     131      467675 :         MalStkPtr env = NULL;
     132      467675 :         int actions = 0, constantblock = 0;
     133      467675 :         int *assigned = 0, use;
     134      467675 :         str msg = MAL_SUCCEED;
     135             : 
     136      467675 :         (void) stk;
     137             : 
     138      467675 :         if (mb->inlineProp)
     139             :                 return MAL_SUCCEED;
     140             : 
     141      467675 :         assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
     142      467673 :         if (assigned == NULL)
     143           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     144             : 
     145      467673 :         alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2);      /* we introduce more */
     146      467659 :         if (alias == NULL) {
     147           0 :                 GDKfree(assigned);
     148           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     149             :         }
     150             :         // arguments are implicitly assigned by context
     151      467659 :         p = getInstrPtr(mb, 0);
     152      468528 :         for (k = p->retc; k < p->argc; k++) {
     153         869 :                 assert(getArg(p, k) >= 0);
     154         869 :                 assigned[getArg(p, k)]++;
     155             :         }
     156      467659 :         limit = mb->stop;
     157    22033948 :         for (i = 1; i < limit; i++) {
     158    21566289 :                 p = getInstrPtr(mb, i);
     159             :                 // The double count emerging from a barrier exit is ignored.
     160    21566289 :                 if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
     161    43390188 :                         for (k = 0; k < p->retc; k++)
     162    21825016 :                                 if (p->retc != p->argc || p->token != ASSIGNsymbol) {
     163    21824646 :                                         assert(getArg(p, k) >= 0);
     164    21824646 :                                         assigned[getArg(p, k)]++;
     165             :                                 }
     166             :         }
     167             : 
     168    22035166 :         for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
     169    21567507 :                 p = getInstrPtr(mb, i);
     170             :                 // to avoid management of duplicate assignments over multiple blocks
     171             :                 // we limit ourselves to evaluation of the first assignment only.
     172    21567507 :                 assert(getArg(p, 0) >= 0);
     173    21567507 :                 use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
     174    11408522 :                                                                                            && blockExit(p));
     175    51039508 :                 for (k = p->retc; k < p->argc; k++)
     176    29472001 :                         if (alias[getArg(p, k)])
     177      105212 :                                 getArg(p, k) = alias[getArg(p, k)];
     178             :                 /* be aware that you only assign once to a variable */
     179    21567507 :                 if (use && p->retc == 1 && getFunctionId(p)
     180    20432006 :                         && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
     181      104748 :                         barrier = p->barrier;
     182      104748 :                         p->barrier = 0;
     183      104748 :                         if (env == NULL) {
     184       26894 :                                 env = prepareMALstack(mb, 2 * mb->vsize);
     185       26894 :                                 if (!env) {
     186           0 :                                         msg = createException(MAL, "optimizer.evaluate",
     187             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     188           0 :                                         p->barrier = barrier;
     189           0 :                                         goto wrapup;
     190             :                                 }
     191       26894 :                                 env->keepAlive = TRUE;
     192             :                         }
     193      104748 :                         msg = reenterMAL(cntxt, mb, i, i + 1, env);
     194      104749 :                         p->barrier = barrier;
     195      104749 :                         if (msg == MAL_SUCCEED) {
     196      104221 :                                 int nvar;
     197      104221 :                                 ValRecord cst;
     198             : 
     199      104221 :                                 actions++;
     200      104221 :                                 cst.vtype = 0;
     201      104221 :                                 if (VALcopy(&cst, &env->stk[getArg(p, 0)]) == NULL) {
     202           0 :                                         msg = createException(MAL, "optimizer.evaluate",
     203             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     204           0 :                                         goto wrapup;
     205             :                                 }
     206             :                                 /* You may not overwrite constants.  They may be used by
     207             :                                  * other instructions */
     208      104221 :                                 nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
     209      104220 :                                 if (nvar >= 0)
     210      104220 :                                         getArg(p, 1) = nvar;
     211      104220 :                                 if (nvar >= env->stktop) {
     212       52894 :                                         if (VALcopy(&env->stk[getArg(p, 1)],
     213       52894 :                                                                 &getVarConstant(mb, getArg(p, 1))) == NULL) {
     214           0 :                                                 msg = createException(MAL, "optimizer.evaluate",
     215             :                                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
     216           0 :                                                 goto wrapup;
     217             :                                         }
     218       52894 :                                         env->stktop = getArg(p, 1) + 1;
     219             :                                 }
     220      104220 :                                 alias[getArg(p, 0)] = getArg(p, 1);
     221      104220 :                                 p->argc = 2;
     222      104220 :                                 p->token = ASSIGNsymbol;
     223      104220 :                                 clrFunction(p);
     224      104219 :                                 p->barrier = barrier;
     225             :                                 /* freeze the type */
     226      104219 :                                 setVarFixed(mb, getArg(p, 1));
     227             :                         } else {
     228             :                                 /* if there is an error, we should postpone message handling,
     229             :                                    as the actual error (eg. division by zero ) may not happen) */
     230         528 :                                 freeException(msg);
     231         528 :                                 msg = MAL_SUCCEED;
     232         528 :                                 mb->errors = 0;
     233             :                         }
     234             :                 }
     235    43134294 :                 constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
     236             :         }
     237             :         // produces errors in SQL when enabled
     238      467659 :         if (constantblock)
     239         307 :                 msg = OPTremoveUnusedBlocks(cntxt, mb);
     240             : 
     241             :         /* Defense line against incorrect plans */
     242             :         /* Plan is unaffected */
     243      467659 :         if (!msg)
     244      467659 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     245      467667 :         if (!msg)
     246      467669 :                 msg = chkFlow(mb);
     247      467666 :         if (!msg)
     248      467666 :                 msg = chkDeclarations(mb);
     249             :         /* keep all actions taken as a post block comment */
     250             : 
     251           0 :   wrapup:
     252             :         /* keep actions taken as a fake argument */
     253      467664 :         (void) pushInt(mb, pci, actions);
     254             : 
     255      467671 :         if (env) {
     256       26895 :                 assert(env->stktop < env->stksize);
     257       26895 :                 freeStack(env);
     258             :         }
     259      467670 :         if (assigned)
     260      467670 :                 GDKfree(assigned);
     261      467675 :         if (alias)
     262      467675 :                 GDKfree(alias);
     263      467675 :         return msg;
     264             : }

Generated by: LCOV version 1.14