├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
├── src
├── main
│ └── java
│ │ ├── AlgeNode
│ │ ├── AggNode.java
│ │ ├── AlgeNode.java
│ │ ├── AlgeNodeHelper.java
│ │ ├── EmptyNode.java
│ │ ├── SPJNode.java
│ │ ├── SymbolicAggPair.java
│ │ ├── TableNode.java
│ │ └── UnionNode.java
│ │ ├── AlgeNodeParser
│ │ ├── AggParser.java
│ │ ├── AlgeNodeParser.java
│ │ ├── AlgeNodeParserPair.java
│ │ ├── FilterParser.java
│ │ ├── JoinParser.java
│ │ ├── ProjectParser.java
│ │ ├── TableParser.java
│ │ └── UnionParser.java
│ │ ├── AlgeRule
│ │ ├── AggregateMerge.java
│ │ ├── AlgeRule.java
│ │ ├── AlgeRuleBase.java
│ │ ├── CleanEmpty.java
│ │ ├── ConditionPushAgg.java
│ │ ├── DummyRule.java
│ │ ├── JoinToProject.java
│ │ └── SPJ2Empty.java
│ │ ├── RexNodeHelper
│ │ ├── NotIn.java
│ │ └── RexNodeHelper.java
│ │ ├── SymbolicRexNode
│ │ ├── ArithmeticExpr.java
│ │ ├── ArithmeticPredicate.java
│ │ ├── BoolPredicate.java
│ │ ├── CaseNode.java
│ │ ├── Constant.java
│ │ ├── DumpRexNode.java
│ │ ├── NullPredicate.java
│ │ ├── RexInputRefConstraints.java
│ │ ├── RexNodeBase.java
│ │ ├── RexNodeConverter.java
│ │ ├── RexNodeUtility.java
│ │ ├── RexNotIn.java
│ │ ├── SymbolicColumn.java
│ │ └── UserDeFun.java
│ │ └── Z3Helper
│ │ └── z3Utility.java
└── test
│ └── java
│ ├── SimpleQueryTests
│ ├── JoinEqualOuterJoin.java
│ ├── SimpleAnalysis.java
│ ├── SimpleEmptyTable.java
│ ├── SimpleLeftOuterJoin.java
│ ├── SingleAnalysis.java
│ ├── simpleAgg.java
│ ├── simpleExists.java
│ ├── simpleFilter.java
│ ├── simpleJoin.java
│ ├── simpleParser.java
│ ├── simpleTest.java
│ ├── tableSchema
│ │ ├── ACCOUNT.java
│ │ ├── BONUS.java
│ │ ├── DEPT.java
│ │ └── EMP.java
│ └── testOftest.java
│ └── z3Test1.java
└── testData
└── calcite_tests.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SQL Query Equivalence
2 | A tool for checking equivalence of SQL queries.
3 |
4 | # z3 update
5 | needs to build on z3 4.6 version:
6 | github link: https://github.com/Z3Prover/z3/releases
7 |
8 | # test case
9 | 1. check SimpleTest in test/java/SimpleQuery/Tests.
10 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | GT
8 | equitas
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 8
17 | 8
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | org.apache.calcite
26 | calcite-core
27 | 1.19.0
28 |
29 |
30 | org.hamcrest
31 | hamcrest
32 | 2.1
33 | test
34 |
35 |
36 | com.google.code.gson
37 | gson
38 | 2.8.5
39 |
40 |
41 | junit
42 | junit
43 | 4.12
44 | test
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/AggNode.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import SymbolicRexNode.SymbolicColumn;
4 | import Z3Helper.z3Utility;
5 | import com.microsoft.z3.BoolExpr;
6 | import com.microsoft.z3.Context;
7 | import org.apache.calcite.rel.core.AggregateCall;
8 | import org.apache.calcite.rel.type.RelDataType;
9 | import org.apache.calcite.rex.RexInputRef;
10 | import org.apache.calcite.rex.RexNode;
11 | import org.apache.calcite.sql.SqlKind;
12 |
13 | import java.util.*;
14 |
15 | public class AggNode extends AlgeNode{
16 | static public SqlKind[] distinctInsensitive = {SqlKind.MAX, SqlKind.MIN};
17 | static public SqlKind[] appendableAgg = {SqlKind.MAX, SqlKind.MIN,SqlKind.SUM,SqlKind.COUNT};
18 | private List groupByList;
19 | private List aggregateCallList;
20 | public AggNode(List groupByList, List aggregateCallList, List inputTypes, AlgeNode input, Context z3Context){
21 | List inputs = new ArrayList<>();
22 | inputs.add(input);
23 | List outputExpr = new ArrayList<>();
24 | for(int i=0;i());
30 |
31 | this.groupByList = groupByList;
32 | this.aggregateCallList = aggregateCallList;
33 |
34 | }
35 |
36 | public AlgeNode getInput(){
37 | return this.getInputs().get(0);
38 | }
39 |
40 | public void setAggregateCallList(List aggregateCallList){
41 | this.aggregateCallList = aggregateCallList;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | StringBuilder result = new StringBuilder("Agg Node: \n Group By:(");
47 | for (Integer integer : groupByList) {
48 | result.append(integer).append(",");
49 | }
50 | result.append(")\n AggCallSet: (");
51 | for (AggregateCall aggregateCall : aggregateCallList) {
52 | result.append(aggregateCall.toString()).append(",");
53 | }
54 | result.append(")\n").append(super.toString());
55 | return result.toString();
56 | }
57 |
58 | public boolean constructQPSR (AlgeNode node) {
59 | if (node instanceof AggNode) {
60 | AggNode aggNode = (AggNode) node;
61 | if (aggNode.getInput() instanceof EmptyNode) {
62 | if (this.getInput() instanceof EmptyNode){
63 | this.emptyTableSymbolicColumn();
64 | aggNode.emptyTableSymbolicColumn();
65 | return true;
66 | }
67 | }
68 | if (this.isCartesianEq(aggNode)){
69 | List symbolicAggPairs = new ArrayList<>();
70 | this.constructSymbolicColumns(symbolicAggPairs);
71 | aggNode.constructSymbolicColumns(symbolicAggPairs);
72 | return true;
73 | }
74 | }
75 | return false;
76 | }
77 |
78 | public void emptyTableSymbolicColumn(){
79 | this.symbolicColumns = new ArrayList<>();
80 | for (AggregateCall aggregateCall : this.aggregateCallList){
81 | if (aggregateCall.getAggregation().getKind().equals(SqlKind.COUNT)){
82 | SymbolicColumn value0 = new SymbolicColumn(z3Context.mkInt(0),z3Context.mkFalse(),z3Context);
83 | symbolicColumns.add(value0);
84 | }else{
85 | SymbolicColumn nullValue = new SymbolicColumn(z3Utility.mkDumpValue(aggregateCall.getType(),z3Context),z3Context.mkTrue(),z3Context);
86 | symbolicColumns.add(nullValue);
87 | }
88 | }
89 | }
90 |
91 | public boolean isCartesianEq(AggNode aggNode) {
92 | if (groupByEq(aggNode)) {
93 | return true;
94 | }
95 | return false;
96 | }
97 |
98 | private boolean groupByEq(AggNode node){
99 | AlgeNode input1 = this.getInput();
100 | AlgeNode input2 = node.getInput();
101 | if(input1.constructQPSR(input2)){
102 | this.setVariableConstraints();
103 | node.setVariableConstraints();
104 | return groupByColumnBijective(node);
105 | }
106 | return false;
107 | }
108 |
109 | public void constructSymbolicColumns(List symbolicAggPairs){
110 | this.symbolicColumns = new ArrayList<>();
111 | this.symbolicColumns.addAll(this.getSymbolicGroupByColumns());
112 | this.symbolicColumns.addAll(this.constructSymbolicAggCalls(symbolicAggPairs));
113 | }
114 |
115 | private List constructSymbolicAggCalls(List symbolicAggPairs){
116 | List symbolicAggCalls = new ArrayList<>();
117 | AlgeNode input = this.getInput();
118 | for (AggregateCall aggCall : this.aggregateCallList) {
119 | boolean findMatch = symbolicAggPairs.stream().anyMatch(
120 | (SymbolicAggPair pair) -> {
121 | if (pair.isEqualAggCall(input, aggCall)) {
122 | symbolicAggCalls.add(pair.getSymbolicColumn());
123 | return true;
124 | } else {
125 | return false;
126 | }});
127 | if (!findMatch) {
128 | SymbolicColumn newColumn = SymbolicColumn.mkNewSymbolicColumn(z3Context, aggCall.getType());
129 | symbolicAggCalls.add(newColumn);
130 | symbolicAggPairs.add(new SymbolicAggPair(aggCall, newColumn, input));
131 | }
132 | }
133 | return symbolicAggCalls;
134 | }
135 |
136 | public List getGroupByList(){
137 | return this.groupByList;
138 | }
139 |
140 | public List getGroupByVariables() {
141 | return this.outputExpr.subList(0,this.groupByList.size());
142 | }
143 |
144 | public List getAggregateCallList(){
145 | return this.aggregateCallList;
146 | }
147 |
148 | public List getSymbolicGroupByColumns(){
149 | List symbolicGroupByColumns = new ArrayList<>();
150 | for (int index : this.groupByList) {
151 | symbolicGroupByColumns.add(this.getInput().getSymbolicColumns().get(index));
152 | }
153 | return symbolicGroupByColumns;
154 | }
155 |
156 | private boolean groupByColumnBijective(AggNode node){
157 | List groupByColumn1 = this.getSymbolicGroupByColumns();
158 | List groupByColumn2 = node.getSymbolicGroupByColumns();
159 | if(groupByColumn1.isEmpty() && groupByColumn2.isEmpty()){
160 | return true;
161 | }
162 | BoolExpr env = constructFreshEnv(node);
163 | return groupBySymbolicDecide(env,groupByColumn1, groupByColumn2);
164 |
165 | }
166 |
167 | private boolean groupBySymbolicDecide(BoolExpr env, List groupByColumn1, List groupByColumn2) {
168 | BoolExpr eq1 = freshEq(groupByColumn1);
169 | BoolExpr eq2 = freshEq(groupByColumn2);
170 | BoolExpr Eq1DecideEq2 = z3Context.mkAnd(env,eq1,z3Context.mkNot(eq2));
171 | if(z3Utility.isUnsat(Eq1DecideEq2,z3Context)){
172 | BoolExpr Eq2DecideEq1 = z3Context.mkAnd(env,eq2,z3Context.mkNot(eq1));
173 | return z3Utility.isUnsat(Eq2DecideEq1,z3Context);
174 | }
175 | return false;
176 | }
177 |
178 | private BoolExpr freshEq(List groupByColumn){
179 | List freshColumn = SymbolicColumn.constructFreshColumns(groupByColumn,z3Context);
180 | BoolExpr[] columnEqs1 = new BoolExpr[groupByColumn.size()];
181 | for(int i=0;i columnTypes = new ArrayList<>();
198 | for (RexNode outputExpr : this.outputExpr){
199 | columnTypes.add(outputExpr.getType());
200 | }
201 | List newGroupByList = new ArrayList<>();
202 | for (Integer value : this.groupByList){
203 | int index = value;
204 | newGroupByList.add(index);
205 | }
206 | List newAggregateCallList = new ArrayList<>();
207 | for (AggregateCall oldCall : this.aggregateCallList){
208 | List newArgList = new ArrayList<>();
209 | for (Integer oldArg : oldCall.getArgList()){
210 | int arg = oldArg;
211 | newArgList.add(arg);
212 | }
213 | AggregateCall newCall = oldCall.copy(newArgList,oldCall.filterArg,oldCall.collation);
214 | newAggregateCallList.add(newCall);
215 | }
216 | return (new AggNode(newGroupByList,newAggregateCallList,columnTypes,newInput,this.z3Context));
217 | }
218 | }
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/AlgeNode.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import RexNodeHelper.NotIn;
4 | import SymbolicRexNode.SymbolicColumn;
5 | import Z3Helper.z3Utility;
6 | import com.microsoft.z3.BoolExpr;
7 | import com.microsoft.z3.Context;
8 | import org.apache.calcite.rel.type.RelDataType;
9 | import org.apache.calcite.rex.RexNode;
10 |
11 | import java.util.*;
12 |
13 | abstract public class AlgeNode {
14 | protected Context z3Context;
15 | protected List inputTypes;
16 | protected List inputs;
17 | protected List outputExpr;
18 | protected Set conditions;
19 |
20 | protected List symbolicColumns;
21 | protected SymbolicColumn symbolicCondition;
22 |
23 | protected BoolExpr variableConstraints;
24 |
25 | private boolean rewritable;
26 |
27 |
28 | protected void setBasicFields(Context z3Context, List inputTypes, List inputs, List outputExpr, Set conditions){
29 | this.z3Context = z3Context;
30 | this.inputTypes = inputTypes;
31 | this.inputs = inputs;
32 | this.outputExpr = outputExpr;
33 | this.conditions = conditions;
34 | this.variableConstraints = z3Context.mkTrue();
35 | this.rewritable = true;
36 | }
37 |
38 | public Context getZ3Context() { return this.z3Context; }
39 |
40 | // get basic output types
41 | public List getInputTypes(){
42 | return this.inputTypes;
43 | }
44 |
45 | // get the algebraic nodes inputs
46 | public List getInputs(){
47 | return this.inputs;
48 | }
49 |
50 |
51 | public void setInputs(List inputs){
52 | this.inputs = inputs;
53 | }
54 | // set the output expr
55 | public void setOutputExpr(List outputExpr) {
56 | this.outputExpr = outputExpr;
57 | }
58 |
59 | // return the output expression
60 | public List getOutputExpr(){
61 | return this.outputExpr;
62 | }
63 |
64 | // return the set of filter conditions
65 | public Set getConditions(){
66 | return this.conditions;
67 | }
68 |
69 | //set the filter conditions
70 | public void setConditions(Set conditions){
71 | this.conditions = conditions;
72 | }
73 |
74 | // add one condition into the filter condition
75 | public void addCondition(RexNode condition) {
76 | this.conditions.add(condition);
77 | }
78 |
79 | public void addConditions(Collection conditions) {
80 | this.conditions.addAll(conditions);
81 | }
82 |
83 | // return the symbolic output tuple
84 | public List getSymbolicColumns(){
85 | return this.symbolicColumns;
86 | }
87 |
88 | // check if two nodes symbolic outputs are equivalent with default match
89 | public boolean checkSymbolicOutput(AlgeNode node){
90 | if(this == node){
91 | return true;
92 | }
93 | if(this.getOutputExpr().isEmpty() && node.getOutputExpr().isEmpty()){
94 | return true;
95 | }
96 | List symbolicOutputs1 = this.getSymbolicColumns();
97 | List symbolicOutputs2 = node.getSymbolicColumns();
98 | boolean result = z3Utility.symbolicOutputEqual(buildOutputEnv(node),symbolicOutputs1,symbolicOutputs2,z3Context);
99 | return result;
100 | }
101 |
102 | public boolean checkSymbolicOutput(AlgeNode node, Map columnPairs){
103 | Map simplifyColumnPairs = eliminateMatches(node,columnPairs);
104 | if(simplifyColumnPairs.isEmpty()){
105 | return true;
106 | }
107 |
108 | List symbolicTuple1 = new ArrayList<>();
109 | List symbolicTuple2 = new ArrayList<>();
110 | List symbolicOutputs1 = this.getSymbolicColumns();
111 | List symbolicOutputs2 = node.getSymbolicColumns();
112 |
113 | for(Map.Entry columnPair:simplifyColumnPairs.entrySet()){
114 | symbolicTuple1.add(symbolicOutputs1.get(columnPair.getKey()));
115 | symbolicTuple2.add(symbolicOutputs2.get(columnPair.getValue()));
116 | }
117 |
118 | return z3Utility.symbolicOutputEqual(buildOutputEnv(node),symbolicTuple1,symbolicTuple2,z3Context);
119 | }
120 |
121 | private Map eliminateMatches(AlgeNode node,Map columnPairs){
122 | if(this == node) {
123 | Map newColumnPairs = new HashMap<>();
124 | for (Map.Entry columnPair : columnPairs.entrySet()) {
125 | int key = columnPair.getKey();
126 | int value = columnPair.getValue();
127 | if (key != value) {
128 | newColumnPairs.put(key, value);
129 | }
130 | }
131 | return newColumnPairs;
132 | }else{
133 | return columnPairs;
134 | }
135 | }
136 |
137 | private BoolExpr buildOutputEnv(AlgeNode node){
138 | List env = new ArrayList<>();
139 | env.add(this.getVariableConstraints());
140 | env.add(node.getVariableConstraints());
141 | return z3Utility.mkAnd(env,z3Context);
142 | }
143 |
144 | public boolean isEq(AlgeNode node) {
145 | if(this.constructQPSR(node)){
146 | return checkSymbolicOutput(node);
147 | }
148 | return false;
149 | }
150 |
151 | public boolean isRewritable() {
152 | return rewritable;
153 | }
154 |
155 | public void disableRewrite(){
156 | this.rewritable = false;
157 | }
158 | public void enableRewrite(){
159 | this.rewritable = true;
160 | }
161 |
162 | public BoolExpr getVariableConstraints () {
163 | return this.variableConstraints;
164 | }
165 |
166 | public void setVariableConstraints () {
167 | List childrenAssign = new ArrayList<>();
168 | for (AlgeNode child : this.inputs){
169 | childrenAssign.add(child.variableConstraints);
170 | }
171 | this.variableConstraints = z3Utility.mkAnd(childrenAssign,z3Context);
172 | }
173 |
174 | abstract public boolean constructQPSR(AlgeNode node);
175 |
176 | @Override
177 | public String toString() {
178 | StringBuilder result = new StringBuilder("outputExpr: (");
179 | for (RexNode rexNode : outputExpr) {
180 | result.append(rexNode.toString());
181 | }
182 | result.append(")\nConditions : (");
183 | for(RexNode condition:conditions){
184 | if (condition instanceof NotIn){
185 | result.append(((NotIn) condition).print());
186 | }else {
187 | result.append("[").append(condition.toString()).append("] , ");
188 | }
189 | }
190 | result.append(")\n inputTables:\n");
191 | for (AlgeNode input : inputs) {
192 | result.append(input.toString()).append("\n");
193 | }
194 | return result.toString();
195 | }
196 | abstract public AlgeNode clone ();
197 | }
198 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/AlgeNodeHelper.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import java.util.*;
4 |
5 | public class AlgeNodeHelper {
6 |
7 | static Map constructListQPSR (List inputs1, List inputs2,boolean isEq){
8 | if(inputs1.size()==inputs2.size()){
9 | Map result = new HashMap<>();
10 | if (inputs1.size() >= 100){
11 | if (checkSimpleMatch(inputs1,inputs2,result,isEq)){
12 | return result;
13 | }
14 | }else {
15 | if (checkInputMatch(inputs1, 0, inputs2, new HashSet<>(), result, isEq)) {
16 | return result;
17 | }
18 | }
19 | }
20 | return null;
21 | }
22 |
23 | static private boolean checkSimpleMatch(List inputs1, List inputs2,Map result,boolean isEq){
24 | for (int i = 0; i inputs1, int index, List inputs2, Set used, Map inputMatches,boolean isEq){
43 | if(index(),new ArrayList<>(),new ArrayList<>(),new HashSet<>());
11 | }
12 |
13 | public boolean constructQPSR(AlgeNode node) {
14 | return (node instanceof EmptyNode);
15 | }
16 |
17 | public AlgeNode clone(){
18 | return (new EmptyNode(this.z3Context));
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return "EmptyTable";
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/SPJNode.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import RexNodeHelper.RexNodeHelper;
4 | import SymbolicRexNode.*;
5 | import Z3Helper.z3Utility;
6 | import com.microsoft.z3.BoolExpr;
7 | import com.microsoft.z3.Context;
8 | import org.apache.calcite.rel.type.RelDataType;
9 | import org.apache.calcite.rex.RexNode;
10 |
11 | import java.util.*;
12 |
13 | public class SPJNode extends AlgeNode{
14 | private List inputSymbolicColumns;
15 |
16 | public SPJNode(List outputExpr,Set conditions, List inputs, Context z3Context){
17 | List types = new ArrayList<>();
18 | for(AlgeNode input: inputs){
19 | types.addAll(input.getInputTypes());
20 | }
21 | setBasicFields(z3Context,types,inputs,outputExpr,conditions);
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "SPJ Node: " + "\n" + super.toString();
27 | }
28 |
29 |
30 | public boolean constructQPSR (AlgeNode node) {
31 | if (node instanceof SPJNode) {
32 | SPJNode spjNode = (SPJNode) node;
33 | if (this.isCartesianEq(spjNode)){
34 | RexNodeUtility.reset();
35 | this.constructSR();
36 | spjNode.constructSR();
37 | RexNodeUtility.reset();
38 | return true;
39 | }
40 | }
41 | return false;
42 | }
43 |
44 | public boolean isCartesianEq(SPJNode spjNode) {
45 | Map inputMatches = checkInputMatch(spjNode);
46 | if(inputMatches!=null){
47 | this.constructSymbolicColumns();
48 | spjNode.constructSymbolicColumns();
49 | this.setVariableConstraints();
50 | spjNode.setVariableConstraints();
51 | RexNodeUtility.reset();
52 | boolean result = checkSymbolicCondition(spjNode);
53 | RexNodeUtility.reset();
54 | return result;
55 | }
56 | return false;
57 | }
58 |
59 | // construct the symbolic conditions based the symbolic inputs
60 | public SymbolicColumn constructSymbolicCondition(){
61 | List assign = new ArrayList<>();
62 | if(this.conditions.isEmpty()){
63 | this.symbolicCondition = new SymbolicColumn(z3Context.mkTrue(),z3Context.mkFalse(),z3Context);
64 | }else{
65 | this.symbolicCondition = BoolPredicate.getAndNodeSymbolicColumn(this.conditions,this.inputSymbolicColumns,assign,z3Context);
66 | }
67 | assign.add(this.variableConstraints);
68 | this.variableConstraints = z3Utility.mkAnd(assign,z3Context);
69 | return this.symbolicCondition;
70 | }
71 |
72 | /**
73 | * Check if the symbolic condition for this node is logically equivalent to that of another node.
74 | */
75 | private boolean checkSymbolicCondition(SPJNode node){
76 | SymbolicColumn condition1 = this.constructSymbolicCondition();
77 | SymbolicColumn condition2 = node.constructSymbolicCondition();
78 | List env = new ArrayList<>();
79 | env.add(this.variableConstraints);
80 | env.add(node.getVariableConstraints());
81 | if (z3Utility.isConditionEq(env, condition1.isValueTrue(), condition2.isValueTrue(), z3Context)){
82 | this.joinCondition(condition1.isValueTrue());
83 | node.joinCondition(condition2.isValueTrue());
84 | return true;
85 | }
86 | return false;
87 | }
88 |
89 | public void joinCondition(BoolExpr condition){
90 | this.variableConstraints = z3Context.mkAnd(this.variableConstraints,condition);
91 | }
92 |
93 | public void constructSR () {
94 | List assign = new ArrayList<>();
95 | this.symbolicColumns = new ArrayList<>();
96 | for (RexNode rexNode : this.outputExpr) {
97 | RexNodeBase converter = RexNodeConverter.rexConstraints(this.inputSymbolicColumns, rexNode, z3Context);
98 | this.symbolicColumns.add(converter.getOutput());
99 | assign.addAll(converter.getAssignConstrains());
100 | }
101 | assign.add(this.variableConstraints);
102 | this.variableConstraints = z3Utility.mkAnd(assign,z3Context);
103 | }
104 |
105 | public void constructSymbolicColumns () {
106 | this.inputSymbolicColumns = new ArrayList<>();
107 | for (AlgeNode input : this.inputs ){
108 | for (SymbolicColumn symbolicColumn : input.getSymbolicColumns()){
109 | this.inputSymbolicColumns.add(symbolicColumn);
110 | }
111 | }
112 | }
113 |
114 | private Map checkInputMatch(SPJNode node){
115 | List inputs1 = this.inputs;
116 | List inputs2 = node.getInputs();
117 | return AlgeNodeHelper.constructListQPSR(inputs1,inputs2,false);
118 | }
119 |
120 | public AlgeNode clone () {
121 | List newInputs = new ArrayList<>();
122 | for (AlgeNode input : this.inputs){
123 | newInputs.add(input.clone());
124 | }
125 | List newInputExprs = new ArrayList<>();
126 | int offSize = 0;
127 | for (AlgeNode input : newInputs){
128 | for (RexNode inputExpr : input.getOutputExpr()){
129 | newInputExprs.add(RexNodeHelper.addOffSize(inputExpr,offSize));
130 | }
131 | offSize = offSize+input.getOutputExpr().size();
132 | }
133 | List newOutputExprs = new ArrayList<>();
134 | for (RexNode oldOutputExpr : this.outputExpr){
135 | newOutputExprs.add(RexNodeHelper.substitute(oldOutputExpr,newInputExprs));
136 | }
137 | Set newConditions = new HashSet<>();
138 | for (RexNode oldCondition : this.conditions){
139 | newConditions.add(RexNodeHelper.substitute(oldCondition,newInputExprs));
140 | }
141 | return (new SPJNode(newOutputExprs,newConditions,newInputs,this.z3Context));
142 |
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/SymbolicAggPair.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import SymbolicRexNode.SymbolicColumn;
4 | import org.apache.calcite.rel.core.AggregateCall;
5 | import org.apache.calcite.sql.SqlAggFunction;
6 | import org.apache.calcite.sql.SqlKind;
7 |
8 | import java.util.HashMap;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | public class SymbolicAggPair {
13 |
14 | private AggregateCall aggCall;
15 | private SymbolicColumn symbolicColumn;
16 | private AlgeNode input;
17 |
18 | public SymbolicAggPair(AggregateCall aggCall, SymbolicColumn symbolicColumn, AlgeNode input) {
19 | this.aggCall = aggCall;
20 | this.symbolicColumn = symbolicColumn;
21 | this.input = input;
22 | }
23 |
24 | public boolean isEqualAggCall(AlgeNode cpInput, AggregateCall aggCall2) {
25 | if(isCallEqual(this.aggCall,aggCall2)){
26 | List args1 = this.aggCall.getArgList();
27 | List args2 = aggCall2.getArgList();
28 | if(args1.size()==args2.size()) {
29 | return input.checkSymbolicOutput(cpInput, constructColumnPairs(args1, args2));
30 | }
31 | }
32 | return false;
33 | }
34 |
35 | public SymbolicColumn getSymbolicColumn() {
36 | return symbolicColumn;
37 | }
38 |
39 | private Map constructColumnPairs(List args1, List args2) {
40 | Map columnPairs = new HashMap<>();
41 | for(int i=0;i columnTypes, Context z3Context) {
14 | List columns = constructColumns(columnTypes);
15 | List emptyInputTables = new ArrayList<>();
16 | Set emptyFilterCondition = new HashSet<>();
17 | setBasicFields(z3Context, columnTypes, emptyInputTables, columns, emptyFilterCondition);
18 | this.name = name;
19 | }
20 |
21 | private List constructColumns (List columnTypes){
22 | List columns = new ArrayList<>();
23 | int count = 0;
24 | for (RelDataType columnType:columnTypes){
25 | RexInputRef expr = new RexInputRef(count, columnType);
26 | columns.add(expr);
27 | count++;
28 | }
29 | return columns;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return "Table: " + name + "\n" + super.toString();
35 | }
36 |
37 | public String getName(){
38 | return this.name;
39 | }
40 |
41 | public boolean constructQPSR(AlgeNode node){
42 | if (node instanceof TableNode){
43 | TableNode tableNode = (TableNode) node;
44 | if (this.isCartesianEq(tableNode)){
45 | this.constructQPSR(tableNode);
46 | this.variableConstraintTrue();
47 | tableNode.variableConstraintTrue();
48 | return true;
49 | }
50 | }
51 | return false;
52 | }
53 |
54 | public boolean isCartesianEq(TableNode tableNode) {
55 | if (this.name.equals(tableNode.getName())) {
56 | return true;
57 | }
58 | return false;
59 | }
60 |
61 |
62 | private void constructQPSR(TableNode node){
63 | List symbolicTuple = SymbolicColumn.constructSymbolicTuple(inputTypes,z3Context);
64 | this.setSymbolicColumns(symbolicTuple);
65 | node.setSymbolicColumns(symbolicTuple);
66 | }
67 |
68 | public void setSymbolicColumns(List symbolicTuple){
69 | this.symbolicColumns = symbolicTuple;
70 | }
71 |
72 | public void variableConstraintTrue () {
73 | this.variableConstraints = z3Context.mkTrue();
74 | }
75 |
76 | public AlgeNode clone () {
77 | List columnsTypes = new ArrayList<>();
78 | for (RexNode expr : this.outputExpr ){
79 | columnsTypes.add(expr.getType());
80 | }
81 | return (new TableNode(this.name,columnsTypes,z3Context));
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNode/UnionNode.java:
--------------------------------------------------------------------------------
1 | package AlgeNode;
2 |
3 | import RexNodeHelper.RexNodeHelper;
4 | import SymbolicRexNode.SymbolicColumn;
5 | import Z3Helper.z3Utility;
6 | import com.microsoft.z3.BoolExpr;
7 | import com.microsoft.z3.Context;
8 | import org.apache.calcite.rel.type.RelDataType;
9 | import org.apache.calcite.rex.RexInputRef;
10 | import org.apache.calcite.rex.RexNode;
11 |
12 | import java.util.*;
13 |
14 | public class UnionNode extends AlgeNode{
15 | public UnionNode(List inputTables, Context z3Context, List inputTypes){
16 | Set conditions = new HashSet<>();
17 | List outputExpr = new ArrayList<>();
18 | for(int i=0;i inputMatches = findEqMatches(unionNode);
38 | if (inputMatches != null){
39 | this.constructQPSR(unionNode);
40 | return true;
41 | }
42 | }
43 | return false;
44 | }
45 |
46 | public boolean constructQPSR1 (AlgeNode node){
47 | if (node instanceof UnionNode){
48 | UnionNode unionNode = (UnionNode) node;
49 | Map inputMatches = findQPSRMatches(unionNode);
50 | if (inputMatches != null){
51 | List boolPredicates = new ArrayList<>();
52 | int count = 0;
53 | while (count leftPredicates = new ArrayList<>();
58 | List rightPreicates = new ArrayList<>();
59 | for (Map.Entry pairs : inputMatches.entrySet()){
60 | leftPredicates.add(boolPredicates.get(pairs.getKey()));
61 | rightPreicates.add(boolPredicates.get(pairs.getValue()));
62 | }
63 | this.constructSR(leftPredicates);
64 | unionNode.constructSR(rightPreicates);
65 | return true;
66 | }
67 | }
68 | return false;
69 | }
70 |
71 | private void constructSR(List boolPredicates) {
72 | List outputTypes = new ArrayList<>();
73 | for (RexNode outputExpr : this.inputs.get(0).getOutputExpr()){
74 | outputTypes.add(outputExpr.getType());
75 | }
76 | this.symbolicColumns = SymbolicColumn.constructSymbolicTuple(outputTypes,z3Context);
77 | List columnsEqs = new ArrayList<>();
78 | List predicateRelations = new ArrayList<>();
79 | for (int i=0;i variableConstraints = new ArrayList<>();
86 | BoolExpr orColumnsEqs = z3Utility.mkAnd(columnsEqs,z3Context);
87 | BoolExpr orFalse = z3Utility.mkAnd(predicateRelations,z3Context);
88 | BoolExpr onHolds = z3Utility.mkOr(boolPredicates,z3Context);
89 | variableConstraints.add(orColumnsEqs);
90 | variableConstraints.add(orFalse);
91 | variableConstraints.add(onHolds);
92 | this.setVariableConstraints();
93 | variableConstraints.add(this.variableConstraints);
94 | this.variableConstraints = z3Utility.mkAnd(variableConstraints,z3Context);
95 | }
96 |
97 | private BoolExpr exceptOneFalse(List boolPredicates, int index){
98 | if (boolPredicates.size() > 1) {
99 | BoolExpr truePredicate = boolPredicates.get(index);
100 | BoolExpr[] allFalse = new BoolExpr[boolPredicates.size() - 1];
101 | int count = 0;
102 | for (int i = 0; i < boolPredicates.size(); i++) {
103 | if (i != index){
104 | allFalse[count] = z3Context.mkNot(boolPredicates.get(i));
105 | count++;
106 | }
107 | }
108 | return z3Context.mkImplies(truePredicate,z3Context.mkAnd(allFalse));
109 | }else{
110 | return z3Context.mkTrue();
111 | }
112 | }
113 |
114 | private void constructQPSR (UnionNode unionNode){
115 | List outputTypes = new ArrayList<>();
116 | for (RexNode outputExpr : this.inputs.get(0).getOutputExpr()){
117 | outputTypes.add(outputExpr.getType());
118 | }
119 | this.symbolicColumns = SymbolicColumn.constructSymbolicTuple(outputTypes,z3Context);
120 | unionNode.setSymbolicColumns(this.symbolicColumns);
121 | this.variableConstraintTrue();
122 | unionNode.variableConstraintTrue();
123 | }
124 |
125 | public void setSymbolicColumns(List symbolicTuple){
126 | this.symbolicColumns = symbolicTuple;
127 | }
128 |
129 | public void variableConstraintTrue () {
130 | this.variableConstraints = z3Context.mkTrue();
131 | }
132 |
133 | private Map findEqMatches(UnionNode node){
134 | List inputs1 = this.getInputs();
135 | List inputs2 = node.getInputs();
136 | return AlgeNodeHelper.constructListQPSR(inputs1,inputs2,true);
137 | }
138 |
139 | private Map findQPSRMatches(UnionNode node){
140 | List inputs1 = this.getInputs();
141 | List inputs2 = node.getInputs();
142 | return AlgeNodeHelper.constructListQPSR(inputs1,inputs2,false);
143 | }
144 |
145 | public AlgeNode clone () {
146 | List newInputs = new ArrayList<>();
147 | for (AlgeNode input : this.inputs){
148 | newInputs.add(input.clone());
149 | }
150 | List columnTypes = new ArrayList<>();
151 | for (RexNode outputExpr : this.outputExpr){
152 | columnTypes.add(outputExpr.getType());
153 | }
154 | return (new UnionNode(newInputs,this.z3Context,columnTypes));
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/AggParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.AggNode;
5 | import AlgeNode.TableNode;
6 | import AlgeNode.SPJNode;
7 | import AlgeRule.JoinToProject;
8 | import SymbolicRexNode.SymbolicColumn;
9 |
10 | import com.microsoft.z3.Context;
11 |
12 | import org.apache.calcite.plan.RelOptUtil;
13 | import org.apache.calcite.rel.RelNode;
14 | import org.apache.calcite.rel.core.AggregateCall;
15 | import org.apache.calcite.rel.logical.LogicalAggregate;
16 | import org.apache.calcite.rel.type.RelDataType;
17 | import org.apache.calcite.rex.RexNode;
18 |
19 | import java.util.ArrayList;
20 | import java.util.HashSet;
21 | import java.util.List;
22 | import java.util.Set;
23 |
24 |
25 | public class AggParser extends AlgeNodeParser{
26 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
27 | LogicalAggregate aggregate = (LogicalAggregate) input;
28 | AlgeNode inputNode = AlgeNodeParserPair.constructAlgeNode(aggregate.getInput(),z3Context);
29 | if (trivialAgg(aggregate, inputNode)){
30 | return inputNode;
31 | }
32 | List groupByList = aggregate.getGroupSet().asList();
33 | ArrayList columnTypes = new ArrayList<>();
34 | for(int i=0;i aggregateCallList = aggregate.getAggCallList();
40 | for(int i=0;i groupByList = aggregate.getGroupSet().asList();
50 | if (aggregate.getAggCallList().isEmpty()){
51 | if (groupByList.size() == 1){
52 | int index = groupByList.get(0);
53 | List subInputs = input.getInputs();
54 | int count = 0;
55 | for (AlgeNode subInput : subInputs){
56 | if (count <= index && index < count + subInput.getOutputExpr().size()){
57 | int fixIndex = index - count;
58 | if (subInput instanceof TableNode){
59 | String tableName = ((TableNode)subInput).getName();
60 | if (JoinToProject.checkKeyIndex(tableName) == fixIndex){
61 | if (subInputs.size() == 1) {
62 | return true;
63 | }else{
64 | System.out.println(RelOptUtil.toString(aggregate));
65 | }
66 | }
67 | }
68 | }else{
69 | count = count + subInput.getOutputExpr().size();
70 | }
71 | }
72 | }
73 | }
74 | return false;
75 | }
76 |
77 | static public AlgeNode distinctToAgg (AlgeNode input){
78 | List groupByList = new ArrayList<>();
79 | for (int i=0;i columnTypes = new ArrayList<>();
83 | for(int i=0;i aggregateCallList = new ArrayList<>();
87 | AggNode newAggNode = new AggNode(groupByList,aggregateCallList,columnTypes,input,input.getZ3Context());
88 | return JoinParser.wrapBySPJ(newAggNode,input.getZ3Context());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/AlgeNodeParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import com.microsoft.z3.Context;
5 | import org.apache.calcite.rel.RelNode;
6 |
7 | public abstract class AlgeNodeParser {
8 | abstract public AlgeNode constructRelNode(RelNode input, Context z3Context);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/AlgeNodeParserPair.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import com.microsoft.z3.Context;
5 | import org.apache.calcite.rel.RelNode;
6 | import org.apache.calcite.rel.core.TableScan;
7 | import org.apache.calcite.rel.logical.*;
8 |
9 | public enum AlgeNodeParserPair {
10 | Projection(LogicalProject.class,ProjectParser.class),
11 | Table(TableScan.class,TableParser.class),
12 | Filter(LogicalFilter.class,FilterParser.class),
13 | Join(LogicalJoin.class, JoinParser.class),
14 | Aggregate(LogicalAggregate.class,AggParser.class),
15 | Union(LogicalUnion.class,UnionParser.class)
16 | ;
17 | private final Class relNode;
18 | private final Class parserClass;
19 |
20 | AlgeNodeParserPair(Class relNode, Class converterClass) {
21 | this.relNode = relNode;
22 | this.parserClass = converterClass;
23 | }
24 |
25 | public Class getRelNode() {
26 | return this.relNode;
27 | }
28 |
29 | public Class getParserClass() {
30 | return this.parserClass;
31 | }
32 |
33 | public static AlgeNode constructAlgeNode(RelNode input,Context z3Context) {
34 | for (AlgeNodeParserPair parserPair : AlgeNodeParserPair.values()) {
35 | if (parserPair.getRelNode().isInstance(input)) {
36 | AlgeNodeParser parser = null;
37 | try {
38 | parser = (AlgeNodeParser) parserPair.getParserClass().getDeclaredConstructor().newInstance();
39 | } catch (Exception e) {
40 | System.out.println("here is an exception");
41 | System.out.println(e);
42 | }
43 | if (parser != null) {
44 | return parser.constructRelNode(input,z3Context);
45 | }
46 | }
47 | }
48 | System.out.println("this class: "+input.getClass()+" has not been handled in construct algeNode");
49 | return null;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/FilterParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.SPJNode;
5 | import AlgeNode.UnionNode;
6 | import RexNodeHelper.RexNodeHelper;
7 | import com.microsoft.z3.Context;
8 | import org.apache.calcite.rel.RelNode;
9 | import org.apache.calcite.rel.logical.LogicalFilter;
10 | import org.apache.calcite.rex.RexCall;
11 | import org.apache.calcite.rex.RexNode;
12 | import org.apache.calcite.sql.SqlKind;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | public class FilterParser extends AlgeNodeParser{
18 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
19 | LogicalFilter filter = (LogicalFilter)input;
20 | AlgeNode inputNode = AlgeNodeParserPair.constructAlgeNode(filter.getInput(),z3Context);
21 | if (inputNode instanceof UnionNode){
22 | return distributeCondition((UnionNode) inputNode, filter.getCondition());
23 | }
24 | if (inputNode instanceof SPJNode){
25 | return SPJNode(inputNode,filter.getCondition());
26 | }
27 | else{
28 | System.out.println("error in filter parser"+inputNode.toString());
29 | return inputNode;
30 | }
31 | }
32 | private AlgeNode SPJNode(AlgeNode spjNode,RexNode condition){
33 | RexNode newCondition = RexNodeHelper.substitute(condition,spjNode.getOutputExpr());
34 | spjNode.addConditions(conjunctiveForm(newCondition));
35 | return spjNode;
36 | }
37 |
38 | private UnionNode distributeCondition(UnionNode unionNode, RexNode condition){
39 | for(AlgeNode input: unionNode.getInputs()){
40 | RexNode newCondition = RexNodeHelper.substitute(condition,input.getOutputExpr());
41 | input.addConditions(conjunctiveForm(newCondition));
42 | }
43 | return unionNode;
44 | }
45 |
46 | static public List conjunctiveForm(RexNode condition){
47 | if(condition instanceof RexCall){
48 | RexCall rexCall = (RexCall) condition;
49 | if(rexCall.isA(SqlKind.AND)){
50 | return rexCall.getOperands();
51 | }
52 | }
53 | List result = new ArrayList<>();
54 | result.add(condition);
55 | return result;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/JoinParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.SPJNode;
5 | import AlgeNode.UnionNode;
6 | import AlgeNode.AggNode;
7 | import AlgeRule.AlgeRule;
8 | import RexNodeHelper.RexNodeHelper;
9 | import RexNodeHelper.NotIn;
10 | import com.microsoft.z3.Context;
11 | import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
12 | import org.apache.calcite.rel.RelNode;
13 | import org.apache.calcite.rel.core.JoinRelType;
14 | import org.apache.calcite.rel.logical.LogicalJoin;
15 | import org.apache.calcite.rel.type.RelDataType;
16 | import org.apache.calcite.rel.type.RelDataTypeFactory;
17 | import org.apache.calcite.rel.type.RelDataTypeSystem;
18 | import org.apache.calcite.rex.RexBuilder;
19 | import org.apache.calcite.rex.RexCall;
20 | import org.apache.calcite.rex.RexLiteral;
21 | import org.apache.calcite.rex.RexNode;
22 | import org.apache.calcite.sql.SqlKind;
23 |
24 | import java.util.ArrayList;
25 | import java.util.HashSet;
26 | import java.util.List;
27 | import java.util.Set;
28 |
29 | public class JoinParser extends AlgeNodeParser{
30 | static RelDataTypeFactory typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
31 | static RexBuilder nullBuilder = new RexBuilder(typeFactory);
32 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
33 | LogicalJoin joinNode = (LogicalJoin) input;
34 | AlgeNode leftNode = AlgeNodeParserPair.constructAlgeNode(joinNode.getLeft(),z3Context);
35 | AlgeNode rightNode = AlgeNodeParserPair.constructAlgeNode(joinNode.getRight(),z3Context);
36 | RexNode joinCondition = joinNode.getCondition();
37 | List result = innerJoinAll(leftNode,rightNode,z3Context,joinCondition);
38 | if(joinNode.getJoinType() == JoinRelType.INNER) {
39 | return constructNode(result,z3Context);
40 | }
41 | if (joinCondition.getKind() == SqlKind.IS_TRUE) {
42 | return constructNode(result,z3Context);
43 | }
44 | if (joinCondition.getKind() == SqlKind.LITERAL) {
45 | RexLiteral maybeTrue = (RexLiteral) joinCondition;
46 | if (maybeTrue.isAlwaysTrue()){
47 | return constructNode(result,z3Context);
48 | }
49 | }
50 | if(joinNode.getJoinType() == JoinRelType.LEFT){
51 | result.addAll(leftJoinAll(leftNode,rightNode,joinCondition,z3Context));
52 | return constructNode(result,z3Context);
53 | }
54 | if(joinNode.getJoinType() == JoinRelType.RIGHT){
55 | result.addAll(rightJoinAll(leftNode,rightNode,joinCondition,z3Context));
56 | return constructNode(result,z3Context);
57 | }
58 | if(joinNode.getJoinType() == JoinRelType.FULL){
59 | result.addAll(leftJoinAll(leftNode,rightNode,joinCondition,z3Context));
60 | result.addAll(rightJoinAll(leftNode,rightNode,joinCondition,z3Context));
61 | return constructNode(result,z3Context);
62 | }
63 | else{
64 | System.out.println("what is the join type? "+joinNode.getJoinType().toString());
65 | System.exit(1);
66 | }
67 | return null;
68 | }
69 |
70 | private AlgeNode constructNode (List result,Context z3Context){
71 | if (result.size() == 1) {
72 | return result.get(0);
73 | }else{
74 | List inputTypes = new ArrayList<>();
75 | for(RexNode column:result.get(0).getOutputExpr()){
76 | inputTypes.add(column.getType());
77 | }
78 | return new UnionNode(result,z3Context,inputTypes);
79 | }
80 | }
81 |
82 | private List innerJoinAll (AlgeNode leftNode, AlgeNode rightNode, Context z3Context, RexNode joinCondition) {
83 | List leftInputs = new ArrayList<>();
84 | if (leftNode instanceof UnionNode) {
85 | leftInputs.addAll(leftNode.getInputs());
86 | }else{
87 | leftInputs.add(leftNode);
88 | }
89 | List rightInputs = new ArrayList<>();
90 | if (rightNode instanceof UnionNode) {
91 | rightInputs.addAll(rightNode.getInputs());
92 | }else{
93 | rightInputs.add(rightNode);
94 | }
95 | List result = new ArrayList<>();
96 | for (AlgeNode left : leftInputs) {
97 | for (AlgeNode right: rightInputs){
98 | result.add(innerJoin(left,right,z3Context,joinCondition));
99 | }
100 | }
101 | return result;
102 | }
103 |
104 | private SPJNode innerJoin (AlgeNode leftNode, AlgeNode rightNode ,Context z3Context, RexNode joinCondition) {
105 |
106 | // getInput tables
107 | List inputs = new ArrayList<>();
108 | addInputs(leftNode,inputs);
109 | int offSize = 0;
110 | for (AlgeNode leftInput : inputs) {
111 | offSize = offSize+leftInput.getOutputExpr().size();
112 | }
113 | addInputs(rightNode,inputs);
114 |
115 | // build new output expr;
116 | List newOutputExpr = new ArrayList<>(leftNode.getOutputExpr());
117 |
118 | List rightOutputExpr = rightNode.getOutputExpr();
119 | for (RexNode rexNode : rightOutputExpr) {
120 | newOutputExpr.add(RexNodeHelper.addOffSize(rexNode, offSize));
121 | }
122 |
123 | // build new condition;
124 | Set newCondition = new HashSet<>(leftNode.getConditions());
125 |
126 | Set rightConditions = rightNode.getConditions();
127 | for(RexNode rightCondition:rightConditions){
128 | newCondition.add(RexNodeHelper.addOffSize(rightCondition,offSize));
129 | }
130 | RexNode newJoinCondition = RexNodeHelper.substitute(joinCondition,newOutputExpr);
131 | newCondition.add(newJoinCondition);
132 |
133 |
134 | return new SPJNode(newOutputExpr,newCondition,inputs,z3Context);
135 | }
136 |
137 | private List leftJoinAll (AlgeNode leftNode, AlgeNode rightNode,RexNode joinCondition,Context z3Context){
138 | List leftInputs = new ArrayList<>();
139 | if (leftNode instanceof UnionNode) {
140 | leftInputs.addAll(leftNode.getInputs());
141 | }else{
142 | leftInputs.add(leftNode);
143 | }
144 | List result = new ArrayList<>();
145 | for (AlgeNode left : leftInputs) {
146 | result.add(leftJoin(left,rightNode,joinCondition,z3Context));
147 | }
148 | return result;
149 | }
150 |
151 | private AlgeNode leftJoin(AlgeNode leftNode, AlgeNode rightNode, RexNode joinCondition,Context z3Context) {
152 |
153 | // build new output expr;
154 |
155 | List newOutputExpr = new ArrayList<>(leftNode.getOutputExpr());
156 |
157 | List rightOutputExpr = rightNode.getOutputExpr();
158 | for (RexNode rexNode : rightOutputExpr) {
159 | RexLiteral nullValue = nullBuilder.makeNullLiteral(rexNode.getType());
160 | newOutputExpr.add(nullValue);
161 | }
162 |
163 | // build new condition;
164 | Set newConditions = new HashSet<>(leftNode.getConditions());
165 |
166 | RexNode inCondition = inCondition(leftNode,rightNode,joinCondition,true);
167 | newConditions.add(inCondition);
168 | return new SPJNode(newOutputExpr,newConditions,leftNode.getInputs(),z3Context);
169 | }
170 |
171 | private List rightJoinAll (AlgeNode leftNode, AlgeNode rightNode,RexNode joinCondition,Context z3Context){
172 | List rightInputs = new ArrayList<>();
173 | if (rightNode instanceof UnionNode) {
174 | rightInputs.addAll(rightNode.getInputs());
175 | }else{
176 | rightInputs.add(rightNode);
177 | }
178 | List result = new ArrayList<>();
179 | for (AlgeNode right: rightInputs){
180 | result.add(rightJoin(leftNode,right,joinCondition,z3Context));
181 | }
182 | return result;
183 | }
184 |
185 | private AlgeNode rightJoin(AlgeNode leftNode, AlgeNode rightNode, RexNode joinCondition,Context z3Context){
186 | // build new output expr;
187 | List newOutputExpr = new ArrayList<>();
188 | for (RexNode rexNode : leftNode.getOutputExpr()){
189 | RexLiteral nullValue = nullBuilder.makeNullLiteral(rexNode.getType());
190 | newOutputExpr.add(nullValue);
191 | }
192 |
193 | newOutputExpr.addAll(rightNode.getOutputExpr());
194 |
195 | // build new condition;
196 | Set newConditions = new HashSet<>();
197 | newConditions.addAll(rightNode.getConditions());
198 | RexNode inCondition = inCondition(leftNode,rightNode,joinCondition,false);
199 | newConditions.add(inCondition);
200 | return new SPJNode(newOutputExpr,newConditions,rightNode.getInputs(),z3Context);
201 |
202 | }
203 |
204 | private RexNode inCondition (AlgeNode leftNode, AlgeNode rightNode, RexNode joinCondition, boolean isLeft){
205 | List leftJoinColumns = new ArrayList<>();
206 | List rightJoinColumns = new ArrayList<>();
207 | separateJoinCondition(joinCondition,leftJoinColumns,rightJoinColumns,leftNode.getOutputExpr().size());
208 | if (isLeft) {
209 | AlgeNode newRightNode = rightNode.clone();
210 | updateNode(newRightNode, rightJoinColumns);
211 | List properLeftJoinColumns = new ArrayList<>();
212 | for (RexNode leftJoinColumn : leftJoinColumns){
213 | properLeftJoinColumns.add(RexNodeHelper.substitute(leftJoinColumn,leftNode.getOutputExpr()));
214 | }
215 | newRightNode = AlgeRule.normalize(newRightNode);
216 | return (new NotIn(newRightNode,properLeftJoinColumns));
217 | }else{
218 | AlgeNode newLeftNode = leftNode.clone();
219 | updateNode(newLeftNode,leftJoinColumns);
220 | List properRightJoinColumns = new ArrayList<>();
221 | for (RexNode rightJoinColumn : rightJoinColumns){
222 | properRightJoinColumns.add(RexNodeHelper.substitute(rightJoinColumn,rightNode.getOutputExpr()));
223 | }
224 | newLeftNode = AlgeRule.normalize(newLeftNode);
225 | return (new NotIn(newLeftNode,properRightJoinColumns));
226 | }
227 | }
228 |
229 | private void separateJoinCondition (RexNode joinCondition, List leftJoinColumns, List rightJoinColumns,int offSize){
230 | if (joinCondition.getKind() == SqlKind.EQUALS) {
231 | RexCall callNode = (RexCall) joinCondition;
232 | leftJoinColumns.add(callNode.getOperands().get(0));
233 | RexNode rightColumn = callNode.getOperands().get(1);
234 | rightJoinColumns.add(RexNodeHelper.minusOffSize(rightColumn,offSize));
235 | return;
236 | }
237 | if (joinCondition.getKind() == SqlKind.AND ) {
238 | RexCall callNode = (RexCall) joinCondition;
239 | for (RexNode newJoinCondition : callNode.getOperands()){
240 | separateJoinCondition(newJoinCondition,leftJoinColumns,rightJoinColumns,offSize);
241 | }
242 | return;
243 | }
244 | System.out.println("the SQL kind IS NOT support in separateJoinCondition:"+joinCondition.getKind());
245 | return;
246 | }
247 |
248 | private void updateNode (AlgeNode node, List joinColumns){
249 | if (node instanceof SPJNode){
250 | updateSPJ((SPJNode)node,joinColumns);
251 | }else{
252 | for (AlgeNode input : node.getInputs()){
253 | updateSPJ((SPJNode)input,joinColumns);
254 | }
255 | }
256 |
257 | }
258 |
259 | private void updateSPJ (SPJNode spjNode,List joinColumns){
260 | List newOutputExprs = new ArrayList<>();
261 | for (RexNode joinColumn : joinColumns){
262 | newOutputExprs.add(RexNodeHelper.substitute(joinColumn,spjNode.getOutputExpr()));
263 | }
264 | spjNode.setOutputExpr(newOutputExprs);
265 | }
266 |
267 | private void addInputs(AlgeNode child,List inputs){
268 | if(child instanceof SPJNode){
269 | inputs.addAll(child.getInputs());
270 | }else{
271 | inputs.add(child);
272 | }
273 | }
274 |
275 | static public SPJNode wrapBySPJ (AggNode aggNode, Context z3Context){
276 | Set emptyCondition = new HashSet<>();
277 | List inputs = new ArrayList();
278 | inputs.add(aggNode);
279 | return (new SPJNode(aggNode.getOutputExpr(),emptyCondition,inputs,z3Context));
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/ProjectParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.UnionNode;
5 | import AlgeNode.SPJNode;
6 | import RexNodeHelper.RexNodeHelper;
7 | import com.microsoft.z3.Context;
8 | import org.apache.calcite.rel.RelNode;
9 | import org.apache.calcite.rel.logical.LogicalProject;
10 | import org.apache.calcite.rex.RexNode;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class ProjectParser extends AlgeNodeParser{
16 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
17 | LogicalProject project = (LogicalProject) input;
18 | AlgeNode inputNode = AlgeNodeParserPair.constructAlgeNode(project.getInput(),z3Context);
19 | if (inputNode instanceof UnionNode){
20 | updateUnion((UnionNode) inputNode,project.getProjects());
21 | return inputNode;
22 | }
23 | if (inputNode instanceof SPJNode){
24 | updateSPJ(inputNode,project.getProjects());
25 | return inputNode;
26 | }
27 | else {
28 | System.out.println("error in project parser:"+inputNode.toString());
29 | return inputNode;
30 | }
31 | }
32 | private void updateSPJ (AlgeNode spjNode, List columns){
33 | updateOutputExprs(spjNode,columns);
34 | }
35 | private void updateUnion (UnionNode unionNode,List columns){
36 | for (AlgeNode input:unionNode.getInputs()){
37 | updateOutputExprs(input,columns);
38 | }
39 | }
40 | private void updateOutputExprs(AlgeNode inputNode,List columns){
41 | List inputExprs = inputNode.getOutputExpr();
42 | List newOutputExpr = new ArrayList<>();
43 | for (RexNode column:columns){
44 | newOutputExpr.add(RexNodeHelper.substitute(column,inputExprs));
45 | }
46 | inputNode.setOutputExpr(newOutputExpr);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/TableParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.TableNode;
5 | import AlgeNode.SPJNode;
6 | import com.microsoft.z3.Context;
7 | import org.apache.calcite.adapter.enumerable.EnumerableTableScan;
8 | import org.apache.calcite.plan.RelOptTable;
9 | import org.apache.calcite.rel.RelNode;
10 | import org.apache.calcite.rel.type.RelDataType;
11 | import org.apache.calcite.rel.type.RelDataTypeField;
12 | import org.apache.calcite.rex.RexInputRef;
13 | import org.apache.calcite.rex.RexNode;
14 |
15 | import java.util.ArrayList;
16 | import java.util.HashSet;
17 | import java.util.List;
18 | import java.util.Set;
19 |
20 |
21 | public class TableParser extends AlgeNodeParser{
22 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
23 | EnumerableTableScan tableScan = (EnumerableTableScan) input;
24 | RelOptTable table = tableScan.getTable();
25 | String tableName = table.getQualifiedName().get(0);
26 | List columns = tableScan.getRowType().getFieldList();
27 | ArrayList columnTypes = new ArrayList<>();
28 | for (RelDataTypeField column:columns){
29 | columnTypes.add(column.getType());
30 | }
31 | TableNode tableNode = new TableNode(tableName,columnTypes,z3Context);
32 | return wrapBySPJ(tableNode,z3Context);
33 |
34 | }
35 |
36 | private SPJNode wrapBySPJ (TableNode tableNode, Context z3Context){
37 | Set emptyCondition = new HashSet<>();
38 | List inputs = new ArrayList();
39 | inputs.add(tableNode);
40 | return (new SPJNode(tableNode.getOutputExpr(),emptyCondition,inputs,z3Context));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/AlgeNodeParser/UnionParser.java:
--------------------------------------------------------------------------------
1 | package AlgeNodeParser;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.UnionNode;
5 | import com.microsoft.z3.Context;
6 | import org.apache.calcite.rel.RelNode;
7 | import org.apache.calcite.rel.logical.LogicalUnion;
8 | import org.apache.calcite.rel.type.RelDataType;
9 | import org.apache.calcite.rel.type.RelDataTypeField;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class UnionParser extends AlgeNodeParser{
14 | public AlgeNode constructRelNode(RelNode input, Context z3Context){
15 | LogicalUnion logicalUnion = (LogicalUnion) input;
16 | List inputs = new ArrayList();
17 | for(int i=0;i inputTypes = new ArrayList<>();
22 | for(RelDataTypeField field:logicalUnion.getRowType().getFieldList()){
23 | inputTypes.add(field.getType());
24 | }
25 | UnionNode unionNode = new UnionNode(inputs,z3Context,inputTypes);
26 | if (logicalUnion.all){
27 | return unionNode;
28 | }else{
29 | return AggParser.distinctToAgg(unionNode);
30 | }
31 | }
32 | public List normalizeNodes (AlgeNode input){
33 | List result = new ArrayList<>();
34 | if (input instanceof UnionNode){
35 | result.addAll(input.getInputs());
36 | }else{
37 | result.add(input);
38 | }
39 | return result;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/AggregateMerge.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.AggNode;
5 | import AlgeNode.SPJNode;
6 | import AlgeNode.UnionNode;
7 | import RexNodeHelper.RexNodeHelper;
8 | import org.apache.calcite.rel.core.AggregateCall;
9 | import org.apache.calcite.rex.RexInputRef;
10 | import org.apache.calcite.rex.RexNode;
11 | import org.apache.calcite.sql.SqlKind;
12 |
13 | import java.util.*;
14 |
15 | public class AggregateMerge extends AlgeRuleBase{
16 | private List newCalls;
17 | public AggregateMerge(AlgeNode input){
18 | this.input = input;
19 | }
20 | public boolean preCondition() {
21 | if(this.input instanceof AggNode){
22 | AggNode aggNode = (AggNode) this.input;
23 | AlgeNode subInput = aggNode.getInput();
24 | if(subInput instanceof SPJNode){
25 | SPJNode parent = (SPJNode) subInput;
26 | if (parent.getInputs().size() == 1) {
27 | AlgeNode child = parent.getInputs().get(0);
28 | if (child instanceof AggNode){
29 | return canMerge(aggNode,(AggNode) child,parent);
30 | }
31 | }
32 | }
33 | }
34 | return false;
35 | }
36 |
37 | private boolean canMerge (AggNode input, AggNode subInput, SPJNode parent) {
38 | if (GroupByEntail(input,subInput,parent.getOutputExpr())){
39 | if (conditionsNoAgg(subInput,parent.getConditions())){
40 | return isMergeAggCalls(input,subInput,parent.getOutputExpr());
41 | }
42 | }
43 | return false;
44 | }
45 |
46 | private boolean isMergeAggCalls(AggNode input,AggNode subInput,List outputExprs){
47 | this.newCalls = new ArrayList<>();
48 | for(AggregateCall aggregateCall:input.getAggregateCallList()){
49 | if(!isMergeAggCall(aggregateCall,subInput,outputExprs)){
50 | return false;
51 | }
52 | }
53 | return true;
54 | }
55 |
56 | private AggregateCall setDistinct(AggregateCall call){
57 | return AggregateCall.create(call.getAggregation(),true,call.isApproximate(),call.getArgList(),call.filterArg,call.getCollation(),call.getType(),call.getName());
58 | }
59 |
60 | private boolean isMergeAggCall(AggregateCall call,AggNode subInput, List outputExprs){
61 | if(isAppendableAgg(call)){
62 | //TODO: currently only support aggCall take one operands
63 | Integer operand = call.getArgList().get(0);
64 | RexNode inputColumn = outputExprs.get(operand);
65 | int groupBySize = subInput.getGroupByList().size();
66 | if(inputColumn instanceof RexInputRef){
67 | int index = ((RexInputRef)inputColumn).getIndex();
68 | if(index >= groupBySize){
69 | AggregateCall inputAggCall = subInput.getAggregateCallList().get(index - groupBySize);
70 | if(inputAggCall.getAggregation().getKind().equals(call.getAggregation().getKind())){
71 | if ((!inputAggCall.isDistinct()) && (!inputAggCall.isApproximate()) && (!call.isDistinct()) && (!call.isApproximate())){
72 | this.newCalls.add(call);
73 | return true;
74 | }
75 | }else{
76 | return false;
77 | }
78 | }else{
79 | if((index==0) && (groupBySize == 1)){
80 | this.newCalls.add(setDistinct(call));
81 | }else{
82 | this.newCalls.add(call);
83 | }
84 | return true;
85 | }
86 | }
87 | }
88 | return false;
89 | }
90 | private boolean isAppendableAgg(AggregateCall call){
91 | for(SqlKind sqlKind : AggNode.appendableAgg){
92 | if(call.getAggregation().getKind().equals(sqlKind)){
93 | return true;
94 | }
95 | }
96 | return false;
97 | }
98 |
99 | private boolean GroupByEntail (AggNode input, AggNode subInput, List outputExprs){
100 | List subInputGroups = subInput.getGroupByVariables();
101 | for (int index: input.getGroupByList()){
102 | RexNode outputExpr = outputExprs.get(index);
103 | if(!subInputGroups.containsAll(RexNodeHelper.collectVariables(outputExpr))){
104 | return false;
105 | }
106 | }
107 | return true;
108 | }
109 |
110 | private boolean conditionsNoAgg(AggNode input,Set conditions){
111 | List groupByVariables = input.getGroupByVariables();
112 | for(RexNode condition:conditions){
113 | if(!groupByVariables.containsAll(RexNodeHelper.collectVariables(condition))){
114 | return false;
115 | }
116 | }
117 | return true;
118 | }
119 |
120 | public AlgeNode transformation(){
121 | AggNode aggNode = (AggNode) input;
122 | SPJNode parent = (SPJNode) aggNode.getInput();
123 | AggNode child = (AggNode) parent.getInputs().get(0);
124 | AlgeNode childInput = child.getInput();
125 | if (childInput instanceof SPJNode){
126 | normalizeSPJNode((SPJNode) childInput,child);
127 | updateSPJCode((SPJNode)childInput,parent.getOutputExpr(),parent.getConditions());
128 | }
129 | if (childInput instanceof UnionNode){
130 | normalizeUnionNode((UnionNode) childInput,child);
131 | updateUnionNode((UnionNode)childInput,parent.getOutputExpr(),parent.getConditions());
132 | }
133 | List newInput = new ArrayList<>();
134 | newInput.add(childInput);
135 | aggNode.setInputs(newInput);
136 | aggNode.setAggregateCallList(this.newCalls);
137 | return aggNode;
138 | }
139 |
140 | private void normalizeSPJNode (SPJNode input, AggNode aggNode){
141 | List newOutputExpr = new ArrayList<>();
142 | for (Integer columnIndex:aggNode.getGroupByList()){
143 | newOutputExpr.add(input.getOutputExpr().get(columnIndex));
144 | }
145 | for (AggregateCall aggregateCall : aggNode.getAggregateCallList()){
146 | List argList = aggregateCall.getArgList();
147 | if (argList.size() == 1){
148 | newOutputExpr.add(input.getOutputExpr().get(argList.get(0)));
149 | }
150 | }
151 | input.setOutputExpr(newOutputExpr);
152 | }
153 |
154 | private void normalizeUnionNode (UnionNode input, AggNode aggNode){
155 | for (AlgeNode spj : input.getInputs()){
156 | normalizeSPJNode((SPJNode) spj,aggNode);
157 | }
158 | }
159 |
160 | private void updateSPJCode (SPJNode input, List outputExprs, Set conditions){
161 | List newOutputExprs = new ArrayList<>();
162 | for (RexNode oldExpr : outputExprs){
163 | newOutputExprs.add(RexNodeHelper.substitute(oldExpr,input.getOutputExpr()));
164 | }
165 | input.setOutputExpr(newOutputExprs);
166 | for (RexNode condition: conditions){
167 | input.addCondition(RexNodeHelper.substitute(condition,input.getOutputExpr()));
168 | }
169 | }
170 |
171 | private void updateUnionNode (UnionNode input, List outputExprs, Set conditions){
172 | for (AlgeNode spj : input.getInputs()){
173 | updateSPJCode((SPJNode) spj, outputExprs,conditions);
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/AlgeRule.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class AlgeRule {
9 | public static AlgeNode normalize(AlgeNode node){
10 | return pushDownNormalize(pullUpNormalize(node));
11 | }
12 |
13 | private static AlgeNode pullUpNormalize(AlgeNode node){
14 | List pullUpSimplifyRules = new ArrayList<>();
15 | pullUpSimplifyRules.add(SPJ2Empty.class);
16 | pullUpSimplifyRules.add(CleanEmpty.class);
17 | List newInputs = new ArrayList<>();
18 | for (AlgeNode input : node.getInputs()) {
19 | newInputs.add(pullUpNormalize(input));
20 | }
21 | node.setInputs(newInputs);
22 | node = simplifyBaseRules(node,pullUpSimplifyRules);
23 | return node;
24 | }
25 |
26 | private static AlgeNode simplifyBaseRules(AlgeNode node,List simplifyRules) {
27 | boolean canBeRewrite = true;
28 | while (canBeRewrite) {
29 | canBeRewrite = false;
30 | for (Class rule : simplifyRules) {
31 | AlgeRuleBase rulePerform = new DummyRule(node);
32 | try {
33 | rulePerform = (AlgeRuleBase) rule.getDeclaredConstructor(AlgeNode.class).newInstance(node);
34 | } catch (Exception e) {
35 | System.out.println(e);
36 | }
37 | if (rulePerform.preCondition()) {
38 | node = rulePerform.transformation();
39 | node.enableRewrite();
40 | canBeRewrite = true;
41 | }
42 | }
43 | }
44 | return node;
45 | }
46 |
47 | private static AlgeNode pushDownNormalize(AlgeNode node){
48 | List pushDownSimplifyRules = new ArrayList<>();
49 | pushDownSimplifyRules.add(AggregateMerge.class);
50 | pushDownSimplifyRules.add(ConditionPushAgg.class);
51 | pushDownSimplifyRules.add(JoinToProject.class);
52 | node = simplifyBaseRules(node,pushDownSimplifyRules);
53 | List newInputs = new ArrayList<>();
54 | for (AlgeNode input : node.getInputs()) {
55 | newInputs.add(pushDownNormalize(input));
56 | }
57 | node.setInputs(newInputs);
58 | return node;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/AlgeRuleBase.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 |
5 | public abstract class AlgeRuleBase {
6 | protected AlgeNode input;
7 | public abstract boolean preCondition();
8 | public abstract AlgeNode transformation();
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/CleanEmpty.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.UnionNode;
5 | import AlgeNode.AggNode;
6 | import AlgeNode.SPJNode;
7 | import AlgeNode.EmptyNode;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class CleanEmpty extends AlgeRuleBase{
13 | private List unionInputs;
14 |
15 | public CleanEmpty(AlgeNode input) { this.input = input; }
16 |
17 | @Override
18 | public boolean preCondition() {
19 | if (input instanceof UnionNode) {
20 | unionInputs = new ArrayList<>();
21 | for (AlgeNode input : input.getInputs()){
22 | if (!(input instanceof EmptyNode)) {
23 | unionInputs.add(input);
24 | }
25 | }
26 | return (unionInputs.size()==1)||(unionInputs.size() != input.getInputs().size());
27 | }
28 | if (input instanceof AggNode){
29 | AggNode aggNode = (AggNode) input;
30 | if (aggNode.getGroupByList().isEmpty()) {
31 | if (aggNode.getInput() instanceof EmptyNode) {
32 | return true;
33 | }
34 | }
35 | }
36 | if (input instanceof SPJNode){
37 | for (AlgeNode input : input.getInputs()){
38 | if (input instanceof EmptyNode){
39 | return true;
40 | }
41 | }
42 | }
43 | return false;
44 | }
45 |
46 | @Override
47 | public AlgeNode transformation() {
48 | if (this.input instanceof UnionNode){
49 | if (this.unionInputs.isEmpty()){
50 | return (new EmptyNode(this.input.getZ3Context()));
51 | }
52 | if (this.unionInputs.size() == 1) {
53 | return this.unionInputs.get(0);
54 | }else{
55 | this.input.setInputs(this.unionInputs);
56 | return (this.input);
57 | }
58 | }
59 | if (this.input instanceof SPJNode || this.input instanceof AggNode){
60 | return (new EmptyNode(this.input.getZ3Context()));
61 | }
62 | return this.input;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/ConditionPushAgg.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 | import AlgeNode.SPJNode;
5 | import AlgeNode.UnionNode;
6 | import AlgeNode.AggNode;
7 | import AlgeNodeParser.FilterParser;
8 | import RexNodeHelper.RexNodeHelper;
9 | import org.apache.calcite.rex.RexNode;
10 |
11 | import java.util.*;
12 |
13 | public class ConditionPushAgg extends AlgeRuleBase{
14 | private Set pushDownConditions;
15 | private Set nonPushedConditions;
16 | class pushDownCondition {
17 | private int tableIndex;
18 | private RexNode condition;
19 | public pushDownCondition (int tableIndex,RexNode condition){
20 | this.tableIndex = tableIndex;
21 | this.condition = condition;
22 | }
23 |
24 | public int getTableIndex() {
25 | return tableIndex;
26 | }
27 |
28 | public RexNode getCondition() {
29 | return condition;
30 | }
31 | }
32 | public ConditionPushAgg (AlgeNode input){
33 | this.input = input;
34 | }
35 | public boolean preCondition(){
36 | this.pushDownConditions = new HashSet<>();
37 | this.nonPushedConditions = new HashSet<>();
38 | boolean result = false;
39 | if (this.input instanceof SPJNode) {
40 | SPJNode spjNode = (SPJNode) this.input;
41 | Set conditions = spjNode.getConditions();
42 | int offSize = 0;
43 | int tableIndex = 0;
44 | for (AlgeNode input : spjNode.getInputs()) {
45 | if (input instanceof AggNode) {
46 | AggNode aggNode = (AggNode) input;
47 | for (RexNode condition : conditions) {
48 | if (isPushDown(aggNode, condition,offSize)) {
49 | result = true;
50 | RexNode newCondition = offsetCondition(condition, offSize);
51 | this.pushDownConditions.add(new pushDownCondition(tableIndex, newCondition));
52 | }else{
53 | this.nonPushedConditions.add(condition);
54 | }
55 | }
56 | }
57 | offSize = offSize + input.getOutputExpr().size();
58 | tableIndex++;
59 | }
60 | }
61 | return result;
62 | }
63 |
64 | private RexNode offsetCondition (RexNode condition, int offsize) {
65 | return RexNodeHelper.minusOffSize(condition,offsize);
66 | }
67 |
68 | private boolean isPushDown(AggNode aggNode, RexNode condition,int offsize){
69 | List groupByVariables = aggNode.getGroupByVariables();
70 | List newGroupByVariables = new ArrayList<>();
71 | for (RexNode groupByVariable : groupByVariables){
72 | newGroupByVariables.add(RexNodeHelper.addOffSize(groupByVariable,offsize));
73 | }
74 | Set variables = new HashSet<>();
75 | RexNodeHelper.collectVariables(condition,variables);
76 | return groupByVariables.containsAll(variables);
77 | }
78 |
79 | public AlgeNode transformation () {
80 | for (pushDownCondition c : pushDownConditions){
81 | AggNode aggNode = (AggNode) input.getInputs().get(c.getTableIndex());
82 | pushDown(aggNode,c.getCondition());
83 | }
84 | this.input.setConditions(this.nonPushedConditions);
85 | return input;
86 | }
87 |
88 | private AlgeNode pushDown (AggNode aggNode, RexNode condition){
89 | AlgeNode inputNode = aggNode.getInput();
90 | if (inputNode instanceof UnionNode) {
91 | UnionNode unionNode = (UnionNode) inputNode;
92 | for (AlgeNode input : unionNode.getInputs()){
93 | RexNode newCondition = RexNodeHelper.substitute(condition,input.getOutputExpr());
94 | input.addConditions(FilterParser.conjunctiveForm(newCondition));
95 | }
96 | }
97 | if (inputNode instanceof SPJNode) {
98 | RexNode newCondition = RexNodeHelper.substitute(condition,inputNode.getOutputExpr());
99 | inputNode.addConditions(FilterParser.conjunctiveForm(newCondition));
100 | }
101 | return aggNode;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/DummyRule.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import AlgeNode.AlgeNode;
4 |
5 | public class DummyRule extends AlgeRuleBase{
6 | public DummyRule(AlgeNode node) {this.input = node;};
7 |
8 | @Override
9 | public boolean preCondition() {
10 | return false;
11 | }
12 |
13 | @Override
14 | public AlgeNode transformation() {
15 | return this.input;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/AlgeRule/JoinToProject.java:
--------------------------------------------------------------------------------
1 | package AlgeRule;
2 |
3 | import org.apache.calcite.rex.RexCall;
4 | import org.apache.calcite.rex.RexInputRef;
5 | import org.apache.calcite.rex.RexNode;
6 | import org.apache.calcite.rex.RexVisitorImpl;
7 | import org.apache.calcite.sql.SqlKind;
8 |
9 | import com.microsoft.z3.BoolExpr;
10 | import com.microsoft.z3.Context;
11 |
12 | import AlgeNode.AlgeNode;
13 | import AlgeNode.SPJNode;
14 | import AlgeNode.TableNode;
15 | import RexNodeHelper.RexNodeHelper;
16 | import SymbolicRexNode.BoolPredicate;
17 | import SymbolicRexNode.SymbolicColumn;
18 | import Z3Helper.z3Utility;
19 |
20 | import java.util.ArrayList;
21 | import java.util.HashMap;
22 | import java.util.HashSet;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.Set;
26 |
27 | public class JoinToProject extends AlgeRuleBase{
28 | static Map keys;
29 |
30 | private Map> duplicateIndexes;
31 | static public int checkKeyIndex(String name){
32 | if (keys == null){
33 | keys = new HashMap<>();
34 | keys.put("EMP", 0);
35 | keys.put("DEPT", 0);
36 | }
37 | if (keys.containsKey(name)){
38 | return keys.get(name);
39 | }else{
40 | return -1;
41 | }
42 | }
43 | public JoinToProject(AlgeNode input){
44 | this.input = input;
45 | }
46 | public boolean preCondition() {
47 | if (this.input instanceof SPJNode){
48 | SPJNode spjNode = (SPJNode) this.input;
49 | List inputs = spjNode.getInputs();
50 | calculateDuplicateSet(inputs);
51 | // System.out.println("it is here");
52 | // System.out.println(this.input.toString());
53 | return !this.duplicateIndexes.isEmpty();
54 | }
55 | return false;
56 | }
57 |
58 | private void calculateDuplicateSet(List inputs){
59 | Map> nameToTableIndex = new HashMap<>();
60 | int tableIndex = 0;
61 | for (AlgeNode input : inputs){
62 | if (input instanceof TableNode){
63 | TableNode tableNode = (TableNode) input;
64 | String tableName = tableNode.getName();
65 | if (nameToTableIndex.containsKey(tableName)){
66 | Set indexes = nameToTableIndex.get(tableName);
67 | indexes.add(tableIndex);
68 | }else{
69 | Set indexes = new HashSet<>();
70 | indexes.add(tableIndex);
71 | nameToTableIndex.put(tableName,indexes);
72 | }
73 | }
74 | tableIndex++;
75 | }
76 | // System.out.println("first result");
77 | // System.out.println(nameToTableIndex);
78 | this.duplicateIndexes = new HashMap<>();
79 | for (Map.Entry> tableIndexes : nameToTableIndex.entrySet()){
80 | String tableName = tableIndexes.getKey();
81 | Set duplicateIndexes = verifyDuplicateJoin(tableName, tableIndexes.getValue());
82 | // System.out.println("duplicate index:");
83 | // System.out.println(duplicateIndexes);
84 | if (duplicateIndexes.size() > 1){
85 | this.duplicateIndexes.put(tableName, duplicateIndexes);
86 | }
87 | }
88 | }
89 |
90 | private Set verifyDuplicateJoin(String tableName, Set tableIndexes){
91 | SPJNode spjNode = (SPJNode) this.input;
92 | Set conditions = spjNode.getConditions();
93 | List startIndex = new ArrayList<>();
94 | int count = 0;
95 | for (AlgeNode input : spjNode.getInputs()){
96 | startIndex.add(count);
97 | count = count + input.getOutputExpr().size();
98 | }
99 | Set duplicateIndex = new HashSet<>();
100 | int columnIndex = checkKeyIndex(tableName);
101 | if (columnIndex == -1){
102 | return new HashSet<>();
103 | }
104 | for (Integer i1 : tableIndexes){
105 | for (Integer i2 : tableIndexes){
106 | if (!duplicateIndex.contains(i1) || !duplicateIndex.contains(i2)){
107 | int columnIndex1 = startIndex.get(i1) + columnIndex;
108 | int columnIndex2 = startIndex.get(i2) + columnIndex;
109 | if (checkEquivalent(columnIndex1, columnIndex2, conditions)){
110 | duplicateIndex.add(i1);
111 | duplicateIndex.add(i2);
112 | }
113 | }
114 | }
115 | }
116 | return duplicateIndex;
117 | }
118 |
119 | static class EqHelper extends RexVisitorImpl {
120 | boolean isEq = false;
121 | int index1;
122 | int index2;
123 | protected EqHelper (int index1, int index2) {
124 | super(false);
125 | this.index1 = index1;
126 | this.index2 = index2;
127 | }
128 |
129 | public boolean isEq(){
130 | return isEq;
131 | }
132 |
133 | @Override public Void visitCall(RexCall call) {
134 | if (call.getKind().equals(SqlKind.EQUALS)){
135 | RexNode left = call.getOperands().get(0);
136 | RexNode right = call.getOperands().get(1);
137 | if ((left instanceof RexInputRef) && (right instanceof RexInputRef)){
138 | int leftIndex = ((RexInputRef)left).getIndex();
139 | int rightIndex = ((RexInputRef)right).getIndex();
140 | isEq = (leftIndex == index1 && rightIndex == index2) || (rightIndex == index1 && leftIndex == index2);
141 | }
142 | }else {
143 | for (RexNode operand : call.operands) {
144 | operand.accept(this);
145 | }
146 | }
147 | return null;
148 | }
149 |
150 | }
151 |
152 | private boolean checkEquivalent(int index1, int index2, Set conditions){
153 | List symbolicColumns = new ArrayList<>();
154 | Context z3Context = this.input.getZ3Context();
155 | for (int i=0;i assign = new ArrayList<>();
162 | SymbolicColumn symbolicCondition = BoolPredicate.getAndNodeSymbolicColumn(conditions, symbolicColumns ,assign,z3Context);
163 | BoolExpr conditionHold = symbolicCondition.isValueTrue();
164 | List column1 = new ArrayList<>();
165 | column1.add(symbolicColumns.get(index1));
166 | List column2 = new ArrayList<>();
167 | column2.add(symbolicColumns.get(index2));
168 | return z3Utility.symbolicOutputEqual(conditionHold, column1, column2, z3Context);
169 | }
170 |
171 | public AlgeNode transformation() {
172 | // System.out.println("what is repeat");
173 | // System.out.println(this.duplicateIndexes);
174 | // System.out.println("something needs to be done");
175 | Map minTableIndex = new HashMap<>();
176 | for (Map.Entry> duplicateIndex : this.duplicateIndexes.entrySet()){
177 | minTableIndex.put(duplicateIndex.getKey(),getMin(duplicateIndex.getValue()));
178 | }
179 | List newInputs = new ArrayList();
180 | int tableIndex = 0;
181 | Map columnIndexSub = new HashMap<>();
182 | List removedTable = new ArrayList<>();
183 | List newInputStartIndex = new ArrayList<>();
184 | int removedInputs = 0;
185 | int startIndex = 0;
186 | for (AlgeNode input : this.input.getInputs()){
187 | removedTable.add(removedInputs);
188 | newInputStartIndex.add(startIndex);
189 | if (isRemove(input, tableIndex)){
190 | removedInputs++;
191 | buildMap(tableIndex,removedTable, newInputStartIndex, columnIndexSub);
192 | }else{
193 | buildMap(tableIndex, startIndex, columnIndexSub);
194 | startIndex = startIndex + input.getOutputExpr().size();
195 | newInputs.add(input);
196 | }
197 | tableIndex++;
198 | }
199 | List newOutputExprs = new ArrayList<>();
200 | for (RexNode outputExpr : this.input.getOutputExpr()){
201 | newOutputExprs.add(RexNodeHelper.substitute(outputExpr,columnIndexSub));
202 | }
203 | Set newConditions = new HashSet<>();
204 | for (RexNode condition : this.input.getConditions()){
205 | newConditions.add(RexNodeHelper.substitute(condition, columnIndexSub));
206 | }
207 | // System.out.println("after transformation");
208 | // System.out.println(new SPJNode(newOutputExprs, newConditions, newInputs, this.input.getZ3Context()));
209 | return new SPJNode(newOutputExprs, newConditions, newInputs, this.input.getZ3Context());
210 | }
211 |
212 | private void buildMap(int tableIndex, int startIndex, Map columnIndexSub){
213 | int oldStartIndex = getOldStartIndex(tableIndex);
214 | int bound = this.input.getInputs().get(tableIndex).getOutputExpr().size();
215 | for (int i=0; i < bound; i++){
216 | columnIndexSub.put(oldStartIndex+i, startIndex+i);
217 | }
218 | }
219 |
220 | // TODO
221 | private void buildMap(int removeIndex, List tableOffSet, List startIndexes, Map columnIndexSub){
222 | TableNode removeTable = (TableNode) this.input.getInputs().get(removeIndex);
223 | // System.out.println("show again" + this.duplicateIndexes);
224 | // System.out.println("table name:"+removeTable.getName());
225 | // System.out.println();
226 | int minIndex = this.getMin(this.duplicateIndexes.get(removeTable.getName()));
227 | // System.out.println("minIndex:"+minIndex);
228 | // System.out.println("tableOffSet:"+tableOffSet.get(minIndex));
229 | int currentTableIndex = minIndex - tableOffSet.get(minIndex);
230 | int startIndex = startIndexes.get(currentTableIndex);
231 | int oldStartIndex = getOldStartIndex(removeIndex);
232 | for (int i=0; i < removeTable.getOutputExpr().size(); i++){
233 | columnIndexSub.put(oldStartIndex+i, startIndex+i);
234 | }
235 | }
236 |
237 | private int getOldStartIndex(int removeIndex){
238 | int count = 0;
239 | for (int i=0; i copyIndex = this.duplicateIndexes.get(tableNode.getName());
251 | if (copyIndex.contains(tableIndex)){
252 | int minIndex = getMin(copyIndex);
253 | if (minIndex != tableIndex){
254 | return true;
255 | }
256 | }
257 | }
258 | }
259 | return false;
260 | }
261 |
262 | private int getMin (Set