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/* (c) M. Kersten
10 * Also include down-casting decisions on the SQL code produced
11 */
12
13#include "monetdb_config.h"
14#include "opt_coercion.h"
15#include "opt_aliases.h"
16
17typedef struct{
18 int pc;
19 int fromtype;
20 int totype;
21 int src;
22} Coercion;
23
24/* Check coercions for numeric types towards :hge that can be handled with smaller ones.
25 * For now, limit to +,-,/,*,% hge expressions
26 * Not every combination may be available in the MAL layer, which calls
27 * for a separate type check before fixing it.
28 * Superflous coercion statements will be garbagecollected later on in the pipeline
29 */
30static void
31coercionOptimizerCalcStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
32{
33 InstrPtr p = getInstrPtr(mb,i);
34 int r, a, b, varid;
35
36 r = getBatType(getVarType(mb, getArg(p,0)));
37#ifdef HAVE_HGE
38 if ( r != TYPE_hge)
39 return;
40#endif
41 if( getModuleId(p) != batcalcRef || getFunctionId(p) == 0) return;
42 if( ! (getFunctionId(p) == plusRef || getFunctionId(p) == minusRef || getFunctionId(p) == mulRef || getFunctionId(p) == divRef || *getFunctionId(p) =='%') || p->argc !=3)
43 return;
44
45 a = getBatType(getVarType(mb, getArg(p,1)));
46 b = getBatType(getVarType(mb, getArg(p,2)));
47 varid = getArg(p,1);
48 if ( a == r && coerce[varid].src && coerce[varid].fromtype < r )
49 {
50 if( OPTdebug & OPTaliases){
51 fprintf(stderr,"#remove upcast on first argument %d\n", varid);
52 fprintInstruction(stderr, mb, 0, p, LIST_MAL_ALL);
53 }
54 getArg(p,1) = coerce[varid].src;
55 if ( chkInstruction(cntxt->usermodule, mb, p) || p->typechk == TYPE_UNKNOWN)
56 getArg(p,1) = varid;
57 }
58 varid = getArg(p,2);
59 if ( b == r && coerce[varid].src && coerce[varid].fromtype < r )
60 {
61 if( OPTdebug & OPTaliases){
62 fprintf(stderr,"#remove upcast on second argument %d\n", varid);
63 fprintInstruction(stderr, mb, 0, p, LIST_MAL_ALL);
64 }
65 getArg(p,2) = coerce[varid].src;
66 if ( chkInstruction(cntxt->usermodule, mb, p) || p->typechk == TYPE_UNKNOWN)
67 getArg(p,2) = varid;
68 }
69 if( OPTdebug & OPTaliases){
70 fprintf(stderr,"#final instruction\n");
71 fprintInstruction(stderr, mb, 0, p, LIST_MAL_ALL);
72 }
73 return;
74}
75
76static void
77coercionOptimizerAggrStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
78{
79 InstrPtr p = getInstrPtr(mb,i);
80 int r, k;
81
82 (void) cntxt;
83
84 if( getModuleId(p) != aggrRef || getFunctionId(p) == 0) return;
85 if( ! (getFunctionId(p) == subavgRef ) || p->argc !=6)
86 return;
87
88 r = getBatType(getVarType(mb, getArg(p,0)));
89 k = getArg(p,1);
90 if( r == TYPE_dbl && coerce[k].src ){
91 getArg(p,1) = coerce[k].src;
92 if ( chkInstruction(cntxt->usermodule, mb, p) || p->typechk == TYPE_UNKNOWN)
93 getArg(p,1)= k;
94 }
95 return;
96}
97
98str
99OPTcoercionImplementation(Client cntxt,MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
100{
101 int i, k, t;
102 InstrPtr p;
103 int actions = 0;
104 str calcRef= putName("calc");
105 Coercion *coerce = GDKzalloc(sizeof(Coercion) * mb->vtop);
106 char buf[256];
107 lng usec = GDKusec();
108 str msg = MAL_SUCCEED;
109
110 if( coerce == NULL)
111 throw(MAL,"optimizer.coercion", SQLSTATE(HY001) MAL_MALLOC_FAIL);
112 (void) cntxt;
113 (void) pci;
114 (void) stk; /* to fool compilers */
115
116 for (i = 1; i < mb->stop; i++) {
117 p = getInstrPtr(mb, i);
118 if (getModuleId(p) == NULL)
119 continue;
120/* Downscale the type, avoiding hge storage when lng would be sufficient.
121 */
122#ifdef HAVE_HGE
123 if ( getModuleId(p) == batcalcRef
124 && getFunctionId(p) == hgeRef
125 && p->retc == 1
126 && ( p->argc == 5
127 && isVarConstant(mb,getArg(p,1))
128 && getArgType(mb,p,1) == TYPE_int
129 && isVarConstant(mb,getArg(p,3))
130 && getArgType(mb,p,3) == TYPE_int
131 && isVarConstant(mb,getArg(p,4))
132 && getArgType(mb,p,4) == TYPE_int
133 /* from-scale == to-scale, i.e., no scale change */
134 && *(int*) getVarValue(mb, getArg(p,1)) == *(int*) getVarValue(mb, getArg(p,4)) ) ){
135 k = getArg(p,0);
136 coerce[k].pc= i;
137 coerce[k].totype= TYPE_hge;
138 coerce[k].src= getArg(p,2);
139 coerce[k].fromtype= getBatType(getArgType(mb,p,2));
140 }
141#endif
142 if ( getModuleId(p) == batcalcRef
143 && getFunctionId(p) == dblRef
144 && p->retc == 1
145 && ( p->argc == 2
146 || ( p->argc == 3
147 && isVarConstant(mb,getArg(p,1))
148 && getArgType(mb,p,1) == TYPE_int
149 //to-scale == 0, i.e., no scale change
150 && *(int*) getVarValue(mb, getArg(p,1)) == 0 ) ) ) {
151 k = getArg(p,0);
152 coerce[k].pc= i;
153 coerce[k].totype= TYPE_dbl;
154 coerce[k].src= getArg(p,1 + (p->argc ==3));
155 coerce[k].fromtype= getBatType(getArgType(mb,p,1 + (p->argc ==3)));
156 }
157 coercionOptimizerAggrStep(cntxt,mb, i, coerce);
158 coercionOptimizerCalcStep(cntxt,mb, i, coerce);
159 if (getModuleId(p)==calcRef && p->argc == 2) {
160 t = getVarType(mb, getArg(p,1));
161 if (getVarType(mb, getArg(p,0)) == t && strcmp(getFunctionId(p), ATOMname(t)) == 0) {
162 /* turn it into an assignment */
163 clrFunction(p);
164 actions ++;
165 }
166 }
167 }
168 /*
169 * This optimizer affects the flow, but not the type and declaration
170 * structure. A cheaper optimizer is sufficient.
171 */
172 GDKfree(coerce);
173
174 /* Defense line against incorrect plans */
175 if( actions > 0){
176 chkTypes(cntxt->usermodule, mb, FALSE);
177 chkFlow(mb);
178 chkDeclarations(mb);
179 }
180 /* keep all actions taken as a post block comment */
181 usec = GDKusec()- usec;
182 snprintf(buf,256,"%-20s actions=%2d time=" LLFMT " usec","coercion",actions, usec);
183 newComment(mb,buf);
184 if( actions >= 0)
185 addtoMalBlkHistory(mb);
186 /* else we can also remove the request to apply the next alias optimizer */
187
188 if( OPTdebug & OPTcoercion){
189 fprintf(stderr, "#COERCION optimizer entry\n");
190 fprintFunction(stderr, mb, 0, LIST_MAL_ALL);
191 }
192 return msg;
193}
194