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-10-04 20:04:04 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      566239 : OPTemptybindImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
      43             :                                                    InstrPtr pci)
      44             : {
      45      566239 :         int i, j, actions = 0, extras = 0;
      46      566239 :         int *empty = NULL;
      47      566239 :         int limit = mb->stop, slimit = mb->ssize;
      48      566239 :         InstrPtr p, q, *old = NULL, *updated = NULL;
      49      566239 :         str sch, tbl;
      50      566239 :         int etop = 0, esize = 256;
      51      566239 :         str msg = MAL_SUCCEED;
      52             : 
      53      566239 :         (void) stk;
      54      566239 :         (void) cntxt;
      55             : 
      56             :         // use an instruction reference table to keep
      57             : 
      58    25310908 :         for (i = 0; i < mb->stop; i++) {
      59    24744669 :                 p = getInstrPtr(mb, i);
      60    24744669 :                 if (getModuleId(p) == sqlRef
      61     3551139 :                         && (getFunctionId(p) == emptybindRef
      62     3265860 :                                 || getFunctionId(p) == emptybindidxRef))
      63      288459 :                         extras += p->argc;
      64             :         }
      65      566239 :         if (extras == 0) {
      66      522992 :                 (void) pushInt(mb, pci, actions);
      67      522992 :                 return msg;
      68             :         }
      69             :         // track of where 'emptybind' results are produced
      70             :         // reserve space for maximal number of emptybat variables created
      71       43247 :         empty = (int *) GDKzalloc((mb->vsize + extras) * sizeof(int));
      72       43248 :         if (empty == NULL)
      73           0 :                 throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      74             : 
      75       43248 :         updated = (InstrPtr *) GDKzalloc(esize * sizeof(InstrPtr));
      76       43248 :         if (updated == 0) {
      77           0 :                 GDKfree(empty);
      78           0 :                 throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      79             :         }
      80             : 
      81       43248 :         old = mb->stmt;
      82       43248 :         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     4400530 :         for (i = 0; mb->errors == NULL && i < limit; i++) {
      91     4400530 :                 p = old[i];
      92     4400530 :                 if (p == NULL)
      93           0 :                         continue;
      94             : 
      95     4400530 :                 pushInstruction(mb, p);
      96     4400545 :                 old[i] = NULL;
      97     4400545 :                 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     4357298 :                 if (getModuleId(p) == batRef && getFunctionId(p) == newRef) {
     106       47322 :                         empty[getArg(p, 0)] = i;
     107       47322 :                         continue;
     108             :                 }
     109             :                 // any of these instructions leave a non-empty BAT behind
     110     4309976 :                 if (getModuleId(p) == sqlRef && isUpdateInstruction(p)) {
     111       58494 :                         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       58494 :                         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     4309946 :                 if (getFunctionId(p) == emptybindRef) {
     130      285300 :                         setFunctionId(p, bindRef);
     131      285316 :                         p->typeresolved = false;
     132      285316 :                         empty[getArg(p, 0)] = i;
     133      285316 :                         if (p->retc == 2) {
     134      268179 :                                 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      285316 :                         sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
     138      285316 :                         tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
     139      309842 :                         for (j = 0; j < etop; j++) {
     140       24594 :                                 q = updated[j];
     141       24594 :                                 if (q && getModuleId(q) == sqlRef && isUpdateInstruction(q)) {
     142       24594 :                                         int c = getFunctionId(q) == claimRef;   /* claim has 2 results */
     143       24594 :                                         int cl = getFunctionId(q) == clear_tableRef;    /* clear table has no mvc dependency */
     144       24594 :                                         if (strcmp(getVarConstant(mb, getArg(q,
     145       24594 :                                                                                                                  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       24526 :                                 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      285316 :                         continue;
     170             :                 }
     171             : 
     172     4024646 :                 if (getFunctionId(p) == emptybindidxRef) {
     173        3180 :                         setFunctionId(p, bindidxRef);
     174        3180 :                         p->typeresolved = false;
     175        3180 :                         empty[getArg(p, 0)] = i;
     176        3180 :                         if (p->retc == 2) {
     177        2865 :                                 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        3180 :                         sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
     181        3180 :                         tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
     182        3356 :                         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        3180 :                         continue;
     207             :                 }
     208             :                 // delta operations without updates can be replaced by an assignment
     209     4021466 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef
     210      271666 :                         && p->argc == 4) {
     211      271665 :                         if (empty[getArg(p, 2)] && empty[getArg(p, 3)]) {
     212      270981 :                                 actions++;
     213      270981 :                                 clrFunction(p);
     214      270982 :                                 p->argc = 2;
     215      270982 :                                 if (empty[getArg(p, 1)]) {
     216       11447 :                                         empty[getArg(p, 0)] = i;
     217             :                                 }
     218             :                         }
     219      271666 :                         continue;
     220             :                 }
     221             : 
     222     3749801 :                 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     3749801 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) {
     233     2265132 :                         if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
     234       37187 :                                 actions++;
     235       37187 :                                 emptyresult(0);
     236             :                         }
     237             :                 }
     238     3749801 :                 if ((getModuleId(p) == algebraRef || getModuleId(p) == dictRef)
     239     2496374 :                         && (getFunctionId(p) == thetaselectRef
     240     2386263 :                                 || getFunctionId(p) == selectRef)) {
     241      125567 :                         if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
     242        2912 :                                 actions++;
     243        2912 :                                 emptyresult(0);
     244             :                         }
     245             :                 }
     246     3749801 :                 if (getModuleId(p) == forRef && getFunctionId(p) == decompressRef) {
     247           8 :                         if (empty[getArg(p, 1)]) {
     248           0 :                                 actions++;
     249           0 :                                 emptyresult(0);
     250             :                         }
     251             :                 }
     252     3749801 :                 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     3749801 :                 if (getModuleId(p) == batmkeyRef
     264     3743509 :                         || getModuleId(p) == batstrRef
     265     3743066 :                         || getModuleId(p) == batmtimeRef
     266     3742789 :                         || getModuleId(p) == batmmathRef
     267     3742731 :                         || getModuleId(p) == batcalcRef
     268     3639708 :                         || (getModuleId(p) == algebraRef
     269     2493288 :                                 && getFunctionId(p) == projectionpathRef)) {
     270      435672 :                         for (int j = p->retc; j < p->argc; j++) {
     271      327502 :                                 if (empty[getArg(p, j)]) {
     272        1923 :                                         actions++;
     273        1923 :                                         emptyresult(0);
     274        1923 :                                         break;
     275             :                                 }
     276             :                         }
     277             :                 }
     278     3749801 :                 if (getModuleId(p) == batRef && isUpdateInstruction(p)) {
     279      104736 :                         if (empty[getArg(p, 1)] && empty[getArg(p, 2)]) {
     280        7572 :                                 emptyresult(0);
     281       97164 :                         } else if (empty[getArg(p, 2)]) {
     282          95 :                                 actions++;
     283          95 :                                 clrFunction(p);
     284          95 :                                 p->argc = 2;
     285             :                         }
     286             :                 }
     287             :         }
     288             : 
     289       86494 :   wrapup:
     290     9244560 :         for (; i < slimit; i++)
     291     9201312 :                 if (old[i])
     292      830171 :                         pushInstruction(mb, old[i]);
     293       43248 :         GDKfree(old);
     294       43248 :         GDKfree(empty);
     295       43248 :         GDKfree(updated);
     296             :         /* Defense line against incorrect plans */
     297       43248 :         if (msg == MAL_SUCCEED)
     298       43248 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     299       43248 :         if (msg == MAL_SUCCEED)
     300       43248 :                 msg = chkFlow(mb);
     301       43248 :         if (msg == MAL_SUCCEED)
     302       43248 :                 msg = chkDeclarations(mb);
     303             :         /* keep all actions taken as a post block comment */
     304             :         /* keep actions taken as a fake argument */
     305       43248 :         (void) pushInt(mb, pci, actions);
     306       43248 :         return msg;
     307             : }

Generated by: LCOV version 1.14