LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_emptybind.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 144 172 83.7 %
Date: 2024-11-12 19:36:54 Functions: 1 1 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             : /* author M.Kersten
      14             :  * This optimizer hunts for the empty persistent tables accessed and propagates them.
      15             :  *
      16             :  * Patterns to look for:
      17             :  *  X_13 := algebra.projection(X_1,X_4);
      18             :  *  where either argument is empty
      19             :  *
      20             :  */
      21             : #include "monetdb_config.h"
      22             : #include "opt_emptybind.h"
      23             : #include "opt_aliases.h"
      24             : #include "opt_deadcode.h"
      25             : #include "mal_builder.h"
      26             : 
      27             : #define emptyresult(I)                                                  \
      28             :         do {                                                                            \
      29             :                 int tpe = getVarType(mb, getArg(p, I)); \
      30             :                 clrFunction(p);                                                 \
      31             :                 setModuleId(p, batRef);                                 \
      32             :                 setFunctionId(p, newRef);                               \
      33             :                 p->argc = p->retc;                                                \
      34             :                 p = pushType(mb, p, getBatType(tpe));   \
      35             :                 setVarType(mb, getArg(p, 0), tpe);              \
      36             :                 setVarFixed(mb, getArg(p, 0));                  \
      37             :                 empty[getArg(p, 0)]= i;                                 \
      38             :         } while (0)
      39             : 
      40             : 
      41             : str
      42      553607 : OPTemptybindImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
      43             :                                                    InstrPtr pci)
      44             : {
      45      553607 :         int i, j, actions = 0, extras = 0;
      46      553607 :         int *empty = NULL;
      47      553607 :         int limit = mb->stop, slimit = mb->ssize;
      48      553607 :         InstrPtr p, q, *old = NULL, *updated = NULL;
      49      553607 :         str sch, tbl;
      50      553607 :         int etop = 0, esize = 256;
      51      553607 :         str msg = MAL_SUCCEED;
      52             : 
      53      553607 :         (void) stk;
      54      553607 :         (void) cntxt;
      55             : 
      56             :         // use an instruction reference table to keep
      57             : 
      58    24769288 :         for (i = 0; i < mb->stop; i++) {
      59    24215681 :                 p = getInstrPtr(mb, i);
      60    24215681 :                 if (getModuleId(p) == sqlRef
      61     3405171 :                         && (getFunctionId(p) == emptybindRef
      62     3120226 :                                 || getFunctionId(p) == emptybindidxRef))
      63      288137 :                         extras += p->argc;
      64             :         }
      65      553607 :         if (extras == 0) {
      66      510410 :                 (void) pushInt(mb, pci, actions);
      67      510410 :                 return msg;
      68             :         }
      69             :         // track of where 'emptybind' results are produced
      70             :         // reserve space for maximal number of emptybat variables created
      71       43197 :         empty = (int *) GDKzalloc((mb->vsize + extras) * sizeof(int));
      72       43228 :         if (empty == NULL)
      73           0 :                 throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      74             : 
      75       43228 :         updated = (InstrPtr *) GDKzalloc(esize * sizeof(InstrPtr));
      76       43229 :         if (updated == 0) {
      77           0 :                 GDKfree(empty);
      78           0 :                 throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      79             :         }
      80             : 
      81       43229 :         old = mb->stmt;
      82       43229 :         if (newMalBlkStmt(mb, mb->ssize) < 0) {
      83           0 :                 GDKfree(empty);
      84           0 :                 GDKfree(updated);
      85           0 :                 throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      86             :         }
      87             : 
      88             :         /* Symbolic evaluation of instructions with empty BAT variables */
      89             :         actions = 0;
      90     4399945 :         for (i = 0; mb->errors == NULL && i < limit; i++) {
      91     4399945 :                 p = old[i];
      92     4399945 :                 if (p == NULL)
      93           0 :                         continue;
      94             : 
      95     4399945 :                 pushInstruction(mb, p);
      96     4399884 :                 old[i] = NULL;
      97     4399884 :                 if (p->token == ENDsymbol) {
      98             :                         break;
      99             :                 }
     100             : 
     101             :                 /*
     102             :                  * The bulk of the intelligence lies in inspecting calling
     103             :                  * sequences to filter and replace results
     104             :                  */
     105     4356660 :                 if (getModuleId(p) == batRef && getFunctionId(p) == newRef) {
     106       47393 :                         empty[getArg(p, 0)] = i;
     107       47393 :                         continue;
     108             :                 }
     109             :                 // any of these instructions leave a non-empty BAT behind
     110     4309267 :                 if (getModuleId(p) == sqlRef && isUpdateInstruction(p)) {
     111       58497 :                         if (etop == esize) {
     112           5 :                                 InstrPtr *tmp = updated;
     113           5 :                                 updated = GDKrealloc(updated,
     114             :                                                                          (esize += 256) * sizeof(InstrPtr));
     115           5 :                                 if (updated == NULL) {
     116           0 :                                         GDKfree(tmp);
     117           0 :                                         msg = createException(MAL, "optimizer.emptybind",
     118             :                                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
     119           0 :                                         goto wrapup;
     120             :                                 }
     121             :                         }
     122       58497 :                         updated[etop++] = p;
     123             :                 }
     124             : 
     125             :                 /* restore the naming, dropping the runtime property 'empty'
     126             :                  * Keep the bind operation, because it is cheap, rather focus on their reuse
     127             :                  */
     128             : 
     129     4309298 :                 if (getFunctionId(p) == emptybindRef) {
     130      285235 :                         setFunctionId(p, bindRef);
     131      285268 :                         p->typeresolved = false;
     132      285268 :                         empty[getArg(p, 0)] = i;
     133      285268 :                         if (p->retc == 2) {
     134      268071 :                                 empty[getArg(p, 1)] = i;
     135             :                         }
     136             :                         // replace the call into a empty bat creation unless the table was updated already in the same query
     137      285268 :                         sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
     138      285268 :                         tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
     139      309800 :                         for (j = 0; j < etop; j++) {
     140       24600 :                                 q = updated[j];
     141       24600 :                                 if (q && getModuleId(q) == sqlRef && isUpdateInstruction(q)) {
     142       24600 :                                         int c = getFunctionId(q) == claimRef;   /* claim has 2 results */
     143       24600 :                                         int cl = getFunctionId(q) == clear_tableRef;    /* clear table has no mvc dependency */
     144       24600 :                                         if (strcmp(getVarConstant(mb, getArg(q,
     145       24600 :                                                                                                                  2 - cl + c)).val.sval,
     146             :                                                            sch) == 0
     147         168 :                                                 && strcmp(getVarConstant(mb,
     148             :                                                                                                  getArg(q,
     149         168 :                                                                                                                 3 - cl + c)).val.sval,
     150             :                                                                   tbl) == 0) {
     151          68 :                                                 empty[getArg(p, 0)] = 0;
     152          68 :                                                 if (p->retc == 2) {
     153          57 :                                                         empty[getArg(p, 1)] = 0;
     154             :                                                 }
     155             :                                                 break;
     156             :                                         }
     157             :                                 }
     158       24532 :                                 if (q && getModuleId(q) == sqlcatalogRef) {
     159           0 :                                         if (strcmp(getVarConstant(mb, getArg(q, 2)).val.sval, sch)
     160             :                                                 == 0) {
     161           0 :                                                 empty[getArg(p, 0)] = 0;
     162           0 :                                                 if (p->retc == 2) {
     163           0 :                                                         empty[getArg(p, 1)] = 0;
     164             :                                                 }
     165             :                                                 break;
     166             :                                         }
     167             :                                 }
     168             :                         }
     169      285268 :                         continue;
     170             :                 }
     171             : 
     172     4024063 :                 if (getFunctionId(p) == emptybindidxRef) {
     173        3192 :                         setFunctionId(p, bindidxRef);
     174        3192 :                         p->typeresolved = false;
     175        3192 :                         empty[getArg(p, 0)] = i;
     176        3192 :                         if (p->retc == 2) {
     177        2876 :                                 empty[getArg(p, 1)] = i;
     178             :                         }
     179             :                         // replace the call into a empty bat creation unless the table was updated already in the same query
     180        3192 :                         sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
     181        3192 :                         tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
     182        3368 :                         for (j = 0; j < etop; j++) {
     183         181 :                                 q = updated[j];
     184         181 :                                 if (q && getModuleId(q) == sqlRef
     185         181 :                                         && (getFunctionId(q) == appendRef
     186         181 :                                                 || getFunctionId(q) == updateRef)) {
     187          76 :                                         if (strcmp(getVarConstant(mb, getArg(q, 2)).val.sval, sch)
     188             :                                                 == 0
     189          76 :                                                 && strcmp(getVarConstant(mb, getArg(q, 3)).val.sval,
     190             :                                                                   tbl) == 0) {
     191           5 :                                                 empty[getArg(p, 0)] = 0;
     192           5 :                                                 if (p->retc == 2) {
     193           2 :                                                         empty[getArg(p, 1)] = 0;
     194             :                                                 }
     195             :                                                 break;
     196             :                                         }
     197             :                                 }
     198         176 :                                 if (q && getModuleId(q) == sqlcatalogRef) {
     199           0 :                                         if (strcmp(getVarConstant(mb, getArg(q, 2)).val.sval, sch)
     200             :                                                 == 0) {
     201           0 :                                                 empty[getArg(p, 0)] = 0;
     202           0 :                                                 break;
     203             :                                         }
     204             :                                 }
     205             :                         }
     206        3192 :                         continue;
     207             :                 }
     208             :                 // delta operations without updates can be replaced by an assignment
     209     4020871 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef
     210      271572 :                         && p->argc == 4) {
     211      271572 :                         if (empty[getArg(p, 2)] && empty[getArg(p, 3)]) {
     212      270888 :                                 actions++;
     213      270888 :                                 clrFunction(p);
     214      270887 :                                 p->argc = 2;
     215      270887 :                                 if (empty[getArg(p, 1)]) {
     216       11498 :                                         empty[getArg(p, 0)] = i;
     217             :                                 }
     218             :                         }
     219      271571 :                         continue;
     220             :                 }
     221             : 
     222     3749299 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == projectdeltaRef) {
     223           0 :                         if (empty[getArg(p, 3)] && empty[getArg(p, 4)]) {
     224           0 :                                 actions++;
     225           0 :                                 setModuleId(p, algebraRef);
     226           0 :                                 setFunctionId(p, projectionRef);
     227           0 :                                 p->argc = 3;
     228           0 :                                 p->typeresolved = false;
     229             :                         }
     230           0 :                         continue;
     231             :                 }
     232     3749299 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) {
     233     2264988 :                         if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
     234       37275 :                                 actions++;
     235       37275 :                                 emptyresult(0);
     236             :                         }
     237             :                 }
     238     3749299 :                 if ((getModuleId(p) == algebraRef || getModuleId(p) == dictRef)
     239     2496872 :                         && (getFunctionId(p) == thetaselectRef
     240     2400962 :                                 || getFunctionId(p) == selectRef)) {
     241      126246 :                         if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
     242        2933 :                                 actions++;
     243        2933 :                                 emptyresult(0);
     244             :                         }
     245             :                 }
     246     3749299 :                 if (getModuleId(p) == forRef && getFunctionId(p) == decompressRef) {
     247           8 :                         if (empty[getArg(p, 1)]) {
     248           0 :                                 actions++;
     249           0 :                                 emptyresult(0);
     250             :                         }
     251             :                 }
     252     3749299 :                 if (getModuleId(p) == dictRef) {
     253         176 :                         if (getFunctionId(p) == decompressRef
     254         176 :                                 && (empty[getArg(p, 1)] || empty[getArg(p, 2)])) {
     255           3 :                                 actions++;
     256           3 :                                 emptyresult(0);
     257             :                         }
     258         176 :                         if (getFunctionId(p) == compressRef && empty[getArg(p, 2)]) {
     259           0 :                                 actions++;
     260           0 :                                 emptyresult(0);
     261             :                         }
     262             :                 }
     263     3749299 :                 if (getModuleId(p) == batmkeyRef
     264     3742987 :                         || getModuleId(p) == batstrRef
     265     3742544 :                         || getModuleId(p) == batmtimeRef
     266     3742267 :                         || getModuleId(p) == batmmathRef
     267     3742209 :                         || getModuleId(p) == batcalcRef
     268     3639934 :                         || (getModuleId(p) == algebraRef
     269     2493773 :                                 && getFunctionId(p) == projectionpathRef)) {
     270      433578 :                         for (int j = p->retc; j < p->argc; j++) {
     271      326145 :                                 if (empty[getArg(p, j)]) {
     272        1932 :                                         actions++;
     273        1932 :                                         emptyresult(0);
     274        1932 :                                         break;
     275             :                                 }
     276             :                         }
     277             :                 }
     278     3749299 :                 if (getModuleId(p) == batRef && isUpdateInstruction(p)) {
     279      104878 :                         if (empty[getArg(p, 1)] && empty[getArg(p, 2)]) {
     280        7578 :                                 emptyresult(0);
     281       97300 :                         } else if (empty[getArg(p, 2)]) {
     282          96 :                                 actions++;
     283          96 :                                 clrFunction(p);
     284          96 :                                 p->argc = 2;
     285             :                         }
     286             :                 }
     287             :         }
     288             : 
     289       86448 :   wrapup:
     290     9232206 :         for (; i < slimit; i++)
     291     9188976 :                 if (old[i])
     292      830086 :                         pushInstruction(mb, old[i]);
     293       43230 :         GDKfree(old);
     294       43231 :         GDKfree(empty);
     295       43231 :         GDKfree(updated);
     296             :         /* Defense line against incorrect plans */
     297       43231 :         if (msg == MAL_SUCCEED)
     298       43231 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     299       43230 :         if (msg == MAL_SUCCEED)
     300       43225 :                 msg = chkFlow(mb);
     301       43226 :         if (msg == MAL_SUCCEED)
     302       43226 :                 msg = chkDeclarations(mb);
     303             :         /* keep all actions taken as a post block comment */
     304             :         /* keep actions taken as a fake argument */
     305       43232 :         (void) pushInt(mb, pci, actions);
     306       43232 :         return msg;
     307             : }

Generated by: LCOV version 1.14