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_generator.h"
15 : #include "mal_builder.h"
16 :
17 : /*
18 : * (c) Martin Kersten, Sjoerd Mullender
19 : * Series generating module for integer, decimal, real, double and timestamps.
20 : */
21 :
22 : #define errorCheck(P,IDX,MOD,I) \
23 : do { \
24 : setModuleId(P, generatorRef); \
25 : typeChecker(cntxt->usermodule, mb, P, IDX, TRUE); \
26 : if(P->typechk == TYPE_UNKNOWN){ \
27 : setModuleId(P, MOD); \
28 : typeChecker(cntxt->usermodule, mb, P, IDX, TRUE); \
29 : setModuleId(series[I], generatorRef); \
30 : setFunctionId(series[I], seriesRef); \
31 : typeChecker(cntxt->usermodule, mb, series[I], I, TRUE); \
32 : } \
33 : pushInstruction(mb,P); \
34 : } while (0)
35 :
36 : #define casting(TPE) \
37 : do { \
38 : k = getArg(p, 1); \
39 : p->argc = p->retc; \
40 : q = newInstruction(0, calcRef, TPE##Ref); \
41 : if (q == NULL) { \
42 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
43 : goto bailout; \
44 : } \
45 : if (setDestVar(q, newTmpVariable(mb, TYPE_##TPE)) < 0) { \
46 : freeInstruction(q); \
47 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
48 : goto bailout; \
49 : } \
50 : q = pushArgument(mb, q, getArg(series[k], 1)); \
51 : typeChecker(cntxt->usermodule, mb, q, 0, TRUE); \
52 : p = pushArgument(mb, p, getArg(q, 0)); \
53 : pushInstruction(mb, q); \
54 : q = newInstruction(0, calcRef, TPE##Ref); \
55 : if (q == NULL) { \
56 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
57 : goto bailout; \
58 : } \
59 : if (setDestVar(q, newTmpVariable(mb, TYPE_##TPE)) < 0) { \
60 : freeInstruction(q); \
61 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
62 : goto bailout; \
63 : } \
64 : q = pushArgument(mb, q, getArg(series[k], 2)); \
65 : pushInstruction(mb, q); \
66 : typeChecker(cntxt->usermodule, mb, q, 0, TRUE); \
67 : p = pushArgument(mb, p, getArg(q, 0)); \
68 : if( p->argc == 4){ \
69 : q = newInstruction(0, calcRef, TPE##Ref); \
70 : if (q == NULL) { \
71 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
72 : goto bailout; \
73 : } \
74 : if (setDestVar(q, newTmpVariable(mb, TYPE_##TPE)) < 0) { \
75 : freeInstruction(q); \
76 : msg = createException(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
77 : goto bailout; \
78 : } \
79 : q = pushArgument(mb, q, getArg(series[k], 3)); \
80 : typeChecker(cntxt->usermodule, mb, q, 0, TRUE); \
81 : p = pushArgument(mb, p, getArg(q, 0)); \
82 : pushInstruction(mb, q); \
83 : } \
84 : setModuleId(p, generatorRef); \
85 : setFunctionId(p, parametersRef); \
86 : series[getArg(p, 0)] = p; \
87 : pushInstruction(mb, p); \
88 : old[i] = NULL; \
89 : } while (0)
90 :
91 : str
92 439287 : OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
93 : InstrPtr pci)
94 : {
95 439287 : InstrPtr p, q, *old, *series;
96 439287 : int i, k, limit, slimit, actions = 0;
97 439287 : const char *bteRef = getName("bte");
98 439288 : const char *shtRef = getName("sht");
99 439288 : const char *intRef = getName("int");
100 439288 : const char *lngRef = getName("lng");
101 439288 : const char *fltRef = getName("flt");
102 439288 : const char *dblRef = getName("dbl");
103 439288 : str msg = MAL_SUCCEED;
104 439288 : int needed = 0;
105 :
106 439288 : (void) stk;
107 :
108 439288 : old = mb->stmt;
109 439288 : limit = mb->stop;
110 439288 : slimit = mb->ssize;
111 :
112 : // check applicability first
113 22561284 : for (i = 0; i < limit; i++) {
114 22122497 : p = old[i];
115 22122497 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef)
116 22122497 : needed = 1;
117 : /* avoid error in table-udf-column-descriptor */
118 22122497 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol) {
119 501 : old = NULL;
120 501 : goto wrapup;
121 : }
122 : }
123 438787 : if (!needed)
124 438589 : goto wrapup;
125 :
126 198 : series = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * mb->vtop);
127 198 : if (series == NULL)
128 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
129 :
130 198 : if (newMalBlkStmt(mb, mb->ssize) < 0) {
131 0 : GDKfree(series);
132 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
133 : }
134 :
135 5283 : for (i = 0; mb->errors == NULL && i < limit; i++) {
136 5283 : p = old[i];
137 5283 : if (p->token == ENDsymbol) {
138 : break;
139 : }
140 5085 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef) {
141 204 : series[getArg(p, 0)] = p;
142 204 : setModuleId(p, generatorRef);
143 204 : setFunctionId(p, parametersRef);
144 204 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
145 204 : pushInstruction(mb, p);
146 204 : old[i] = NULL;
147 4881 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == selectRef
148 84 : && series[getArg(p, 1)]) {
149 23 : errorCheck(p, i, algebraRef, getArg(p, 1));
150 4858 : } else if (getModuleId(p) == algebraRef
151 1086 : && getFunctionId(p) == thetaselectRef
152 34 : && series[getArg(p, 1)]) {
153 27 : errorCheck(p, i, algebraRef, getArg(p, 1));
154 4831 : } else if (getModuleId(p) == algebraRef
155 1059 : && getFunctionId(p) == projectionRef
156 678 : && series[getArg(p, 2)]) {
157 135 : errorCheck(p, i, algebraRef, getArg(p, 2));
158 4696 : } else if (getModuleId(p) == sqlRef
159 733 : && getFunctionId(p) == putName("exportValue")
160 0 : && isaBatType(getArgType(mb, p, 0))) {
161 : // interface expects scalar type only, not expressable in MAL signature
162 0 : mb->errors = createException(MAL, "generate_series",
163 : SQLSTATE(42000)
164 : "internal error, generate_series is a table producing function");
165 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef
166 0 : && series[getArg(p, 1)] && p->argc == 2) {
167 0 : casting(bte);
168 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef
169 0 : && series[getArg(p, 1)] && p->argc == 2) {
170 0 : casting(sht);
171 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == intRef
172 45 : && series[getArg(p, 1)] && p->argc == 2) {
173 0 : casting(int);
174 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef
175 14 : && series[getArg(p, 1)] && p->argc == 2) {
176 0 : casting(lng);
177 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef
178 0 : && series[getArg(p, 1)] && p->argc == 2) {
179 0 : casting(flt);
180 4696 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef
181 0 : && series[getArg(p, 1)] && p->argc == 2) {
182 0 : casting(dbl);
183 4696 : } else if (getModuleId(p) == languageRef && getFunctionId(p) == passRef) {
184 556 : pushInstruction(mb, p);
185 556 : old[i] = NULL;
186 : } else {
187 : // check for use without conversion
188 14114 : for (k = p->retc; k < p->argc; k++) {
189 9974 : if (series[getArg(p, k)]) {
190 231 : const char *m = getModuleId(p);
191 231 : setModuleId(p, generatorRef);
192 231 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
193 231 : if (p->typechk == TYPE_UNKNOWN) {
194 231 : setModuleId(p, m);
195 231 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
196 231 : InstrPtr r = series[getArg(p, k)];
197 231 : setModuleId(r, generatorRef);
198 231 : setFunctionId(r, seriesRef);
199 231 : typeChecker(cntxt->usermodule, mb, r, getPC(mb, r),
200 : TRUE);
201 : }
202 : }
203 : }
204 4140 : pushInstruction(mb, p);
205 4140 : old[i] = NULL;
206 : }
207 : }
208 6326 : for (; i < limit; i++)
209 6128 : pushInstruction(mb, old[i]);
210 198 : bailout:
211 39673 : for (; i < slimit; i++) {
212 39475 : if (old[i])
213 0 : pushInstruction(mb, old[i]);
214 : }
215 198 : GDKfree(old);
216 198 : GDKfree(series);
217 :
218 : /* Defense line against incorrect plans */
219 : /* all new/modified statements are already checked */
220 : // msg = chkTypes(cntxt->usermodule, mb, FALSE);
221 : // if (!msg)
222 : // msg = chkFlow(mb);
223 : // if (!msg)
224 : // msg = chkDeclarations(mb);
225 : /* keep all actions taken as a post block comment */
226 439288 : wrapup:
227 : /* keep actions taken as a fake argument */
228 439288 : (void) pushInt(mb, pci, actions);
229 439288 : return msg;
230 : }
|