1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#include "opt_generator.h"
11#include "mal_builder.h"
12
13/*
14 * (c) Martin Kersten, Sjoerd Mullender
15 * Series generating module for integer, decimal, real, double and timestamps.
16 */
17
18#define errorCheck(P,MOD,I) \
19setModuleId(P, generatorRef);\
20typeChecker(cntxt->usermodule, mb, P, TRUE);\
21if(P->typechk == TYPE_UNKNOWN){\
22 setModuleId(P,MOD);\
23 typeChecker(cntxt->usermodule, mb, P, TRUE);\
24 setModuleId(series[I], generatorRef);\
25 setFunctionId(series[I], seriesRef);\
26 typeChecker(cntxt->usermodule, mb, series[I], TRUE);\
27}\
28pushInstruction(mb,P);
29
30#define casting(TPE)\
31 k= getArg(p,1);\
32 p->argc = p->retc;\
33 q= newInstruction(0,calcRef, TPE##Ref);\
34 setDestVar(q, newTmpVariable(mb, TYPE_##TPE));\
35 pushArgument(mb,q,getArg(series[k],1));\
36 typeChecker(cntxt->usermodule, mb, q, TRUE);\
37 p = pushArgument(mb,p, getArg(q,0));\
38 pushInstruction(mb,q);\
39 q= newInstruction(0,calcRef,TPE##Ref);\
40 setDestVar(q, newTmpVariable(mb, TYPE_##TPE));\
41 pushArgument(mb,q,getArg(series[k],2));\
42 pushInstruction(mb,q);\
43 typeChecker(cntxt->usermodule, mb, q, TRUE);\
44 p = pushArgument(mb,p, getArg(q,0));\
45 if( p->argc == 4){\
46 q= newInstruction(0,calcRef,TPE##Ref);\
47 setDestVar(q, newTmpVariable(mb, TYPE_##TPE));\
48 pushArgument(mb,q,getArg(series[k],3));\
49 typeChecker(cntxt->usermodule, mb, q, TRUE);\
50 p = pushArgument(mb,p, getArg(q,0));\
51 pushInstruction(mb,q);\
52 }\
53 setModuleId(p,generatorRef);\
54 setFunctionId(p,parametersRef);\
55 setVarUDFtype(mb,getArg(p,0));\
56 series[getArg(p,0)] = p;\
57 pushInstruction(mb,p);
58
59str
60OPTgeneratorImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
61{
62 InstrPtr p,q, *old, *series;
63 int i, k, limit, slimit, actions=0;
64 str m;
65 str bteRef = getName("bte");
66 str shtRef = getName("sht");
67 str intRef = getName("int");
68 str lngRef = getName("lng");
69 str fltRef = getName("flt");
70 str dblRef = getName("dbl");
71 char buf[256];
72 lng usec= GDKusec();
73
74 (void) cntxt;
75 (void) stk;
76 (void) pci;
77
78 series = (InstrPtr*) GDKzalloc(sizeof(InstrPtr) * mb->vtop);
79 if(series == NULL)
80 throw(MAL,"optimizer.generator", SQLSTATE(HY001) MAL_MALLOC_FAIL);
81 old = mb->stmt;
82 limit = mb->stop;
83 slimit = mb->ssize;
84
85 // check applicability first
86 for( i=0; i < limit; i++){
87 p = old[i];
88 if ( getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef)
89 break;
90 }
91 if (i == limit) {
92 GDKfree(series);
93 return 0;
94 }
95
96 if (newMalBlkStmt(mb, mb->ssize) < 0) {
97 GDKfree(series);
98 throw(MAL,"optimizer.generator", SQLSTATE(HY001) MAL_MALLOC_FAIL);
99 }
100
101 for( i=0; i < limit; i++){
102 p = old[i];
103 if (p->token == ENDsymbol){
104 pushInstruction(mb,p);
105 break;
106 }
107 if ( getModuleId(p) == generatorRef && getFunctionId(p) == seriesRef){
108 series[getArg(p,0)] = p;
109 setModuleId(p, generatorRef);
110 setFunctionId(p, parametersRef);
111 typeChecker(cntxt->usermodule, mb, p, TRUE);
112 pushInstruction(mb,p);
113 } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == selectRef && series[getArg(p,1)]){
114 errorCheck(p,algebraRef,getArg(p,1));
115 } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == thetaselectRef && series[getArg(p,1)]){
116 errorCheck(p,algebraRef,getArg(p,1));
117 } else if ( getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef && series[getArg(p,2)]){
118 errorCheck(p,algebraRef,getArg(p,2));
119 } else if ( getModuleId(p) == sqlRef && getFunctionId(p) == putName("exportValue") && isaBatType(getArgType(mb,p,0)) ){
120 // interface expects scalar type only, not expressable in MAL signature
121 mb->errors=createException(MAL, "generate_series", SQLSTATE(42000) "internal error, generate_series is a table producing function");
122 }else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == bteRef && series[getArg(p,1)] && p->argc == 2 ){
123 casting(bte);
124 } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == shtRef && series[getArg(p,1)] && p->argc == 2 ){
125 casting(sht);
126 } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == intRef && series[getArg(p,1)] && p->argc == 2 ){
127 casting(int);
128 } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == lngRef && series[getArg(p,1)] && p->argc == 2 ){
129 casting(lng);
130 } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == fltRef && series[getArg(p,1)] && p->argc == 2 ){
131 casting(flt);
132 } else if ( getModuleId(p) == batcalcRef && getFunctionId(p) == dblRef && series[getArg(p,1)] && p->argc == 2 ){
133 casting(dbl);
134 } else if ( getModuleId(p) == languageRef && getFunctionId(p) == passRef )
135 pushInstruction(mb,p);
136 else {
137 // check for use without conversion
138 for(k = p->retc; k < p->argc; k++)
139 if( series[getArg(p,k)]){
140 m = getModuleId(p);
141 setModuleId(p, generatorRef);
142 typeChecker(cntxt->usermodule, mb, p, TRUE);
143 if(p->typechk == TYPE_UNKNOWN){
144 setModuleId(p,m);
145 typeChecker(cntxt->usermodule, mb, p, TRUE);
146 setModuleId(series[getArg(p,k)], generatorRef);
147 setFunctionId(series[getArg(p,k)], seriesRef);
148 typeChecker(cntxt->usermodule, mb, series[getArg(p,k)], TRUE);
149 }
150 }
151 pushInstruction(mb,p);
152 }
153 }
154 for (i++; i < limit; i++)
155 pushInstruction(mb, old[i]);
156 for (; i < slimit; i++)
157 if (old[i])
158 freeInstruction(old[i]);
159 GDKfree(old);
160 GDKfree(series);
161
162 /* Defense line against incorrect plans */
163 /* all new/modified statements are already checked */
164 //chkTypes(cntxt->usermodule, mb, FALSE);
165 //chkFlow(mb);
166 //chkDeclarations(mb);
167 /* keep all actions taken as a post block comment */
168 usec = GDKusec()- usec;
169 snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","generator",actions, usec);
170 newComment(mb,buf);
171 if( actions >= 0)
172 addtoMalBlkHistory(mb);
173
174 if( OPTdebug & OPTgenerator){
175 fprintf(stderr, "#GENERATOR optimizer exit\n");
176 fprintFunction(stderr, mb, 0, LIST_MAL_ALL);
177 }
178 return MAL_SUCCEED;
179}
180