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 466878 : OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
93 : InstrPtr pci)
94 : {
95 466878 : InstrPtr p, q, *old, *series;
96 466878 : int i, k, limit, slimit, actions = 0;
97 466878 : const char *bteRef = getName("bte");
98 466878 : const char *shtRef = getName("sht");
99 466878 : const char *intRef = getName("int");
100 466878 : const char *lngRef = getName("lng");
101 466878 : const char *fltRef = getName("flt");
102 466877 : const char *dblRef = getName("dbl");
103 466878 : str msg = MAL_SUCCEED;
104 466878 : int needed = 0;
105 :
106 466878 : (void) stk;
107 :
108 466878 : old = mb->stmt;
109 466878 : limit = mb->stop;
110 466878 : slimit = mb->ssize;
111 :
112 : // check applicability first
113 23962692 : for (i = 0; i < limit; i++) {
114 23496285 : p = old[i];
115 23496285 : if (getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef)
116 23496285 : needed = 1;
117 : /* avoid error in table-udf-column-descriptor */
118 23496285 : if (p->token == RETURNsymbol || p->barrier == RETURNsymbol) {
119 471 : old = NULL;
120 471 : goto wrapup;
121 : }
122 : }
123 466407 : if (!needed)
124 466173 : 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 5394 : for (i = 0; mb->errors == NULL && i < limit; i++) {
136 5394 : p = old[i];
137 5394 : if (p->token == ENDsymbol) {
138 : break;
139 : }
140 5160 : 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 4918 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == rangejoinRef
148 6 : && series[getArg(p, 2)]) {
149 4 : errorCheck(p, i, algebraRef, getArg(p, 2));
150 4914 : } else if (getModuleId(p) == algebraRef && getFunctionId(p) == selectRef
151 53 : && series[getArg(p, 1)]) {
152 23 : errorCheck(p, i, algebraRef, getArg(p, 1));
153 4891 : } else if (getModuleId(p) == algebraRef
154 958 : && getFunctionId(p) == thetaselectRef
155 49 : && series[getArg(p, 1)]) {
156 29 : errorCheck(p, i, algebraRef, getArg(p, 1));
157 4862 : } else if (getModuleId(p) == algebraRef
158 929 : && getFunctionId(p) == projectionRef
159 578 : && series[getArg(p, 2)]) {
160 141 : errorCheck(p, i, algebraRef, getArg(p, 2));
161 4721 : } else if (getModuleId(p) == sqlRef
162 748 : && getFunctionId(p) == putName("exportValue")
163 0 : && isaBatType(getArgType(mb, p, 0))) {
164 : // interface expects scalar type only, not expressible in MAL signature
165 0 : mb->errors = createException(MAL, "generate_series",
166 : SQLSTATE(42000)
167 : "internal error, generate_series is a table producing function");
168 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef
169 0 : && series[getArg(p, 1)] && p->argc == 2) {
170 0 : casting(bte);
171 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef
172 0 : && series[getArg(p, 1)] && p->argc == 2) {
173 0 : casting(sht);
174 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == intRef
175 41 : && series[getArg(p, 1)] && p->argc == 2) {
176 0 : casting(int);
177 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef
178 6 : && series[getArg(p, 1)] && p->argc == 2) {
179 0 : casting(lng);
180 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef
181 0 : && series[getArg(p, 1)] && p->argc == 2) {
182 0 : casting(flt);
183 4721 : } else if (getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef
184 0 : && series[getArg(p, 1)] && p->argc == 2) {
185 0 : casting(dbl);
186 4721 : } else if (getModuleId(p) == languageRef && getFunctionId(p) == passRef) {
187 512 : pushInstruction(mb, p);
188 512 : old[i] = NULL;
189 : } else {
190 : // check for use without conversion
191 13885 : for (k = p->retc; k < p->argc; k++) {
192 9676 : if (series[getArg(p, k)]) {
193 270 : const char *m = getModuleId(p);
194 270 : setModuleId(p, generatorRef);
195 270 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
196 270 : if (!p->typeresolved) {
197 270 : setModuleId(p, m);
198 270 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
199 270 : InstrPtr r = series[getArg(p, k)];
200 270 : setModuleId(r, generatorRef);
201 270 : setFunctionId(r, seriesRef);
202 270 : typeChecker(cntxt->usermodule, mb, r, getPC(mb, r),
203 : TRUE);
204 : }
205 : }
206 : }
207 4209 : pushInstruction(mb, p);
208 4209 : old[i] = NULL;
209 : }
210 : }
211 7480 : for (; i < limit; i++)
212 7246 : pushInstruction(mb, old[i]);
213 234 : bailout:
214 47732 : for (; i < slimit; i++) {
215 47498 : if (old[i])
216 0 : pushInstruction(mb, old[i]);
217 : }
218 234 : GDKfree(old);
219 234 : GDKfree(series);
220 :
221 : /* Defense line against incorrect plans */
222 : /* all new/modified statements are already checked */
223 : // msg = chkTypes(cntxt->usermodule, mb, FALSE);
224 : // if (!msg)
225 : // msg = chkFlow(mb);
226 : // if (!msg)
227 : // msg = chkDeclarations(mb);
228 : /* keep all actions taken as a post block comment */
229 466878 : wrapup:
230 : /* keep actions taken as a fake argument */
231 466878 : (void) pushInt(mb, pci, actions);
232 466878 : return msg;
233 : }
|