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