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, date 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 470752 : OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
93 : InstrPtr pci)
94 : {
95 470752 : InstrPtr p, q, *old, *series;
96 470752 : int i, k, limit, slimit, actions = 0;
97 : /* intRef, lngRef and dblRef are globally defined */
98 470752 : const char *bteRef = getName("bte");
99 470769 : const char *shtRef = getName("sht");
100 : //const char *intRef = getName("int");
101 : //const char *lngRef = getName("lng");
102 470769 : const char *fltRef = getName("flt");
103 : //const char *dblRef = getName("dbl");
104 470760 : str msg = MAL_SUCCEED;
105 470760 : int needed = 0;
106 :
107 470760 : (void) stk;
108 :
109 470760 : old = mb->stmt;
110 470760 : limit = mb->stop;
111 470760 : slimit = mb->ssize;
112 :
113 : // check applicability first
114 29469976 : for (i = 0; i < limit; i++) {
115 28999687 : p = old[i];
116 28999687 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef)
117 28999687 : needed = 1;
118 : /* avoid error in table-udf-column-descriptor */
119 28999687 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol) {
120 471 : old = NULL;
121 471 : goto wrapup;
122 : }
123 : }
124 470289 : if (!needed)
125 470034 : goto wrapup;
126 :
127 255 : series = (InstrPtr *) GDKzalloc(sizeof(InstrPtr) * mb->vtop);
128 255 : if (series == NULL)
129 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
130 :
131 255 : if (newMalBlkStmt(mb, mb->ssize) < 0) {
132 0 : GDKfree(series);
133 0 : throw(MAL, "optimizer.generator", SQLSTATE(HY013) MAL_MALLOC_FAIL);
134 : }
135 :
136 6665 : for (i = 0; mb->errors == NULL && i < limit; i++) {
137 6665 : p = old[i];
138 6665 : if (p->token == ENDsymbol) {
139 : break;
140 : }
141 6410 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef) {
142 268 : series[getArg(p, 0)] = p;
143 268 : setModuleId(p, generatorRef);
144 268 : setFunctionId(p, parametersRef);
145 268 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
146 268 : pushInstruction(mb, p);
147 268 : old[i] = NULL;
148 6142 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == rangejoinRef
149 6 : && series[getArg(p, 2)]) {
150 4 : errorCheck(p, i, algebraRef, getArg(p, 2));
151 6138 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == selectRef
152 80 : && series[getArg(p, 1)]) {
153 23 : errorCheck(p, i, algebraRef, getArg(p, 1));
154 6115 : } else if (getModuleId(p) == algebraRef
155 1417 : && getFunctionId(p) == thetaselectRef
156 77 : && series[getArg(p, 1)]) {
157 29 : errorCheck(p, i, algebraRef, getArg(p, 1));
158 6086 : } else if (getModuleId(p) == algebraRef
159 1388 : && getFunctionId(p) == projectionRef
160 856 : && series[getArg(p, 2)]) {
161 173 : errorCheck(p, i, algebraRef, getArg(p, 2));
162 5913 : } else if (getModuleId(p) == sqlRef
163 795 : && getFunctionId(p) == putName("exportValue")
164 0 : && isaBatType(getArgType(mb, p, 0))) {
165 : // interface expects scalar type only, not expressible in MAL signature
166 0 : mb->errors = createException(MAL, "generate_series",
167 : SQLSTATE(42000)
168 : "internal error, generate_series is a table producing function");
169 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef
170 10 : && series[getArg(p, 1)] && p->argc == 2) {
171 0 : casting(bte);
172 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef
173 2 : && series[getArg(p, 1)] && p->argc == 2) {
174 0 : casting(sht);
175 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == intRef
176 41 : && series[getArg(p, 1)] && p->argc == 2) {
177 0 : casting(int);
178 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef
179 6 : && series[getArg(p, 1)] && p->argc == 2) {
180 0 : casting(lng);
181 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef
182 1 : && series[getArg(p, 1)] && p->argc == 2) {
183 0 : casting(flt);
184 5913 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef
185 3 : && series[getArg(p, 1)] && p->argc == 2) {
186 0 : casting(dbl);
187 5913 : } else if (getModuleId(p) == languageRef && getFunctionId(p) == passRef) {
188 524 : pushInstruction(mb, p);
189 524 : old[i] = NULL;
190 : } else {
191 : // check for use without conversion
192 17921 : for (k = p->retc; k < p->argc; k++) {
193 12532 : if (series[getArg(p, k)]) {
194 311 : const char *m = getModuleId(p);
195 311 : setModuleId(p, generatorRef);
196 311 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
197 311 : if (!p->typeresolved) {
198 311 : setModuleId(p, m);
199 311 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
200 311 : InstrPtr r = series[getArg(p, k)];
201 311 : setModuleId(r, generatorRef);
202 311 : setFunctionId(r, seriesRef);
203 311 : typeChecker(cntxt->usermodule, mb, r, getPC(mb, r),
204 : TRUE);
205 : }
206 : }
207 : }
208 5389 : pushInstruction(mb, p);
209 5389 : old[i] = NULL;
210 : }
211 : }
212 8082 : for (; i < limit; i++)
213 7827 : pushInstruction(mb, old[i]);
214 255 : bailout:
215 52322 : for (; i < slimit; i++) {
216 52067 : if (old[i])
217 0 : pushInstruction(mb, old[i]);
218 : }
219 255 : GDKfree(old);
220 255 : GDKfree(series);
221 :
222 : /* Defense line against incorrect plans */
223 : /* all new/modified statements are already checked */
224 : // msg = chkTypes(cntxt->usermodule, mb, FALSE);
225 : // if (!msg)
226 : // msg = chkFlow(mb);
227 : // if (!msg)
228 : // msg = chkDeclarations(mb);
229 : /* keep all actions taken as a post block comment */
230 470760 : wrapup:
231 : /* keep actions taken as a fake argument */
232 470760 : (void) pushInt(mb, pci, actions);
233 470760 : return msg;
234 : }
|