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 538683 : OPTemptybindImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
43 : InstrPtr pci)
44 : {
45 538683 : int i, j, actions = 0, extras = 0;
46 538683 : int *empty = NULL;
47 538683 : int limit = mb->stop, slimit = mb->ssize;
48 538683 : InstrPtr p, q, *old = NULL, *updated = NULL;
49 538683 : str sch, tbl;
50 538683 : int etop = 0, esize = 256;
51 538683 : str msg = MAL_SUCCEED;
52 :
53 538683 : (void) stk;
54 538683 : (void) cntxt;
55 :
56 : // use an instruction reference table to keep
57 :
58 24034802 : for (i = 0; i < mb->stop; i++) {
59 23496119 : p = getInstrPtr(mb, i);
60 23496119 : if (getModuleId(p) == sqlRef
61 3341722 : && (getFunctionId(p) == emptybindRef
62 3059644 : || getFunctionId(p) == emptybindidxRef))
63 285202 : extras += p->argc;
64 : }
65 538683 : if (extras == 0) {
66 497443 : (void) pushInt(mb, pci, actions);
67 497443 : return msg;
68 : }
69 : // track of where 'emptybind' results are produced
70 : // reserve space for maximal number of emptybat variables created
71 41240 : empty = (int *) GDKzalloc((mb->vsize + extras) * sizeof(int));
72 41239 : if (empty == NULL)
73 0 : throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
74 :
75 41239 : updated = (InstrPtr *) GDKzalloc(esize * sizeof(InstrPtr));
76 41239 : if (updated == 0) {
77 0 : GDKfree(empty);
78 0 : throw(MAL, "optimizer.emptybind", SQLSTATE(HY013) MAL_MALLOC_FAIL);
79 : }
80 :
81 41239 : old = mb->stmt;
82 41239 : 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 4400165 : for (i = 0; mb->errors == NULL && i < limit; i++) {
91 4400165 : p = old[i];
92 4400165 : if (p == NULL)
93 0 : continue;
94 :
95 4400165 : pushInstruction(mb, p);
96 4400176 : old[i] = NULL;
97 4400176 : 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 4358936 : if (getModuleId(p) == batRef && getFunctionId(p) == newRef) {
106 52797 : empty[getArg(p, 0)] = i;
107 52797 : continue;
108 : }
109 : // any of these instructions leave a non-empty BAT behind
110 4306139 : if (getModuleId(p) == sqlRef && isUpdateInstruction(p)) {
111 51938 : 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 51938 : 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 re-use
127 : */
128 :
129 4306108 : if (getFunctionId(p) == emptybindRef) {
130 282099 : setFunctionId(p, bindRef);
131 282120 : p->typechk = TYPE_UNKNOWN;
132 282120 : empty[getArg(p, 0)] = i;
133 282120 : if (p->retc == 2) {
134 265253 : 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 282120 : sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
138 282120 : tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
139 305699 : for (j = 0; j < etop; j++) {
140 23647 : q = updated[j];
141 23647 : if (q && getModuleId(q) == sqlRef && isUpdateInstruction(q)) {
142 23647 : int c = getFunctionId(q) == claimRef; /* claim has 2 results */
143 23647 : int cl = getFunctionId(q) == clear_tableRef; /* clear table has no mvc dependency */
144 23647 : if (strcmp(getVarConstant(mb, getArg(q,
145 23647 : 2 - cl + c)).val.sval,
146 : sch) == 0
147 163 : && strcmp(getVarConstant(mb,
148 : getArg(q,
149 163 : 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 23579 : 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 282120 : continue;
170 : }
171 :
172 4024009 : if (getFunctionId(p) == emptybindidxRef) {
173 3124 : setFunctionId(p, bindidxRef);
174 3124 : p->typechk = TYPE_UNKNOWN;
175 3124 : empty[getArg(p, 0)] = i;
176 3124 : if (p->retc == 2) {
177 2816 : 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 3124 : sch = getVarConstant(mb, getArg(p, 2 + (p->retc == 2))).val.sval;
181 3124 : tbl = getVarConstant(mb, getArg(p, 3 + (p->retc == 2))).val.sval;
182 3300 : 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 3124 : continue;
207 : }
208 : // delta operations without updates can be replaced by an assignment
209 4020885 : if (getModuleId(p) == sqlRef && getFunctionId(p) == deltaRef
210 268756 : && p->argc == 4) {
211 268756 : if (empty[getArg(p, 2)] && empty[getArg(p, 3)]) {
212 268008 : actions++;
213 268008 : clrFunction(p);
214 268007 : p->argc = 2;
215 268007 : if (empty[getArg(p, 1)]) {
216 11290 : empty[getArg(p, 0)] = i;
217 : }
218 : }
219 268755 : continue;
220 : }
221 :
222 3752129 : 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->typechk = TYPE_UNKNOWN;
229 : }
230 0 : continue;
231 : }
232 3752129 : if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef) {
233 2253524 : if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
234 38368 : actions++;
235 38368 : emptyresult(0);
236 : }
237 : }
238 3752129 : if ((getModuleId(p) == algebraRef || getModuleId(p) == dictRef)
239 2481072 : && (getFunctionId(p) == thetaselectRef
240 2385242 : || getFunctionId(p) == selectRef)) {
241 125726 : if (empty[getArg(p, 1)] || empty[getArg(p, 2)]) {
242 3206 : actions++;
243 3206 : emptyresult(0);
244 : }
245 : }
246 3752129 : if (getModuleId(p) == forRef && getFunctionId(p) == decompressRef) {
247 8 : if (empty[getArg(p, 1)]) {
248 0 : actions++;
249 0 : emptyresult(0);
250 : }
251 : }
252 3752129 : if (getModuleId(p) == dictRef) {
253 172 : if (getFunctionId(p) == decompressRef
254 172 : && (empty[getArg(p, 1)] || empty[getArg(p, 2)])) {
255 3 : actions++;
256 3 : emptyresult(0);
257 : }
258 172 : if (getFunctionId(p) == compressRef && empty[getArg(p, 2)]) {
259 0 : actions++;
260 0 : emptyresult(0);
261 : }
262 : }
263 3752129 : if (getModuleId(p) == batmkeyRef
264 3745939 : || getModuleId(p) == batstrRef
265 3745506 : || getModuleId(p) == batmtimeRef
266 3745266 : || getModuleId(p) == batmmathRef
267 3745214 : || getModuleId(p) == batcalcRef
268 3599422 : || (getModuleId(p) == algebraRef
269 2477693 : && getFunctionId(p) == projectionpathRef)) {
270 560915 : for (int j = p->retc; j < p->argc; j++) {
271 410073 : if (empty[getArg(p, j)]) {
272 1865 : actions++;
273 1865 : emptyresult(0);
274 1865 : break;
275 : }
276 : }
277 : }
278 3752129 : if (getModuleId(p) == batRef && isUpdateInstruction(p)) {
279 115837 : if (empty[getArg(p, 1)] && empty[getArg(p, 2)]) {
280 7489 : emptyresult(0);
281 108348 : } else if (empty[getArg(p, 2)]) {
282 95 : actions++;
283 95 : clrFunction(p);
284 95 : p->argc = 2;
285 : }
286 : }
287 : }
288 :
289 82480 : wrapup:
290 8755270 : for (; i < slimit; i++)
291 8714030 : if (old[i])
292 770035 : pushInstruction(mb, old[i]);
293 41240 : GDKfree(old);
294 41240 : GDKfree(empty);
295 41240 : GDKfree(updated);
296 : /* Defense line against incorrect plans */
297 41240 : if (msg == MAL_SUCCEED)
298 41240 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
299 41240 : if (msg == MAL_SUCCEED)
300 41240 : msg = chkFlow(mb);
301 41240 : if (msg == MAL_SUCCEED)
302 41240 : msg = chkDeclarations(mb);
303 : /* keep all actions taken as a post block comment */
304 : /* keep actions taken as a fake argument */
305 41240 : (void) pushInt(mb, pci, actions);
306 41240 : return msg;
307 : }
|