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 21777936 : coercionOptimizerCalcStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
36 : {
37 21777936 : InstrPtr p = getInstrPtr(mb, i);
38 21777936 : int r, a, b, varid;
39 :
40 21777936 : r = getBatType(getVarType(mb, getArg(p, 0)));
41 : #ifdef HAVE_HGE
42 21777936 : if (r != TYPE_hge)
43 : return;
44 : #endif
45 8690 : if (getModuleId(p) != batcalcRef || getFunctionId(p) == 0)
46 : return;
47 1108 : if ((getFunctionId(p) != plusRef && getFunctionId(p) != minusRef
48 894 : && getFunctionId(p) != mulRef && getFunctionId(p) != divRef
49 1108 : && 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 21777943 : coercionOptimizerAggrStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
73 : {
74 21777943 : InstrPtr p = getInstrPtr(mb, i);
75 21777943 : int r, k;
76 :
77 21777943 : (void) cntxt;
78 :
79 21777943 : if (getModuleId(p) != aggrRef || getFunctionId(p) == 0)
80 : return;
81 57899 : 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 483205 : OPTcoercionImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
96 : InstrPtr pci)
97 : {
98 483205 : int i, k, t;
99 483205 : InstrPtr p;
100 483205 : int actions = 0;
101 483205 : const char *calcRef = putName("calc");
102 483207 : Coercion *coerce = GDKzalloc(sizeof(Coercion) * mb->vtop);
103 483206 : str msg = MAL_SUCCEED;
104 :
105 483206 : if (coerce == NULL)
106 0 : throw(MAL, "optimizer.coercion", SQLSTATE(HY013) MAL_MALLOC_FAIL);
107 : (void) cntxt;
108 : (void) stk; /* to fool compilers */
109 :
110 25573616 : for (i = 1; i < mb->stop; i++) {
111 25090419 : p = getInstrPtr(mb, i);
112 25090419 : if (getModuleId(p) == NULL)
113 3312469 : continue;
114 : /* Downscale the type, avoiding hge storage when lng would be sufficient.
115 : */
116 : #ifdef HAVE_HGE
117 21777950 : if (getModuleId(p) == batcalcRef
118 164068 : && getFunctionId(p) == hgeRef
119 347 : && p->retc == 1 && p->argc == 5 && isVarConstant(mb, getArg(p, 1))
120 114 : && getArgType(mb, p, 1) == TYPE_int
121 0 : && isVarConstant(mb, getArg(p, 3))
122 0 : && getArgType(mb, p, 3) == TYPE_int
123 0 : && isVarConstant(mb, getArg(p, 4))
124 0 : && getArgType(mb, p, 4) == TYPE_int
125 : /* from-scale == to-scale, i.e., no scale change */
126 0 : && *(int *) getVarValue(mb, getArg(p, 1)) == *(int *) getVarValue(mb, getArg (p, 4)))
127 : {
128 0 : k = getArg(p, 0);
129 0 : coerce[k].pc = i;
130 0 : coerce[k].totype = TYPE_hge;
131 0 : coerce[k].src = getArg(p, 2);
132 0 : coerce[k].fromtype = getBatType(getArgType(mb, p, 2));
133 : }
134 : #endif
135 21777950 : if (getModuleId(p) == batcalcRef
136 164068 : && getFunctionId(p) == dblRef
137 1336 : && p->retc == 1
138 1336 : && (p->argc == 2
139 1336 : || (p->argc == 3 && isVarConstant(mb, getArg(p, 1))
140 1274 : && getArgType(mb, p, 1) == TYPE_int
141 : //to-scale == 0, i.e., no scale change
142 0 : && *(int *) getVarValue(mb, getArg(p, 1)) == 0))) {
143 0 : k = getArg(p, 0);
144 0 : coerce[k].pc = i;
145 0 : coerce[k].totype = TYPE_dbl;
146 0 : coerce[k].src = getArg(p, 1 + (p->argc == 3));
147 0 : coerce[k].fromtype = getBatType(getArgType(mb, p, 1 + (p->argc == 3)));
148 : }
149 21777950 : coercionOptimizerAggrStep(cntxt, mb, i, coerce);
150 21777940 : coercionOptimizerCalcStep(cntxt, mb, i, coerce);
151 21777941 : if (getModuleId(p) == calcRef && p->argc == 2) {
152 24633 : t = getVarType(mb, getArg(p, 1));
153 24633 : if (getVarType(mb, getArg(p, 0)) == t
154 4246 : && strcmp(getFunctionId(p), ATOMname(t)) == 0) {
155 : /* turn it into an assignment */
156 161 : clrFunction(p);
157 161 : actions++;
158 : }
159 : }
160 : }
161 : /*
162 : * This optimizer affects the flow, but not the type and declaration
163 : * structure. A cheaper optimizer is sufficient.
164 : */
165 483197 : GDKfree(coerce);
166 :
167 : /* Defense line against incorrect plans */
168 483207 : if (actions > 0) {
169 70 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
170 70 : if (!msg)
171 70 : msg = chkFlow(mb);
172 70 : if (!msg)
173 70 : msg = chkDeclarations(mb);
174 : }
175 : /* keep actions taken as a fake argument */
176 483207 : (void) pushInt(mb, pci, actions);
177 483207 : return msg;
178 : }
|