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->typeresolved) { \
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 455096 : OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
93 : InstrPtr pci)
94 : {
95 455096 : InstrPtr p, q, *old, *series;
96 455096 : int i, k, limit, slimit, actions = 0;
97 455096 : const char *bteRef = getName("bte");
98 455116 : const char *shtRef = getName("sht");
99 455116 : const char *intRef = getName("int");
100 455117 : const char *lngRef = getName("lng");
101 455117 : const char *fltRef = getName("flt");
102 455116 : const char *dblRef = getName("dbl");
103 455112 : str msg = MAL_SUCCEED;
104 455112 : int needed = 0;
105 :
106 455112 : (void) stk;
107 :
108 455112 : old = mb->stmt;
109 455112 : limit = mb->stop;
110 455112 : slimit = mb->ssize;
111 :
112 : // check applicability first
113 28621851 : for (i = 0; i < limit; i++) {
114 28167210 : p = old[i];
115 28167210 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef)
116 28167210 : needed = 1;
117 : /* avoid error in table-udf-column-descriptor */
118 28167210 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol) {
119 471 : old = NULL;
120 471 : goto wrapup;
121 : }
122 : }
123 454641 : if (!needed)
124 454407 : goto wrapup;
125 :
126 234 : series = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * mb->vtop);
127 234 : if (series == NULL)
128 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
129 :
130 234 : if (newMalBlkStmt(mb, mb->ssize) < 0) {
131 0 : GDKfree(series);
132 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
133 : }
134 :
135 5450 : for (i = 0; mb->errors == NULL && i < limit; i++) {
136 5450 : p = old[i];
137 5450 : if (p->token == ENDsymbol) {
138 : break;
139 : }
140 5216 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef) {
141 242 : series[getArg(p, 0)] = p;
142 242 : setModuleId(p, generatorRef);
143 242 : setFunctionId(p, parametersRef);
144 242 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
145 242 : pushInstruction(mb, p);
146 242 : old[i] = NULL;
147 4974 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == selectRef
148 62 : && series[getArg(p, 1)]) {
149 23 : errorCheck(p, i, algebraRef, getArg(p, 1));
150 4951 : } else if (getModuleId(p) == algebraRef
151 986 : && getFunctionId(p) == thetaselectRef
152 40 : && series[getArg(p, 1)]) {
153 29 : errorCheck(p, i, algebraRef, getArg(p, 1));
154 4922 : } else if (getModuleId(p) == algebraRef
155 957 : && getFunctionId(p) == projectionRef
156 596 : && series[getArg(p, 2)]) {
157 143 : errorCheck(p, i, algebraRef, getArg(p, 2));
158 4779 : } else if (getModuleId(p) == sqlRef
159 760 : && getFunctionId(p) == putName("exportValue")
160 0 : && isaBatType(getArgType(mb, p, 0))) {
161 : // interface expects scalar type only, not expressible 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 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef
166 0 : && series[getArg(p, 1)] && p->argc == 2) {
167 0 : casting(bte);
168 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef
169 0 : && series[getArg(p, 1)] && p->argc == 2) {
170 0 : casting(sht);
171 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == intRef
172 42 : && series[getArg(p, 1)] && p->argc == 2) {
173 0 : casting(int);
174 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef
175 6 : && series[getArg(p, 1)] && p->argc == 2) {
176 0 : casting(lng);
177 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef
178 0 : && series[getArg(p, 1)] && p->argc == 2) {
179 0 : casting(flt);
180 4779 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef
181 0 : && series[getArg(p, 1)] && p->argc == 2) {
182 0 : casting(dbl);
183 4779 : } else if (getModuleId(p) == languageRef && getFunctionId(p) == passRef) {
184 519 : pushInstruction(mb, p);
185 519 : old[i] = NULL;
186 : } else {
187 : // check for use without conversion
188 14160 : for (k = p->retc; k < p->argc; k++) {
189 9900 : if (series[getArg(p, k)]) {
190 273 : const char *m = getModuleId(p);
191 273 : setModuleId(p, generatorRef);
192 273 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
193 273 : if (!p->typeresolved) {
194 273 : setModuleId(p, m);
195 273 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
196 273 : InstrPtr r = series[getArg(p, k)];
197 273 : setModuleId(r, generatorRef);
198 273 : setFunctionId(r, seriesRef);
199 273 : typeChecker(cntxt->usermodule, mb, r, getPC(mb, r),
200 : TRUE);
201 : }
202 : }
203 : }
204 4260 : pushInstruction(mb, p);
205 4260 : old[i] = NULL;
206 : }
207 : }
208 7480 : for (; i < limit; i++)
209 7246 : pushInstruction(mb, old[i]);
210 234 : bailout:
211 47676 : for (; i < slimit; i++) {
212 47442 : if (old[i])
213 0 : pushInstruction(mb, old[i]);
214 : }
215 234 : GDKfree(old);
216 234 : 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 455112 : wrapup:
227 : /* keep actions taken as a fake argument */
228 455112 : (void) pushInt(mb, pci, actions);
229 455112 : return msg;
230 : }
|