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 : * Superflous coercion statements will be garbagecollected later on in the pipeline
33 : */
34 : static void
35 21096773 : coercionOptimizerCalcStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
36 : {
37 21096773 : InstrPtr p = getInstrPtr(mb, i);
38 21096773 : int r, a, b, varid;
39 :
40 21096773 : r = getBatType(getVarType(mb, getArg(p, 0)));
41 : #ifdef HAVE_HGE
42 21096773 : if (r != TYPE_hge)
43 : return;
44 : #endif
45 40978 : if (getModuleId(p) != batcalcRef || getFunctionId(p) == 0)
46 : return;
47 28046 : if ((getFunctionId(p) != plusRef && getFunctionId(p) != minusRef
48 17877 : && getFunctionId(p) != mulRef && getFunctionId(p) != divRef
49 28046 : && 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)
59 0 : || p->typechk == TYPE_UNKNOWN)
60 0 : getArg(p, 1) = varid;
61 : }
62 0 : varid = getArg(p, 2);
63 0 : if (b == r && coerce[varid].src && coerce[varid].fromtype < r) {
64 : // Remove upcast on second argument
65 0 : getArg(p, 2) = coerce[varid].src;
66 0 : if (chkInstruction(cntxt->usermodule, mb, p)
67 0 : || p->typechk == TYPE_UNKNOWN)
68 0 : getArg(p, 2) = varid;
69 : }
70 : return;
71 : }
72 :
73 : static void
74 21096783 : coercionOptimizerAggrStep(Client cntxt, MalBlkPtr mb, int i, Coercion *coerce)
75 : {
76 21096783 : InstrPtr p = getInstrPtr(mb, i);
77 21096783 : int r, k;
78 :
79 21096783 : (void) cntxt;
80 :
81 21096783 : if (getModuleId(p) != aggrRef || getFunctionId(p) == 0)
82 : return;
83 55593 : if (!(getFunctionId(p) == subavgRef) || p->argc != 6)
84 : return;
85 :
86 0 : r = getBatType(getVarType(mb, getArg(p, 0)));
87 0 : k = getArg(p, 1);
88 0 : if (r == TYPE_dbl && coerce[k].src) {
89 0 : getArg(p, 1) = coerce[k].src;
90 0 : if (chkInstruction(cntxt->usermodule, mb, p)
91 0 : || p->typechk == TYPE_UNKNOWN)
92 0 : getArg(p, 1) = k;
93 : }
94 : return;
95 : }
96 :
97 : str
98 467670 : OPTcoercionImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
99 : InstrPtr pci)
100 : {
101 467670 : int i, k, t;
102 467670 : InstrPtr p;
103 467670 : int actions = 0;
104 467670 : const char *calcRef = putName("calc");
105 467672 : Coercion *coerce = GDKzalloc(sizeof(Coercion) * mb->vtop);
106 467672 : str msg = MAL_SUCCEED;
107 :
108 467672 : if (coerce == NULL)
109 0 : throw(MAL, "optimizer.coercion", SQLSTATE(HY013) MAL_MALLOC_FAIL);
110 : (void) cntxt;
111 : (void) stk; /* to fool compilers */
112 :
113 24783656 : for (i = 1; i < mb->stop; i++) {
114 24315996 : p = getInstrPtr(mb, i);
115 24315996 : if (getModuleId(p) == NULL)
116 3219218 : continue;
117 : /* Downscale the type, avoiding hge storage when lng would be sufficient.
118 : */
119 : #ifdef HAVE_HGE
120 21096778 : if (getModuleId(p) == batcalcRef
121 216849 : && getFunctionId(p) == hgeRef
122 16219 : && p->retc == 1 && p->argc == 5 && isVarConstant(mb, getArg(p, 1))
123 0 : && getArgType(mb, p, 1) == TYPE_int
124 0 : && isVarConstant(mb, getArg(p, 3))
125 0 : && getArgType(mb, p, 3) == TYPE_int
126 0 : && isVarConstant(mb, getArg(p, 4))
127 0 : && getArgType(mb, p, 4) == TYPE_int
128 : /* from-scale == to-scale, i.e., no scale change */
129 0 : && *(int *) getVarValue(mb, getArg(p, 1)) == *(int *) getVarValue(mb, getArg (p, 4)))
130 : {
131 0 : k = getArg(p, 0);
132 0 : coerce[k].pc = i;
133 0 : coerce[k].totype = TYPE_hge;
134 0 : coerce[k].src = getArg(p, 2);
135 0 : coerce[k].fromtype = getBatType(getArgType(mb, p, 2));
136 : }
137 : #endif
138 21096778 : if (getModuleId(p) == batcalcRef
139 216849 : && getFunctionId(p) == dblRef
140 1281 : && p->retc == 1
141 1281 : && (p->argc == 2
142 1281 : || (p->argc == 3 && isVarConstant(mb, getArg(p, 1))
143 0 : && getArgType(mb, p, 1) == TYPE_int
144 : //to-scale == 0, i.e., no scale change
145 0 : && *(int *) getVarValue(mb, getArg(p, 1)) == 0))) {
146 0 : k = getArg(p, 0);
147 0 : coerce[k].pc = i;
148 0 : coerce[k].totype = TYPE_dbl;
149 0 : coerce[k].src = getArg(p, 1 + (p->argc == 3));
150 0 : coerce[k].fromtype = getBatType(getArgType(mb, p, 1 + (p->argc == 3)));
151 : }
152 21096778 : coercionOptimizerAggrStep(cntxt, mb, i, coerce);
153 21096770 : coercionOptimizerCalcStep(cntxt, mb, i, coerce);
154 21096766 : if (getModuleId(p) == calcRef && p->argc == 2) {
155 24745 : t = getVarType(mb, getArg(p, 1));
156 24745 : if (getVarType(mb, getArg(p, 0)) == t
157 4192 : && strcmp(getFunctionId(p), ATOMname(t)) == 0) {
158 : /* turn it into an assignment */
159 163 : clrFunction(p);
160 163 : actions++;
161 : }
162 : }
163 : }
164 : /*
165 : * This optimizer affects the flow, but not the type and declaration
166 : * structure. A cheaper optimizer is sufficient.
167 : */
168 467660 : GDKfree(coerce);
169 :
170 : /* Defense line against incorrect plans */
171 467671 : if (actions > 0) {
172 71 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
173 71 : if (!msg)
174 71 : msg = chkFlow(mb);
175 71 : if (!msg)
176 71 : msg = chkDeclarations(mb);
177 : }
178 : /* keep actions taken as a fake argument */
179 467671 : (void) pushInt(mb, pci, actions);
180 467671 : return msg;
181 : }
|