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 : * Post-optimization of projection lists.
15 : */
16 : #include "monetdb_config.h"
17 : #include "opt_deadcode.h"
18 : #include "opt_projectionpath.h"
19 :
20 : str
21 467672 : OPTprojectionpathImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
22 : InstrPtr pci)
23 : {
24 467672 : int i, j, k, actions = 0, maxprefixlength = 0;
25 467672 : int *pc = NULL;
26 467672 : InstrPtr p, q, r;
27 467672 : InstrPtr *old = 0;
28 467672 : int *varcnt = NULL; /* use count */
29 467672 : int limit, slimit;
30 467672 : str msg = MAL_SUCCEED;
31 :
32 467672 : (void) cntxt;
33 467672 : (void) stk;
34 467672 : if (mb->inlineProp)
35 0 : goto wrapupall;
36 :
37 16668390 : for (i = 0; i < mb->stop; i++) {
38 16259658 : p = getInstrPtr(mb, i);
39 16259658 : if (getModuleId(p) == algebraRef
40 291655 : && ((getFunctionId(p) == projectionRef && p->argc == 3)
41 232715 : || getFunctionId(p) == projectionpathRef)) {
42 : break;
43 : }
44 : }
45 467672 : if (i == mb->stop) {
46 408732 : goto wrapupall;
47 : }
48 :
49 58940 : limit = mb->stop;
50 58940 : slimit = mb->ssize;
51 58940 : old = mb->stmt;
52 58940 : if (newMalBlkStmt(mb, 2 * mb->stop) < 0)
53 0 : throw(MAL, "optimizer.projectionpath", SQLSTATE(HY013) MAL_MALLOC_FAIL);
54 :
55 : /* beware, new variables and instructions are introduced */
56 58940 : pc = (int *) GDKzalloc(sizeof(int) * mb->vtop * 2); /* to find last assignment */
57 58940 : varcnt = (int *) GDKzalloc(sizeof(int) * mb->vtop * 2);
58 58940 : if (pc == NULL || varcnt == NULL) {
59 0 : if (pc)
60 0 : GDKfree(pc);
61 0 : if (varcnt)
62 0 : GDKfree(varcnt);
63 0 : throw(MAL, "optimizer.projectionpath", SQLSTATE(HY013) MAL_MALLOC_FAIL);
64 : }
65 :
66 : /*
67 : * Count the variable re-use used as arguments first.
68 : * A pass operation is not a real re-use
69 : */
70 9526362 : for (i = 0; i < limit; i++) {
71 9467422 : p = old[i];
72 36975808 : for (j = p->retc; j < p->argc; j++)
73 27508386 : if (!(getModuleId(p) == languageRef && getFunctionId(p) == passRef))
74 27508386 : varcnt[getArg(p, j)]++;
75 : }
76 :
77 : /* assume a single pass over the plan, and only consider projection sequences
78 : * beware, we are only able to deal with projections without candidate lists. (argc=3)
79 : * We also should not change the type of the outcome, i.e. leaving the last argument untouched.
80 : */
81 9527901 : for (i = 0; i < limit; i++) {
82 9468962 : p = old[i];
83 9468962 : if (getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef
84 3684120 : && p->argc == 3) {
85 : /*
86 : * Try to expand its argument list with what we have found so far.
87 : */
88 3684120 : int args = p->retc;
89 11052314 : for (j = p->retc; j < p->argc; j++) {
90 7368194 : if (pc[getArg(p, j)]
91 3092975 : && (r = getInstrPtr(mb, pc[getArg(p, j)])) != NULL
92 3092975 : && varcnt[getArg(p, j)] <= 1 && getModuleId(r) == algebraRef
93 2385275 : && (getFunctionId(r) == projectionRef
94 2072899 : || getFunctionId(r) == projectionpathRef))
95 2385275 : args += r->argc - r->retc;
96 : else
97 4982919 : args++;
98 : }
99 3684120 : if ((q = copyInstructionArgs(p, args)) == NULL) {
100 0 : msg = createException(MAL, "optimizer.projectionpath",
101 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
102 0 : goto wrapupall;
103 : }
104 :
105 3684146 : q->argc = p->retc;
106 11052418 : for (j = p->retc; j < p->argc; j++) {
107 7368275 : if (pc[getArg(p, j)])
108 3092995 : r = getInstrPtr(mb, pc[getArg(p, j)]);
109 : else
110 : r = 0;
111 3092995 : if (r && varcnt[getArg(p, j)] > 1)
112 4982999 : r = 0;
113 :
114 : /* inject the complete sub-path */
115 :
116 7368275 : if (getFunctionId(p) == projectionRef) {
117 7368274 : if (r && getModuleId(r) == algebraRef
118 2385276 : && (getFunctionId(r) == projectionRef
119 2072899 : || getFunctionId(r) == projectionpathRef)) {
120 39810135 : for (k = r->retc; k < r->argc; k++)
121 37424860 : q = pushArgument(mb, q, getArg(r, k));
122 : } else
123 4982998 : q = pushArgument(mb, q, getArg(p, j));
124 : }
125 : }
126 3684143 : if (q->argc <= p->argc) {
127 : /* no change */
128 1307771 : freeInstruction(q);
129 1307770 : goto wrapup;
130 : }
131 : /*
132 : * Final type check and hardwire the result type, because that can not be inferred directly from the signature
133 : * We already know that all heads are void. Only the last element may have a non-oid type.
134 : */
135 39792326 : for (j = 1; j < q->argc - 1; j++)
136 37415954 : if (getBatType(getArgType(mb, q, j)) != TYPE_oid
137 37415954 : && getBatType(getArgType(mb, q, j)) != TYPE_void) {
138 : /* don't use the candidate list */
139 0 : freeInstruction(q);
140 0 : goto wrapup;
141 : }
142 :
143 : /* fix the type */
144 2376372 : setVarType(mb, getArg(q, 0),
145 : newBatType(getBatType(getArgType(mb, q, q->argc - 1))));
146 2376372 : if (getFunctionId(q) == projectionRef)
147 2376371 : setFunctionId(q, projectionpathRef);
148 2376373 : q->typechk = TYPE_UNKNOWN;
149 :
150 2376373 : freeInstruction(p);
151 2376373 : p = q;
152 : /* keep track of the longest projection path */
153 2376373 : if (p->argc > maxprefixlength)
154 : maxprefixlength = p->argc;
155 2376373 : actions++;
156 : }
157 5784842 : wrapup:
158 9468985 : pushInstruction(mb, p);
159 29021929 : for (j = 0; j < p->retc; j++)
160 10083983 : if (getModuleId(p) == algebraRef
161 4731724 : && (getFunctionId(p) == projectionRef
162 3424021 : || getFunctionId(p) == projectionpathRef)) {
163 3684076 : pc[getArg(p, j)] = mb->stop - 1;
164 : }
165 : }
166 :
167 10302336 : for (; i < slimit; i++)
168 10243396 : if (old[i])
169 0 : pushInstruction(mb, old[i]);
170 :
171 : /* At this location there used to be commented out experimental code
172 : * to reuse common prefixes, but this was counter productive. This
173 : * comment is all that is left. */
174 :
175 : /* Defense line against incorrect plans */
176 58940 : if (actions > 0) {
177 33088 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
178 33085 : if (!msg)
179 33085 : msg = chkFlow(mb);
180 33088 : if (!msg)
181 33088 : msg = chkDeclarations(mb);
182 : }
183 25852 : wrapupall:
184 : /* keep actions taken as a fake argument */
185 467671 : (void) pushInt(mb, pci, actions);
186 :
187 467669 : if (pc)
188 58938 : GDKfree(pc);
189 467671 : if (varcnt)
190 58940 : GDKfree(varcnt);
191 467671 : if (old)
192 58940 : GDKfree(old);
193 :
194 : return msg;
195 : }
|