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-26 00:35:57 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    20561764 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
      19             : {
      20    20561764 :         int i;
      21    20561764 :         (void) cntxt;
      22             : 
      23    20561764 :         if (p->token != ASSIGNsymbol
      24    20560705 :                 && getModuleId(p) != calcRef
      25    20464122 :                 && getModuleId(p) != strRef
      26    20463724 :                 && getModuleId(p) != mtimeRef
      27    20463210 :                 && getModuleId(p) != mmathRef)
      28             :                 return false;
      29       98783 :         if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
      30             :                 return false;
      31             : 
      32      210133 :         for (i = p->retc; i < p->argc; i++)
      33      149145 :                 if (isVarConstant(mb, getArg(p, i)) == FALSE)
      34             :                         return false;
      35      121816 :         for (i = 0; i < p->retc; i++) {
      36       60903 :                 if (isaBatType(getArgType(mb, p, i)))
      37             :                         return false;
      38       60903 :                 if (p->unsafeProp || mb->unsafeProp)
      39             :                         return false;
      40             :         }
      41             :         return true;
      42             : }
      43             : 
      44             : static bool
      45         136 : OPTsimpleflow(MalBlkPtr mb, int pc)
      46             : {
      47         136 :         int i, block = 0;
      48         136 :         bool simple = true;
      49         136 :         InstrPtr p;
      50             : 
      51         610 :         for (i = pc; i < mb->stop; i++) {
      52         610 :                 p = getInstrPtr(mb, i);
      53         610 :                 if (blockStart(p))
      54         147 :                         block++;
      55         610 :                 if (blockExit(p))
      56         147 :                         block--;
      57         610 :                 if (blockCntrl(p))
      58          26 :                         simple = false;
      59         610 :                 if (block == 0) {
      60         136 :                         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         299 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
      69             : {
      70             :         /* catch and remove constant bounded blocks */
      71         299 :         int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
      72         299 :         InstrPtr p;
      73         299 :         str msg = MAL_SUCCEED;
      74             : 
      75         601 :         while (multipass--) {
      76             :                 block = -1;
      77             :                 skip = 0;
      78             :                 j = 0;
      79       24752 :                 for (i = 0; i < mb->stop; i++) {
      80       24450 :                         p = mb->stmt[i];
      81       24450 :                         if (blockExit(p) && block == getArg(p, 0)) {
      82         305 :                                 block = -1;
      83         305 :                                 skip = 0;
      84         305 :                                 freeInstruction(p);
      85         305 :                                 mb->stmt[i] = 0;
      86         305 :                                 continue;
      87             :                         }
      88       24145 :                         if (p->argc == 2 && blockStart(p) && block < 0
      89         425 :                                 && isVarConstant(mb, getArg(p, 1))
      90         425 :                                 && getArgType(mb, p, 1) == TYPE_bit) {
      91         329 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
      92         182 :                                         block = getArg(p, 0);
      93         182 :                                         skip++;
      94         182 :                                         action++;
      95             :                                 }
      96             :                                 // Try to remove the barrier statement itself (when true).
      97         329 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
      98         136 :                                         && OPTsimpleflow(mb, i)) {
      99         123 :                                         block = getArg(p, 0);
     100         123 :                                         skip = 0;
     101         123 :                                         action++;
     102         123 :                                         freeInstruction(p);
     103         123 :                                         mb->stmt[i] = 0;
     104         123 :                                         continue;
     105             :                                 }
     106       23816 :                         } 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       24022 :                                 multipass++;
     110       24022 :                         if (skip) {
     111         539 :                                 freeInstruction(p);
     112         539 :                                 mb->stmt[i] = 0;
     113             :                         } else
     114       23483 :                                 mb->stmt[j++] = p;
     115             :                 }
     116         302 :                 mb->stop = j;
     117        1269 :                 for (; j < i; j++)
     118         967 :                         mb->stmt[j] = NULL;
     119             :         }
     120         299 :         if (action)
     121         108 :                 msg = chkTypes(cntxt->usermodule, mb, TRUE);
     122         299 :         return msg;
     123             : }
     124             : 
     125             : str
     126      477354 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     127             :                                                   InstrPtr pci)
     128             : {
     129      477354 :         InstrPtr p;
     130      477354 :         int i, k, limit, *alias = 0, barrier;
     131      477354 :         MalStkPtr env = NULL;
     132      477354 :         int actions = 0, constantblock = 0;
     133      477354 :         int *assigned = 0, use;
     134      477354 :         str msg = MAL_SUCCEED;
     135             : 
     136      477354 :         (void) stk;
     137             : 
     138      477354 :         if (mb->inlineProp)
     139             :                 return MAL_SUCCEED;
     140             : 
     141      477354 :         assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
     142      477468 :         if (assigned == NULL)
     143           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     144             : 
     145      477468 :         alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2);      /* we introduce more */
     146      477466 :         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      477466 :         p = getInstrPtr(mb, 0);
     152      478291 :         for (k = p->retc; k < p->argc; k++) {
     153         825 :                 assert(getArg(p, k) >= 0);
     154         825 :                 assigned[getArg(p, k)]++;
     155             :         }
     156      477466 :         limit = mb->stop;
     157    22178980 :         for (i = 1; i < limit; i++) {
     158    21701514 :                 p = getInstrPtr(mb, i);
     159             :                 // The double count emerging from a barrier exit is ignored.
     160    21701514 :                 if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
     161    43649445 :                         for (k = 0; k < p->retc; k++)
     162    21948987 :                                 if (p->retc != p->argc || p->token != ASSIGNsymbol) {
     163    21948625 :                                         assert(getArg(p, k) >= 0);
     164    21948625 :                                         assigned[getArg(p, k)]++;
     165             :                                 }
     166             :         }
     167             : 
     168    22182230 :         for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
     169    21704786 :                 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    21704786 :                 assert(getArg(p, 0) >= 0);
     173    21704786 :                 use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
     174    11660535 :                                                                                            && blockExit(p));
     175    50887676 :                 for (k = p->retc; k < p->argc; k++)
     176    29182890 :                         if (alias[getArg(p, k)])
     177       60597 :                                 getArg(p, k) = alias[getArg(p, k)];
     178             :                 /* be aware that you only assign once to a variable */
     179    21704786 :                 if (use && p->retc == 1 && getFunctionId(p)
     180    20560813 :                         && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
     181       60174 :                         barrier = p->barrier;
     182       60174 :                         p->barrier = 0;
     183       60174 :                         if (env == NULL) {
     184       26844 :                                 env = prepareMALstack(mb, 2 * mb->vsize);
     185       26881 :                                 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       26881 :                                 env->keepAlive = TRUE;
     192             :                         }
     193       60211 :                         msg = reenterMAL(cntxt, mb, i, i + 1, env);
     194       60147 :                         p->barrier = barrier;
     195       60147 :                         if (msg == MAL_SUCCEED) {
     196       59683 :                                 int nvar;
     197       59683 :                                 ValRecord cst;
     198             : 
     199       59683 :                                 actions++;
     200       59683 :                                 cst.vtype = 0;
     201       59683 :                                 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       59712 :                                 nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
     209       59694 :                                 if (nvar >= 0)
     210       59697 :                                         getArg(p, 1) = nvar;
     211       59694 :                                 if (nvar >= env->stktop) {
     212       51713 :                                         if (VALcopy(&env->stk[getArg(p, 1)],
     213       51705 :                                                                 &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       51713 :                                         env->stktop = getArg(p, 1) + 1;
     219             :                                 }
     220       59702 :                                 alias[getArg(p, 0)] = getArg(p, 1);
     221       59702 :                                 p->argc = 2;
     222       59702 :                                 p->token = ASSIGNsymbol;
     223       59702 :                                 clrFunction(p);
     224       59736 :                                 p->barrier = barrier;
     225             :                                 /* freeze the type */
     226       59736 :                                 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         464 :                                 freeException(msg);
     231         464 :                                 msg = MAL_SUCCEED;
     232         464 :                                 mb->errors = 0;
     233             :                         }
     234             :                 }
     235    43408826 :                 constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
     236             :         }
     237             :         // produces errors in SQL when enabled
     238      477444 :         if (constantblock)
     239         299 :                 msg = OPTremoveUnusedBlocks(cntxt, mb);
     240             : 
     241             :         /* Defense line against incorrect plans */
     242             :         /* Plan is unaffected */
     243      477444 :         if (!msg)
     244      477435 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     245      477445 :         if (!msg)
     246      477417 :                 msg = chkFlow(mb);
     247      477438 :         if (!msg)
     248      477438 :                 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      477434 :         (void) pushInt(mb, pci, actions);
     254             : 
     255      477419 :         if (env) {
     256       26863 :                 assert(env->stktop < env->stksize);
     257       26863 :                 freeStack(env);
     258             :         }
     259      477447 :         if (assigned)
     260      477447 :                 GDKfree(assigned);
     261      477465 :         if (alias)
     262      477465 :                 GDKfree(alias);
     263      477465 :         return msg;
     264             : }

Generated by: LCOV version 1.14