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 : /* The SQL code generator can not always look ahead to avoid
14 : * generation of intermediates.
15 : * Some of these patterns are captured in a postfix optimalisation.
16 : */
17 : #include "monetdb_config.h"
18 : #include "mal_instruction.h"
19 : #include "opt_postfix.h"
20 :
21 : #define isCandidateList(M,P,I) ((M)->var[getArg(P,I)].id[0]== 'C')
22 : str
23 483202 : OPTpostfixImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
24 : InstrPtr pci)
25 : {
26 483202 : int i, slimit, actions = 0;
27 483202 : str msg = MAL_SUCCEED;
28 483202 : InstrPtr p;
29 :
30 483202 : (void) cntxt;
31 483202 : (void) stk;
32 :
33 483202 : slimit = mb->stop;
34 483202 : setVariableScope(mb);
35 : /* Remove the result from any join/group instruction when it is not used later on */
36 24864297 : for (i = 0; i < slimit; i++) {
37 : /* POSTFIX ACTION FOR THE JOIN CASE */
38 23897893 : p = getInstrPtr(mb, i);
39 23897893 : if (getModuleId(p) == algebraRef && p->retc == 2) {
40 241264 : if (getFunctionId(p) == leftjoinRef || /*getFunctionId(p) == outerjoinRef || */
41 240616 : getFunctionId(p) == bandjoinRef
42 240616 : || getFunctionId(p) == rangejoinRef
43 240484 : || getFunctionId(p) == likejoinRef) {
44 825 : if (getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
45 45 : delArgument(p, p->retc - 1);
46 45 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
47 45 : actions++;
48 45 : continue;
49 : }
50 240439 : } else if (getFunctionId(p) == semijoinRef
51 240170 : || getFunctionId(p) == joinRef
52 48123 : || getFunctionId(p) == thetajoinRef
53 31288 : || /*getFunctionId(p) == outerjoinRef || */
54 31288 : getFunctionId(p) == crossRef) {
55 235706 : int is_first_ret_not_used = getVarEolife(mb, getArg(p, p->retc - 2)) == i;
56 235706 : int is_second_ret_not_used = getVarEolife(mb, getArg(p, p->retc - 1)) == i;
57 :
58 235706 : if (getFunctionId(p) == semijoinRef
59 269 : &&
60 : ((is_first_ret_not_used
61 58 : && getVarConstant(mb, getArg(p, 7)).val.btval != 1 /*not single */ )
62 269 : || is_second_ret_not_used)) {
63 : /* Can't swap arguments on single semijoins */
64 89 : if (is_first_ret_not_used) {
65 : /* semijoin with just the right output is a join */
66 0 : getArg(p, 2) ^= getArg(p, 3); /* swap join inputs */
67 0 : getArg(p, 3) ^= getArg(p, 2);
68 0 : getArg(p, 2) ^= getArg(p, 3);
69 :
70 0 : getArg(p, 4) ^= getArg(p, 5); /* swap candidate lists */
71 0 : getArg(p, 5) ^= getArg(p, 4);
72 0 : getArg(p, 4) ^= getArg(p, 5);
73 0 : setFunctionId(p, joinRef);
74 0 : delArgument(p, 7); /* delete 'max_one' argument */
75 : } else {
76 : /* semijoin with just the left output is an intersection */
77 89 : setFunctionId(p, intersectRef);
78 : }
79 :
80 178 : delArgument(p,
81 89 : is_second_ret_not_used ? p->retc - 1 : p->retc -
82 : 2);
83 89 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
84 89 : actions++;
85 89 : continue;
86 235617 : } else if (is_second_ret_not_used) {
87 25556 : delArgument(p, p->retc - 1);
88 25556 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
89 25556 : actions++;
90 25556 : continue;
91 210061 : } else if (is_first_ret_not_used &&
92 12361 : (getFunctionId(p) == joinRef
93 5556 : || (getFunctionId(p) == thetajoinRef
94 5232 : && isVarConstant(mb, getArg(p, 6)))
95 324 : || (getFunctionId(p) == crossRef
96 266 : && getVarConstant(mb, getArg(p, 4)).val.btval != 1 /*not single */ ))) {
97 : /* Can't swap arguments on single cross products */
98 : /* swap join inputs */
99 12299 : getArg(p, 2) ^= getArg(p, 3);
100 12299 : getArg(p, 3) ^= getArg(p, 2);
101 12299 : getArg(p, 2) ^= getArg(p, 3);
102 :
103 12299 : if (getFunctionId(p) != crossRef) { /* swap candidate lists */
104 12037 : getArg(p, 4) ^= getArg(p, 5);
105 12037 : getArg(p, 5) ^= getArg(p, 4);
106 12037 : getArg(p, 4) ^= getArg(p, 5);
107 12037 : if (getFunctionId(p) == thetajoinRef) { /* swap the comparison */
108 5232 : ValRecord *x = &getVarConstant(mb, getArg(p, 6)),
109 5232 : cst = {
110 : .vtype = TYPE_int
111 : };
112 5232 : switch (x->val.ival) {
113 5184 : case JOIN_LT:
114 5184 : cst.val.ival = JOIN_GT;
115 5184 : break;
116 9 : case JOIN_LE:
117 9 : cst.val.ival = JOIN_GE;
118 9 : break;
119 35 : case JOIN_GT:
120 35 : cst.val.ival = JOIN_LT;
121 35 : break;
122 4 : case JOIN_GE:
123 4 : cst.val.ival = JOIN_LE;
124 4 : break;
125 0 : default:
126 0 : cst.val.ival = x->val.ival;
127 : }
128 5232 : setArg(p, 6, defConstant(mb, TYPE_int, &cst));
129 : }
130 : }
131 12299 : delArgument(p, p->retc - 2);
132 12299 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
133 12299 : actions++;
134 12299 : continue;
135 : }
136 : }
137 : }
138 : /* POSTFIX ACTION FOR THE EXTENT CASE */
139 23859904 : if (getModuleId(p) == groupRef && getFunctionId(p) == groupRef
140 12408 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
141 12366 : delArgument(p, p->retc - 1);
142 12366 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
143 12366 : actions++;
144 12366 : continue;
145 : }
146 23847538 : if (getModuleId(p) == groupRef && getFunctionId(p) == subgroupRef
147 3355 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
148 3355 : delArgument(p, p->retc - 1);
149 3355 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
150 3355 : actions++;
151 3355 : continue;
152 : }
153 23844183 : if (getModuleId(p) == groupRef && getFunctionId(p) == subgroupdoneRef
154 12581 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
155 12268 : delArgument(p, p->retc - 1);
156 12268 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
157 12268 : actions++;
158 12268 : continue;
159 : }
160 23831915 : if (getModuleId(p) == groupRef && getFunctionId(p) == groupdoneRef
161 28909 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
162 19454 : delArgument(p, p->retc - 1);
163 19454 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
164 19454 : actions++;
165 19454 : continue;
166 : }
167 : /* POSTFIX ACTION FOR SORT, could be dropping the last two */
168 23812461 : if (getModuleId(p) == algebraRef && getFunctionId(p) == sortRef
169 23591 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
170 10121 : delArgument(p, p->retc - 1);
171 10121 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
172 10121 : actions++;
173 10121 : if (getModuleId(p) == algebraRef && getFunctionId(p) == sortRef
174 10121 : && getVarEolife(mb, getArg(p, p->retc - 1)) == i) {
175 3413 : delArgument(p, p->retc - 1);
176 3413 : typeChecker(cntxt->usermodule, mb, p, i, TRUE);
177 3413 : actions++;
178 : }
179 10121 : continue;
180 : }
181 : }
182 : /* Defense line against incorrect plans */
183 483202 : if (actions) {
184 : // msg = chkTypes(cntxt->usermodule, mb, FALSE);
185 : // if (!msg)
186 : // msg = chkFlow(mb);
187 : // if (!msg)
188 : // msg = chkDeclarations(mb);
189 483202 : }
190 : /* keep actions taken as a fake argument */
191 483202 : (void) pushInt(mb, pci, actions);
192 483202 : return msg;
193 : }
|