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-12-20 21:24:02 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    21780477 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
      19             : {
      20    21780477 :         int i;
      21    21780477 :         (void) cntxt;
      22             : 
      23    21780477 :         if (p->token != ASSIGNsymbol
      24    21779218 :                 && getModuleId(p) != calcRef
      25    21635884 :                 && getModuleId(p) != strRef
      26    21635327 :                 && getModuleId(p) != mtimeRef
      27    21634768 :                 && getModuleId(p) != mmathRef)
      28             :                 return false;
      29      145962 :         if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
      30             :                 return false;
      31             : 
      32      347553 :         for (i = p->retc; i < p->argc; i++)
      33      241283 :                 if (isVarConstant(mb, getArg(p, i)) == FALSE)
      34             :                         return false;
      35      212377 :         for (i = 0; i < p->retc; i++) {
      36      106182 :                 if (isaBatType(getArgType(mb, p, i)))
      37             :                         return false;
      38      106182 :                 if (p->unsafeProp || mb->unsafeProp)
      39             :                         return false;
      40             :         }
      41             :         return true;
      42             : }
      43             : 
      44             : static bool
      45         212 : OPTsimpleflow(MalBlkPtr mb, int pc)
      46             : {
      47         212 :         int i, block = 0;
      48         212 :         bool simple = true;
      49         212 :         InstrPtr p;
      50             : 
      51        2746 :         for (i = pc; i < mb->stop; i++) {
      52        2746 :                 p = getInstrPtr(mb, i);
      53        2746 :                 if (blockStart(p))
      54         227 :                         block++;
      55        2746 :                 if (blockExit(p))
      56         227 :                         block--;
      57        2746 :                 if (blockCntrl(p))
      58         178 :                         simple = false;
      59        2746 :                 if (block == 0) {
      60         212 :                         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         372 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
      69             : {
      70             :         /* catch and remove constant bounded blocks */
      71         372 :         int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
      72         372 :         InstrPtr p;
      73         372 :         str msg = MAL_SUCCEED;
      74             : 
      75         747 :         while (multipass--) {
      76             :                 block = -1;
      77             :                 skip = 0;
      78             :                 j = 0;
      79       30510 :                 for (i = 0; i < mb->stop; i++) {
      80       30135 :                         p = mb->stmt[i];
      81       30135 :                         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       29820 :                         if (p->argc == 2 && blockStart(p) && block < 0
      89         507 :                                 && isVarConstant(mb, getArg(p, 1))
      90         507 :                                 && getArgType(mb, p, 1) == TYPE_bit) {
      91         411 :                                 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         411 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
      98         212 :                                         && 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       29409 :                         } 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       29691 :                                 multipass++;
     110       29691 :                         if (skip) {
     111         559 :                                 freeInstruction(p);
     112         559 :                                 mb->stmt[i] = 0;
     113             :                         } else
     114       29132 :                                 mb->stmt[j++] = p;
     115             :                 }
     116         375 :                 mb->stop = j;
     117        1378 :                 for (; j < i; j++)
     118        1003 :                         mb->stmt[j] = NULL;
     119             :         }
     120         372 :         if (action)
     121         113 :                 msg = chkTypes(cntxt->usermodule, mb, TRUE);
     122         372 :         return msg;
     123             : }
     124             : 
     125             : str
     126      499044 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     127             :                                                   InstrPtr pci)
     128             : {
     129      499044 :         InstrPtr p;
     130      499044 :         int i, k, limit, *alias = 0, barrier;
     131      499044 :         MalStkPtr env = NULL;
     132      499044 :         int actions = 0, constantblock = 0;
     133      499044 :         int *assigned = 0, use;
     134      499044 :         str msg = MAL_SUCCEED;
     135             : 
     136      499044 :         (void) stk;
     137             : 
     138      499044 :         if (mb->inlineProp)
     139             :                 return MAL_SUCCEED;
     140             : 
     141      499044 :         assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
     142      499172 :         if (assigned == NULL)
     143           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     144             : 
     145      499172 :         alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2);      /* we introduce more */
     146      499183 :         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      499183 :         p = getInstrPtr(mb, 0);
     152      500056 :         for (k = p->retc; k < p->argc; k++) {
     153         873 :                 assert(getArg(p, k) >= 0);
     154         873 :                 assigned[getArg(p, k)]++;
     155             :         }
     156      499183 :         limit = mb->stop;
     157    23496145 :         for (i = 1; i < limit; i++) {
     158    22996962 :                 p = getInstrPtr(mb, i);
     159             :                 // The double count emerging from a barrier exit is ignored.
     160    22996962 :                 if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
     161    46282322 :                         for (k = 0; k < p->retc; k++)
     162    23286619 :                                 if (p->retc != p->argc || p->token != ASSIGNsymbol) {
     163    23286247 :                                         assert(getArg(p, k) >= 0);
     164    23286247 :                                         assigned[getArg(p, k)]++;
     165             :                                 }
     166             :         }
     167             : 
     168    23503784 :         for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
     169    23004619 :                 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    23004619 :                 assert(getArg(p, 0) >= 0);
     173    23004619 :                 use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
     174    12226247 :                                                                                            && blockExit(p));
     175    54492104 :                 for (k = p->retc; k < p->argc; k++)
     176    31487485 :                         if (alias[getArg(p, k)])
     177      105631 :                                 getArg(p, k) = alias[getArg(p, k)];
     178             :                 /* be aware that you only assign once to a variable */
     179    23004619 :                 if (use && p->retc == 1 && getFunctionId(p)
     180    21779351 :                         && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
     181      105326 :                         barrier = p->barrier;
     182      105326 :                         p->barrier = 0;
     183      105326 :                         if (env == NULL) {
     184       27797 :                                 env = prepareMALstack(mb, 2 * mb->vsize);
     185       27851 :                                 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       27851 :                                 env->keepAlive = TRUE;
     192             :                         }
     193      105380 :                         msg = reenterMAL(cntxt, mb, i, i + 1, env);
     194      105270 :                         p->barrier = barrier;
     195      105270 :                         if (msg == MAL_SUCCEED) {
     196      104775 :                                 int nvar;
     197      104775 :                                 ValRecord cst;
     198             : 
     199      104775 :                                 actions++;
     200      104775 :                                 cst.vtype = 0;
     201      104775 :                                 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      104854 :                                 nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
     209      104880 :                                 if (nvar >= 0)
     210      104887 :                                         getArg(p, 1) = nvar;
     211      104880 :                                 if (nvar >= env->stktop) {
     212       53711 :                                         if (VALcopy(&env->stk[getArg(p, 1)],
     213       53712 :                                                                 &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       53711 :                                         env->stktop = getArg(p, 1) + 1;
     219             :                                 }
     220      104879 :                                 alias[getArg(p, 0)] = getArg(p, 1);
     221      104879 :                                 p->argc = 2;
     222      104879 :                                 p->token = ASSIGNsymbol;
     223      104879 :                                 clrFunction(p);
     224      104905 :                                 p->barrier = barrier;
     225             :                                 /* freeze the type */
     226      104905 :                                 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         495 :                                 freeException(msg);
     231         495 :                                 msg = MAL_SUCCEED;
     232         495 :                                 mb->errors = 0;
     233             :                         }
     234             :                 }
     235    46008406 :                 constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
     236             :         }
     237             :         // produces errors in SQL when enabled
     238      499165 :         if (constantblock)
     239         372 :                 msg = OPTremoveUnusedBlocks(cntxt, mb);
     240             : 
     241             :         /* Defense line against incorrect plans */
     242             :         /* Plan is unaffected */
     243      499165 :         if (!msg)
     244      499152 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     245      499140 :         if (!msg)
     246      499116 :                 msg = chkFlow(mb);
     247      499135 :         if (!msg)
     248      499135 :                 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      499161 :         (void) pushInt(mb, pci, actions);
     254             : 
     255      499137 :         if (env) {
     256       27846 :                 assert(env->stktop < env->stksize);
     257       27846 :                 freeStack(env);
     258             :         }
     259      499147 :         if (assigned)
     260      499147 :                 GDKfree(assigned);
     261      499175 :         if (alias)
     262      499175 :                 GDKfree(alias);
     263      499175 :         return msg;
     264             : }

Generated by: LCOV version 1.14