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-19 23:10:26 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    21740531 : OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p)
      19             : {
      20    21740531 :         int i;
      21    21740531 :         (void) cntxt;
      22             : 
      23    21740531 :         if (p->token != ASSIGNsymbol
      24    21739273 :                 && getModuleId(p) != calcRef
      25    21596575 :                 && getModuleId(p) != strRef
      26    21596020 :                 && getModuleId(p) != mtimeRef
      27    21595461 :                 && getModuleId(p) != mmathRef)
      28             :                 return false;
      29      145333 :         if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0)
      30             :                 return false;
      31             : 
      32      345579 :         for (i = p->retc; i < p->argc; i++)
      33      239983 :                 if (isVarConstant(mb, getArg(p, i)) == FALSE)
      34             :                         return false;
      35      211056 :         for (i = 0; i < p->retc; i++) {
      36      105536 :                 if (isaBatType(getArgType(mb, p, i)))
      37             :                         return false;
      38      105536 :                 if (p->unsafeProp || mb->unsafeProp)
      39             :                         return false;
      40             :         }
      41             :         return true;
      42             : }
      43             : 
      44             : static bool
      45         211 : OPTsimpleflow(MalBlkPtr mb, int pc)
      46             : {
      47         211 :         int i, block = 0;
      48         211 :         bool simple = true;
      49         211 :         InstrPtr p;
      50             : 
      51        2661 :         for (i = pc; i < mb->stop; i++) {
      52        2661 :                 p = getInstrPtr(mb, i);
      53        2661 :                 if (blockStart(p))
      54         226 :                         block++;
      55        2661 :                 if (blockExit(p))
      56         226 :                         block--;
      57        2661 :                 if (blockCntrl(p))
      58         176 :                         simple = false;
      59        2661 :                 if (block == 0) {
      60         211 :                         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         371 : OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb)
      69             : {
      70             :         /* catch and remove constant bounded blocks */
      71         371 :         int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1;
      72         371 :         InstrPtr p;
      73         371 :         str msg = MAL_SUCCEED;
      74             : 
      75         745 :         while (multipass--) {
      76             :                 block = -1;
      77             :                 skip = 0;
      78             :                 j = 0;
      79       30369 :                 for (i = 0; i < mb->stop; i++) {
      80       29995 :                         p = mb->stmt[i];
      81       29995 :                         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       29680 :                         if (p->argc == 2 && blockStart(p) && block < 0
      89         506 :                                 && isVarConstant(mb, getArg(p, 1))
      90         506 :                                 && getArgType(mb, p, 1) == TYPE_bit) {
      91         410 :                                 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         410 :                                 if (getVarConstant(mb, getArg(p, 1)).val.btval == 1
      98         211 :                                         && 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       29270 :                         } 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       29551 :                                 multipass++;
     110       29551 :                         if (skip) {
     111         559 :                                 freeInstruction(p);
     112         559 :                                 mb->stmt[i] = 0;
     113             :                         } else
     114       28992 :                                 mb->stmt[j++] = p;
     115             :                 }
     116         374 :                 mb->stop = j;
     117        1377 :                 for (; j < i; j++)
     118        1003 :                         mb->stmt[j] = NULL;
     119             :         }
     120         371 :         if (action)
     121         113 :                 msg = chkTypes(cntxt->usermodule, mb, TRUE);
     122         371 :         return msg;
     123             : }
     124             : 
     125             : str
     126      498114 : OPTevaluateImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     127             :                                                   InstrPtr pci)
     128             : {
     129      498114 :         InstrPtr p;
     130      498114 :         int i, k, limit, *alias = 0, barrier;
     131      498114 :         MalStkPtr env = NULL;
     132      498114 :         int actions = 0, constantblock = 0;
     133      498114 :         int *assigned = 0, use;
     134      498114 :         str msg = MAL_SUCCEED;
     135             : 
     136      498114 :         (void) stk;
     137             : 
     138      498114 :         if (mb->inlineProp)
     139             :                 return MAL_SUCCEED;
     140             : 
     141      498114 :         assigned = (int *) GDKzalloc(sizeof(int) * mb->vtop);
     142      498213 :         if (assigned == NULL)
     143           0 :                 throw(MAL, "optimizer.evaluate", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     144             : 
     145      498213 :         alias = (int *) GDKzalloc(mb->vsize * sizeof(int) * 2);      /* we introduce more */
     146      498227 :         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      498227 :         p = getInstrPtr(mb, 0);
     152      499100 :         for (k = p->retc; k < p->argc; k++) {
     153         873 :                 assert(getArg(p, k) >= 0);
     154         873 :                 assigned[getArg(p, k)]++;
     155             :         }
     156      498227 :         limit = mb->stop;
     157    23455855 :         for (i = 1; i < limit; i++) {
     158    22957628 :                 p = getInstrPtr(mb, i);
     159             :                 // The double count emerging from a barrier exit is ignored.
     160    22957628 :                 if (!blockExit(p) || (blockExit(p) && p->retc != p->argc))
     161    46203088 :                         for (k = 0; k < p->retc; k++)
     162    23246718 :                                 if (p->retc != p->argc || p->token != ASSIGNsymbol) {
     163    23246346 :                                         assert(getArg(p, k) >= 0);
     164    23246346 :                                         assigned[getArg(p, k)]++;
     165             :                                 }
     166             :         }
     167             : 
     168    23460354 :         for (i = 1; i < limit && cntxt->mode != FINISHCLIENT; i++) {
     169    22962148 :                 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    22962148 :                 assert(getArg(p, 0) >= 0);
     173    22962148 :                 use = assigned[getArg(p, 0)] == 1 && !(p->argc == p->retc
     174    12202055 :                                                                                            && blockExit(p));
     175    54404252 :                 for (k = p->retc; k < p->argc; k++)
     176    31442104 :                         if (alias[getArg(p, k)])
     177      105059 :                                 getArg(p, k) = alias[getArg(p, k)];
     178             :                 /* be aware that you only assign once to a variable */
     179    22962148 :                 if (use && p->retc == 1 && getFunctionId(p)
     180    21739286 :                         && OPTallConstant(cntxt, mb, p) && !isUnsafeFunction(p)) {
     181      104690 :                         barrier = p->barrier;
     182      104690 :                         p->barrier = 0;
     183      104690 :                         if (env == NULL) {
     184       27479 :                                 env = prepareMALstack(mb, 2 * mb->vsize);
     185       27510 :                                 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       27510 :                                 env->keepAlive = TRUE;
     192             :                         }
     193      104721 :                         msg = reenterMAL(cntxt, mb, i, i + 1, env);
     194      104663 :                         p->barrier = barrier;
     195      104663 :                         if (msg == MAL_SUCCEED) {
     196      104172 :                                 int nvar;
     197      104172 :                                 ValRecord cst;
     198             : 
     199      104172 :                                 actions++;
     200      104172 :                                 cst.vtype = 0;
     201      104172 :                                 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      104207 :                                 nvar = defConstant(mb, getArgType(mb, p, 0), &cst);
     209      104200 :                                 if (nvar >= 0)
     210      104205 :                                         getArg(p, 1) = nvar;
     211      104200 :                                 if (nvar >= env->stktop) {
     212       53070 :                                         if (VALcopy(&env->stk[getArg(p, 1)],
     213       53065 :                                                                 &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       53070 :                                         env->stktop = getArg(p, 1) + 1;
     219             :                                 }
     220      104205 :                                 alias[getArg(p, 0)] = getArg(p, 1);
     221      104205 :                                 p->argc = 2;
     222      104205 :                                 p->token = ASSIGNsymbol;
     223      104205 :                                 clrFunction(p);
     224      104232 :                                 p->barrier = barrier;
     225             :                                 /* freeze the type */
     226      104232 :                                 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    45923459 :                 constantblock += blockStart(p) && OPTallConstant(cntxt, mb, p); /* default */
     236             :         }
     237             :         // produces errors in SQL when enabled
     238      498206 :         if (constantblock)
     239         371 :                 msg = OPTremoveUnusedBlocks(cntxt, mb);
     240             : 
     241             :         /* Defense line against incorrect plans */
     242             :         /* Plan is unaffected */
     243      498206 :         if (!msg)
     244      498192 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     245      498194 :         if (!msg)
     246      498181 :                 msg = chkFlow(mb);
     247      498188 :         if (!msg)
     248      498188 :                 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      498189 :         (void) pushInt(mb, pci, actions);
     254             : 
     255      498183 :         if (env) {
     256       27505 :                 assert(env->stktop < env->stksize);
     257       27505 :                 freeStack(env);
     258             :         }
     259      498195 :         if (assigned)
     260      498195 :                 GDKfree(assigned);
     261      498216 :         if (alias)
     262      498216 :                 GDKfree(alias);
     263      498216 :         return msg;
     264             : }

Generated by: LCOV version 1.14