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-10-07 21:21:43 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    21490462 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
      19             : {
      20    21490462 :         int i;
      21    21490462 :         (void) cntxt;
      22             : 
      23    21490462 :         if (p->token != ASSIGNsymbol
      24    21489280 :                 && getModuleId(p) != calcRef
      25    21347000 :                 && getModuleId(p) != strRef
      26    21346560 :                 && getModuleId(p) != mtimeRef
      27    21346002 :                 && getModuleId(p) != mmathRef)
      28             :                 return false;
      29      144723 :         if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
      30             :                 return false;
      31             : 
      32      344560 :         for (i = p->retc; i < p->argc; i++)
      33      239196 :                 if (isVarConstant(mb, getArg(p, i)) == FALSE)
      34             :                         return false;
      35      210552 :         for (i = 0; i < p->retc; i++) {
      36      105262 :                 if (isaBatType(getArgType(mb, p, i)))
      37             :                         return false;
      38      105262 :                 if (p->unsafeProp || mb->unsafeProp)
      39             :                         return false;
      40             :         }
      41             :         return true;
      42             : }
      43             : 
      44             : static bool
      45         140 : OPTsimpleflow(MalBlkPtr mb, int pc)
      46             : {
      47         140 :         int i, block = 0;
      48         140 :         bool simple = true;
      49         140 :         InstrPtr p;
      50             : 
      51         594 :         for (i = pc; i < mb->stop; i++) {
      52         594 :                 p = getInstrPtr(mb, i);
      53         594 :                 if (blockStart(p))
      54         151 :                         block++;
      55         594 :                 if (blockExit(p))
      56         151 :                         block--;
      57         594 :                 if (blockCntrl(p))
      58          22 :                         simple = false;
      59         594 :                 if (block == 0) {
      60         140 :                         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         308 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
      69             : {
      70             :         /* catch and remove constant bounded blocks */
      71         308 :         int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
      72         308 :         InstrPtr p;
      73         308 :         str msg = MAL_SUCCEED;
      74             : 
      75         619 :         while (multipass--) {
      76             :                 block = -1;
      77             :                 skip = 0;
      78             :                 j = 0;
      79       25065 :                 for (i = 0; i < mb->stop; i++) {
      80       24754 :                         p = mb->stmt[i];
      81       24754 :                         if (blockExit(p) && block == getArg(p, 0)) {
      82         315 :                                 block = -1;
      83         315 :                                 skip = 0;
      84         315 :                                 freeInstruction(p);
      85         315 :                                 mb->stmt[i] = 0;
      86         315 :                                 continue;
      87             :                         }
      88       24439 :                         if (p->argc == 2 && blockStart(p) && block < 0
      89         435 :                                 && isVarConstant(mb, getArg(p, 1))
      90         435 :                                 && getArgType(mb, p, 1) == TYPE_bit) {
      91         339 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 0) {
      92         186 :                                         block = getArg(p, 0);
      93         186 :                                         skip++;
      94         186 :                                         action++;
      95             :                                 }
      96             :                                 // Try to remove the barrier statement itself (when true).
      97         339 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
      98         140 :                                         && OPTsimpleflow(mb, i)) {
      99         129 :                                         block = getArg(p, 0);
     100         129 :                                         skip = 0;
     101         129 :                                         action++;
     102         129 :                                         freeInstruction(p);
     103         129 :                                         mb->stmt[i] = 0;
     104         129 :                                         continue;
     105             :                                 }
     106       24100 :                         } 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       24310 :                                 multipass++;
     110       24310 :                         if (skip) {
     111         559 :                                 freeInstruction(p);
     112         559 :                                 mb->stmt[i] = 0;
     113             :                         } else
     114       23751 :                                 mb->stmt[j++] = p;
     115             :                 }
     116         311 :                 mb->stop = j;
     117        1314 :                 for (; j < i; j++)
     118        1003 :                         mb->stmt[j] = NULL;
     119             :         }
     120         308 :         if (action)
     121         113 :                 msg = chkTypes(cntxt->usermodule, mb, TRUE);
     122         308 :         return msg;
     123             : }
     124             : 
     125             : str
     126      493343 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     127             :                                                   InstrPtr pci)
     128             : {
     129      493343 :         InstrPtr p;
     130      493343 :         int i, k, limit, *alias = 0, barrier;
     131      493343 :         MalStkPtr env = NULL;
     132      493343 :         int actions = 0, constantblock = 0;
     133      493343 :         int *assigned = 0, use;
     134      493343 :         str msg = MAL_SUCCEED;
     135             : 
     136      493343 :         (void) stk;
     137             : 
     138      493343 :         if (mb->inlineProp)
     139             :                 return MAL_SUCCEED;
     140             : 
     141      493343 :         assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
     142      493451 :         if (assigned == NULL)
     143           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     144             : 
     145      493451 :         alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2);      /* we introduce more */
     146      493480 :         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      493480 :         p = getInstrPtr(mb, 0);
     152      494350 :         for (k = p->retc; k < p->argc; k++) {
     153         870 :                 assert(getArg(p, k) >= 0);
     154         870 :                 assigned[getArg(p, k)]++;
     155             :         }
     156      493480 :         limit = mb->stop;
     157    23181433 :         for (i = 1; i < limit; i++) {
     158    22687953 :                 p = getInstrPtr(mb, i);
     159             :                 // The double count emerging from a barrier exit is ignored.
     160    22687953 :                 if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
     161    45654290 :                         for (k = 0; k < p->retc; k++)
     162    22967516 :                                 if (p->retc != p->argc || p->token != ASSIGNsymbol) {
     163    22967144 :                                         assert(getArg(p, k) >= 0);
     164    22967144 :                                         assigned[getArg(p, k)]++;
     165             :                                 }
     166             :         }
     167             : 
     168    23185901 :         for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
     169    22692458 :                 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    22692458 :                 assert(getArg(p, 0) >= 0);
     173    22692458 :                 use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
     174    12077937 :                                                                                            && blockExit(p));
     175    53667161 :                 for (k = p->retc; k < p->argc; k++)
     176    30974703 :                         if (alias[getArg(p, k)])
     177      104849 :                                 getArg(p, k) = alias[getArg(p, k)];
     178             :                 /* be aware that you only assign once to a variable */
     179    22692458 :                 if (use && p->retc == 1 && getFunctionId(p)
     180    21489243 :                         && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
     181      104524 :                         barrier = p->barrier;
     182      104524 :                         p->barrier = 0;
     183      104524 :                         if (env == NULL) {
     184       27383 :                                 env = prepareMALstack(mb, 2 * mb->vsize);
     185       27417 :                                 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       27417 :                                 env->keepAlive = TRUE;
     192             :                         }
     193      104558 :                         msg = reenterMAL(cntxt, mb, i, i + 1, env);
     194      104516 :                         p->barrier = barrier;
     195      104516 :                         if (msg == MAL_SUCCEED) {
     196      104025 :                                 int nvar;
     197      104025 :                                 ValRecord cst;
     198             : 
     199      104025 :                                 actions++;
     200      104025 :                                 cst.vtype = 0;
     201      104025 :                                 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      104038 :                                 nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
     209      104042 :                                 if (nvar >= 0)
     210      104045 :                                         getArg(p, 1) = nvar;
     211      104042 :                                 if (nvar >= env->stktop) {
     212       52977 :                                         if (VALcopy(&env->stk[getArg(p, 1)],
     213       52971 :                                                                 &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       52977 :                                         env->stktop = getArg(p, 1) + 1;
     219             :                                 }
     220      104048 :                                 alias[getArg(p, 0)] = getArg(p, 1);
     221      104048 :                                 p->argc = 2;
     222      104048 :                                 p->token = ASSIGNsymbol;
     223      104048 :                                 clrFunction(p);
     224      104063 :                                 p->barrier = barrier;
     225             :                                 /* freeze the type */
     226      104063 :                                 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         491 :                                 freeException(msg);
     231         491 :                                 msg = MAL_SUCCEED;
     232         491 :                                 mb->errors = 0;
     233             :                         }
     234             :                 }
     235    45384118 :                 constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
     236             :         }
     237             :         // produces errors in SQL when enabled
     238      493443 :         if (constantblock)
     239         308 :                 msg = OPTremoveUnusedBlocks(cntxt, mb);
     240             : 
     241             :         /* Defense line against incorrect plans */
     242             :         /* Plan is unaffected */
     243      493443 :         if (!msg)
     244      493432 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     245      493407 :         if (!msg)
     246      493408 :                 msg = chkFlow(mb);
     247      493417 :         if (!msg)
     248      493417 :                 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      493422 :         (void) pushInt(mb, pci, actions);
     254             : 
     255      493404 :         if (env) {
     256       27413 :                 assert(env->stktop < env->stksize);
     257       27413 :                 freeStack(env);
     258             :         }
     259      493414 :         if (assigned)
     260      493414 :                 GDKfree(assigned);
     261      493454 :         if (alias)
     262      493454 :                 GDKfree(alias);
     263      493454 :         return msg;
     264             : }

Generated by: LCOV version 1.14