You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2014/01/17 10:23:31 UTC
[01/12] TAJO-501: Rewrite the projection part of logical planning.
Updated Branches:
refs/heads/master 568c52392 -> ebb12b7dc
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin2.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin2.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin2.result
new file mode 100644
index 0000000..178ddd6
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin2.result
@@ -0,0 +1,27 @@
+n_name,r_name
+-------------------------------
+ALGERIA,AFRICA
+ARGENTINA,AMERICA
+BRAZIL,AMERICA
+CANADA,AMERICA
+EGYPT,MIDDLE EAST
+ETHIOPIA,AFRICA
+FRANCE,EUROPE
+GERMANY,EUROPE
+INDIA,ASIA
+INDONESIA,ASIA
+IRAN,MIDDLE EAST
+IRAQ,MIDDLE EAST
+JAPAN,ASIA
+JORDAN,MIDDLE EAST
+KENYA,AFRICA
+MOROCCO,AFRICA
+MOZAMBIQUE,AFRICA
+PERU,AMERICA
+CHINA,ASIA
+ROMANIA,EUROPE
+SAUDI ARABIA,MIDDLE EAST
+VIETNAM,ASIA
+RUSSIA,EUROPE
+UNITED KINGDOM,EUROPE
+UNITED STATES,AMERICA
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin3.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin3.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin3.result
new file mode 100644
index 0000000..9f3123a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin3.result
@@ -0,0 +1,27 @@
+n_name,r_name,p1,p2
+-------------------------------
+ALGERIA,AFRICA,1,1
+ARGENTINA,AMERICA,2,2
+BRAZIL,AMERICA,3,2
+CANADA,AMERICA,4,2
+EGYPT,MIDDLE EAST,5,5
+ETHIOPIA,AFRICA,6,1
+FRANCE,EUROPE,7,4
+GERMANY,EUROPE,8,4
+INDIA,ASIA,9,3
+INDONESIA,ASIA,10,3
+IRAN,MIDDLE EAST,11,5
+IRAQ,MIDDLE EAST,12,5
+JAPAN,ASIA,13,3
+JORDAN,MIDDLE EAST,14,5
+KENYA,AFRICA,15,1
+MOROCCO,AFRICA,16,1
+MOZAMBIQUE,AFRICA,17,1
+PERU,AMERICA,18,2
+CHINA,ASIA,19,3
+ROMANIA,EUROPE,20,4
+SAUDI ARABIA,MIDDLE EAST,21,5
+VIETNAM,ASIA,22,3
+RUSSIA,EUROPE,23,4
+UNITED KINGDOM,EUROPE,24,4
+UNITED STATES,AMERICA,25,2
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin4.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin4.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin4.result
new file mode 100644
index 0000000..b7f95a8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin4.result
@@ -0,0 +1,27 @@
+n_name,r_name,?plus
+-------------------------------
+ALGERIA,AFRICA,0
+ARGENTINA,AMERICA,2
+BRAZIL,AMERICA,3
+CANADA,AMERICA,4
+EGYPT,MIDDLE EAST,8
+ETHIOPIA,AFRICA,5
+FRANCE,EUROPE,9
+GERMANY,EUROPE,10
+INDIA,ASIA,10
+INDONESIA,ASIA,11
+IRAN,MIDDLE EAST,14
+IRAQ,MIDDLE EAST,15
+JAPAN,ASIA,14
+JORDAN,MIDDLE EAST,17
+KENYA,AFRICA,14
+MOROCCO,AFRICA,15
+MOZAMBIQUE,AFRICA,16
+PERU,AMERICA,18
+CHINA,ASIA,20
+ROMANIA,EUROPE,22
+SAUDI ARABIA,MIDDLE EAST,24
+VIETNAM,ASIA,23
+RUSSIA,EUROPE,25
+UNITED KINGDOM,EUROPE,26
+UNITED STATES,AMERICA,25
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin5.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin5.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin5.result
new file mode 100644
index 0000000..ea3b0ff
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin5.result
@@ -0,0 +1,5 @@
+s_acctbal,s_name,p_partkey
+-------------------------------
+4032.68,Supplier#000000002,1
+4192.4,Supplier#000000003,2
+4641.08,Supplier#000000004,3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSelectQuery/testSelectColumnAlias1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSelectQuery/testSelectColumnAlias1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSelectQuery/testSelectColumnAlias1.result
new file mode 100644
index 0000000..eecb82a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSelectQuery/testSelectColumnAlias1.result
@@ -0,0 +1,7 @@
+col1,col2
+-------------------------------
+1,2
+1,2
+2,3
+3,4
+3,4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortAfterGroupby.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortAfterGroupby.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortAfterGroupby.result
index bf94765..be89a9f 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortAfterGroupby.result
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortAfterGroupby.result
@@ -1,4 +1,4 @@
-?max,l_orderkey
+maxq,l_orderkey
-------------------------------
36.0,1
38.0,2
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAlias1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAlias1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAlias1.result
new file mode 100644
index 0000000..81bb293
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAlias1.result
@@ -0,0 +1,7 @@
+l_linenumber,sortkey
+-------------------------------
+1,1
+2,1
+1,2
+1,3
+2,3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAliasKey.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAliasKey.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAliasKey.result
deleted file mode 100644
index 81bb293..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithAliasKey.result
+++ /dev/null
@@ -1,7 +0,0 @@
-l_linenumber,sortkey
--------------------------------
-1,1
-2,1
-1,2
-1,3
-2,3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr1.result
new file mode 100644
index 0000000..81bb293
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr1.result
@@ -0,0 +1,7 @@
+l_linenumber,sortkey
+-------------------------------
+1,1
+2,1
+1,2
+1,3
+2,3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr2.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr2.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr2.result
new file mode 100644
index 0000000..0d447c8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSortQuery/testSortWithExpr2.result
@@ -0,0 +1,7 @@
+l_linenumber,sortkey
+-------------------------------
+1,1
+1,2
+1,3
+2,1
+2,3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion1.result
new file mode 100644
index 0000000..3b4dcf4
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion1.result
@@ -0,0 +1,10 @@
+num
+-------------------------------
+1
+2
+3
+4
+5
+36901
+78002
+123314
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
new file mode 100644
index 0000000..83e693d
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
@@ -0,0 +1,22 @@
+n_nationkey,n_name
+-------------------------------
+16,MOZAMBIQUE
+16,MOZAMBIQUE
+15,MOROCCO
+15,MOROCCO
+14,KENYA
+14,KENYA
+5,ETHIOPIA
+5,ETHIOPIA
+0,ALGERIA
+0,ALGERIA
+0,ALGERIA
+0,ALGERIA
+5,ETHIOPIA
+5,ETHIOPIA
+14,KENYA
+14,KENYA
+15,MOROCCO
+15,MOROCCO
+16,MOZAMBIQUE
+16,MOZAMBIQUE
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion2.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion2.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion2.result
new file mode 100644
index 0000000..d269baa
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion2.result
@@ -0,0 +1,12 @@
+l_orderkey
+-------------------------------
+1
+1
+1
+1
+2
+2
+3
+3
+3
+3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion3.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion3.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion3.result
new file mode 100644
index 0000000..2562bd4
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion3.result
@@ -0,0 +1,4 @@
+total
+-------------------------------
+3
+5
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion4.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion4.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion4.result
new file mode 100644
index 0000000..22227ba
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion4.result
@@ -0,0 +1,3 @@
+?count
+-------------------------------
+2
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion5.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion5.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion5.result
new file mode 100644
index 0000000..22227ba
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion5.result
@@ -0,0 +1,3 @@
+?count
+-------------------------------
+2
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion6.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion6.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion6.result
new file mode 100644
index 0000000..7ccc8c2
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion6.result
@@ -0,0 +1,3 @@
+?count
+-------------------------------
+10
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion7.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion7.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion7.result
new file mode 100644
index 0000000..6a3fbd5
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion7.result
@@ -0,0 +1,12 @@
+orderkey
+-------------------------------
+1
+1
+1
+1
+2
+2
+3
+3
+3
+3
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion8.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion8.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion8.result
new file mode 100644
index 0000000..ba35aa1
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion8.result
@@ -0,0 +1,3 @@
+l_returnflag,l_linestatus
+-------------------------------
+R,F
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion9.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion9.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion9.result
new file mode 100644
index 0000000..482dd52
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion9.result
@@ -0,0 +1,7 @@
+n_nationkey,n_name
+-------------------------------
+16,MOZAMBIQUE
+15,MOROCCO
+14,KENYA
+5,ETHIOPIA
+0,ALGERIA
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-storage/src/main/java/org/apache/tajo/storage/v2/DiskUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-storage/src/main/java/org/apache/tajo/storage/v2/DiskUtil.java b/tajo-core/tajo-core-storage/src/main/java/org/apache/tajo/storage/v2/DiskUtil.java
index 2daf0f5..c50e244 100644
--- a/tajo-core/tajo-core-storage/src/main/java/org/apache/tajo/storage/v2/DiskUtil.java
+++ b/tajo-core/tajo-core-storage/src/main/java/org/apache/tajo/storage/v2/DiskUtil.java
@@ -166,7 +166,6 @@ public class DiskUtil {
int indexEnd = line.indexOf(" ", indexStart + 4);
String deviceName = line.substring(0, indexStart).trim();
- System.out.println(deviceName);
String[] deviceNameTokens = deviceName.split("/");
if(deviceNameTokens.length == 3) {
if("dev".equals(deviceNameTokens[1])) {
[09/12] git commit: TAJO-501: Rewrite the projection part of logical
planning.
Posted by hy...@apache.org.
TAJO-501: Rewrite the projection part of logical planning.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/8e1f989a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/8e1f989a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/8e1f989a
Branch: refs/heads/master
Commit: 8e1f989aad27022371d1c973d5acea68568918db
Parents: b822c28
Author: Hyunsik Choi <hy...@apache.org>
Authored: Fri Jan 17 13:58:53 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Fri Jan 17 15:57:55 2014 +0900
----------------------------------------------------------------------
.../org/apache/tajo/algebra/Aggregation.java | 30 +-
.../apache/tajo/algebra/BetweenPredicate.java | 7 +
.../org/apache/tajo/algebra/BinaryOperator.java | 10 +
.../apache/tajo/algebra/CaseWhenPredicate.java | 19 +
.../java/org/apache/tajo/algebra/CastExpr.java | 16 +-
.../tajo/algebra/ColumnReferenceExpr.java | 44 +-
.../tajo/algebra/CountRowsFunctionExpr.java | 5 +
.../org/apache/tajo/algebra/CreateTable.java | 127 +-
.../org/apache/tajo/algebra/DataTypeExpr.java | 7 +
.../java/org/apache/tajo/algebra/DropTable.java | 7 +
.../apache/tajo/algebra/ExistsPredicate.java | 16 +-
.../main/java/org/apache/tajo/algebra/Expr.java | 3 +
.../org/apache/tajo/algebra/FunctionExpr.java | 6 +
.../tajo/algebra/GeneralSetFunctionExpr.java | 11 +
.../java/org/apache/tajo/algebra/Having.java | 6 +
.../java/org/apache/tajo/algebra/Insert.java | 6 +
.../apache/tajo/algebra/IsNullPredicate.java | 15 +-
.../main/java/org/apache/tajo/algebra/Join.java | 18 +-
.../java/org/apache/tajo/algebra/Limit.java | 6 +
.../org/apache/tajo/algebra/LiteralValue.java | 6 +
.../java/org/apache/tajo/algebra/NamedExpr.java | 89 +
.../org/apache/tajo/algebra/NullLiteral.java | 5 +
.../java/org/apache/tajo/algebra/OpType.java | 2 +-
.../tajo/algebra/PatternMatchPredicate.java | 17 +-
.../org/apache/tajo/algebra/Projection.java | 13 +-
.../java/org/apache/tajo/algebra/Relation.java | 13 +-
.../org/apache/tajo/algebra/RelationList.java | 6 +
.../org/apache/tajo/algebra/ScalarSubQuery.java | 10 +-
.../java/org/apache/tajo/algebra/Selection.java | 5 +
.../org/apache/tajo/algebra/SetOperation.java | 5 +
.../org/apache/tajo/algebra/SignedExpr.java | 6 +
.../tajo/algebra/SimpleTableSubQuery.java | 9 +-
.../main/java/org/apache/tajo/algebra/Sort.java | 25 +-
.../tajo/algebra/TablePrimarySubQuery.java | 10 +-
.../org/apache/tajo/algebra/TargetExpr.java | 67 -
.../org/apache/tajo/algebra/UnaryOperator.java | 6 +
.../org/apache/tajo/algebra/ValueListExpr.java | 6 +
.../java/org/apache/tajo/algebra/TestExpr.java | 9 +-
.../java/org/apache/tajo/catalog/Column.java | 8 +-
.../java/org/apache/tajo/catalog/Schema.java | 111 +-
.../tajo/catalog/partition/PartitionDesc.java | 6 +-
.../org/apache/tajo/catalog/TestColumn.java | 1 -
.../org/apache/tajo/catalog/TestSchema.java | 4 +-
.../apache/tajo/catalog/store/HCatalogUtil.java | 3 +-
.../java/org/apache/tajo/client/TajoClient.java | 12 +-
.../java/org/apache/tajo/datum/Float8Datum.java | 5 +-
.../java/org/apache/tajo/datum/TextDatum.java | 2 +-
.../org/apache/tajo/common/type/TestIPv4.java | 8 +-
.../org/apache/tajo/datum/TestBitDatum.java | 4 +-
.../org/apache/tajo/engine/parser/SQLParser.g4 | 14 +-
.../apache/tajo/engine/eval/AlgebraicUtil.java | 5 +
.../org/apache/tajo/engine/eval/BinaryEval.java | 3 +-
.../apache/tajo/engine/eval/CaseWhenEval.java | 9 +-
.../apache/tajo/engine/eval/EvalTreeUtil.java | 35 +-
.../org/apache/tajo/engine/eval/FieldEval.java | 15 +-
.../org/apache/tajo/engine/eval/InEval.java | 11 +
.../org/apache/tajo/engine/eval/IsNullEval.java | 5 +
.../org/apache/tajo/engine/eval/NotEval.java | 3 +-
.../engine/exception/NoSuchColumnException.java | 2 +-
.../tajo/engine/parser/HiveConverter.java | 18 +-
.../apache/tajo/engine/parser/SQLAnalyzer.java | 39 +-
.../tajo/engine/planner/AlgebraVisitor.java | 112 +-
.../tajo/engine/planner/BaseAlgebraVisitor.java | 256 +--
.../engine/planner/BasicLogicalPlanVisitor.java | 12 +
.../planner/ExplainLogicalPlanVisitor.java | 5 +
.../tajo/engine/planner/ExprAnnotator.java | 622 ++++++
.../apache/tajo/engine/planner/ExprFinder.java | 72 +
.../tajo/engine/planner/ExprNormalizer.java | 259 +++
.../tajo/engine/planner/GroupElement.java | 21 +-
.../apache/tajo/engine/planner/InsertNode.java | 17 +-
.../tajo/engine/planner/LogicalOptimizer.java | 36 +-
.../apache/tajo/engine/planner/LogicalPlan.java | 599 ++----
.../engine/planner/LogicalPlanPreprocessor.java | 301 +++
.../engine/planner/LogicalPlanVerifier.java | 3 -
.../tajo/engine/planner/LogicalPlanVisitor.java | 3 +
.../tajo/engine/planner/LogicalPlanner.java | 1873 +++++++++---------
.../tajo/engine/planner/NamedExprsManager.java | 271 +++
.../engine/planner/PhysicalPlannerImpl.java | 63 +-
.../apache/tajo/engine/planner/PlannerUtil.java | 113 +-
.../apache/tajo/engine/planner/Projector.java | 66 +-
.../engine/planner/RangePartitionAlgorithm.java | 3 +
.../engine/planner/SimpleAlgebraVisitor.java | 210 ++
.../org/apache/tajo/engine/planner/Target.java | 22 +-
.../tajo/engine/planner/TargetListManager.java | 234 ---
.../engine/planner/global/GlobalPlanner.java | 80 +-
.../engine/planner/logical/CreateTableNode.java | 12 +-
.../engine/planner/logical/DropTableNode.java | 5 +-
.../engine/planner/logical/EvalExprNode.java | 3 +-
.../engine/planner/logical/GroupbyNode.java | 53 +-
.../tajo/engine/planner/logical/HavingNode.java | 73 +
.../engine/planner/logical/IndexScanNode.java | 1 -
.../tajo/engine/planner/logical/JoinNode.java | 33 +-
.../tajo/engine/planner/logical/LimitNode.java | 7 +-
.../tajo/engine/planner/logical/NodeType.java | 1 +
.../engine/planner/logical/Projectable.java | 7 +
.../engine/planner/logical/ProjectionNode.java | 8 +-
.../engine/planner/logical/RelationNode.java | 10 +
.../tajo/engine/planner/logical/ScanNode.java | 1 +
.../engine/planner/logical/SelectionNode.java | 9 +-
.../tajo/engine/planner/logical/SortNode.java | 13 +-
.../planner/logical/TableSubQueryNode.java | 53 +-
.../tajo/engine/planner/logical/UnionNode.java | 8 +-
.../engine/planner/logical/join/JoinGraph.java | 69 +-
.../planner/physical/AggregationExec.java | 44 +-
.../engine/planner/physical/BNLJoinExec.java | 153 +-
.../planner/physical/BSTIndexScanExec.java | 2 +-
.../physical/BasicPhysicalExecutorVisitor.java | 201 +-
.../engine/planner/physical/EvalExprExec.java | 8 +-
.../planner/physical/HashAggregateExec.java | 20 +-
.../planner/physical/HashFullOuterJoinExec.java | 2 +-
.../engine/planner/physical/HashJoinExec.java | 16 +-
.../planner/physical/HashLeftOuterJoinExec.java | 2 +-
.../engine/planner/physical/HavingExec.java | 59 +
.../physical/MergeFullOuterJoinExec.java | 2 +-
.../engine/planner/physical/MergeJoinExec.java | 2 +-
.../engine/planner/physical/NLJoinExec.java | 2 +-
.../planner/physical/NLLeftOuterJoinExec.java | 2 +-
.../physical/PhysicalExecutorVisitor.java | 89 +-
.../planner/physical/PhysicalPlanUtil.java | 7 +-
.../engine/planner/physical/ProjectionExec.java | 8 +-
.../physical/RightOuterMergeJoinExec.java | 2 +-
.../engine/planner/physical/SelectionExec.java | 21 +-
.../engine/planner/physical/SeqScanExec.java | 2 +-
.../planner/rewrite/FilterPushDownRule.java | 2 +-
.../rewrite/PartitionedTableRewriter.java | 7 +-
.../planner/rewrite/ProjectionPushDownRule.java | 848 +++++---
.../apache/tajo/engine/utils/SchemaUtil.java | 24 +-
.../org/apache/tajo/master/GlobalEngine.java | 14 +-
.../master/GreedyFragmentScheduleAlgorithm.java | 4 +-
.../java/org/apache/tajo/master/TajoMaster.java | 2 -
.../apache/tajo/engine/eval/ExprTestBase.java | 38 +-
.../apache/tajo/engine/eval/TestEvalTree.java | 247 +--
.../tajo/engine/eval/TestEvalTreeUtil.java | 66 +-
.../apache/tajo/engine/eval/TestPredicates.java | 233 ++-
.../tajo/engine/parser/TestHiveConverter.java | 12 -
.../tajo/engine/planner/TestLogicalNode.java | 6 +-
.../tajo/engine/planner/TestLogicalPlan.java | 2 +-
.../tajo/engine/planner/TestLogicalPlanner.java | 106 +-
.../tajo/engine/planner/TestPlannerUtil.java | 2 -
.../planner/physical/TestBSTIndexExec.java | 6 +-
.../planner/physical/TestHashAntiJoinExec.java | 4 +-
.../planner/physical/TestHashSemiJoinExec.java | 1 -
.../planner/physical/TestPhysicalPlanner.java | 28 +-
.../apache/tajo/engine/query/TestCTASQuery.java | 5 +-
.../tajo/engine/query/TestGroupByQuery.java | 29 +
.../apache/tajo/engine/query/TestJoinQuery.java | 48 +-
.../tajo/engine/query/TestSelectQuery.java | 26 +-
.../apache/tajo/engine/query/TestSortQuery.java | 19 +-
.../tajo/engine/query/TestTablePartitions.java | 18 +-
.../tajo/engine/query/TestUnionQuery.java | 135 ++
.../org/apache/tajo/jdbc/TestResultSet.java | 3 -
.../java/org/apache/tajo/jdbc/TestTajoJdbc.java | 1 -
.../tajo/master/TestExecutionBlockCursor.java | 3 +-
.../tajo/worker/TestRangeRetrieverHandler.java | 26 +-
.../worker/dataserver/TestHttpDataServer.java | 2 -
.../resources/dataset/TestJoinQuery/table1.tbl | 5 +
.../resources/dataset/TestJoinQuery/table2.tbl | 4 +
.../TestGroupByQuery/testGroupByNested1.sql | 1 +
.../TestGroupByQuery/testGroupByNested2.sql | 1 +
.../queries/TestJoinQuery/oj_table1_ddl.sql | 6 +
.../queries/TestJoinQuery/oj_table2_ddl.sql | 6 +
.../queries/TestJoinQuery/testCrossJoin.sql | 2 +-
.../TestJoinQuery/testCrossJoinAndCaseWhen.sql | 18 +
.../testCrossJoinWithExplicitJoinQual.sql | 1 -
.../TestJoinQuery/testJoinAndCaseWhen.sql | 15 -
.../queries/TestJoinQuery/testJoinRefEval.sql | 12 +-
.../TestJoinQuery/testOuterJoinAndCaseWhen1.sql | 9 +
.../queries/TestJoinQuery/testTPCHQ2Join.sql | 5 +
.../TestJoinQuery/testWhereClauseJoin1.sql | 10 +
.../TestJoinQuery/testWhereClauseJoin2.sql | 8 +
.../TestJoinQuery/testWhereClauseJoin3.sql | 9 +
.../TestJoinQuery/testWhereClauseJoin4.sql | 8 +
.../TestJoinQuery/testWhereClauseJoin5.sql | 15 +
.../TestJoinQuery/testWhereClauseJoin6.sql | 19 +
.../TestSelectQuery/testSelectColumnAlias1.sql | 1 +
.../queries/TestSelectQuery/testUnion1.sql | 19 -
.../queries/TestSelectQuery/testUnion2.sql | 9 -
.../TestSortQuery/testSortAfterGroupby.sql | 2 +-
.../TestSortQuery/testSortWithAlias1.sql | 1 +
.../TestSortQuery/testSortWithAliasKey.sql | 1 -
.../queries/TestSortQuery/testSortWithExpr1.sql | 1 +
.../queries/TestSortQuery/testSortWithExpr2.sql | 1 +
.../queries/TestTPCH/testQ2FourJoins.sql | 14 +-
.../queries/TestTPCH/testTPCH14Expr.sql | 11 +-
.../queries/TestUnionQuery/testUnion1.sql | 19 +
.../queries/TestUnionQuery/testUnion10.sql | 150 ++
.../queries/TestUnionQuery/testUnion2.sql | 18 +
.../queries/TestUnionQuery/testUnion3.sql | 19 +
.../queries/TestUnionQuery/testUnion4.sql | 16 +
.../queries/TestUnionQuery/testUnion5.sql | 20 +
.../queries/TestUnionQuery/testUnion6.sql | 15 +
.../queries/TestUnionQuery/testUnion7.sql | 18 +
.../queries/TestUnionQuery/testUnion8.sql | 24 +
.../queries/TestUnionQuery/testUnion9.sql | 29 +
.../TestGroupByQuery/testGroupByNested1.result | 6 +
.../TestGroupByQuery/testGroupByNested2.result | 6 +
.../results/TestJoinQuery/testCrossJoin.result | 200 +-
.../testCrossJoinAndCaseWhen.result | 27 +
.../testCrossJoinWithExplicitJoinQual.result | 27 -
.../TestJoinQuery/testJoinAndCaseWhen.result | 27 -
.../TestJoinQuery/testJoinRefEval.result | 28 +-
.../testOuterJoinAndCaseWhen1.result | 7 +
.../results/TestJoinQuery/testTPCHQ2Join.result | 2 +-
.../TestJoinQuery/testWhereClauseJoin1.result | 27 +
.../TestJoinQuery/testWhereClauseJoin2.result | 27 +
.../TestJoinQuery/testWhereClauseJoin3.result | 27 +
.../TestJoinQuery/testWhereClauseJoin4.result | 27 +
.../TestJoinQuery/testWhereClauseJoin5.result | 5 +
.../testSelectColumnAlias1.result | 7 +
.../TestSortQuery/testSortAfterGroupby.result | 2 +-
.../TestSortQuery/testSortWithAlias1.result | 7 +
.../TestSortQuery/testSortWithAliasKey.result | 7 -
.../TestSortQuery/testSortWithExpr1.result | 7 +
.../TestSortQuery/testSortWithExpr2.result | 7 +
.../results/TestUnionQuery/testUnion1.result | 10 +
.../results/TestUnionQuery/testUnion10.result | 22 +
.../results/TestUnionQuery/testUnion2.result | 12 +
.../results/TestUnionQuery/testUnion3.result | 4 +
.../results/TestUnionQuery/testUnion4.result | 3 +
.../results/TestUnionQuery/testUnion5.result | 3 +
.../results/TestUnionQuery/testUnion6.result | 3 +
.../results/TestUnionQuery/testUnion7.result | 12 +
.../results/TestUnionQuery/testUnion8.result | 3 +
.../results/TestUnionQuery/testUnion9.result | 7 +
.../org/apache/tajo/storage/v2/DiskUtil.java | 1 -
225 files changed, 6843 insertions(+), 3480 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Aggregation.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Aggregation.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Aggregation.java
index 72acaa9..affb3bb 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Aggregation.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Aggregation.java
@@ -18,10 +18,11 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Aggregation extends UnaryOperator {
- private TargetExpr[] targets;
+ private NamedExpr[] targets;
private GroupElement [] groups;
private Expr havingCondition;
@@ -29,11 +30,11 @@ public class Aggregation extends UnaryOperator {
super(OpType.Aggregation);
}
- public TargetExpr[] getTargets() {
+ public NamedExpr[] getTargets() {
return this.targets;
}
- public void setTargets(TargetExpr[] targets) {
+ public void setTargets(NamedExpr[] targets) {
this.targets = targets;
}
@@ -62,6 +63,11 @@ public class Aggregation extends UnaryOperator {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(targets, groups, havingCondition);
+ }
+
+ @Override
public boolean equalsTo(Expr expr) {
Aggregation another = (Aggregation) expr;
boolean a = TUtil.checkEquals(groups, another.groups);
@@ -73,19 +79,19 @@ public class Aggregation extends UnaryOperator {
public static class GroupElement implements JsonSerializable {
private GroupType group_type;
- private ColumnReferenceExpr[] columns;
+ private Expr [] grouping_sets;
- public GroupElement(GroupType groupType, ColumnReferenceExpr[] columns) {
+ public GroupElement(GroupType groupType, Expr[] grouping_sets) {
this.group_type = groupType;
- this.columns = columns;
+ this.grouping_sets = grouping_sets;
}
public GroupType getType() {
return this.group_type;
}
- public ColumnReferenceExpr[] getColumns() {
- return this.columns;
+ public Expr[] getGroupingSets() {
+ return this.grouping_sets;
}
public String toString() {
@@ -97,11 +103,17 @@ public class Aggregation extends UnaryOperator {
return JsonHelper.toJson(this);
}
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(group_type, grouping_sets);
+ }
+
+ @Override
public boolean equals(Object obj) {
if (obj instanceof GroupElement) {
GroupElement other = (GroupElement) obj;
return group_type.equals(other) &&
- TUtil.checkEquals(columns, other.columns);
+ TUtil.checkEquals(grouping_sets, other.grouping_sets);
}
return false;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
index 19f66af..f504994 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import java.util.Objects;
+
public class BetweenPredicate extends Expr {
private boolean not;
// if symmetric is not set, asymmetric is implicit.
@@ -57,6 +59,11 @@ public class BetweenPredicate extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hash(not, symmetric, predicand, begin, end);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
BetweenPredicate another = (BetweenPredicate) expr;
return symmetric == another.symmetric && predicand.equals(another.predicand) && begin.equals(another.begin) &&
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BinaryOperator.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BinaryOperator.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BinaryOperator.java
index a090623..da37098 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BinaryOperator.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BinaryOperator.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public class BinaryOperator extends Expr {
protected Expr left;
protected Expr right;
@@ -48,8 +50,16 @@ public class BinaryOperator extends Expr {
this.right = right;
}
+ public int hashCode() {
+ return Objects.hashCode(opType, left, right);
+ }
+
@Override
boolean equalsTo(Expr expr) {
return true;
}
+
+ public String toString() {
+ return left.toString() + " " + opType.toString() + " " + right.toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CaseWhenPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CaseWhenPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CaseWhenPredicate.java
index 398aa55..27869b3 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CaseWhenPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CaseWhenPredicate.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -51,6 +53,11 @@ public class CaseWhenPredicate extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(whens, elseResult);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
return false;
}
@@ -69,14 +76,26 @@ public class CaseWhenPredicate extends Expr {
this.result = result;
}
+ public void setCondition(Expr condition) {
+ this.condition = condition;
+ }
+
public Expr getCondition() {
return this.condition;
}
+ public void setResult(Expr result) {
+ this.result = result;
+ }
+
public Expr getResult() {
return this.result;
}
+ public int hashCode() {
+ return Objects.hashCode(condition, result);
+ }
+
public boolean equals(Object obj) {
if (obj instanceof WhenExpr) {
WhenExpr another = (WhenExpr) obj;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CastExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CastExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CastExpr.java
index ad793cd..24f6415 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CastExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CastExpr.java
@@ -18,18 +18,19 @@
package org.apache.tajo.algebra;
-public class CastExpr extends Expr {
- private Expr operand;
+import com.google.common.base.Objects;
+
+public class CastExpr extends UnaryOperator {
private DataTypeExpr target;
public CastExpr(Expr operand, DataTypeExpr target) {
super(OpType.Cast);
- this.operand = operand;
this.target = target;
+ setChild(operand);
}
public Expr getOperand() {
- return operand;
+ return getChild();
}
public DataTypeExpr getTarget() {
@@ -37,8 +38,13 @@ public class CastExpr extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(target, getChild());
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
CastExpr another = (CastExpr) expr;
- return operand.equals(another.operand) && target.equals(another.target);
+ return target.equals(another.target);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnReferenceExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnReferenceExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnReferenceExpr.java
index 340577c..9734593 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnReferenceExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnReferenceExpr.java
@@ -18,37 +18,48 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class ColumnReferenceExpr extends Expr {
private String qualifier;
private String name;
- public ColumnReferenceExpr(String columnName) {
+ public ColumnReferenceExpr(String referenceName) {
super(OpType.Column);
- this.name = columnName;
+ setName(referenceName);
}
public ColumnReferenceExpr(String qualifier, String columnName) {
super(OpType.Column);
- this.qualifier = qualifier;
- this.name = columnName;
+ this.qualifier = qualifier.toLowerCase();
+ this.name = columnName.toLowerCase();
+ }
+
+ public boolean hasQualifier() {
+ return this.qualifier != null;
}
public void setQualifier(String qualifier) {
- this.qualifier = qualifier;
+ this.qualifier = qualifier.toLowerCase();
}
- public String getName() {
- return this.name;
+ public String getQualifier() {
+ return this.qualifier;
}
- public boolean hasQualifier() {
- return this.qualifier != null;
+ public String getName() {
+ return this.name;
}
- public String getQualifier() {
- return this.qualifier;
+ public void setName(String qualifiedName) {
+ String [] parts = qualifiedName.toLowerCase().split("\\.");
+ if (parts.length == 2) {
+ qualifier = parts[0];
+ name = parts[1];
+ } else {
+ name = parts[0];
+ }
}
public String getCanonicalName() {
@@ -59,9 +70,20 @@ public class ColumnReferenceExpr extends Expr {
}
}
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, qualifier);
+ }
+
+ @Override
public boolean equalsTo(Expr expr) {
ColumnReferenceExpr another = (ColumnReferenceExpr) expr;
return name.equals(another.name) &&
TUtil.checkEquals(qualifier, another.qualifier);
}
+
+ @Override
+ public String toString() {
+ return qualifier != null ? qualifier + "." + name : name;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CountRowsFunctionExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CountRowsFunctionExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CountRowsFunctionExpr.java
index 77468fb..cf2efb5 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CountRowsFunctionExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CountRowsFunctionExpr.java
@@ -18,4 +18,9 @@ public class CountRowsFunctionExpr extends FunctionExpr {
public CountRowsFunctionExpr() {
super(OpType.CountRowsFunction, "count");
}
+
+ @Override
+ public int hashCode() {
+ return "count_row".hashCode();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CreateTable.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CreateTable.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CreateTable.java
index a85e366..3aadd8a 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/CreateTable.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/CreateTable.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
import java.util.List;
@@ -128,9 +129,15 @@ public class CreateTable extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(external, tableElements, tableName, storageType, location, subquery, params, getSubQuery());
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
CreateTable another = (CreateTable) expr;
- return tableName.equals(another.tableName) &&
+ return external == another.external &&
+ tableName.equals(another.tableName) &&
TUtil.checkEquals(tableElements, another.tableElements) &&
TUtil.checkEquals(storageType, another.storageType) &&
TUtil.checkEquals(location, another.location) &&
@@ -161,10 +168,18 @@ public class CreateTable extends Expr {
return this.col_name;
}
- public boolean equals(Object obj) {
- if (obj instanceof ColumnDefinition) {
- ColumnDefinition another = (ColumnDefinition) obj;
- return col_name.equals(another.col_name) && super.equals(another);
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ return hash * 89 * col_name.hashCode();
+
+ }
+
+ @Override
+ public boolean equalsTo(Expr expr) {
+ if (expr instanceof ColumnDefinition) {
+ ColumnDefinition another = (ColumnDefinition) expr;
+ return col_name.equals(another.col_name) && super.equalsTo(another);
}
return false;
@@ -207,12 +222,27 @@ public class CreateTable extends Expr {
public List<RangePartitionSpecifier> getSpecifiers() {
return specifiers;
}
+
+ public int hashCode() {
+ return Objects.hashCode(type, columns, specifiers);
+ }
+
+ public boolean equals(Object object) {
+ if (object instanceof RangePartition) {
+ RangePartition another = (RangePartition) object;
+ return type == another.type && TUtil.checkEquals(columns, another.columns) &&
+ specifiers.equals(another.specifiers);
+ } else {
+ return false;
+ }
+ }
}
public static class HashPartition extends PartitionDescExpr {
ColumnReferenceExpr [] columns;
Expr quantity;
List<PartitionSpecifier> specifiers;
+
public HashPartition(ColumnReferenceExpr [] columns, Expr quantity) {
super(PartitionType.HASH);
this.columns = columns;
@@ -244,6 +274,20 @@ public class CreateTable extends Expr {
public List<PartitionSpecifier> getSpecifiers() {
return specifiers;
}
+
+ public int hashCode() {
+ return Objects.hashCode(type, columns, specifiers);
+ }
+
+ public boolean equals(Object object) {
+ if (object instanceof HashPartition) {
+ HashPartition another = (HashPartition) object;
+ return type == another.type && TUtil.checkEquals(columns, another.columns) &&
+ specifiers.equals(another.specifiers);
+ } else {
+ return false;
+ }
+ }
}
public static class ListPartition extends PartitionDescExpr {
@@ -263,6 +307,20 @@ public class CreateTable extends Expr {
public List<ListPartitionSpecifier> getSpecifiers() {
return specifiers;
}
+
+ public int hashCode() {
+ return Objects.hashCode(columns, specifiers);
+ }
+
+ public boolean equals(Object object) {
+ if (object instanceof HashPartition) {
+ HashPartition another = (HashPartition) object;
+ return type == another.type && TUtil.checkEquals(columns, another.columns) &&
+ specifiers.equals(another.specifiers);
+ } else {
+ return false;
+ }
+ }
}
public static class ColumnPartition extends PartitionDescExpr {
@@ -282,6 +340,19 @@ public class CreateTable extends Expr {
public boolean isOmitValues() {
return isOmitValues;
}
+
+ public int hashCode() {
+ return Objects.hashCode(columns);
+ }
+
+ public boolean equals(Object object) {
+ if (object instanceof HashPartition) {
+ HashPartition another = (HashPartition) object;
+ return type == another.type && TUtil.checkEquals(columns, another.columns);
+ } else {
+ return false;
+ }
+ }
}
public static class RangePartitionSpecifier extends PartitionSpecifier {
@@ -305,6 +376,23 @@ public class CreateTable extends Expr {
public boolean isEndMaxValue() {
return this.maxValue;
}
+
+ public int hashCode() {
+ return Objects.hashCode(end, maxValue);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RangePartitionSpecifier that = (RangePartitionSpecifier) o;
+
+ if (maxValue != that.maxValue) return false;
+ if (!end.equals(that.end)) return false;
+
+ return true;
+ }
}
public static class ListPartitionSpecifier extends PartitionSpecifier {
@@ -318,6 +406,23 @@ public class CreateTable extends Expr {
public ValueListExpr getValueList() {
return valueList;
}
+
+ @Override
+ public int hashCode() {
+ return valueList.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ListPartitionSpecifier that = (ListPartitionSpecifier) o;
+
+ if (!valueList.equals(that.valueList)) return false;
+
+ return true;
+ }
}
public static class PartitionSpecifier {
@@ -330,5 +435,17 @@ public class CreateTable extends Expr {
public String getName() {
return this.name;
}
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj instanceof PartitionSpecifier ) {
+ return name == ((PartitionSpecifier)obj).name;
+ } else {
+ return false;
+ }
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
index 7b2b903..15d6d7e 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
@@ -20,6 +20,8 @@ package org.apache.tajo.algebra;
import org.apache.tajo.util.TUtil;
+import java.util.Objects;
+
public class DataTypeExpr extends Expr {
String typeName;
Integer lengthOrPrecision;
@@ -59,6 +61,11 @@ public class DataTypeExpr extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hash(typeName, lengthOrPrecision, scale);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
DataTypeExpr another = (DataTypeExpr) expr;
return typeName.equals(another.typeName) &&
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DropTable.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DropTable.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DropTable.java
index e359ae0..57e0fcf 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DropTable.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DropTable.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public class DropTable extends Expr {
private final String tableName;
private final boolean purge;
@@ -37,6 +39,11 @@ public class DropTable extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(tableName, purge);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
if (expr instanceof DropTable) {
DropTable another = (DropTable) expr;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ExistsPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ExistsPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ExistsPredicate.java
index 0823807..fcb8531 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ExistsPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ExistsPredicate.java
@@ -18,14 +18,15 @@
package org.apache.tajo.algebra;
-public class ExistsPredicate extends Expr {
- private SimpleTableSubQuery simpleTableSubQuery;
+import com.google.common.base.Objects;
+
+public class ExistsPredicate extends UnaryOperator {
private boolean not;
public ExistsPredicate(SimpleTableSubQuery simpleTableSubQuery, boolean not) {
super(OpType.InPredicate);
- this.simpleTableSubQuery = simpleTableSubQuery;
this.not = not;
+ setChild(simpleTableSubQuery);
}
public boolean isNot() {
@@ -33,12 +34,17 @@ public class ExistsPredicate extends Expr {
}
public SimpleTableSubQuery getSubQuery() {
- return simpleTableSubQuery;
+ return (SimpleTableSubQuery) getChild();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(not, getChild());
}
@Override
boolean equalsTo(Expr expr) {
ExistsPredicate another = (ExistsPredicate) expr;
- return not == another.not && simpleTableSubQuery.equals(another.simpleTableSubQuery);
+ return not == another.not;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
index 54c230b..27184b3 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
@@ -33,6 +33,9 @@ public abstract class Expr implements JsonSerializable {
return this.opType;
}
+ @Override
+ public abstract int hashCode();
+
abstract boolean equalsTo(Expr expr);
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/FunctionExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/FunctionExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/FunctionExpr.java
index 008bfc0..7f1dcd3 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/FunctionExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/FunctionExpr.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class FunctionExpr extends Expr {
@@ -63,6 +64,11 @@ public class FunctionExpr extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(signature, params);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
FunctionExpr another = (FunctionExpr) expr;
return signature.equals(another.signature) &&
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
index dcceae4..c45a58f 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
@@ -25,4 +25,15 @@ public class GeneralSetFunctionExpr extends FunctionExpr {
public boolean isDistinct() {
return distinct;
}
+
+ @Override
+ public int hashCode() {
+ int hash = super.hashCode();
+ return hash * 89 * (distinct ? 31 : 23);
+ }
+
+ @Override
+ public boolean equalsTo(Expr expr) {
+ return distinct == ((GeneralSetFunctionExpr)expr).distinct;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Having.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Having.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Having.java
index d48537a..53bd9ba 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Having.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Having.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Having extends UnaryOperator implements JsonSerializable {
@@ -46,6 +47,11 @@ public class Having extends UnaryOperator implements JsonSerializable {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(qual, getChild());
+ }
+
+ @Override
public boolean equalsTo(Expr expr) {
if (expr instanceof Having) {
Having other = (Having) expr;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Insert.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Insert.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Insert.java
index 38c7ad4..c58c040 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Insert.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Insert.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
import java.util.Map;
@@ -112,6 +113,11 @@ public class Insert extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(overwrite, tableName, subquery, storageType, location, params);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
Insert another = (Insert) expr;
return overwrite == another.overwrite &&
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/IsNullPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/IsNullPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/IsNullPredicate.java
index 35fc769..40f5dd2 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/IsNullPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/IsNullPredicate.java
@@ -18,14 +18,15 @@
package org.apache.tajo.algebra;
-public class IsNullPredicate extends Expr {
+import com.google.common.base.Objects;
+
+public class IsNullPredicate extends UnaryOperator {
private final boolean not;
- private final Expr predicand;
public IsNullPredicate(boolean not, Expr column) {
super(OpType.IsNullPredicate);
this.not = not;
- this.predicand = column;
+ setChild(column);
}
public boolean isNot() {
@@ -33,12 +34,16 @@ public class IsNullPredicate extends Expr {
}
public Expr getPredicand() {
- return predicand;
+ return getChild();
+ }
+
+ public int hashCode() {
+ return Objects.hashCode(not, getChild());
}
@Override
boolean equalsTo(Expr expr) {
IsNullPredicate nullPredicate = (IsNullPredicate) expr;
- return not == nullPredicate.not && predicand.equals(nullPredicate.predicand);
+ return not == nullPredicate.not;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Join.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Join.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Join.java
index 51c84c2..da2b153 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Join.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Join.java
@@ -18,10 +18,9 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
-import java.util.Arrays;
-
public class Join extends BinaryOperator {
private JoinType joinType;
private Expr joinQual;
@@ -69,6 +68,11 @@ public class Join extends BinaryOperator {
return natural;
}
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(joinType, joinQual, joinColumns, natural);
+ }
+
boolean equalsTo(Expr expr) {
Join another = (Join) expr;
return joinType.equals(another.joinType) &&
@@ -81,14 +85,4 @@ public class Join extends BinaryOperator {
public String toJson() {
return JsonHelper.toJson(this);
}
-
- @Override
- public int hashCode() {
- int result = getType().hashCode();
- result = 31 * result + joinType.hashCode();
- result = 31 * result + (joinQual != null ? joinQual.hashCode() : 0);
- result = 31 * result + (joinColumns != null ? Arrays.hashCode(joinColumns) : 0);
- result = 31 * result + (natural ? 1 : 0);
- return result;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Limit.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Limit.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Limit.java
index dd3aee9..a217c5e 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Limit.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Limit.java
@@ -19,6 +19,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public class Limit extends UnaryOperator {
private Expr fetchFirstNum;
@@ -41,6 +43,10 @@ public class Limit extends UnaryOperator {
return JsonHelper.toJson(this);
}
+ public int hashCode() {
+ return Objects.hashCode(fetchFirstNum, getChild());
+ }
+
@Override
boolean equalsTo(Expr expr) {
Limit another = (Limit) expr;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
index 9d8d71a..f7d7720 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/LiteralValue.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public class LiteralValue extends Expr {
protected LiteralType valueType;
protected String value;
@@ -44,6 +46,10 @@ public class LiteralValue extends Expr {
return this.value;
}
+ public int hashCode() {
+ return Objects.hashCode(valueType, value);
+ }
+
public boolean equalsTo(Expr expr) {
LiteralValue another = (LiteralValue) expr;
boolean a = valueType.equals(another.valueType);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/NamedExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/NamedExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/NamedExpr.java
new file mode 100644
index 0000000..bd73481
--- /dev/null
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/NamedExpr.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.algebra;
+
+import com.google.common.base.Objects;
+import org.apache.tajo.util.TUtil;
+
+/**
+ * <code>NamedExpr</code> is an expression which can be aliased in a target list.
+ *
+ * <pre>
+ * SELECT col1 + col2 as a, sum(col2) as b, col3 as c, col4, ... FROM ...
+ * ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^
+ * expr1 expr2 expr3 expr4
+ * </pre>
+ *
+ * We define each expression in expr1 - expr4 as a named expression.
+ * In database community, each of them is called target or an expression in a select list,
+ * Each expression can be explicitly aliased as an given name.
+ */
+public class NamedExpr extends UnaryOperator {
+ private String alias;
+
+ public NamedExpr(Expr expr) {
+ super(OpType.Target);
+ setChild(expr);
+ }
+
+ public NamedExpr(Expr expr, String alias) {
+ this(expr);
+ setAlias(alias);
+ }
+
+ public Expr getExpr() {
+ return getChild();
+ }
+
+ public boolean hasAlias() {
+ return this.alias != null;
+ }
+
+ public String getAlias() {
+ return this.alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(alias, getChild());
+ }
+
+ @Override
+ public boolean equalsTo(Expr obj) {
+ if (obj instanceof NamedExpr) {
+ NamedExpr another = (NamedExpr) obj;
+ return TUtil.checkEquals(alias, another.alias);
+ }
+
+ return false;
+ }
+
+ public String toString() {
+ return getChild().toString() + (hasAlias() ? " AS " + alias : "");
+ }
+
+ @Override
+ public String toJson() {
+ return JsonHelper.toJson(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/NullLiteral.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/NullLiteral.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/NullLiteral.java
index e4e7749..55d225a 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/NullLiteral.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/NullLiteral.java
@@ -25,6 +25,11 @@ public class NullLiteral extends Expr {
}
@Override
+ public int hashCode() {
+ return getType().hashCode();
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
return expr instanceof NullLiteral;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
index ec6be1c..84f784e 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
@@ -85,7 +85,7 @@ public enum OpType {
// Other Expressions
Sign(SignedExpr.class),
Column(ColumnReferenceExpr.class),
- Target(TargetExpr.class),
+ Target(NamedExpr.class),
Function(FunctionExpr.class),
// Set Functions
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/PatternMatchPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/PatternMatchPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/PatternMatchPredicate.java
index e3c7ba4..6f5ab68 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/PatternMatchPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/PatternMatchPredicate.java
@@ -20,10 +20,8 @@ package org.apache.tajo.algebra;
import com.google.common.base.Preconditions;
-public class PatternMatchPredicate extends Expr {
+public class PatternMatchPredicate extends BinaryOperator {
private boolean not;
- private Expr columnRef;
- private Expr pattern;
private boolean caseInsensitive;
public PatternMatchPredicate(OpType opType, boolean not, Expr predicand, Expr pattern,
@@ -33,9 +31,9 @@ public class PatternMatchPredicate extends Expr {
opType == OpType.LikePredicate || opType == OpType.SimilarToPredicate || opType == OpType.Regexp,
"pattern matching predicate is only available: " + opType.name());
this.not = not;
- this.columnRef = predicand;
- this.pattern = pattern;
this.caseInsensitive = caseInsensitive;
+ setLeft(predicand);
+ setRight(pattern);
}
public PatternMatchPredicate(OpType opType, boolean not, Expr predicand, Expr pattern) {
@@ -47,11 +45,11 @@ public class PatternMatchPredicate extends Expr {
}
public Expr getPredicand() {
- return this.columnRef;
+ return getLeft();
}
public Expr getPattern() {
- return this.pattern;
+ return getRight();
}
public boolean isCaseInsensitive() {
@@ -61,9 +59,6 @@ public class PatternMatchPredicate extends Expr {
boolean equalsTo(Expr expr) {
PatternMatchPredicate another = (PatternMatchPredicate) expr;
return opType == another.opType &&
- not == another.not &&
- columnRef.equals(another.columnRef) &&
- pattern.equals(another.pattern) &&
- caseInsensitive == another.caseInsensitive;
+ not == another.not && caseInsensitive == another.caseInsensitive;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Projection.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Projection.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Projection.java
index 958f20c..bcb6253 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Projection.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Projection.java
@@ -18,13 +18,14 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Projection extends UnaryOperator implements Cloneable {
private boolean all;
private boolean distinct = false;
- private TargetExpr [] targets;
+ private NamedExpr[] targets;
public Projection() {
super(OpType.Projection);
@@ -50,18 +51,22 @@ public class Projection extends UnaryOperator implements Cloneable {
return all;
}
- public TargetExpr[] getTargets() {
+ public NamedExpr[] getNamedExprs() {
return this.targets;
}
- public void setTargets(TargetExpr[] targets) {
+ public void setNamedExprs(NamedExpr[] targets) {
this.targets = targets;
}
+ public int hashCode() {
+ return Objects.hashCode(all, distinct, targets, getChild());
+ }
+
@Override
boolean equalsTo(Expr expr) {
Projection another = (Projection) expr;
- return TUtil.checkEquals(all, another.all) &&
+ return TUtil.checkEquals(all, another.all) && distinct == another.distinct &&
TUtil.checkEquals(targets, another.targets);
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Relation.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Relation.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Relation.java
index 0cb0bbe..406794a 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Relation.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Relation.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Relation extends Expr {
@@ -59,16 +60,14 @@ public class Relation extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(tableName, alias);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
Relation other = (Relation) expr;
return TUtil.checkEquals(tableName, other.tableName) &&
TUtil.checkEquals(alias, other.alias);
}
-
- @Override
- public int hashCode() {
- int result = tableName.hashCode();
- result = 31 * result + (alias != null ? alias.hashCode() : 0);
- return result;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/RelationList.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/RelationList.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/RelationList.java
index 918ff46..18c4ce9 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/RelationList.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/RelationList.java
@@ -14,6 +14,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import org.apache.tajo.util.TUtil;
@@ -53,6 +54,11 @@ public class RelationList extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(relations);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
Set<Expr> thisSet = TUtil.newHashSet(relations);
RelationList another = (RelationList) expr;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ScalarSubQuery.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ScalarSubQuery.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ScalarSubQuery.java
index 2273a48..425c08f 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ScalarSubQuery.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ScalarSubQuery.java
@@ -18,22 +18,20 @@
package org.apache.tajo.algebra;
-public class ScalarSubQuery extends Expr {
- private Expr subquery;
+public class ScalarSubQuery extends UnaryOperator {
public ScalarSubQuery(Expr subQuery) {
super(OpType.ScalarSubQuery);
- this.subquery = subQuery;
+ this.setChild(subQuery);
}
public Expr getSubQuery() {
- return this.subquery;
+ return getChild();
}
@Override
boolean equalsTo(Expr expr) {
- ScalarSubQuery another = (ScalarSubQuery) expr;
- return subquery.equals(another);
+ return true;
}
public String toJson() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Selection.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Selection.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Selection.java
index f43c252..364e1b7 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Selection.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Selection.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Selection extends UnaryOperator implements JsonSerializable {
@@ -45,6 +46,10 @@ public class Selection extends UnaryOperator implements JsonSerializable {
return JsonHelper.toJson(this);
}
+ public int hashCode() {
+ return Objects.hashCode(qual, getChild());
+ }
+
@Override
public boolean equalsTo(Expr expr) {
if (expr instanceof Selection) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SetOperation.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SetOperation.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SetOperation.java
index 47ab44a..08ebd6a 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SetOperation.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SetOperation.java
@@ -19,6 +19,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
public class SetOperation extends BinaryOperator {
@@ -40,6 +41,10 @@ public class SetOperation extends BinaryOperator {
distinct = false;
}
+ public int hashCode() {
+ return Objects.hashCode(distinct, getLeft(), getRight());
+ }
+
boolean equalsTo(Expr expr) {
SetOperation another = (SetOperation) expr;
return distinct == another.distinct;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SignedExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SignedExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SignedExpr.java
index 15fcb51..7b3438c 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SignedExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SignedExpr.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public class SignedExpr extends UnaryOperator {
private boolean negative;
@@ -31,6 +33,10 @@ public class SignedExpr extends UnaryOperator {
return negative;
}
+ public int hashCode() {
+ return Objects.hashCode(negative, getChild());
+ }
+
@Override
boolean equalsTo(Expr expr) {
return negative == ((SignedExpr)expr).negative;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SimpleTableSubQuery.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SimpleTableSubQuery.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SimpleTableSubQuery.java
index 91442dc..7bd3b78 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/SimpleTableSubQuery.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/SimpleTableSubQuery.java
@@ -18,21 +18,20 @@
package org.apache.tajo.algebra;
-public class SimpleTableSubQuery extends Expr {
- private Expr subquery;
+public class SimpleTableSubQuery extends UnaryOperator {
public SimpleTableSubQuery(Expr subquery) {
super(OpType.SimpleTableSubQuery);
- this.subquery = subquery;
+ setChild(subquery);
}
public Expr getSubQuery() {
- return subquery;
+ return getChild();
}
@Override
boolean equalsTo(Expr expr) {
- return subquery.equals(subquery);
+ return true;
}
public String toJson() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Sort.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Sort.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Sort.java
index f57cd89..c047c54 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Sort.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Sort.java
@@ -18,7 +18,7 @@
package org.apache.tajo.algebra;
-import com.google.gson.annotations.SerializedName;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class Sort extends UnaryOperator {
@@ -38,6 +38,11 @@ public class Sort extends UnaryOperator {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(sortSpecs);
+ }
+
+ @Override
public boolean equalsTo(Expr expr) {
Sort another = (Sort) expr;
return TUtil.checkEquals(sortSpecs, another.sortSpecs);
@@ -49,12 +54,11 @@ public class Sort extends UnaryOperator {
}
public static class SortSpec {
- private ColumnReferenceExpr key;
+ private Expr key;
private boolean asc = true;
- @SerializedName("null_first")
private boolean nullFirst = false;
- public SortSpec(final ColumnReferenceExpr key) {
+ public SortSpec(final Expr key) {
this.key = key;
}
@@ -88,10 +92,16 @@ public class Sort extends UnaryOperator {
this.nullFirst = true;
}
- public final ColumnReferenceExpr getKey() {
+ public final Expr getKey() {
return this.key;
}
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(asc, key, nullFirst);
+ }
+
+ @Override
public boolean equals(Object obj) {
if (obj instanceof SortSpec) {
SortSpec other = (SortSpec) obj;
@@ -101,5 +111,10 @@ public class Sort extends UnaryOperator {
}
return false;
}
+
+ @Override
+ public String toString() {
+ return key + " " + (asc ? "asc" : "desc") + " " + (nullFirst ? "null first" :"");
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TablePrimarySubQuery.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TablePrimarySubQuery.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/TablePrimarySubQuery.java
index 929e9b2..90d89a4 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TablePrimarySubQuery.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/TablePrimarySubQuery.java
@@ -18,6 +18,9 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+import org.apache.tajo.util.TUtil;
+
public class TablePrimarySubQuery extends Relation {
private Expr subquery;
private String [] columnNames;
@@ -43,9 +46,14 @@ public class TablePrimarySubQuery extends Relation {
return subquery;
}
+ public int hashCode() {
+ return Objects.hashCode(subquery, columnNames);
+ }
+
@Override
boolean equalsTo(Expr expr) {
- return subquery.equals(subquery);
+ TablePrimarySubQuery another = (TablePrimarySubQuery) expr;
+ return subquery.equals(subquery) && TUtil.checkEquals(columnNames, another.columnNames);
}
public String toJson() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TargetExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TargetExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/TargetExpr.java
deleted file mode 100644
index 393790b..0000000
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/TargetExpr.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.algebra;
-
-import org.apache.tajo.util.TUtil;
-
-public class TargetExpr extends Expr {
- private Expr expr;
- private String alias;
-
- public TargetExpr(Expr expr) {
- super(OpType.Target);
- this.expr = expr;
- }
-
- public TargetExpr(Expr expr, String alias) {
- this(expr);
- setAlias(alias);
- }
-
- public Expr getExpr() {
- return expr;
- }
-
- public boolean hasAlias() {
- return this.alias != null;
- }
-
- public String getAlias() {
- return this.alias;
- }
-
- public void setAlias(String alias) {
- this.alias = alias;
- }
-
- @Override
- public boolean equalsTo(Expr obj) {
- if (obj instanceof TargetExpr) {
- TargetExpr another = (TargetExpr) obj;
- return expr.equals(another.expr) && TUtil.checkEquals(alias, another.alias);
- }
-
- return false;
- }
-
- @Override
- public String toJson() {
- return JsonHelper.toJson(this);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/UnaryOperator.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/UnaryOperator.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/UnaryOperator.java
index fec87d0..2a1e730 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/UnaryOperator.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/UnaryOperator.java
@@ -18,6 +18,8 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
+
public abstract class UnaryOperator extends Expr {
private Expr child;
@@ -36,4 +38,8 @@ public abstract class UnaryOperator extends Expr {
public void setChild(Expr op) {
this.child = op;
}
+
+ public int hashCode() {
+ return Objects.hashCode(getType(), child.hashCode());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ValueListExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ValueListExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ValueListExpr.java
index bbcbd21..8d51a95 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ValueListExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ValueListExpr.java
@@ -18,6 +18,7 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
public class ValueListExpr extends Expr {
@@ -33,6 +34,11 @@ public class ValueListExpr extends Expr {
}
@Override
+ public int hashCode() {
+ return Objects.hashCode(values);
+ }
+
+ @Override
boolean equalsTo(Expr expr) {
ValueListExpr valueListExpr = (ValueListExpr) expr;
return TUtil.checkEquals(values, valueListExpr.values);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-algebra/src/test/java/org/apache/tajo/algebra/TestExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/test/java/org/apache/tajo/algebra/TestExpr.java b/tajo-algebra/src/test/java/org/apache/tajo/algebra/TestExpr.java
index 660176d..f327739 100644
--- a/tajo-algebra/src/test/java/org/apache/tajo/algebra/TestExpr.java
+++ b/tajo-algebra/src/test/java/org/apache/tajo/algebra/TestExpr.java
@@ -36,6 +36,7 @@ public class TestExpr {
new LiteralValue("1", LiteralType.Unsigned_Integer),
new LiteralValue("2", LiteralType.Unsigned_Integer));
+ assertEquals(expr1.hashCode(), expr2.hashCode());
assertEquals(expr1, expr2);
Expr expr3 = new BinaryOperator(OpType.Minus,
@@ -102,8 +103,8 @@ public class TestExpr {
selection.setChild(relation);
Aggregation aggregation = new Aggregation();
- aggregation.setTargets(new TargetExpr[]{
- new TargetExpr(new ColumnReferenceExpr("col1"))
+ aggregation.setTargets(new NamedExpr[]{
+ new NamedExpr(new ColumnReferenceExpr("col1"))
}
);
@@ -129,8 +130,8 @@ public class TestExpr {
selection.setChild(relation);
Aggregation aggregation = new Aggregation();
- aggregation.setTargets(new TargetExpr[]{
- new TargetExpr(new ColumnReferenceExpr("col1"))
+ aggregation.setTargets(new NamedExpr[]{
+ new NamedExpr(new ColumnReferenceExpr("col1"))
});
aggregation.setChild(selection);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Column.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Column.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Column.java
index 436560e..cb42086 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Column.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Column.java
@@ -154,7 +154,13 @@ public class Column implements ProtoObject<ColumnProto>, Cloneable, GsonObject {
}
public String toString() {
- return getQualifiedName() +" (" + getDataType().getType() +"(" + getDataType().getLength() + "))";
+ StringBuilder sb = new StringBuilder(getQualifiedName());
+ sb.append(" (").append(getDataType().getType());
+ if (getDataType().getLength() > 0) {
+ sb.append("(" + getDataType().getLength() + ")");
+ }
+ sb.append(")");
+ return sb.toString();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
index 4ea3b81..a19d352 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/Schema.java
@@ -108,6 +108,26 @@ public class Schema implements ProtoObject<SchemaProto>, Cloneable, GsonObject {
return fields.get(id);
}
+ public Column getColumn(Column column) {
+ if (!contains(column)) {
+ return null;
+ }
+ if (column.hasQualifier()) {
+ return fields.get(fieldsByQualifiedName.get(column.getQualifiedName()));
+ } else {
+ return fields.get(fieldsByName.get(column.getColumnName()).get(0));
+ }
+ }
+
+ public Column getColumn(String name) {
+ String [] parts = name.split("\\.");
+ if (parts.length == 2) {
+ return getColumnByFQN(name);
+ } else {
+ return getColumnByName(name);
+ }
+ }
+
public Column getColumnByFQN(String qualifiedName) {
Integer cid = fieldsByQualifiedName.get(qualifiedName.toLowerCase());
return cid != null ? fields.get(cid) : null;
@@ -124,22 +144,44 @@ public class Schema implements ProtoObject<SchemaProto>, Cloneable, GsonObject {
if (list.size() == 1) {
return fields.get(list.get(0));
} else {
- StringBuilder sb = new StringBuilder();
- boolean first = true;
- for (Integer id : list) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(fields.get(id));
- }
- throw new RuntimeException("Ambiguous Column Name: " + sb.toString());
+ throw throwAmbiguousFieldException(list);
}
}
+
+ private RuntimeException throwAmbiguousFieldException(Collection<Integer> idList) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (Integer id : idList) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(fields.get(id));
+ }
+ throw new RuntimeException("Ambiguous Column Name Access: " + sb.toString());
+ }
- public int getColumnId(String qualifiedName) {
- return fieldsByQualifiedName.get(qualifiedName.toLowerCase());
+ public int getColumnId(String name) {
+ String [] parts = name.split("\\.");
+ if (parts.length == 2) {
+ if (fieldsByQualifiedName.containsKey(name)) {
+ return fieldsByQualifiedName.get(name);
+ } else {
+ return -1;
+ }
+ } else {
+ List<Integer> list = fieldsByName.get(name);
+ if (list == null) {
+ return -1;
+ } else if (list.size() == 1) {
+ return fieldsByName.get(name).get(0);
+ } else if (list.size() == 0) {
+ return -1;
+ } else { // if list.size > 2
+ throw throwAmbiguousFieldException(list);
+ }
+ }
}
public int getColumnIdByName(String colName) {
@@ -155,12 +197,47 @@ public class Schema implements ProtoObject<SchemaProto>, Cloneable, GsonObject {
public List<Column> getColumns() {
return ImmutableList.copyOf(fields);
}
-
- public boolean contains(String colName) {
- return fieldsByQualifiedName.containsKey(colName.toLowerCase());
+ public boolean contains(String name) {
+ if (fieldsByQualifiedName.containsKey(name)) {
+ return true;
+ }
+ if (fieldsByName.containsKey(name)) {
+ if (fieldsByName.size() > 1) {
+ throw new RuntimeException("Ambiguous Column name");
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean contains(Column column) {
+ if (column.hasQualifier()) {
+ return fieldsByQualifiedName.containsKey(column.getQualifiedName());
+ } else {
+ if (fieldsByName.containsKey(column.getColumnName())) {
+ int num = fieldsByName.get(column.getColumnName()).size();
+ if (num == 0) {
+ throw new IllegalStateException("No such column name: " + column.getColumnName());
+ }
+ if (num > 1) {
+ throw new RuntimeException("Ambiguous column name: " + column.getColumnName());
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public boolean containsByQualifiedName(String qualifiedName) {
+ return fieldsByQualifiedName.containsKey(qualifiedName.toLowerCase());
}
+ public boolean containsByName(String colName) {
+ return fieldsByName.containsKey(colName);
+ }
+
public boolean containsAll(Collection<Column> columns) {
return fields.containsAll(columns);
}
@@ -229,7 +306,7 @@ public class Schema implements ProtoObject<SchemaProto>, Cloneable, GsonObject {
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("{");
+ sb.append("{(").append(getColumnNum()).append(") ");
int i = 0;
for(Column col : fields) {
sb.append(col);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/partition/PartitionDesc.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/partition/PartitionDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/partition/PartitionDesc.java
index 792d642..c3e31d8 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/partition/PartitionDesc.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/partition/PartitionDesc.java
@@ -181,9 +181,9 @@ public class PartitionDesc implements ProtoObject<CatalogProtos.PartitionDescPro
}
public String toString() {
- Gson gson = new GsonBuilder().setPrettyPrinting().
- excludeFieldsWithoutExposeAnnotation().create();
- return gson.toJson(this);
+ StringBuilder sb = new StringBuilder("Partition Type: " + partitionsType.name()).append(", key=");
+ sb.append(schema);
+ return sb.toString();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestColumn.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestColumn.java b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestColumn.java
index b0b5051..81677c5 100644
--- a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestColumn.java
+++ b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestColumn.java
@@ -97,7 +97,6 @@ public class TestColumn {
public final void testToJson() {
Column col = new Column(field1.getProto());
String json = col.toJson();
- System.out.println(json);
Column fromJson = CatalogGsonHelper.fromJson(json, Column.class);
assertEquals(col, fromJson);
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestSchema.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestSchema.java b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestSchema.java
index 1422cf2..c879ecb 100644
--- a/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestSchema.java
+++ b/tajo-catalog/tajo-catalog-common/src/test/java/org/apache/tajo/catalog/TestSchema.java
@@ -69,9 +69,9 @@ public class TestSchema {
@Test
public final void testAddField() {
Schema schema = new Schema();
- assertFalse(schema.contains("studentId"));
+ assertFalse(schema.containsByQualifiedName("studentId"));
schema.addColumn("studentId", Type.INT4);
- assertTrue(schema.contains("studentId"));
+ assertTrue(schema.containsByQualifiedName("studentId"));
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-catalog/tajo-catalog-drivers/tajo-hcatalog/src/main/java/org/apache/tajo/catalog/store/HCatalogUtil.java
----------------------------------------------------------------------
diff --git a/tajo-catalog/tajo-catalog-drivers/tajo-hcatalog/src/main/java/org/apache/tajo/catalog/store/HCatalogUtil.java b/tajo-catalog/tajo-catalog-drivers/tajo-hcatalog/src/main/java/org/apache/tajo/catalog/store/HCatalogUtil.java
index 33b3e45..2c2400a 100644
--- a/tajo-catalog/tajo-catalog-drivers/tajo-hcatalog/src/main/java/org/apache/tajo/catalog/store/HCatalogUtil.java
+++ b/tajo-catalog/tajo-catalog-drivers/tajo-hcatalog/src/main/java/org/apache/tajo/catalog/store/HCatalogUtil.java
@@ -84,8 +84,7 @@ public class HCatalogUtil {
try {
return Enum.valueOf(TajoDataTypes.Type.class, typeStr);
} catch (IllegalArgumentException iae) {
- System.out.println("Cannot find a matched type aginst from '" + typeStr + "'");
- return null;
+ throw new InternalException("Cannot find a matched type aginst from '" + typeStr + "'");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
----------------------------------------------------------------------
diff --git a/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java b/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
index 7eabc08..a48142e 100644
--- a/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
+++ b/tajo-client/src/main/java/org/apache/tajo/client/TajoClient.java
@@ -318,9 +318,15 @@ public class TajoClient {
builder.setQuery(sql);
TajoMasterClientProtocolService.BlockingInterface tajoMasterService = client.getStub();
- ResultCode resultCode =
- tajoMasterService.updateQuery(null, builder.build()).getResultCode();
- return resultCode == ResultCode.OK;
+ UpdateQueryResponse response = tajoMasterService.updateQuery(null, builder.build());
+ if (response.getResultCode() == ResultCode.OK) {
+ return true;
+ } else {
+ if (response.hasErrorMessage()) {
+ LOG.error(response.getErrorMessage());
+ }
+ return false;
+ }
}
}.withRetries();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
index 3569d02..782bfa3 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/Float8Datum.java
@@ -24,6 +24,7 @@ package org.apache.tajo.datum;
import com.google.gson.annotations.Expose;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.exception.InvalidOperationException;
+import org.apache.tajo.util.Bytes;
import org.apache.tajo.util.NumberUtil;
import java.nio.ByteBuffer;
@@ -70,9 +71,7 @@ public class Float8Datum extends NumericDatum {
@Override
public byte[] asByteArray() {
- ByteBuffer bb = ByteBuffer.allocate(8);
- bb.putDouble(val);
- return bb.array();
+ return Bytes.toBytes(val);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
index 26f7297..fba3fe9 100644
--- a/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
+++ b/tajo-common/src/main/java/org/apache/tajo/datum/TextDatum.java
@@ -138,7 +138,7 @@ public class TextDatum extends Datum {
case NULL_TYPE:
return datum;
default:
- throw new InvalidOperationException();
+ throw new InvalidOperationException("Cannot equivalent check: " + this.type() + " and " + datum.type());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-common/src/test/java/org/apache/tajo/common/type/TestIPv4.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/common/type/TestIPv4.java b/tajo-common/src/test/java/org/apache/tajo/common/type/TestIPv4.java
index 2f11f8a..884ad8f 100644
--- a/tajo-common/src/test/java/org/apache/tajo/common/type/TestIPv4.java
+++ b/tajo-common/src/test/java/org/apache/tajo/common/type/TestIPv4.java
@@ -26,13 +26,9 @@ import static org.junit.Assert.*;
public class TestIPv4 {
@Test
- public final void testSet() {
+ public final void testSet() throws InvalidAddressException {
IPv4 ip = null;
- try {
- ip = new IPv4("255.255.255.255");
- } catch (InvalidAddressException e) {
- System.out.println("InvalidAddressException is catched");
- }
+ ip = new IPv4("255.255.255.255");
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
b[i] = (byte)0xFF;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-common/src/test/java/org/apache/tajo/datum/TestBitDatum.java
----------------------------------------------------------------------
diff --git a/tajo-common/src/test/java/org/apache/tajo/datum/TestBitDatum.java b/tajo-common/src/test/java/org/apache/tajo/datum/TestBitDatum.java
index b6b84d9..812c4c7 100644
--- a/tajo-common/src/test/java/org/apache/tajo/datum/TestBitDatum.java
+++ b/tajo-common/src/test/java/org/apache/tajo/datum/TestBitDatum.java
@@ -66,8 +66,8 @@ public class TestBitDatum {
@Test
public final void testAsChars() {
- Datum d = DatumFactory.createBit((byte) 5);
- System.out.println(d.asChars());
+ Datum d = DatumFactory.createBit((byte) 'a');
+ assertEquals("0x97", d.asChars());
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4 b/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
index 4b5eea4..9b693c7 100644
--- a/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
+++ b/tajo-core/tajo-core-backend/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
@@ -574,11 +574,11 @@ boolean_value_expression
;
or_predicate
- : and_predicate (OR boolean_value_expression)*
+ : and_predicate (OR or_predicate)*
;
and_predicate
- : boolean_factor (AND boolean_value_expression)*
+ : boolean_factor (AND and_predicate)*
;
boolean_factor
@@ -789,8 +789,8 @@ grouping_element
;
ordinary_grouping_set
- : column_reference_list
- | LEFT_PAREN column_reference_list RIGHT_PAREN
+ : row_value_predicand_list
+ | LEFT_PAREN row_value_predicand_list RIGHT_PAREN
;
rollup_list
@@ -809,6 +809,10 @@ having_clause
: HAVING boolean_value_expression
;
+row_value_predicand_list
+ : row_value_predicand (COMMA row_value_predicand)*
+ ;
+
/*
===============================================================================
7.13 <query expression>
@@ -1124,7 +1128,7 @@ sort_specifier_list
;
sort_specifier
- : column=column_reference order=order_specification? null_order=null_ordering?
+ : key=row_value_predicand order=order_specification? null_order=null_ordering?
;
order_specification
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
index e933ddb..70ae712 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/AlgebraicUtil.java
@@ -131,6 +131,11 @@ public class AlgebraicUtil {
* @return the simplified expr
*/
public static EvalNode eliminateConstantExprs(EvalNode expr) {
+
+ if (expr.getType() == EvalType.FIELD) {
+ return expr;
+ }
+
EvalNode left = expr.getLeftExpr();
EvalNode right = expr.getRightExpr();
[02/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlanner.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlanner.java
index 8a3f9f6..cd93a8f 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlanner.java
@@ -366,8 +366,10 @@ public class TestLogicalPlanner {
assertEquals(NodeType.PROJECTION, root.getChild().getType());
ProjectionNode projNode = root.getChild();
- assertEquals(NodeType.GROUP_BY, projNode.getChild().getType());
- GroupbyNode groupByNode = projNode.getChild();
+ assertEquals(NodeType.HAVING, projNode.getChild().getType());
+ HavingNode havingNode = projNode.getChild();
+ assertEquals(NodeType.GROUP_BY, havingNode.getChild().getType());
+ GroupbyNode groupByNode = havingNode.getChild();
assertEquals(NodeType.JOIN, groupByNode.getChild().getType());
JoinNode joinNode = groupByNode.getChild();
@@ -510,11 +512,14 @@ public class TestLogicalPlanner {
String json = plan.toJson();
LogicalNode fromJson = CoreGsonHelper.fromJson(json, LogicalNode.class);
assertEquals(NodeType.ROOT, fromJson.getType());
- LogicalNode groupby = ((LogicalRootNode)fromJson).getChild();
- assertEquals(NodeType.PROJECTION, groupby.getType());
- LogicalNode projNode = ((ProjectionNode)groupby).getChild();
- assertEquals(NodeType.GROUP_BY, projNode.getType());
- LogicalNode scan = ((GroupbyNode)projNode).getChild();
+ LogicalNode project = ((LogicalRootNode)fromJson).getChild();
+ assertEquals(NodeType.PROJECTION, project.getType());
+ assertEquals(NodeType.HAVING, ((ProjectionNode) project).getChild().getType());
+ HavingNode havingNode = ((ProjectionNode) project).getChild();
+ assertEquals(NodeType.GROUP_BY, havingNode.getChild().getType());
+ GroupbyNode groupbyNode = havingNode.getChild();
+ assertEquals(NodeType.SCAN, groupbyNode.getChild().getType());
+ LogicalNode scan = groupbyNode.getChild();
assertEquals(NodeType.SCAN, scan.getType());
}
@@ -694,52 +699,8 @@ public class TestLogicalPlanner {
}
}
- static final String CUBE_ROLLUP [] = {
- "select name, empid, sum(score) from employee natural join score group by cube(name, empid)"
- };
-
- @Test
- public final void testCubeBy() throws PlanningException {
- Expr expr = sqlAnalyzer.parse(CUBE_ROLLUP[0]);
- LogicalNode plan = planner.createPlan(expr).getRootBlock().getRoot();
- testJsonSerDerObject(plan);
-
- Set<Set<Column>> cuboids = Sets.newHashSet();
-
- LogicalRootNode root = (LogicalRootNode) plan;
- assertEquals(NodeType.PROJECTION, root.getChild().getType());
- ProjectionNode projNode = root.getChild();
- assertEquals(NodeType.UNION, projNode.getChild().getType());
- UnionNode u0 = projNode.getChild();
- assertEquals(NodeType.GROUP_BY, u0.getLeftChild().getType());
- assertEquals(NodeType.UNION, u0.getRightChild().getType());
- GroupbyNode grp = u0.getLeftChild();
- cuboids.add(Sets.newHashSet(grp.getGroupingColumns()));
-
- UnionNode u1 = u0.getRightChild();
- assertEquals(NodeType.GROUP_BY, u1.getLeftChild().getType());
- assertEquals(NodeType.UNION, u1.getRightChild().getType());
- grp = u1.getLeftChild();
- cuboids.add(Sets.newHashSet(grp.getGroupingColumns()));
-
- UnionNode u2 = u1.getRightChild();
- assertEquals(NodeType.GROUP_BY, u2.getLeftChild().getType());
- grp = u2.getRightChild();
- cuboids.add(Sets.newHashSet(grp.getGroupingColumns()));
- assertEquals(NodeType.GROUP_BY, u2.getRightChild().getType());
- grp = u2.getLeftChild();
- cuboids.add(Sets.newHashSet(grp.getGroupingColumns()));
-
- assertEquals((int)Math.pow(2, 2), cuboids.size());
- for (Set<Column> result : testCubeByResult) {
- assertTrue(cuboids.contains(result));
- }
- }
-
static final String setStatements [] = {
"select deptName from employee where deptName like 'data%' union select deptName from score where deptName like 'data%'",
- "select deptName from employee union select deptName from score as s1 intersect select deptName from score as s2",
- "select deptName from employee union select deptName from score as s1 except select deptName from score as s2 intersect select deptName from score as s3"
};
@Test
@@ -751,47 +712,8 @@ public class TestLogicalPlanner {
LogicalRootNode root = (LogicalRootNode) plan;
assertEquals(NodeType.UNION, root.getChild().getType());
UnionNode union = root.getChild();
- assertEquals(NodeType.TABLE_SUBQUERY, union.getLeftChild().getType());
- TableSubQueryNode leftSub = union.getLeftChild();
- assertEquals(NodeType.PROJECTION, leftSub.getSubQuery().getType());
- assertEquals(NodeType.TABLE_SUBQUERY, union.getRightChild().getType());
- TableSubQueryNode rightSub = union.getRightChild();
- assertEquals(NodeType.PROJECTION, rightSub.getSubQuery().getType());
- }
-
- @Test
- public final void testSetPlan2() throws PlanningException {
- // for testing multiple set statements
- Expr expr = sqlAnalyzer.parse(setStatements[1]);
- LogicalPlan plan = planner.createPlan(expr);
- System.out.println(plan);
- LogicalRootNode root = plan.getRootBlock().getRoot();
- testJsonSerDerObject(root);
- assertEquals(NodeType.ROOT, root.getType());
- assertEquals(NodeType.UNION, root.getChild().getType());
- UnionNode union = root.getChild();
- assertEquals(NodeType.TABLE_SUBQUERY, union.getLeftChild().getType());
- assertEquals(NodeType.TABLE_SUBQUERY, union.getRightChild().getType());
- TableSubQueryNode subQuery = union.getRightChild();
- assertEquals(NodeType.INTERSECT, subQuery.getSubQuery().getType());
- }
-
- @Test
- public final void testSetPlan3() throws PlanningException {
- // for testing multiple set statements
- Expr expr = sqlAnalyzer.parse(setStatements[2]);
- LogicalPlan plan = planner.createPlan(expr);
- LogicalRootNode root = plan.getRootBlock().getRoot();
- testJsonSerDerObject(root);
- assertEquals(NodeType.ROOT, root.getType());
- assertEquals(NodeType.EXCEPT, root.getChild().getType());
- ExceptNode except = root.getChild();
- assertEquals(NodeType.TABLE_SUBQUERY, except.getLeftChild().getType());
- assertEquals(NodeType.TABLE_SUBQUERY, except.getRightChild().getType());
- TableSubQueryNode leftSubQuery = except.getLeftChild();
- TableSubQueryNode rightSubQuery = except.getRightChild();
- assertEquals(NodeType.UNION, leftSubQuery.getSubQuery().getType());
- assertEquals(NodeType.INTERSECT, rightSubQuery.getSubQuery().getType());
+ assertEquals(NodeType.PROJECTION, union.getLeftChild().getType());
+ assertEquals(NodeType.PROJECTION, union.getRightChild().getType());
}
static final String [] setQualifiers = {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestPlannerUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestPlannerUtil.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestPlannerUtil.java
index b456cf9..85ea4f2 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestPlannerUtil.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestPlannerUtil.java
@@ -101,8 +101,6 @@ public class TestPlannerUtil {
TestLogicalPlanner.testQuery7(root.getChild());
root.postOrder(new TwoPhaseBuilder());
-
- System.out.println(root);
}
private final class TwoPhaseBuilder implements LogicalNodeVisitor {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestBSTIndexExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestBSTIndexExec.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestBSTIndexExec.java
index a8f4631..cf24054 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestBSTIndexExec.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestBSTIndexExec.java
@@ -172,10 +172,11 @@ public class TestBSTIndexExec {
int tupleCount = this.randomValues.get(rndKey);
int counter = 0;
-
+ exec.init();
while (exec.next() != null) {
counter ++;
}
+ exec.close();
assertEquals(tupleCount , counter);
}
@@ -200,8 +201,7 @@ public class TestBSTIndexExec {
Datum[] datum = new Datum[]{DatumFactory.createInt4(rndKey)};
- return new BSTIndexScanExec(ctx, sm, scanNode, fragments.get(0), idxPath,
- idxSchema, comp , datum);
+ return new BSTIndexScanExec(ctx, sm, scanNode, fragments.get(0), idxPath, idxSchema, comp , datum);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashAntiJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashAntiJoinExec.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashAntiJoinExec.java
index c43046f..65ed3c4 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashAntiJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashAntiJoinExec.java
@@ -165,8 +165,8 @@ public class TestHashAntiJoinExec {
MergeJoinExec join = (MergeJoinExec) exec;
ExternalSortExec sortLeftChild = (ExternalSortExec) join.getLeftChild();
ExternalSortExec sortRightChild = (ExternalSortExec) join.getRightChild();
- SeqScanExec scanLeftChild = (SeqScanExec) sortLeftChild.getChild();
- SeqScanExec scanRightChild = (SeqScanExec) sortRightChild.getChild();
+ SeqScanExec scanLeftChild = sortLeftChild.getChild();
+ SeqScanExec scanRightChild = sortRightChild.getChild();
// 'people' should be outer table. So, the below code guarantees that people becomes the outer table.
if (scanLeftChild.getTableName().equals("people")) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
index 93f9c33..0b23bb5 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
@@ -159,7 +159,6 @@ public class TestHashSemiJoinExec {
Expr expr = analyzer.parse(QUERIES[0]);
LogicalPlan plan = planner.createPlan(expr);
optimizer.optimize(plan);
- System.out.println(plan);
LogicalNode rootNode = plan.getRootBlock().getRoot();
PhysicalPlanner phyPlanner = new PhysicalPlannerImpl(conf, sm);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
index 509e72e..0f3c165 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
@@ -176,8 +176,8 @@ public class TestPhysicalPlanner {
"select deptName, nullable from score group by deptName, nullable", // 11
"select 3 < 4 as ineq, 3.5 * 2 as score", // 12
"select (1 > 0) and 3 > 1", // 13
- "select deptName, class, sum(score), max(score), min(score) from score", // 14
- "select deptname, class, sum(score), max(score), min(score) from score group by deptname", // 15
+ "select sum(score), max(score), min(score) from score", // 14
+ "select deptname, sum(score), max(score), min(score) from score group by deptname", // 15
"select name from employee where empid >= 0", // 16
};
@@ -287,10 +287,9 @@ public class TestPhysicalPlanner {
Tuple tuple;
exec.init();
while ((tuple = exec.next()) != null) {
- assertEquals(DatumFactory.createNullDatum(), tuple.get(1));
- assertEquals(12, tuple.get(2).asInt4()); // sum
- assertEquals(3, tuple.get(3).asInt4()); // max
- assertEquals(1, tuple.get(4).asInt4()); // min
+ assertEquals(12, tuple.get(1).asInt4()); // sum
+ assertEquals(3, tuple.get(2).asInt4()); // max
+ assertEquals(1, tuple.get(3).asInt4()); // min
i++;
}
exec.close();
@@ -538,9 +537,9 @@ public class TestPhysicalPlanner {
Tuple tuple;
i = 0;
while ((tuple = scanner.next()) != null) {
- assertEquals(60, tuple.get(2).asInt4()); // sum
- assertEquals(3, tuple.get(3).asInt4()); // max
- assertEquals(1, tuple.get(4).asInt4()); // min
+ assertEquals(60, tuple.get(0).asInt4()); // sum
+ assertEquals(3, tuple.get(1).asInt4()); // max
+ assertEquals(1, tuple.get(2).asInt4()); // min
i++;
}
assertEquals(1, i);
@@ -595,7 +594,6 @@ public class TestPhysicalPlanner {
Expr context = analyzer.parse(QUERIES[9]);
LogicalPlan plan = planner.createPlan(context);
LogicalNode rootNode = optimizer.optimize(plan);
- System.out.println(rootNode.toString());
// Set all aggregation functions to the first phase mode
GroupbyNode groupbyNode = PlannerUtil.findTopNode(rootNode, NodeType.GROUP_BY);
@@ -651,7 +649,9 @@ public class TestPhysicalPlanner {
LogicalPlan plan = planner.createPlan(context);
LogicalNode rootNode = optimizer.optimize(plan);
LogicalRootNode root = (LogicalRootNode) rootNode;
- UnionNode union = new UnionNode(plan.newPID(), root.getChild(), root.getChild());
+ UnionNode union = new UnionNode(plan.newPID());
+ union.setLeftChild(root.getChild());
+ union.setRightChild(root.getChild());
root.setChild(union);
PhysicalPlanner phyPlanner = new PhysicalPlannerImpl(conf,sm);
@@ -875,7 +875,7 @@ public class TestPhysicalPlanner {
exec.next();
exec.close();
- assertTrue(((ProjectionExec)exec).getChild() instanceof MemSortExec);
+ assertTrue(exec instanceof MemSortExec);
context = analyzer.parse(SORT_QUERY[0]);
plan = planner.createPlan(context);
@@ -896,7 +896,7 @@ public class TestPhysicalPlanner {
exec.next();
exec.close();
- assertTrue(((ProjectionExec)exec).getChild() instanceof ExternalSortExec);
+ assertTrue(exec instanceof ExternalSortExec);
}
@Test
@@ -923,7 +923,7 @@ public class TestPhysicalPlanner {
exec.next();
exec.close();
- assertTrue(exec instanceof HashAggregateExec);
+ assertNotNull(PhysicalPlanUtil.findExecutor(exec, HashAggregateExec.class));
context = analyzer.parse(QUERIES[7]);
plan = planner.createPlan(context);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestCTASQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestCTASQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestCTASQuery.java
index 2d2a278..b117f64 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestCTASQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestCTASQuery.java
@@ -67,7 +67,7 @@ public class TestCTASQuery {
CatalogService catalog = cluster.getMaster().getCatalog();
TableDesc desc = catalog.getTableDesc(tableName);
assertTrue(catalog.existsTable(tableName));
- assertTrue(desc.getSchema().contains("testCtasWithoutTableDefinition.col1"));
+ assertTrue(desc.getSchema().containsByQualifiedName("testCtasWithoutTableDefinition.col1"));
PartitionDesc partitionDesc = desc.getPartitions();
assertEquals(partitionDesc.getPartitionsType(), CatalogProtos.PartitionsType.COLUMN);
assertEquals("key", partitionDesc.getColumns().get(0).getColumnName());
@@ -99,7 +99,8 @@ public class TestCTASQuery {
assertEquals(2, i);
}
- @Test
+ //@Test
+ // TODO- to be enabled
public final void testCtasWithColumnedPartition() throws Exception {
String tableName ="testCtasWithColumnedPartition";
tpch.execute(
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestGroupByQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestGroupByQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestGroupByQuery.java
index e0e7e21..e8995ca 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestGroupByQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestGroupByQuery.java
@@ -29,6 +29,7 @@ import java.sql.ResultSet;
public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testGroupBy() throws Exception {
+ // select count(1) as unique_key from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -36,6 +37,7 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testGroupBy2() throws Exception {
+ // select count(1) as unique_key from lineitem group by l_linenumber;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -43,6 +45,7 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testGroupBy3() throws Exception {
+ // select l_orderkey as gkey from lineitem group by gkey order by gkey;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -50,6 +53,23 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testGroupBy4() throws Exception {
+ // select l_orderkey as gkey, count(1) as unique_key from lineitem group by lineitem.l_orderkey;
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testGroupByNested1() throws Exception {
+ // select l_orderkey + l_partkey as unique_key from lineitem group by l_orderkey + l_partkey;
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testGroupByNested2() throws Exception {
+ // select sum(l_orderkey) + sum(l_partkey) as total from lineitem group by l_orderkey + l_partkey;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -57,6 +77,8 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testCountDistinct() throws Exception {
+ // select l_orderkey, max(l_orderkey) as maximum, count(distinct l_linenumber) as unique_key from lineitem
+ // group by l_orderkey;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -67,6 +89,7 @@ public class TestGroupByQuery extends QueryTestCaseBase {
* This is an unit test for a combination of aggregation and distinct aggregation functions.
*/
public final void testCountDistinct2() throws Exception {
+ // select l_orderkey, count(*) as cnt, count(distinct l_linenumber) as unique_key from lineitem group by l_orderkey;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -74,6 +97,7 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testComplexParameter() throws Exception {
+ // select sum(l_extendedprice*l_discount) as revenue from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -88,6 +112,7 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testComplexParameter2() throws Exception {
+ // select count(*) + max(l_orderkey) as merged from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -95,6 +120,8 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testHavingWithNamedTarget() throws Exception {
+ // select l_orderkey, avg(l_partkey) total, sum(l_linenumber) as num from lineitem group by l_orderkey
+ // having total >= 2 or num = 3;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -103,6 +130,8 @@ public class TestGroupByQuery extends QueryTestCaseBase {
@Test
public final void testHavingWithAggFunction() throws Exception {
+ // select l_orderkey, avg(l_partkey) total, sum(l_linenumber) as num from lineitem group by l_orderkey
+ // having avg(l_partkey) = 2.5 or num = 1;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
index ee29379..a9f7849 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestJoinQuery.java
@@ -35,13 +35,48 @@ public class TestJoinQuery extends QueryTestCaseBase {
}
@Test
- public final void testCrossJoinWithExplicitJoinQual() throws Exception {
+ public final void testWhereClauseJoin1() throws Exception {
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
}
@Test
+ public final void testWhereClauseJoin2() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testWhereClauseJoin3() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testWhereClauseJoin4() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testWhereClauseJoin5() throws Exception {
+ ResultSet res = executeQuery();
+ System.out.println(resultSetToString(res));
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testWhereClauseJoin6() throws Exception {
+ ResultSet res = executeQuery();
+ System.out.println(resultSetToString(res));
+ cleanupQuery(res);
+ }
+
+ @Test
public final void testTPCHQ2Join() throws Exception {
ResultSet res = executeQuery();
assertResultSet(res);
@@ -77,7 +112,16 @@ public class TestJoinQuery extends QueryTestCaseBase {
}
@Test
- public void testJoinAndCaseWhen() throws Exception {
+ public void testCrossJoinAndCaseWhen() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public void testOuterJoinAndCaseWhen1() throws Exception {
+ executeDDL("oj_table1_ddl.sql", "table1.tbl");
+ executeDDL("oj_table2_ddl.sql", "table2.tbl");
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSelectQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSelectQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSelectQuery.java
index 4152d85..a17a9f5 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSelectQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSelectQuery.java
@@ -33,8 +33,10 @@ import static org.junit.Assert.assertTrue;
@Category(IntegrationTest.class)
public class TestSelectQuery extends QueryTestCaseBase {
+
@Test
public final void testSelect() throws Exception {
+ // select l_orderkey, l_partkey from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -42,6 +44,7 @@ public class TestSelectQuery extends QueryTestCaseBase {
@Test
public final void testSelect2() throws Exception {
+ // select l_orderkey, l_partkey, l_orderkey + l_partkey as plus from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -49,6 +52,15 @@ public class TestSelectQuery extends QueryTestCaseBase {
@Test
public final void testSelect3() throws Exception {
+ // select l_orderkey + l_partkey as plus from lineitem;
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testSelectColumnAlias1() throws Exception {
+ // select l_orderkey as col1, l_orderkey + 1 as col2 from lineitem;
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
@@ -160,20 +172,6 @@ public class TestSelectQuery extends QueryTestCaseBase {
}
@Test
- public final void testUnion1() throws Exception {
- ResultSet res = executeQuery();
- assertResultSet(res);
- cleanupQuery(res);
- }
-
- @Test
- public final void testUnion2() throws Exception {
- ResultSet res = executeQuery();
- assertResultSet(res);
- cleanupQuery(res);
- }
-
- @Test
public final void testCreateAfterSelect() throws Exception {
ResultSet res = testingCluster.execute(
"create table orderkeys as select l_orderkey from lineitem");
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSortQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSortQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSortQuery.java
index d915ea2..8601cb5 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSortQuery.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestSortQuery.java
@@ -36,7 +36,24 @@ public class TestSortQuery extends QueryTestCaseBase {
}
@Test
- public final void testSortWithAliasKey() throws Exception {
+ public final void testSortWithAlias1() throws Exception {
+ // select l_linenumber, l_orderkey as sortkey from lineitem order by sortkey;
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testSortWithExpr1() throws Exception {
+ // select l_linenumber, l_orderkey as sortkey from lineitem order by l_orderkey + 1;
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testSortWithExpr2() throws Exception {
+ // select l_linenumber, l_orderkey as sortkey from lineitem order by l_linenumber, l_orderkey, (l_orderkey is null);
ResultSet res = executeQuery();
assertResultSet(res);
cleanupQuery(res);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
index e9b43be..ca5c071 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
@@ -83,14 +83,12 @@ public class TestTablePartitions {
resultRows1.put(45.0d, new int[]{3, 2});
resultRows1.put(38.0d, new int[]{2, 2});
- int i = 0;
- while(res.next()) {
+ for (int i = 0; i < 2; i++) {
+ assertTrue(res.next());
assertEquals(resultRows1.get(res.getDouble(4))[0], res.getInt(1));
assertEquals(resultRows1.get(res.getDouble(4))[1], res.getInt(2));
- i++;
}
res.close();
- assertEquals(2, i);
}
@Test
@@ -132,14 +130,12 @@ public class TestTablePartitions {
resultRows1.put(38.0d, new int[]{2, 2});
- int i = 0;
- while(res.next()) {
+ for (int i = 0; i < 2; i++) {
+ assertTrue(res.next());
assertEquals(resultRows1.get(res.getDouble(4))[0], res.getInt(2));
assertEquals(resultRows1.get(res.getDouble(4))[1], res.getInt(3));
- i++;
}
res.close();
- assertEquals(2, i);
Map<Double, int []> resultRows2 = Maps.newHashMap();
@@ -149,14 +145,12 @@ public class TestTablePartitions {
res = tpch.execute("select * from " + tableName + " where (col1 = 2 or col1 = 3) and col2 >= 2");
- i = 0;
- while(res.next()) {
+ for (int i = 0; i < 3; i++) {
+ assertTrue(res.next());
assertEquals(resultRows2.get(res.getDouble(4))[0], res.getInt(2));
assertEquals(resultRows2.get(res.getDouble(4))[1], res.getInt(3));
- i++;
}
res.close();
- assertEquals(3, i);
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestUnionQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestUnionQuery.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestUnionQuery.java
new file mode 100644
index 0000000..7f10736
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/query/TestUnionQuery.java
@@ -0,0 +1,135 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.query;
+
+import org.apache.tajo.IntegrationTest;
+import org.apache.tajo.QueryTestCaseBase;
+import org.apache.tajo.TajoTestingCluster;
+import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.catalog.TableDesc;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.sql.ResultSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/*
+ * Notations
+ * - S - select
+ * - SA - select *
+ * - U - union
+ * - G - group by
+ * - O - order by
+ */
+@Category(IntegrationTest.class)
+public class TestUnionQuery extends QueryTestCaseBase {
+
+ @Test
+ /**
+ * S (SA U SA) O
+ */
+ public final void testUnion1() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S (S U S) O
+ */
+ public final void testUnion2() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S O ((S G) U (S G))
+ */
+ public final void testUnion3() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S G (S G)
+ */
+ public final void testUnion4() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S G (S F G)
+ */
+ public final void testUnion5() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S G (SA)
+ */
+ public final void testUnion6() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ /**
+ * S (SA)
+ */
+ public final void testUnion7() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testUnion8() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testUnion9() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+
+ @Test
+ public final void testUnion10() throws Exception {
+ ResultSet res = executeQuery();
+ assertResultSet(res);
+ cleanupQuery(res);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestResultSet.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestResultSet.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestResultSet.java
index b591a8c..aff996b 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestResultSet.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestResultSet.java
@@ -106,9 +106,6 @@ public class TestResultSet {
for (int i = 0; i < meta.getColumnCount(); i++) {
assertEquals(schema.getColumn(i).getColumnName(), meta.getColumnName(i + 1));
assertEquals(schema.getColumn(i).getQualifier(), meta.getTableName(i + 1));
-// assertEquals(schema.getColumn(i).getDataType().getClass().getCanonicalName(),
-// meta.getColumnTypeName(i + 1));
- System.out.println(">>>>>>>>>>" + meta.getColumnTypeName(i + 1));
}
int i = 0;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java
index 98a7ed2..2313388 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java
@@ -238,7 +238,6 @@ public class TestTajoJdbc {
while(rs.next()) {
assertEquals(tableName, rs.getString("TABLE_NAME"));
- System.out.println(">>>>" + rs.getString("COLUMN_NAME"));
assertEquals(columns.get(numColumns).getColumnName(), rs.getString("COLUMN_NAME"));
//TODO assert type
numColumns++;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
index 4d78a27..053c028 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
@@ -112,7 +112,6 @@ public class TestExecutionBlockCursor {
count++;
}
- // 5 input relations, 1 broadcast join and 2 symmetric repartition joins and 1 terminal = 8 execution blocks
- assertEquals(8, count);
+ assertEquals(6, count);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/TestRangeRetrieverHandler.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/TestRangeRetrieverHandler.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/TestRangeRetrieverHandler.java
index 9c21633..018042c 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/TestRangeRetrieverHandler.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/TestRangeRetrieverHandler.java
@@ -54,8 +54,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
public class TestRangeRetrieverHandler {
private TajoTestingCluster util;
@@ -143,8 +142,15 @@ public class TestRangeRetrieverHandler {
PhysicalPlanner phyPlanner = new PhysicalPlannerImpl(conf,sm);
PhysicalExec exec = phyPlanner.createPlan(ctx, rootNode);
- ProjectionExec proj = (ProjectionExec) exec;
- MemSortExec sort = (MemSortExec) proj.getChild();
+ MemSortExec sort = null;
+ if (exec instanceof ProjectionExec) {
+ ProjectionExec projExec = (ProjectionExec) exec;
+ sort = projExec.getChild();
+ } else if (exec instanceof MemSortExec) {
+ sort = (MemSortExec) exec;
+ } else {
+ assertTrue(false);
+ }
SortSpec[] sortSpecs = sort.getPlan().getSortKeys();
RangeShuffleFileWriteExec idxStoreExec = new RangeShuffleFileWriteExec(ctx, sm, sort, sort.getSchema(),
@@ -257,8 +263,16 @@ public class TestRangeRetrieverHandler {
PhysicalPlanner phyPlanner = new PhysicalPlannerImpl(conf,sm);
PhysicalExec exec = phyPlanner.createPlan(ctx, rootNode);
- ProjectionExec proj = (ProjectionExec) exec;
- MemSortExec sort = (MemSortExec) proj.getChild();
+ MemSortExec sort = null;
+ if (exec instanceof ProjectionExec) {
+ ProjectionExec projExec = (ProjectionExec) exec;
+ sort = projExec.getChild();
+ } else if (exec instanceof MemSortExec) {
+ sort = (MemSortExec) exec;
+ } else {
+ assertTrue(false);
+ }
+
SortSpec[] sortSpecs = sort.getPlan().getSortKeys();
RangeShuffleFileWriteExec idxStoreExec = new RangeShuffleFileWriteExec(ctx, sm, sort,
sort.getSchema(), sort.getSchema(), sortSpecs);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/dataserver/TestHttpDataServer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/dataserver/TestHttpDataServer.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/dataserver/TestHttpDataServer.java
index aa2c5fd..2b3887f 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/dataserver/TestHttpDataServer.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/worker/dataserver/TestHttpDataServer.java
@@ -68,7 +68,6 @@ public class TestHttpDataServer {
String line;
boolean found = false;
while ((line = in.readLine()) != null) {
- System.out.println(line);
if (line.equals(watermark))
found = true;
}
@@ -164,7 +163,6 @@ public class TestHttpDataServer {
String line;
boolean found = false;
while ((line = in.readLine()) != null) {
- System.out.println(line);
if (line.equals(watermark))
found = true;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table1.tbl
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table1.tbl b/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table1.tbl
new file mode 100644
index 0000000..6405b31
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table1.tbl
@@ -0,0 +1,5 @@
+1|ooo|1.1|a
+2|ppp|2.3|b
+3|qqq|3.4|c
+4|rrr|4.5|d
+5|xxx|5.6|e
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table2.tbl
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table2.tbl b/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table2.tbl
new file mode 100644
index 0000000..68340bf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/dataset/TestJoinQuery/table2.tbl
@@ -0,0 +1,4 @@
+1|NULL|NULL|a
+2|NULL|NULL|b
+NULL|NULL|10.0|c
+NULL|NULL|20.0|d
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested1.sql
new file mode 100644
index 0000000..10fa423
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested1.sql
@@ -0,0 +1 @@
+select l_orderkey + l_partkey as unique_key from lineitem group by l_orderkey + l_partkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested2.sql
new file mode 100644
index 0000000..e7bbcac
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestGroupByQuery/testGroupByNested2.sql
@@ -0,0 +1 @@
+select sum(l_orderkey) + sum(l_partkey) as total from lineitem group by l_orderkey + l_partkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table1_ddl.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table1_ddl.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table1_ddl.sql
new file mode 100644
index 0000000..ea2c954
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table1_ddl.sql
@@ -0,0 +1,6 @@
+-- Outer Join's Left Table
+-- It is used in TestJoin::testOuterJoinAndCaseWhen
+
+create external table table1 (id int, name text, score float, type text) using csv
+with ('csvfile.delimiter'='|', 'csvfile.null'='NULL') location ${table.path};
+
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table2_ddl.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table2_ddl.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table2_ddl.sql
new file mode 100644
index 0000000..ac6459a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/oj_table2_ddl.sql
@@ -0,0 +1,6 @@
+-- Outer Join's Left Table
+-- It is used in TestJoin::testOuterJoinAndCaseWhen
+
+create external table table2 (id int, name text, score float, type text) using csv
+with ('csvfile.delimiter'='|', 'csvfile.null'='NULL') location ${table.path};
+
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoin.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoin.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoin.sql
index 5b21842..1bb2916 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoin.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoin.sql
@@ -1 +1 @@
-select n_name, r_name, n_regionkey, r_regionkey from nation, region;
\ No newline at end of file
+select n_name, r_name, n_regionkey, r_regionkey from nation, region order by n_name, r_name;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinAndCaseWhen.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinAndCaseWhen.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinAndCaseWhen.sql
new file mode 100644
index 0000000..d058aba
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinAndCaseWhen.sql
@@ -0,0 +1,18 @@
+select
+ r_regionkey,
+ n_regionkey,
+ case
+ when r_regionkey = 1 then 'one'
+ when r_regionkey = 2 then 'two'
+ when r_regionkey = 3 then 'three'
+ when r_regionkey = 4 then 'four'
+ else 'zero'
+ end as cond
+from
+ region,
+ nation
+where
+ r_regionkey = n_regionkey
+order by
+ r_regionkey,
+ n_regionkey
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinWithExplicitJoinQual.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinWithExplicitJoinQual.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinWithExplicitJoinQual.sql
deleted file mode 100644
index 9910296..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testCrossJoinWithExplicitJoinQual.sql
+++ /dev/null
@@ -1 +0,0 @@
-select n_name, r_name, n_regionkey, r_regionkey from nation, region where n_regionkey = r_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinAndCaseWhen.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinAndCaseWhen.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinAndCaseWhen.sql
deleted file mode 100644
index f22b1b3..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinAndCaseWhen.sql
+++ /dev/null
@@ -1,15 +0,0 @@
-select
- r_regionkey,
- n_regionkey,
- case
- when r_regionkey = 1 then 'one'
- when r_regionkey = 2 then 'two'
- when r_regionkey = 3 then 'three'
- when r_regionkey = 4 then 'four'
- else 'zero'
- end as cond
-from
- region,
- nation
-where
- r_regionkey = n_regionkey
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinRefEval.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinRefEval.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinRefEval.sql
index bc5f180..3a123bb 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinRefEval.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testJoinRefEval.sql
@@ -1 +1,11 @@
-select r_regionkey, n_regionkey, (r_regionkey + n_regionkey) as plus from region, nation where r_regionkey = n_regionkey;
\ No newline at end of file
+select
+ r_regionkey,
+ n_regionkey,
+ (r_regionkey + n_regionkey) as plus
+from
+ region,
+ nation
+where
+ r_regionkey = n_regionkey
+order by
+ r_regionkey, n_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testOuterJoinAndCaseWhen1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testOuterJoinAndCaseWhen1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testOuterJoinAndCaseWhen1.sql
new file mode 100644
index 0000000..ccb58a5
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testOuterJoinAndCaseWhen1.sql
@@ -0,0 +1,9 @@
+select
+ a.id,
+ a.name,
+ b.id as id2,
+ b.name as name2,
+ case when b.name is null then '9991231' else b.name end as c1,
+ case when c.name is null then '9991231' else c.name end as c2
+from
+ table1 a left outer join table2 b on a.id = b.id left outer join table1 c on b.id = c.id;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql
index 80999d5..9b7b5b9 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testTPCHQ2Join.sql
@@ -18,3 +18,8 @@ where
and s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
+order by
+ s_acctbal,
+ s_name,
+ n_name,
+ p_partkey;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin1.sql
new file mode 100644
index 0000000..069be09
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin1.sql
@@ -0,0 +1,10 @@
+select
+ n_name,
+ r_name,
+ n_regionkey,
+ r_regionkey
+from
+ nation,
+ region
+where
+ n_regionkey = r_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin2.sql
new file mode 100644
index 0000000..0c6539b
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin2.sql
@@ -0,0 +1,8 @@
+select
+ n_name,
+ r_name
+from
+ nation,
+ region
+where
+ n_regionkey = r_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin3.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin3.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin3.sql
new file mode 100644
index 0000000..6495958
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin3.sql
@@ -0,0 +1,9 @@
+select
+ n_name,
+ r_name,
+ n_nationkey + 1 as p1,
+ r_regionkey + 1 as p2
+from
+ nation, region
+where
+ n_regionkey = r_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin4.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin4.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin4.sql
new file mode 100644
index 0000000..d8ee615
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin4.sql
@@ -0,0 +1,8 @@
+select
+ n_name,
+ r_name,
+ n_nationkey + r_regionkey
+from
+ nation, region
+where
+ n_regionkey = r_regionkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin5.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin5.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin5.sql
new file mode 100644
index 0000000..3494007
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin5.sql
@@ -0,0 +1,15 @@
+select
+ s_acctbal,
+ s_name,
+ p_partkey
+from
+ part,
+ supplier,
+ partsupp
+where
+ p_partkey = ps_partkey and
+ s_suppkey = ps_suppkey
+order by
+ s_acctbal,
+ s_name,
+ p_partkey;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin6.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin6.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin6.sql
new file mode 100644
index 0000000..3993462
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestJoinQuery/testWhereClauseJoin6.sql
@@ -0,0 +1,19 @@
+select
+ s_acctbal,
+ s_name,
+ p_partkey,
+ n_name,
+from
+ part,
+ supplier,
+ partsupp,
+ nation
+where
+ p_partkey = ps_partkey and
+ s_suppkey = ps_suppkey and
+ s_nationkey = n_nationkey
+order by
+ s_acctbal,
+ s_name,
+ p_partkey,
+ n_name;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testSelectColumnAlias1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testSelectColumnAlias1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testSelectColumnAlias1.sql
new file mode 100644
index 0000000..a9ce4a2
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testSelectColumnAlias1.sql
@@ -0,0 +1 @@
+select l_orderkey as col1, l_orderkey + 1 as col2 from lineitem;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion1.sql
deleted file mode 100644
index 34ca8d6..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion1.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-select
- num
-from (
-
-select
- o_custkey as num
-from
- orders
-
-union
-
-select
- c_custkey as num
-from
- customer
-) table1
-
-order by
- num;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion2.sql
deleted file mode 100644
index 6a42488..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSelectQuery/testUnion2.sql
+++ /dev/null
@@ -1,9 +0,0 @@
-select
- l_orderkey
-from (
- select l_orderkey from lineitem l1
- union
- select l_orderkey from lineitem l2
-) table1
-
-order by l_orderkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortAfterGroupby.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortAfterGroupby.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortAfterGroupby.sql
index 5807873..81a1d8e 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortAfterGroupby.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortAfterGroupby.sql
@@ -1 +1 @@
-select max(l_quantity), l_orderkey from lineitem group by l_orderkey order by l_orderkey;
\ No newline at end of file
+select max(l_quantity) as maxq, l_orderkey from lineitem group by l_orderkey order by l_orderkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAlias1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAlias1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAlias1.sql
new file mode 100644
index 0000000..cd8be3e
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAlias1.sql
@@ -0,0 +1 @@
+select l_linenumber, l_orderkey as sortkey from lineitem order by sortkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAliasKey.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAliasKey.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAliasKey.sql
deleted file mode 100644
index cd8be3e..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithAliasKey.sql
+++ /dev/null
@@ -1 +0,0 @@
-select l_linenumber, l_orderkey as sortkey from lineitem order by sortkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr1.sql
new file mode 100644
index 0000000..2aeba26
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr1.sql
@@ -0,0 +1 @@
+select l_linenumber, l_orderkey as sortkey from lineitem order by l_orderkey + 1;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr2.sql
new file mode 100644
index 0000000..b7247ff
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSortQuery/testSortWithExpr2.sql
@@ -0,0 +1 @@
+select l_linenumber, l_orderkey as sortkey from lineitem order by l_linenumber, l_orderkey, (l_orderkey is null);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testQ2FourJoins.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testQ2FourJoins.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testQ2FourJoins.sql
index 3ee34db..ffaaf87 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testQ2FourJoins.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testQ2FourJoins.sql
@@ -1,6 +1,16 @@
select
- s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment, ps_supplycost,
- r_name, p_type, p_size
+ s_acctbal,
+ s_name,
+ n_name,
+ p_partkey,
+ p_mfgr,
+ s_address,
+ s_phone,
+ s_comment,
+ ps_supplycost,
+ r_name,
+ p_type,
+ p_size
from
region join nation on n_regionkey = r_regionkey and r_name = 'AMERICA'
join supplier on s_nationkey = n_nationkey
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testTPCH14Expr.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testTPCH14Expr.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testTPCH14Expr.sql
index 425f6a1..8f6047f 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testTPCH14Expr.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestTPCH/testTPCH14Expr.sql
@@ -1,6 +1,11 @@
-select 100 * sum(
- case
- when p_type like 'PROMO%' then l_extendedprice else 0.0 end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue
+select
+ 100 *
+ sum(
+ case when p_type like 'PROMO%' then l_extendedprice else 0.0 end
+ ) /
+ sum(
+ l_extendedprice * (1 - l_discount)
+ ) as promo_revenue
from
lineitem, part
where
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion1.sql
new file mode 100644
index 0000000..34ca8d6
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion1.sql
@@ -0,0 +1,19 @@
+select
+ num
+from (
+
+select
+ o_custkey as num
+from
+ orders
+
+union
+
+select
+ c_custkey as num
+from
+ customer
+) table1
+
+order by
+ num;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
new file mode 100644
index 0000000..b4f01d9
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
@@ -0,0 +1,150 @@
+SELECT
+ *
+FROM (
+ SELECT
+ n_nationkey,
+ n_name
+
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+
+ UNION ALL
+
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+ ) T1
+ GROUP BY
+ n_nationkey,
+ n_name
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
+
+ UNION
+
+ SELECT
+ n_nationkey,
+ n_name
+
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+ UNION ALL
+
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+ ) T2
+
+ GROUP BY
+ n_nationkey,
+ n_name
+
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
+
+) TABLE1
+
+ORDER BY
+ n_nationkey desc
+
+UNION
+
+SELECT
+ *
+FROM (
+ SELECT
+ n_nationkey,
+ n_name
+
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+
+ UNION ALL
+
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+ ) T3
+ GROUP BY
+ n_nationkey,
+ n_name
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
+
+ UNION
+
+ SELECT
+ n_nationkey,
+ n_name
+
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+ UNION ALL
+
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+ ) T4
+
+ GROUP BY
+ n_nationkey,
+ n_name
+
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
+
+) TABLE2
+
+ORDER BY
+ n_nationkey,
+ n_name;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion2.sql
new file mode 100644
index 0000000..bcf2433
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion2.sql
@@ -0,0 +1,18 @@
+select
+ l_orderkey
+from (
+ select
+ l_orderkey
+ from
+ lineitem l1
+
+ union
+
+ select
+ l_orderkey
+ from
+ lineitem l2
+) table1
+
+order by
+ l_orderkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion3.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion3.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion3.sql
new file mode 100644
index 0000000..12a5b64
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion3.sql
@@ -0,0 +1,19 @@
+select
+ total
+from (
+
+select
+ count(*) as total
+from
+ orders
+
+union
+
+select
+ count(*) as total
+from
+ customer
+) table1
+
+order by
+ total;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion4.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion4.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion4.sql
new file mode 100644
index 0000000..f42325a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion4.sql
@@ -0,0 +1,16 @@
+select
+ count(*)
+from (
+
+ select
+ count(*) as total
+ from
+ orders
+
+ union
+
+ select
+ count(*) as total
+ from
+ customer
+) table1;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion5.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion5.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion5.sql
new file mode 100644
index 0000000..1d83c5c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion5.sql
@@ -0,0 +1,20 @@
+select
+ count(*)
+from (
+
+ select
+ count(*) as total
+ from
+ orders
+ WHERE
+ o_orderkey > 0
+
+ union
+
+ select
+ count(*) as total
+ from
+ customer
+ WHERE
+ c_custkey > 0
+) table1;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion6.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion6.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion6.sql
new file mode 100644
index 0000000..8052632
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion6.sql
@@ -0,0 +1,15 @@
+SELECT
+ count(*)
+FROM (
+ SELECT
+ *
+ FROM
+ lineitem
+
+ UNION ALL
+
+ SELECT
+ *
+ FROM
+ lineitem
+) T
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion7.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion7.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion7.sql
new file mode 100644
index 0000000..ad3f7d2
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion7.sql
@@ -0,0 +1,18 @@
+SELECT
+ orderkey
+FROM (
+ SELECT
+ l_orderkey as orderkey
+ FROM
+ lineitem
+
+ UNION
+
+ SELECT
+ l_orderkey as orderkey
+ FROM
+ lineitem
+) T
+
+order by
+ orderkey;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion8.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion8.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion8.sql
new file mode 100644
index 0000000..bf5fbee
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion8.sql
@@ -0,0 +1,24 @@
+SELECT
+ l_returnflag,
+ l_linestatus
+
+FROM (
+ SELECT
+ *
+ FROM
+ lineitem
+ WHERE
+ l_returnflag = 'R'
+
+ UNION ALL
+
+ SELECT
+ *
+ FROM
+ lineitem
+ WHERE
+ l_returnflag = 'R'
+) T
+GROUP BY
+ l_returnflag,
+ l_linestatus;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion9.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion9.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion9.sql
new file mode 100644
index 0000000..49ddca8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion9.sql
@@ -0,0 +1,29 @@
+SELECT
+ n_nationkey,
+ n_name
+
+FROM (
+ SELECT
+ *
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+
+ UNION ALL
+
+ SELECT
+ *
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+) T
+GROUP BY
+ n_nationkey,
+ n_name
+ORDER BY
+ n_nationkey desc,
+ n_name desc;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested1.result
new file mode 100644
index 0000000..85c5598
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested1.result
@@ -0,0 +1,6 @@
+unique_key
+-------------------------------
+2
+4
+6
+5
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested2.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested2.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested2.result
new file mode 100644
index 0000000..edae882
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestGroupByQuery/testGroupByNested2.result
@@ -0,0 +1,6 @@
+total
+-------------------------------
+4
+4
+6
+5
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoin.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoin.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoin.result
index 7a1a4c2..607adc4 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoin.result
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoin.result
@@ -1,127 +1,127 @@
n_name,r_name,n_regionkey,r_regionkey
-------------------------------
ALGERIA,AFRICA,0,0
-ARGENTINA,AFRICA,1,0
-BRAZIL,AFRICA,1,0
-CANADA,AFRICA,1,0
-EGYPT,AFRICA,4,0
-ETHIOPIA,AFRICA,0,0
-FRANCE,AFRICA,3,0
-GERMANY,AFRICA,3,0
-INDIA,AFRICA,2,0
-INDONESIA,AFRICA,2,0
-IRAN,AFRICA,4,0
-IRAQ,AFRICA,4,0
-JAPAN,AFRICA,2,0
-JORDAN,AFRICA,4,0
-KENYA,AFRICA,0,0
-MOROCCO,AFRICA,0,0
-MOZAMBIQUE,AFRICA,0,0
-PERU,AFRICA,1,0
-CHINA,AFRICA,2,0
-ROMANIA,AFRICA,3,0
-SAUDI ARABIA,AFRICA,4,0
-VIETNAM,AFRICA,2,0
-RUSSIA,AFRICA,3,0
-UNITED KINGDOM,AFRICA,3,0
-UNITED STATES,AFRICA,1,0
ALGERIA,AMERICA,0,1
-ARGENTINA,AMERICA,1,1
-BRAZIL,AMERICA,1,1
-CANADA,AMERICA,1,1
-EGYPT,AMERICA,4,1
-ETHIOPIA,AMERICA,0,1
-FRANCE,AMERICA,3,1
-GERMANY,AMERICA,3,1
-INDIA,AMERICA,2,1
-INDONESIA,AMERICA,2,1
-IRAN,AMERICA,4,1
-IRAQ,AMERICA,4,1
-JAPAN,AMERICA,2,1
-JORDAN,AMERICA,4,1
-KENYA,AMERICA,0,1
-MOROCCO,AMERICA,0,1
-MOZAMBIQUE,AMERICA,0,1
-PERU,AMERICA,1,1
-CHINA,AMERICA,2,1
-ROMANIA,AMERICA,3,1
-SAUDI ARABIA,AMERICA,4,1
-VIETNAM,AMERICA,2,1
-RUSSIA,AMERICA,3,1
-UNITED KINGDOM,AMERICA,3,1
-UNITED STATES,AMERICA,1,1
ALGERIA,ASIA,0,2
-ARGENTINA,ASIA,1,2
-BRAZIL,ASIA,1,2
-CANADA,ASIA,1,2
-EGYPT,ASIA,4,2
-ETHIOPIA,ASIA,0,2
-FRANCE,ASIA,3,2
-GERMANY,ASIA,3,2
-INDIA,ASIA,2,2
-INDONESIA,ASIA,2,2
-IRAN,ASIA,4,2
-IRAQ,ASIA,4,2
-JAPAN,ASIA,2,2
-JORDAN,ASIA,4,2
-KENYA,ASIA,0,2
-MOROCCO,ASIA,0,2
-MOZAMBIQUE,ASIA,0,2
-PERU,ASIA,1,2
-CHINA,ASIA,2,2
-ROMANIA,ASIA,3,2
-SAUDI ARABIA,ASIA,4,2
-VIETNAM,ASIA,2,2
-RUSSIA,ASIA,3,2
-UNITED KINGDOM,ASIA,3,2
-UNITED STATES,ASIA,1,2
ALGERIA,EUROPE,0,3
-ARGENTINA,EUROPE,1,3
-BRAZIL,EUROPE,1,3
-CANADA,EUROPE,1,3
-EGYPT,EUROPE,4,3
-ETHIOPIA,EUROPE,0,3
-FRANCE,EUROPE,3,3
-GERMANY,EUROPE,3,3
-INDIA,EUROPE,2,3
-INDONESIA,EUROPE,2,3
-IRAN,EUROPE,4,3
-IRAQ,EUROPE,4,3
-JAPAN,EUROPE,2,3
-JORDAN,EUROPE,4,3
-KENYA,EUROPE,0,3
-MOROCCO,EUROPE,0,3
-MOZAMBIQUE,EUROPE,0,3
-PERU,EUROPE,1,3
-CHINA,EUROPE,2,3
-ROMANIA,EUROPE,3,3
-SAUDI ARABIA,EUROPE,4,3
-VIETNAM,EUROPE,2,3
-RUSSIA,EUROPE,3,3
-UNITED KINGDOM,EUROPE,3,3
-UNITED STATES,EUROPE,1,3
ALGERIA,MIDDLE EAST,0,4
+ARGENTINA,AFRICA,1,0
+ARGENTINA,AMERICA,1,1
+ARGENTINA,ASIA,1,2
+ARGENTINA,EUROPE,1,3
ARGENTINA,MIDDLE EAST,1,4
+BRAZIL,AFRICA,1,0
+BRAZIL,AMERICA,1,1
+BRAZIL,ASIA,1,2
+BRAZIL,EUROPE,1,3
BRAZIL,MIDDLE EAST,1,4
+CANADA,AFRICA,1,0
+CANADA,AMERICA,1,1
+CANADA,ASIA,1,2
+CANADA,EUROPE,1,3
CANADA,MIDDLE EAST,1,4
+CHINA,AFRICA,2,0
+CHINA,AMERICA,2,1
+CHINA,ASIA,2,2
+CHINA,EUROPE,2,3
+CHINA,MIDDLE EAST,2,4
+EGYPT,AFRICA,4,0
+EGYPT,AMERICA,4,1
+EGYPT,ASIA,4,2
+EGYPT,EUROPE,4,3
EGYPT,MIDDLE EAST,4,4
+ETHIOPIA,AFRICA,0,0
+ETHIOPIA,AMERICA,0,1
+ETHIOPIA,ASIA,0,2
+ETHIOPIA,EUROPE,0,3
ETHIOPIA,MIDDLE EAST,0,4
+FRANCE,AFRICA,3,0
+FRANCE,AMERICA,3,1
+FRANCE,ASIA,3,2
+FRANCE,EUROPE,3,3
FRANCE,MIDDLE EAST,3,4
+GERMANY,AFRICA,3,0
+GERMANY,AMERICA,3,1
+GERMANY,ASIA,3,2
+GERMANY,EUROPE,3,3
GERMANY,MIDDLE EAST,3,4
+INDIA,AFRICA,2,0
+INDIA,AMERICA,2,1
+INDIA,ASIA,2,2
+INDIA,EUROPE,2,3
INDIA,MIDDLE EAST,2,4
+INDONESIA,AFRICA,2,0
+INDONESIA,AMERICA,2,1
+INDONESIA,ASIA,2,2
+INDONESIA,EUROPE,2,3
INDONESIA,MIDDLE EAST,2,4
+IRAN,AFRICA,4,0
+IRAN,AMERICA,4,1
+IRAN,ASIA,4,2
+IRAN,EUROPE,4,3
IRAN,MIDDLE EAST,4,4
+IRAQ,AFRICA,4,0
+IRAQ,AMERICA,4,1
+IRAQ,ASIA,4,2
+IRAQ,EUROPE,4,3
IRAQ,MIDDLE EAST,4,4
+JAPAN,AFRICA,2,0
+JAPAN,AMERICA,2,1
+JAPAN,ASIA,2,2
+JAPAN,EUROPE,2,3
JAPAN,MIDDLE EAST,2,4
+JORDAN,AFRICA,4,0
+JORDAN,AMERICA,4,1
+JORDAN,ASIA,4,2
+JORDAN,EUROPE,4,3
JORDAN,MIDDLE EAST,4,4
+KENYA,AFRICA,0,0
+KENYA,AMERICA,0,1
+KENYA,ASIA,0,2
+KENYA,EUROPE,0,3
KENYA,MIDDLE EAST,0,4
+MOROCCO,AFRICA,0,0
+MOROCCO,AMERICA,0,1
+MOROCCO,ASIA,0,2
+MOROCCO,EUROPE,0,3
MOROCCO,MIDDLE EAST,0,4
+MOZAMBIQUE,AFRICA,0,0
+MOZAMBIQUE,AMERICA,0,1
+MOZAMBIQUE,ASIA,0,2
+MOZAMBIQUE,EUROPE,0,3
MOZAMBIQUE,MIDDLE EAST,0,4
+PERU,AFRICA,1,0
+PERU,AMERICA,1,1
+PERU,ASIA,1,2
+PERU,EUROPE,1,3
PERU,MIDDLE EAST,1,4
-CHINA,MIDDLE EAST,2,4
+ROMANIA,AFRICA,3,0
+ROMANIA,AMERICA,3,1
+ROMANIA,ASIA,3,2
+ROMANIA,EUROPE,3,3
ROMANIA,MIDDLE EAST,3,4
-SAUDI ARABIA,MIDDLE EAST,4,4
-VIETNAM,MIDDLE EAST,2,4
+RUSSIA,AFRICA,3,0
+RUSSIA,AMERICA,3,1
+RUSSIA,ASIA,3,2
+RUSSIA,EUROPE,3,3
RUSSIA,MIDDLE EAST,3,4
+SAUDI ARABIA,AFRICA,4,0
+SAUDI ARABIA,AMERICA,4,1
+SAUDI ARABIA,ASIA,4,2
+SAUDI ARABIA,EUROPE,4,3
+SAUDI ARABIA,MIDDLE EAST,4,4
+UNITED KINGDOM,AFRICA,3,0
+UNITED KINGDOM,AMERICA,3,1
+UNITED KINGDOM,ASIA,3,2
+UNITED KINGDOM,EUROPE,3,3
UNITED KINGDOM,MIDDLE EAST,3,4
-UNITED STATES,MIDDLE EAST,1,4
\ No newline at end of file
+UNITED STATES,AFRICA,1,0
+UNITED STATES,AMERICA,1,1
+UNITED STATES,ASIA,1,2
+UNITED STATES,EUROPE,1,3
+UNITED STATES,MIDDLE EAST,1,4
+VIETNAM,AFRICA,2,0
+VIETNAM,AMERICA,2,1
+VIETNAM,ASIA,2,2
+VIETNAM,EUROPE,2,3
+VIETNAM,MIDDLE EAST,2,4
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinAndCaseWhen.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinAndCaseWhen.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinAndCaseWhen.result
new file mode 100644
index 0000000..a4c33f8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinAndCaseWhen.result
@@ -0,0 +1,27 @@
+r_regionkey,n_regionkey,cond
+-------------------------------
+0,0,zero
+0,0,zero
+0,0,zero
+0,0,zero
+0,0,zero
+1,1,one
+1,1,one
+1,1,one
+1,1,one
+1,1,one
+2,2,two
+2,2,two
+2,2,two
+2,2,two
+2,2,two
+3,3,three
+3,3,three
+3,3,three
+3,3,three
+3,3,three
+4,4,four
+4,4,four
+4,4,four
+4,4,four
+4,4,four
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinWithExplicitJoinQual.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinWithExplicitJoinQual.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinWithExplicitJoinQual.result
deleted file mode 100644
index 5c54325..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testCrossJoinWithExplicitJoinQual.result
+++ /dev/null
@@ -1,27 +0,0 @@
-n_name,r_name,n_regionkey,r_regionkey
--------------------------------
-ALGERIA,AFRICA,0,0
-ARGENTINA,AMERICA,1,1
-BRAZIL,AMERICA,1,1
-CANADA,AMERICA,1,1
-EGYPT,MIDDLE EAST,4,4
-ETHIOPIA,AFRICA,0,0
-FRANCE,EUROPE,3,3
-GERMANY,EUROPE,3,3
-INDIA,ASIA,2,2
-INDONESIA,ASIA,2,2
-IRAN,MIDDLE EAST,4,4
-IRAQ,MIDDLE EAST,4,4
-JAPAN,ASIA,2,2
-JORDAN,MIDDLE EAST,4,4
-KENYA,AFRICA,0,0
-MOROCCO,AFRICA,0,0
-MOZAMBIQUE,AFRICA,0,0
-PERU,AMERICA,1,1
-CHINA,ASIA,2,2
-ROMANIA,EUROPE,3,3
-SAUDI ARABIA,MIDDLE EAST,4,4
-VIETNAM,ASIA,2,2
-RUSSIA,EUROPE,3,3
-UNITED KINGDOM,EUROPE,3,3
-UNITED STATES,AMERICA,1,1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinAndCaseWhen.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinAndCaseWhen.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinAndCaseWhen.result
deleted file mode 100644
index f5215ea..0000000
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinAndCaseWhen.result
+++ /dev/null
@@ -1,27 +0,0 @@
-r_regionkey,n_regionkey,cond
--------------------------------
-0,0,zero
-1,1,one
-1,1,one
-1,1,one
-4,4,four
-0,0,zero
-3,3,three
-3,3,three
-2,2,two
-2,2,two
-4,4,four
-4,4,four
-2,2,two
-4,4,four
-0,0,zero
-0,0,zero
-0,0,zero
-1,1,one
-2,2,two
-3,3,three
-4,4,four
-2,2,two
-3,3,three
-3,3,three
-1,1,one
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinRefEval.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinRefEval.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinRefEval.result
index 1b960dc..b24e47e 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinRefEval.result
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testJoinRefEval.result
@@ -1,27 +1,27 @@
r_regionkey,n_regionkey,plus
-------------------------------
0,0,0
+0,0,0
+0,0,0
+0,0,0
+0,0,0
+1,1,2
+1,1,2
1,1,2
1,1,2
1,1,2
-4,4,8
-0,0,0
-3,3,6
-3,3,6
2,2,4
2,2,4
-4,4,8
-4,4,8
2,2,4
-4,4,8
-0,0,0
-0,0,0
-0,0,0
-1,1,2
2,2,4
-3,3,6
-4,4,8
2,2,4
3,3,6
3,3,6
-1,1,2
\ No newline at end of file
+3,3,6
+3,3,6
+3,3,6
+4,4,8
+4,4,8
+4,4,8
+4,4,8
+4,4,8
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testOuterJoinAndCaseWhen1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testOuterJoinAndCaseWhen1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testOuterJoinAndCaseWhen1.result
new file mode 100644
index 0000000..f032d32
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testOuterJoinAndCaseWhen1.result
@@ -0,0 +1,7 @@
+id,name,id2,name2,c1,c2
+-------------------------------
+1,ooo,1,,9991231,ooo
+2,ppp,2,,9991231,ppp
+3,qqq,0,,9991231,9991231
+4,rrr,0,,9991231,9991231
+5,xxx,0,,9991231,9991231
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testTPCHQ2Join.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testTPCHQ2Join.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testTPCHQ2Join.result
index dcd7787..dc0968f 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testTPCHQ2Join.result
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testTPCHQ2Join.result
@@ -1,5 +1,5 @@
s_acctbal,s_name,n_name,p_partkey,p_mfgr,s_address,s_phone,s_comment
-------------------------------
-4192.4,Supplier#000000003,ARGENTINA,2,Manufacturer#1,q1,G3Pj6OjIuUYfUoH18BFTKP5aU9bEV3,11-383-516-1199,blithely silent requests after the express dependencies are sl
4032.68,Supplier#000000002,ETHIOPIA,1,Manufacturer#1,89eJ5ksX3ImxJQBvxObC,,15-679-861-2259, slyly bold instructions. idle dependen
+4192.4,Supplier#000000003,ARGENTINA,2,Manufacturer#1,q1,G3Pj6OjIuUYfUoH18BFTKP5aU9bEV3,11-383-516-1199,blithely silent requests after the express dependencies are sl
4641.08,Supplier#000000004,MOROCCO,3,Manufacturer#4,Bk7ah4CK8SYQTepEmvMkkgMwg,25-843-787-7479,riously even requests above the exp
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin1.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin1.result
new file mode 100644
index 0000000..5c54325
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestJoinQuery/testWhereClauseJoin1.result
@@ -0,0 +1,27 @@
+n_name,r_name,n_regionkey,r_regionkey
+-------------------------------
+ALGERIA,AFRICA,0,0
+ARGENTINA,AMERICA,1,1
+BRAZIL,AMERICA,1,1
+CANADA,AMERICA,1,1
+EGYPT,MIDDLE EAST,4,4
+ETHIOPIA,AFRICA,0,0
+FRANCE,EUROPE,3,3
+GERMANY,EUROPE,3,3
+INDIA,ASIA,2,2
+INDONESIA,ASIA,2,2
+IRAN,MIDDLE EAST,4,4
+IRAQ,MIDDLE EAST,4,4
+JAPAN,ASIA,2,2
+JORDAN,MIDDLE EAST,4,4
+KENYA,AFRICA,0,0
+MOROCCO,AFRICA,0,0
+MOZAMBIQUE,AFRICA,0,0
+PERU,AMERICA,1,1
+CHINA,ASIA,2,2
+ROMANIA,EUROPE,3,3
+SAUDI ARABIA,MIDDLE EAST,4,4
+VIETNAM,ASIA,2,2
+RUSSIA,EUROPE,3,3
+UNITED KINGDOM,EUROPE,3,3
+UNITED STATES,AMERICA,1,1
\ No newline at end of file
[08/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
index a67ca7a..ba21b4a 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/BinaryEval.java
@@ -52,6 +52,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
type == EvalType.AND ||
type == EvalType.OR ||
type == EvalType.EQUAL ||
+ type == EvalType.NOT_EQUAL ||
type == EvalType.LTH ||
type == EvalType.GTH ||
type == EvalType.LEQ ||
@@ -187,7 +188,7 @@ public class BinaryEval extends EvalNode implements Cloneable {
@Override
public String getName() {
- return "?";
+ return type.name();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
index c519250..9bbf4b4 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/CaseWhenEval.java
@@ -104,12 +104,12 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("CASE\n");
+ StringBuilder sb = new StringBuilder("CASE ");
for (IfThenEval when : whens) {
- sb.append(when).append("\n");
+ sb.append(when).append(" ");
}
- sb.append("ELSE ").append(elseResult).append(" END\n");
+ sb.append("ELSE ").append(elseResult).append(" END");
return sb.toString();
}
@@ -199,8 +199,7 @@ public class CaseWhenEval extends EvalNode implements GsonObject {
public boolean equals(Object object) {
if (object instanceof IfThenEval) {
IfThenEval other = (IfThenEval) object;
- return condition.equals(other.condition) &&
- result.equals(other.result);
+ return condition.equals(other.condition) && result.equals(other.result);
} else {
return false;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
index d262bc3..4044217 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/EvalTreeUtil.java
@@ -26,6 +26,7 @@ import org.apache.tajo.catalog.Schema;
import org.apache.tajo.common.TajoDataTypes.DataType;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.exception.InternalException;
+import org.apache.tajo.util.TUtil;
import java.util.*;
@@ -124,16 +125,16 @@ public class EvalTreeUtil {
+ expr.getType().toString());
}
}
-
+
/**
* Return all exprs to refer columns corresponding to the target.
- *
- * @param expr
+ *
+ * @param expr
* @param target to be found
* @return a list of exprs
*/
public static Collection<EvalNode> getContainExpr(EvalNode expr, Column target) {
- Set<EvalNode> exprSet = Sets.newHashSet();
+ Set<EvalNode> exprSet = Sets.newHashSet();
getContainExpr(expr, target, exprSet);
return exprSet;
}
@@ -298,4 +299,30 @@ public class EvalTreeUtil {
return this.aggFucntions;
}
}
+
+ public static <T extends EvalNode> Collection<T> findEvalsByType(EvalNode evalNode, EvalType type) {
+ EvalFinder finder = new EvalFinder(type);
+ finder.visitChild(null, evalNode, new Stack<EvalNode>());
+ return (Collection<T>) finder.evalNodes;
+ }
+
+ public static class EvalFinder extends BasicEvalNodeVisitor<Object, Object> {
+ private EvalType targetType;
+ List<EvalNode> evalNodes = TUtil.newList();
+
+ public EvalFinder(EvalType targetType) {
+ this.targetType = targetType;
+ }
+
+ @Override
+ public Object visitChild(Object context, EvalNode evalNode, Stack<EvalNode> stack) {
+ super.visitChild(context, evalNode, stack);
+
+ if (evalNode.type == targetType) {
+ evalNodes.add(evalNode);
+ }
+
+ return evalNode;
+ }
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
index 6a840e4..dd29a3b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/FieldEval.java
@@ -42,17 +42,10 @@ public class FieldEval extends EvalNode implements Cloneable {
@Override
public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
if (fieldId == -1) {
- if(schema.contains(column.getQualifiedName())) {
- fieldId = schema.getColumnId(column.getQualifiedName());
- } else {
- if(schema.getColumnNum() != 0) {
- String schemaColQualName = schema.getColumn(0).getQualifier() +
- "." + column.getColumnName();
- fieldId = schema.getColumnId(schemaColQualName);
- } else {
- fieldId = schema.getColumnId(column.getQualifiedName());
- }
- }
+ fieldId = schema.getColumnId(column.getQualifiedName());
+ if (fieldId == -1) {
+ throw new IllegalStateException("No Such Column Reference: " + column + ", schema: " + schema);
+ }
}
FieldEvalContext fieldCtx = (FieldEvalContext) ctx;
fieldCtx.datum = tuple.get(fieldId);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
index 1e26e14..e113326 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/InEval.java
@@ -25,6 +25,7 @@ import org.apache.tajo.catalog.Schema;
import org.apache.tajo.common.TajoDataTypes;
import org.apache.tajo.datum.Datum;
import org.apache.tajo.datum.DatumFactory;
+import org.apache.tajo.datum.NullDatum;
import org.apache.tajo.storage.Tuple;
public class InEval extends BinaryEval {
@@ -69,6 +70,12 @@ public class InEval extends BinaryEval {
boolean isIncluded = false;
Datum value = tuple.get(fieldId);
+
+ if (value.isNull()) {
+ isNullCtx.isNull = true;
+ return;
+ }
+
for (Datum datum : values) {
if (value.equalsTo(datum).asBool()) {
isIncluded = true;
@@ -80,6 +87,9 @@ public class InEval extends BinaryEval {
@Override
public Datum terminate(EvalContext ctx) {
+ if (((InEvalCtx)ctx).isNull) {
+ return NullDatum.get();
+ }
return DatumFactory.createBool(not ^ ((InEvalCtx)ctx).result);
}
@@ -97,6 +107,7 @@ public class InEval extends BinaryEval {
}
private class InEvalCtx implements EvalContext {
+ boolean isNull;
boolean result;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
index 029f4f4..8bb4d95 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/IsNullEval.java
@@ -59,6 +59,11 @@ public class IsNullEval extends BinaryEval {
}
@Override
+ public String toString() {
+ return leftExpr + " IS " + (isNot ? "NOT NULL" : "NULL");
+ }
+
+ @Override
public void eval(EvalContext ctx, Schema schema, Tuple tuple) {
IsNullEvalCtx isNullCtx = (IsNullEvalCtx) ctx;
leftExpr.eval(isNullCtx.predicandContext, schema, tuple);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
index a45e96d..677708d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/eval/NotEval.java
@@ -64,7 +64,8 @@ public class NotEval extends EvalNode implements Cloneable {
@Override
public Datum terminate(EvalContext ctx) {
- return DatumFactory.createBool(!childEval.terminate(((NotEvalCtx) ctx).childExprCtx).asBool());
+ Datum datum = childEval.terminate(((NotEvalCtx) ctx).childExprCtx);
+ return !datum.isNull() ? DatumFactory.createBool(!datum.asBool()) : datum;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
index 968bf3e..70191a9 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/exception/NoSuchColumnException.java
@@ -20,6 +20,6 @@ package org.apache.tajo.engine.exception;
public class NoSuchColumnException extends VerifyException {
public NoSuchColumnException(String columnName) {
- super("ERROR: no such column '" + columnName + "'");
+ super("ERROR: no such a column '" + columnName + "'");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
index 308faf0..a8a555b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/HiveConverter.java
@@ -153,7 +153,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
}
Projection projection = new Projection();
- projection.setTargets(select.getTargets());
+ projection.setNamedExprs(select.getNamedExprs());
if (current != null)
projection.setChild(current);
@@ -253,7 +253,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
}
Projection projection = new Projection();
- projection.setTargets(select.getTargets());
+ projection.setNamedExprs(select.getNamedExprs());
if (current != null)
projection.setChild(current);
@@ -368,7 +368,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
}
Projection projection = new Projection();
- projection.setTargets(select.getTargets());
+ projection.setNamedExprs(select.getNamedExprs());
if (current != null)
projection.setChild(current);
@@ -542,7 +542,7 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
public Expr visitSelectList(HiveParser.SelectListContext ctx) {
Expr current = null;
Projection projection = new Projection();
- TargetExpr[] targets = new TargetExpr[ctx.selectItem().size()];
+ NamedExpr[] targets = new NamedExpr[ctx.selectItem().size()];
for (int i = 0; i < targets.length; i++) {
targets[i] = visitSelectItem(ctx.selectItem(i));
}
@@ -557,16 +557,16 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
}
if (!projection.isAllProjected())
- projection.setTargets(targets);
+ projection.setNamedExprs(targets);
current = projection;
return current;
}
@Override
- public TargetExpr visitSelectItem(HiveParser.SelectItemContext ctx) {
+ public NamedExpr visitSelectItem(HiveParser.SelectItemContext ctx) {
ColumnReferenceExpr columnReference;
- TargetExpr target = null;
+ NamedExpr target = null;
String tableName = "", itemName = "", alias = "";
@@ -587,9 +587,9 @@ public class HiveConverter extends HiveParserBaseVisitor<Expr> {
if (ctx.selectExpression() != null) {
if (ctx.selectExpression().expression() != null) {
- target = new TargetExpr(visitSelectExpression(ctx.selectExpression()));
+ target = new NamedExpr(visitSelectExpression(ctx.selectExpression()));
} else {
- target = new TargetExpr(columnReference);
+ target = new NamedExpr(columnReference);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
index 2555b9c..48d9e4d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
@@ -37,9 +37,6 @@ import java.util.Map;
import static org.apache.tajo.algebra.Aggregation.GroupElement;
import static org.apache.tajo.algebra.CreateTable.*;
-
-import org.apache.tajo.algebra.DateValue;
-import org.apache.tajo.algebra.TimeValue;
import static org.apache.tajo.common.TajoDataTypes.Type;
import static org.apache.tajo.engine.parser.SQLParser.*;
@@ -229,11 +226,11 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
if (ctx.MULTIPLY() != null) {
projection.setAll();
} else {
- TargetExpr[] targets = new TargetExpr[ctx.select_sublist().size()];
+ NamedExpr[] targets = new NamedExpr[ctx.select_sublist().size()];
for (int i = 0; i < targets.length; i++) {
targets[i] = visitSelect_sublist(ctx.select_sublist(i));
}
- projection.setTargets(targets);
+ projection.setNamedExprs(targets);
}
return projection;
@@ -250,9 +247,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
* @return
*/
@Override
- public TargetExpr visitSelect_sublist(SQLParser.Select_sublistContext ctx) {
+ public NamedExpr visitSelect_sublist(SQLParser.Select_sublistContext ctx) {
if (ctx.asterisked_qualifier != null) {
- return new TargetExpr(new ColumnReferenceExpr(ctx.asterisked_qualifier.getText(), "*"));
+ return new NamedExpr(new ColumnReferenceExpr(ctx.asterisked_qualifier.getText(), "*"));
} else {
return visitDerived_column(ctx.derived_column());
}
@@ -285,13 +282,13 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
ctx.grouping_element_list().grouping_element().get(i);
if (element.ordinary_grouping_set() != null) {
groups[i] = new GroupElement(GroupType.OrdinaryGroup,
- getColumnReferences(element.ordinary_grouping_set().column_reference_list()));
+ getRowValuePredicands(element.ordinary_grouping_set().row_value_predicand_list()));
} else if (element.rollup_list() != null) {
groups[i] = new GroupElement(GroupType.Rollup,
- getColumnReferences(element.rollup_list().c.column_reference_list()));
+ getRowValuePredicands(element.rollup_list().c.row_value_predicand_list()));
} else if (element.cube_list() != null) {
groups[i] = new GroupElement(GroupType.Cube,
- getColumnReferences(element.cube_list().c.column_reference_list()));
+ getRowValuePredicands(element.cube_list().c.row_value_predicand_list()));
}
}
clause.setGroups(groups);
@@ -306,7 +303,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
Sort.SortSpec specs [] = new Sort.SortSpec[size];
for (int i = 0; i < size; i++) {
SQLParser.Sort_specifierContext specContext = ctx.sort_specifier_list().sort_specifier(i);
- ColumnReferenceExpr column = visitColumn_reference(specContext.column);
+ Expr column = visitRow_value_predicand(specContext.key);
specs[i] = new Sort.SortSpec(column);
if (specContext.order_specification() != null) {
if (specContext.order.DESC() != null) {
@@ -387,6 +384,14 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
return join;
}
+ private Expr [] getRowValuePredicands(Row_value_predicand_listContext ctx) {
+ Expr [] rowValuePredicands = new Expr[ctx.row_value_predicand().size()];
+ for (int i = 0; i < rowValuePredicands.length; i++) {
+ rowValuePredicands[i] = visitRow_value_predicand(ctx.row_value_predicand(i));
+ }
+ return rowValuePredicands;
+ }
+
private ColumnReferenceExpr [] getColumnReferences(Column_reference_listContext ctx) {
ColumnReferenceExpr [] columnRefs = new ColumnReferenceExpr[ctx.column_reference().size()];
for (int i = 0; i < columnRefs.length; i++) {
@@ -490,9 +495,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
Expr left;
Expr right;
- for (int i = 0; i < ctx.boolean_value_expression().size(); i++) {
+ for (int i = 0; i < ctx.or_predicate().size(); i++) {
left = current;
- right = visitBoolean_value_expression(ctx.boolean_value_expression(i));
+ right = visitOr_predicate(ctx.or_predicate(i));
current = new BinaryOperator(OpType.Or, left, right);
}
@@ -505,9 +510,9 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
Expr left;
Expr right;
- for (int i = 0; i < ctx.boolean_value_expression().size(); i++) {
+ for (int i = 0; i < ctx.and_predicate().size(); i++) {
left = current;
- right = visitBoolean_value_expression(ctx.boolean_value_expression(i));
+ right = visitAnd_predicate(ctx.and_predicate(i));
current = new BinaryOperator(OpType.And, left, right);
}
@@ -821,8 +826,8 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
}
@Override
- public TargetExpr visitDerived_column(SQLParser.Derived_columnContext ctx) {
- TargetExpr target = new TargetExpr(visitValue_expression(ctx.value_expression()));
+ public NamedExpr visitDerived_column(SQLParser.Derived_columnContext ctx) {
+ NamedExpr target = new NamedExpr(visitValue_expression(ctx.value_expression()));
if (ctx.as_clause() != null) {
target.setAlias(ctx.as_clause().Identifier().getText());
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
index 26a1ba4..1c710dc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/AlgebraVisitor.java
@@ -24,83 +24,83 @@ import java.util.Stack;
public interface AlgebraVisitor<CONTEXT, RESULT> {
// Relational Operators
- RESULT visitProjection(CONTEXT ctx, Stack<OpType> stack, Projection expr) throws PlanningException;
- RESULT visitLimit(CONTEXT ctx, Stack<OpType> stack, Limit expr) throws PlanningException;
- RESULT visitSort(CONTEXT ctx, Stack<OpType> stack, Sort expr) throws PlanningException;
- RESULT visitHaving(CONTEXT ctx, Stack<OpType> stack, Having expr) throws PlanningException;
- RESULT visitGroupBy(CONTEXT ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException;
- RESULT visitJoin(CONTEXT ctx, Stack<OpType> stack, Join expr) throws PlanningException;
- RESULT visitFilter(CONTEXT ctx, Stack<OpType> stack, Selection expr) throws PlanningException;
- RESULT visitUnion(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
- RESULT visitExcept(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
- RESULT visitIntersect(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException;
- RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<OpType> stack, SimpleTableSubQuery expr) throws PlanningException;
- RESULT visitTableSubQuery(CONTEXT ctx, Stack<OpType> stack, TablePrimarySubQuery expr) throws PlanningException;
- RESULT visitRelationList(CONTEXT ctx, Stack<OpType> stack, RelationList expr) throws PlanningException;
- RESULT visitRelation(CONTEXT ctx, Stack<OpType> stack, Relation expr) throws PlanningException;
- RESULT visitScalarSubQuery(CONTEXT ctx, Stack<OpType> stack, ScalarSubQuery expr) throws PlanningException;
+ RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException;
+ RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException;
+ RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException;
+ RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException;
+ RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException;
+ RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException;
+ RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException;
+ RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+ RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+ RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException;
+ RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr) throws PlanningException;
+ RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr) throws PlanningException;
+ RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException;
+ RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException;
+ RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException;
// Data definition language
- RESULT visitCreateTable(CONTEXT ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException;
- RESULT visitDropTable(CONTEXT ctx, Stack<OpType> stack, DropTable expr) throws PlanningException;
+ RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException;
+ RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException;
// Insert or Update
- RESULT visitInsert(CONTEXT ctx, Stack<OpType> stack, Insert expr) throws PlanningException;
+ RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException;
// Logical operators
- RESULT visitAnd(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitOr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitNot(CONTEXT ctx, Stack<OpType> stack, NotExpr expr) throws PlanningException;
+ RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException;
// comparison predicates
- RESULT visitEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitNotEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitLessThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitGreaterThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
// Other Predicates
- RESULT visitBetween(CONTEXT ctx, Stack<OpType> stack, BetweenPredicate expr) throws PlanningException;
- RESULT visitCaseWhen(CONTEXT ctx, Stack<OpType> stack, CaseWhenPredicate expr) throws PlanningException;
- RESULT visitIsNullPredicate(CONTEXT ctx, Stack<OpType> stack, IsNullPredicate expr) throws PlanningException;
- RESULT visitInPredicate(CONTEXT ctx, Stack<OpType> stack, InPredicate expr) throws PlanningException;
- RESULT visitValueListExpr(CONTEXT ctx, Stack<OpType> stack, ValueListExpr expr) throws PlanningException;
- RESULT visitExistsPredicate(CONTEXT ctx, Stack<OpType> stack, ExistsPredicate expr) throws PlanningException;
+ RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException;
+ RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException;
+ RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException;
+ RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException;
+ RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException;
+ RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException;
// String Operator or Pattern Matching Predicates
- RESULT visitLikePredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
- RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
- RESULT visitRegexpPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr) throws PlanningException;
- RESULT visitConcatenate(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+ RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+ RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr) throws PlanningException;
+ RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
// arithmetic operators
- RESULT visitPlus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitMinus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitMultiply(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitDivide(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
- RESULT visitModular(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
+ RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException;
// other expressions
- RESULT visitSign(CONTEXT ctx, Stack<OpType> stack, SignedExpr expr) throws PlanningException;
- RESULT visitColumnReference(CONTEXT ctx, Stack<OpType> stack, ColumnReferenceExpr expr) throws PlanningException;
- RESULT visitTargetExpr(CONTEXT ctx, Stack<OpType> stack, TargetExpr expr) throws PlanningException;
- RESULT visitFunction(CONTEXT ctx, Stack<OpType> stack, FunctionExpr expr) throws PlanningException;
+ RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException;
+ RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr) throws PlanningException;
+ RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException;
+ RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException;
// set functions
- RESULT visitCountRowsFunction(CONTEXT ctx, Stack<OpType> stack, CountRowsFunctionExpr expr) throws PlanningException;
- RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<OpType> stack, GeneralSetFunctionExpr expr)
+ RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr) throws PlanningException;
+ RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
throws PlanningException;
// Literal
- RESULT visitCastExpr(CONTEXT ctx, Stack<OpType> stack, CastExpr expr) throws PlanningException;
-
- RESULT visitDataType(CONTEXT ctx, Stack<OpType> stack, DataTypeExpr expr) throws PlanningException;
- RESULT visitLiteral(CONTEXT ctx, Stack<OpType> stack, LiteralValue expr) throws PlanningException;
- RESULT visitNullLiteral(CONTEXT ctx, Stack<OpType> stack, NullLiteral expr) throws PlanningException;
- RESULT visitTimestampLiteral(CONTEXT ctx, Stack<OpType> stack, TimestampLiteral expr) throws PlanningException;
- RESULT visitTimeLiteral(CONTEXT ctx, Stack<OpType> stack, TimeLiteral expr) throws PlanningException;
- RESULT visitDateLiteral(CONTEXT ctx, Stack<OpType> stack, DateLiteral expr) throws PlanningException;
+ RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException;
+
+ RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException;
+ RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException;
+ RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException;
+ RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException;
+ RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException;
+ RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
index 880a874..a9c026d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BaseAlgebraVisitor.java
@@ -27,14 +27,14 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
/**
* The prehook is called before each expression is visited.
*/
- public void preHook(CONTEXT ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+ public void preHook(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
}
/**
* The posthook is called before each expression is visited.
*/
- public RESULT postHook(CONTEXT ctx, Stack<OpType> stack, Expr expr, RESULT current) throws PlanningException {
+ public RESULT postHook(CONTEXT ctx, Stack<Expr> stack, Expr expr, RESULT current) throws PlanningException {
return current;
}
@@ -44,7 +44,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
* @param stack The stack contains the upper operators' type.
* @param expr The visiting relational operator
*/
- public RESULT visit(CONTEXT ctx, Stack<OpType> stack, Expr expr) throws PlanningException {
+ public RESULT visit(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
preHook(ctx, stack, expr);
RESULT current;
@@ -196,7 +196,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
current = visitColumnReference(ctx, stack, (ColumnReferenceExpr) expr);
break;
case Target:
- current = visitTargetExpr(ctx, stack, (TargetExpr) expr);
+ current = visitTargetExpr(ctx, stack, (NamedExpr) expr);
break;
case Function:
current = visitFunction(ctx, stack, (FunctionExpr) expr);
@@ -222,30 +222,44 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
case NullLiteral:
current = visitNullLiteral(ctx, stack, (NullLiteral) expr);
break;
+ case DateLiteral:
+ current = visitDateLiteral(ctx, stack, (DateLiteral) expr);
+ break;
+ case TimeLiteral:
+ current = visitTimeLiteral(ctx, stack, (TimeLiteral) expr);
+ break;
case TimestampLiteral:
current = visitTimestampLiteral(ctx, stack, (TimestampLiteral) expr);
break;
+
default:
throw new PlanningException("Cannot support this type algebra \"" + expr.getType() + "\"");
}
- postHook(ctx, stack, expr, current);
+ // skip postHook against only one relation
+ if (expr.getType() == OpType.RelationList) {
+ RelationList relationList = (RelationList)expr;
+ if (relationList.size() == 1 && relationList.getRelations()[0].getType() == OpType.Relation) {
+ return current;
+ }
+ }
+ postHook(ctx, stack, expr, current);
return current;
}
- private RESULT visitDefaultUnaryExpr(CONTEXT ctx, Stack<OpType> stack, UnaryOperator expr) throws PlanningException {
- stack.push(expr.getType());
+ private RESULT visitDefaultUnaryExpr(CONTEXT ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
+ stack.push(expr);
RESULT child = visit(ctx, stack, expr.getChild());
stack.pop();
return child;
}
- private RESULT visitDefaultBinaryExpr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr)
+ private RESULT visitDefaultBinaryExpr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
throws PlanningException {
- stack.push(expr.getType());
+ stack.push(expr);
RESULT child = visit(ctx, stack, expr.getLeft());
visit(ctx, stack, expr.getRight());
stack.pop();
@@ -253,76 +267,113 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitProjection(CONTEXT ctx, Stack<OpType> stack, Projection expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException {
+ stack.push(expr);
+ for (NamedExpr target : expr.getNamedExprs()) {
+ visit(ctx, stack, target);
+ }
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitLimit(CONTEXT ctx, Stack<OpType> stack, Limit expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException {
+ stack.push(expr);
+ visit(ctx, stack, expr.getFetchFirstNum());
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitSort(CONTEXT ctx, Stack<OpType> stack, Sort expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
+ stack.push(expr);
+ for (Sort.SortSpec sortSpec : expr.getSortSpecs()) {
+ visit(ctx, stack, sortSpec.getKey());
+ }
+ RESULT result = visit(ctx, stack, expr.getChild());
+ return result;
}
@Override
- public RESULT visitHaving(CONTEXT ctx, Stack<OpType> stack, Having expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException {
+ stack.push(expr);
+ visit(ctx, stack, expr.getQual());
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitGroupBy(CONTEXT ctx, Stack<OpType> stack, Aggregation expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
+ stack.push(expr);
+
+ if (expr.hasHavingCondition()) {
+ visit(ctx, stack, expr.getHavingCondition());
+ }
+ for (org.apache.tajo.algebra.Aggregation.GroupElement groupElement : expr.getGroupSet()) {
+ for (Expr groupingSet : groupElement.getGroupingSets()) {
+ visit(ctx, stack, groupingSet);
+ }
+ }
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitJoin(CONTEXT ctx, Stack<OpType> stack, Join expr) throws PlanningException {
- return visitDefaultBinaryExpr(ctx, stack, expr);
+ public RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException {
+ stack.push(expr);
+ visit(ctx, stack, expr.getQual());
+ visit(ctx, stack, expr.getLeft());
+ RESULT result = visit(ctx, stack, expr.getRight());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitFilter(CONTEXT ctx, Stack<OpType> stack, Selection expr) throws PlanningException {
- return visitDefaultUnaryExpr(ctx, stack, expr);
+ public RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException {
+ stack.push(expr);
+ visit(ctx, stack, expr.getQual());
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
}
@Override
- public RESULT visitUnion(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+ public RESULT visitUnion(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitExcept(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+ public RESULT visitExcept(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitIntersect(CONTEXT ctx, Stack<OpType> stack, SetOperation expr) throws PlanningException {
+ public RESULT visitIntersect(CONTEXT ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<OpType> stack, SimpleTableSubQuery expr)
+ public RESULT visitSimpleTableSubQuery(CONTEXT ctx, Stack<Expr> stack, SimpleTableSubQuery expr)
throws PlanningException {
- stack.push(expr.getType());
- RESULT child = visit(ctx, stack, expr.getSubQuery());
- stack.pop();
- return child;
+ return visitDefaultUnaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitTableSubQuery(CONTEXT ctx, Stack<OpType> stack, TablePrimarySubQuery expr)
+ public RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr)
throws PlanningException {
- stack.push(expr.getType());
+ stack.push(expr);
RESULT child = visit(ctx, stack, expr.getSubQuery());
stack.pop();
return child;
}
@Override
- public RESULT visitRelationList(CONTEXT ctx, Stack<OpType> stack, RelationList expr) throws PlanningException {
- stack.push(expr.getType());
+ public RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException {
+ stack.push(expr);
RESULT child = null;
for (Expr e : expr.getRelations()) {
child = visit(ctx, stack, e);
@@ -332,16 +383,13 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitRelation(CONTEXT ctx, Stack<OpType> stack, Relation expr) throws PlanningException {
+ public RESULT visitRelation(CONTEXT ctx, Stack<Expr> stack, Relation expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitScalarSubQuery(CONTEXT ctx, Stack<OpType> stack, ScalarSubQuery expr) throws PlanningException {
- stack.push(OpType.ScalarSubQuery);
- RESULT result = visit(ctx, stack, expr.getSubQuery());
- stack.pop();
- return result;
+ public RESULT visitScalarSubQuery(CONTEXT ctx, Stack<Expr> stack, ScalarSubQuery expr) throws PlanningException {
+ return visitDefaultUnaryExpr(ctx, stack, expr);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -349,8 +397,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitCreateTable(CONTEXT ctx, Stack<OpType> stack, CreateTable expr) throws PlanningException {
- stack.push(expr.getType());
+ public RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException {
+ stack.push(expr);
RESULT child = null;
if (expr.hasSubQuery()) {
child = visit(ctx, stack, expr.getSubQuery());
@@ -360,7 +408,7 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitDropTable(CONTEXT ctx, Stack<OpType> stack, DropTable expr) throws PlanningException {
+ public RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException {
return null;
}
@@ -368,8 +416,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
// Insert or Update Section
///////////////////////////////////////////////////////////////////////////////////////////////////////////
- public RESULT visitInsert(CONTEXT ctx, Stack<OpType> stack, Insert expr) throws PlanningException {
- stack.push(expr.getType());
+ public RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException {
+ stack.push(expr);
RESULT child = visit(ctx, stack, expr.getSubQuery());
stack.pop();
return child;
@@ -380,17 +428,17 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitAnd(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitAnd(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitOr(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitOr(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitNot(CONTEXT ctx, Stack<OpType> stack, NotExpr expr) throws PlanningException {
+ public RESULT visitNot(CONTEXT ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
return visitDefaultUnaryExpr(ctx, stack, expr);
}
@@ -398,32 +446,32 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
// Comparison Predicates Section
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitNotEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitNotEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitLessThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitLessThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitLessThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitGreaterThan(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitGreaterThan(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr)
+ public RESULT visitGreaterThanOrEquals(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr)
throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@@ -433,8 +481,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitBetween(CONTEXT ctx, Stack<OpType> stack, BetweenPredicate expr) throws PlanningException {
- stack.push(OpType.Between);
+ public RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException {
+ stack.push(expr);
RESULT result = visit(ctx, stack, expr.predicand());
visit(ctx, stack, expr.begin());
visit(ctx, stack, expr.end());
@@ -443,8 +491,8 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitCaseWhen(CONTEXT ctx, Stack<OpType> stack, CaseWhenPredicate expr) throws PlanningException {
- stack.push(OpType.CaseWhen);
+ public RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException {
+ stack.push(expr);
RESULT result = null;
for (CaseWhenPredicate.WhenExpr when : expr.getWhens()) {
result = visit(ctx, stack, when.getCondition());
@@ -458,21 +506,18 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitIsNullPredicate(CONTEXT ctx, Stack<OpType> stack, IsNullPredicate expr) throws PlanningException {
- stack.push(OpType.IsNullPredicate);
- RESULT result = visit(ctx, stack, expr.getPredicand());
- stack.pop();
- return result;
+ public RESULT visitIsNullPredicate(CONTEXT ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
+ return visitDefaultUnaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitInPredicate(CONTEXT ctx, Stack<OpType> stack, InPredicate expr) throws PlanningException {
+ public RESULT visitInPredicate(CONTEXT ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitValueListExpr(CONTEXT ctx, Stack<OpType> stack, ValueListExpr expr) throws PlanningException {
- stack.push(OpType.ValueList);
+ public RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+ stack.push(expr);
RESULT result = null;
for (Expr value : expr.getValues()) {
result = visit(ctx, stack, value);
@@ -482,45 +527,33 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
}
@Override
- public RESULT visitExistsPredicate(CONTEXT ctx, Stack<OpType> stack, ExistsPredicate expr) throws PlanningException {
- stack.push(OpType.ExistsPredicate);
- RESULT result = visit(ctx, stack, expr.getSubQuery());
- stack.pop();
- return result;
+ public RESULT visitExistsPredicate(CONTEXT ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
+ return visitDefaultUnaryExpr(ctx, stack, expr);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// String Operator or Pattern Matching Predicates Section
///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- private RESULT visitPatternMatchPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
- throws PlanningException {
- stack.push(expr.getType());
- RESULT result = visit(ctx, stack, expr.getPredicand());
- visit(ctx, stack, expr.getPattern());
- stack.pop();
- return result;
- }
@Override
- public RESULT visitLikePredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+ public RESULT visitLikePredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
throws PlanningException {
- return visitPatternMatchPredicate(ctx, stack, expr);
+ return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+ public RESULT visitSimilarToPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
throws PlanningException {
- return visitPatternMatchPredicate(ctx, stack, expr);
+ return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitRegexpPredicate(CONTEXT ctx, Stack<OpType> stack, PatternMatchPredicate expr)
+ public RESULT visitRegexpPredicate(CONTEXT ctx, Stack<Expr> stack, PatternMatchPredicate expr)
throws PlanningException {
- return visitPatternMatchPredicate(ctx, stack, expr);
+ return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitConcatenate(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitConcatenate(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@@ -529,27 +562,27 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitPlus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitPlus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitMinus(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitMinus(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitMultiply(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitMultiply(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitDivide(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitDivide(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitModular(CONTEXT ctx, Stack<OpType> stack, BinaryOperator expr) throws PlanningException {
+ public RESULT visitModular(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
return visitDefaultBinaryExpr(ctx, stack, expr);
}
@@ -558,27 +591,24 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitSign(CONTEXT ctx, Stack<OpType> stack, SignedExpr expr) throws PlanningException {
+ public RESULT visitSign(CONTEXT ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
return visitDefaultUnaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitColumnReference(CONTEXT ctx, Stack<OpType> stack, ColumnReferenceExpr expr)
+ public RESULT visitColumnReference(CONTEXT ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
throws PlanningException {
return null;
}
@Override
- public RESULT visitTargetExpr(CONTEXT ctx, Stack<OpType> stack, TargetExpr expr) throws PlanningException {
- stack.push(OpType.Target);
- RESULT result = visit(ctx, stack, expr.getExpr());
- stack.pop();
- return result;
+ public RESULT visitTargetExpr(CONTEXT ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
+ return visitDefaultUnaryExpr(ctx, stack, expr);
}
@Override
- public RESULT visitFunction(CONTEXT ctx, Stack<OpType> stack, FunctionExpr expr) throws PlanningException {
- stack.push(OpType.Function);
+ public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+ stack.push(expr);
RESULT result = null;
for (Expr param : expr.getParams()) {
result = visit(ctx, stack, param);
@@ -592,15 +622,15 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<OpType> stack, CountRowsFunctionExpr expr)
+ public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
throws PlanningException {
return null;
}
@Override
- public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<OpType> stack, GeneralSetFunctionExpr expr)
+ public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
throws PlanningException {
- stack.push(OpType.GeneralSetFunction);
+ stack.push(expr);
RESULT result = null;
for (Expr param : expr.getParams()) {
result = visit(ctx, stack, param);
@@ -614,40 +644,40 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
///////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public RESULT visitDataType(CONTEXT ctx, Stack<OpType> stack, DataTypeExpr expr) throws PlanningException {
+ public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitCastExpr(CONTEXT ctx, Stack<OpType> stack, CastExpr expr) throws PlanningException {
- stack.push(OpType.Cast);
+ public RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+ stack.push(expr);
RESULT result = visit(ctx, stack, expr.getOperand());
stack.pop();
return result;
}
@Override
- public RESULT visitLiteral(CONTEXT ctx, Stack<OpType> stack, LiteralValue expr) throws PlanningException {
+ public RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitNullLiteral(CONTEXT ctx, Stack<OpType> stack, NullLiteral expr) throws PlanningException {
+ public RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<OpType> stack, TimestampLiteral expr) throws PlanningException {
+ public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitTimeLiteral(CONTEXT ctx, Stack<OpType> stack, TimeLiteral expr) throws PlanningException {
+ public RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
return null;
}
@Override
- public RESULT visitDateLiteral(CONTEXT ctx, Stack<OpType> stack, DateLiteral expr) throws PlanningException {
+ public RESULT visitDateLiteral(CONTEXT ctx, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
return null;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
index 9cbb0ad..59c6872 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/BasicLogicalPlanVisitor.java
@@ -68,6 +68,9 @@ public class BasicLogicalPlanVisitor<CONTEXT, RESULT> implements LogicalPlanVisi
case SORT:
current = visitSort(context, plan, block, (SortNode) node, stack);
break;
+ case HAVING:
+ current = visitHaving(context, plan, block, (HavingNode) node, stack);
+ break;
case GROUP_BY:
current = visitGroupBy(context, plan, block, (GroupbyNode) node, stack);
break;
@@ -152,6 +155,15 @@ public class BasicLogicalPlanVisitor<CONTEXT, RESULT> implements LogicalPlanVisi
}
@Override
+ public RESULT visitHaving(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ stack.push(node);
+ RESULT result = visit(context, plan, block, node.getChild(), stack);
+ stack.pop();
+ return result;
+ }
+
+ @Override
public RESULT visitGroupBy(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
Stack<LogicalNode> stack) throws PlanningException {
stack.push(node);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
index fd8a6e1..4cd40f7 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExplainLogicalPlanVisitor.java
@@ -96,6 +96,11 @@ public class ExplainLogicalPlanVisitor extends BasicLogicalPlanVisitor<ExplainLo
return visitUnaryNode(context, plan, block, node, stack);
}
+ public LogicalNode visitHaving(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ return visitUnaryNode(context, plan, block, node, stack);
+ }
+
@Override
public LogicalNode visitGroupBy(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
Stack<LogicalNode> stack) throws PlanningException {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
new file mode 100644
index 0000000..cd49c73
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprAnnotator.java
@@ -0,0 +1,622 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import org.apache.tajo.algebra.*;
+import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.catalog.CatalogUtil;
+import org.apache.tajo.catalog.Column;
+import org.apache.tajo.catalog.FunctionDesc;
+import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.datum.*;
+import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.exception.UndefinedFunctionException;
+import org.apache.tajo.engine.function.AggFunction;
+import org.apache.tajo.engine.function.GeneralFunction;
+import org.apache.tajo.engine.planner.logical.NodeType;
+import org.apache.tajo.exception.InternalException;
+import org.joda.time.DateTime;
+
+import java.util.Stack;
+
+/**
+ * <code>ExprAnnotator</code> makes an annotated expression called <code>EvalNode</code> from an
+ * {@link org.apache.tajo.algebra.Expr}. It visits descendants recursively from a given expression, and finally
+ * it returns an EvalNode.
+ */
+public class ExprAnnotator extends BaseAlgebraVisitor<ExprAnnotator.Context, EvalNode> {
+ private CatalogService catalog;
+
+ public ExprAnnotator(CatalogService catalog) {
+ this.catalog = catalog;
+ }
+
+ static class Context {
+ LogicalPlan plan;
+ LogicalPlan.QueryBlock currentBlock;
+
+ public Context(LogicalPlan plan, LogicalPlan.QueryBlock block) {
+ this.plan = plan;
+ this.currentBlock = block;
+ }
+ }
+
+ public EvalNode createEvalNode(LogicalPlan plan, LogicalPlan.QueryBlock block, Expr expr)
+ throws PlanningException {
+ Context context = new Context(plan, block);
+ return visit(context, new Stack<Expr>(), expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Logical Operator Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitAnd(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.AND, left, right);
+ }
+
+ @Override
+ public EvalNode visitOr(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.OR, left, right);
+ }
+
+ @Override
+ public EvalNode visitNot(Context ctx, Stack<Expr> stack, NotExpr expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode child = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return new NotEval(child);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Comparison Predicates Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public EvalNode visitEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitNotEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitLessThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitLessThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitGreaterThan(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitGreaterThanOrEquals(Context ctx, Stack<Expr> stack, BinaryOperator expr)
+ throws PlanningException {
+ return visitCommonComparison(ctx, stack, expr);
+ }
+
+ public EvalNode visitCommonComparison(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ EvalType evalType;
+ switch (expr.getType()) {
+ case Equals:
+ evalType = EvalType.EQUAL;
+ break;
+ case NotEquals:
+ evalType = EvalType.NOT_EQUAL;
+ break;
+ case LessThan:
+ evalType = EvalType.LTH;
+ break;
+ case LessThanOrEquals:
+ evalType = EvalType.LEQ;
+ break;
+ case GreaterThan:
+ evalType = EvalType.GTH;
+ break;
+ case GreaterThanOrEquals:
+ evalType = EvalType.GEQ;
+ break;
+ default:
+ throw new IllegalStateException("Wrong Expr Type: " + expr.getType());
+ }
+
+ return new BinaryEval(evalType, left, right);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Other Predicates Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitBetween(Context ctx, Stack<Expr> stack, BetweenPredicate between) throws PlanningException {
+ stack.push(between);
+ EvalNode predicand = visit(ctx, stack, between.predicand());
+ EvalNode begin = visit(ctx, stack, between.begin());
+ EvalNode end = visit(ctx, stack, between.end());
+ stack.pop();
+
+ BetweenPredicateEval betweenEval = new BetweenPredicateEval(
+ between.isNot(),
+ between.isSymmetric(),
+ predicand, begin, end);
+ return betweenEval;
+ }
+
+ @Override
+ public EvalNode visitCaseWhen(Context ctx, Stack<Expr> stack, CaseWhenPredicate caseWhen) throws PlanningException {
+ CaseWhenEval caseWhenEval = new CaseWhenEval();
+
+ EvalNode condition;
+ EvalNode result;
+ for (CaseWhenPredicate.WhenExpr when : caseWhen.getWhens()) {
+ condition = visit(ctx, stack, when.getCondition());
+ result = visit(ctx, stack, when.getResult());
+ caseWhenEval.addWhen(condition, result);
+ }
+
+ if (caseWhen.hasElseResult()) {
+ caseWhenEval.setElseResult(visit(ctx, stack, caseWhen.getElseResult()));
+ }
+
+ return caseWhenEval;
+ }
+
+ @Override
+ public EvalNode visitIsNullPredicate(Context ctx, Stack<Expr> stack, IsNullPredicate expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode child = visit(ctx, stack, expr.getPredicand());
+ stack.pop();
+ return new IsNullEval(expr.isNot(), child);
+ }
+
+ @Override
+ public EvalNode visitInPredicate(Context ctx, Stack<Expr> stack, InPredicate expr) throws PlanningException {
+ stack.push(expr);
+ Column predicandColumn = ctx.plan.resolveColumn(ctx.currentBlock, (ColumnReferenceExpr) expr.getPredicand());
+ FieldEval predicand = new FieldEval(predicandColumn);
+ RowConstantEval rowConstantEval = (RowConstantEval) visit(ctx, stack, expr.getInValue());
+ stack.pop();
+ return new InEval(predicand, rowConstantEval, expr.isNot());
+ }
+
+ @Override
+ public EvalNode visitValueListExpr(Context ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+ Datum[] values = new Datum[expr.getValues().length];
+ ConstEval [] constEvals = new ConstEval[expr.getValues().length];
+ for (int i = 0; i < expr.getValues().length; i++) {
+ constEvals[i] = (ConstEval) visit(ctx, stack, expr.getValues()[i]);
+ values[i] = constEvals[i].getValue();
+ }
+ return new RowConstantEval(values);
+ }
+
+ @Override
+ public EvalNode visitExistsPredicate(Context ctx, Stack<Expr> stack, ExistsPredicate expr) throws PlanningException {
+ throw new PlanningException("Cannot support EXISTS clause yet");
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // String Operator or Pattern Matching Predicates Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public EvalNode visitLikePredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+ throws PlanningException {
+ return visitPatternMatchPredicate(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitSimilarToPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+ throws PlanningException {
+ return visitPatternMatchPredicate(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitRegexpPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+ throws PlanningException {
+ return visitPatternMatchPredicate(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitConcatenate(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.CONCATENATE, left, right);
+ }
+
+ private EvalNode visitPatternMatchPredicate(Context ctx, Stack<Expr> stack, PatternMatchPredicate expr)
+ throws PlanningException {
+ EvalNode field = visit(ctx, stack, expr.getPredicand());
+ ConstEval pattern = (ConstEval) visit(ctx, stack, expr.getPattern());
+
+ // A pattern is a const value in pattern matching predicates.
+ // In a binary expression, the result is always null if a const value in left or right side is null.
+ if (pattern.getValue() instanceof NullDatum) {
+ return new ConstEval(NullDatum.get());
+ } else {
+ if (expr.getType() == OpType.LikePredicate) {
+ return new LikePredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
+ } else if (expr.getType() == OpType.SimilarToPredicate) {
+ return new SimilarToPredicateEval(expr.isNot(), field, pattern);
+ } else {
+ return new RegexPredicateEval(expr.isNot(), field, pattern, expr.isCaseInsensitive());
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Arithmetic Operators
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitPlus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.PLUS, left, right);
+ }
+
+ @Override
+ public EvalNode visitMinus(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.MINUS, left, right);
+ }
+
+ @Override
+ public EvalNode visitMultiply(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.MULTIPLY, left, right);
+ }
+
+ @Override
+ public EvalNode visitDivide(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.DIVIDE, left, right);
+ }
+
+ @Override
+ public EvalNode visitModular(Context ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode left = visit(ctx, stack, expr.getLeft());
+ EvalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+
+ return new BinaryEval(EvalType.MODULAR, left, right);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Other Expressions
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitSign(Context ctx, Stack<Expr> stack, SignedExpr expr) throws PlanningException {
+ stack.push(expr);
+ EvalNode numericExpr = visit(ctx, stack, expr.getChild());
+ stack.pop();
+
+ if (expr.isNegative()) {
+ return new SignedEval(expr.isNegative(), numericExpr);
+ } else {
+ return numericExpr;
+ }
+ }
+
+ @Override
+ public EvalNode visitColumnReference(Context ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+ throws PlanningException {
+ Column column = ctx.plan.resolveColumn(ctx.currentBlock, expr);
+ return new FieldEval(column);
+ }
+
+ @Override
+ public EvalNode visitTargetExpr(Context ctx, Stack<Expr> stack, NamedExpr expr) throws PlanningException {
+ throw new PlanningException("ExprAnnotator cannot take NamedExpr");
+ }
+
+ @Override
+ public EvalNode visitFunction(Context ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+ stack.push(expr); // <--- Push
+
+ // Given parameters
+ Expr[] params = expr.getParams();
+ if (params == null) {
+ params = new Expr[1];
+ params[0] = new NullLiteral();
+ }
+
+ EvalNode[] givenArgs = new EvalNode[params.length];
+ TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
+
+ for (int i = 0; i < params.length; i++) {
+ givenArgs[i] = visit(ctx, stack, params[i]);
+ paramTypes[i] = givenArgs[i].getValueType();
+ }
+
+ stack.pop(); // <--- Pop
+
+ if (!catalog.containFunction(expr.getSignature(), paramTypes)) {
+ throw new UndefinedFunctionException(CatalogUtil.getCanonicalName(expr.getSignature(), paramTypes));
+ }
+
+ FunctionDesc funcDesc = catalog.getFunction(expr.getSignature(), paramTypes);
+
+ try {
+ CatalogProtos.FunctionType functionType = funcDesc.getFuncType();
+ if (functionType == CatalogProtos.FunctionType.GENERAL
+ || functionType == CatalogProtos.FunctionType.UDF) {
+ return new GeneralFunctionEval(funcDesc, (GeneralFunction) funcDesc.newInstance(), givenArgs);
+ } else if (functionType == CatalogProtos.FunctionType.AGGREGATION
+ || functionType == CatalogProtos.FunctionType.UDA) {
+ if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
+ ctx.currentBlock.setAggregationRequire();
+ }
+ return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
+ } else if (functionType == CatalogProtos.FunctionType.DISTINCT_AGGREGATION
+ || functionType == CatalogProtos.FunctionType.DISTINCT_UDA) {
+ throw new PlanningException("Unsupported function: " + funcDesc.toString());
+ } else {
+ throw new PlanningException("Unsupported Function Type: " + functionType.name());
+ }
+ } catch (InternalException e) {
+ throw new PlanningException(e);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // General Set Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitCountRowsFunction(Context ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+ throws PlanningException {
+ FunctionDesc countRows = catalog.getFunction("count", CatalogProtos.FunctionType.AGGREGATION,
+ new TajoDataTypes.DataType[] {});
+
+ try {
+ ctx.currentBlock.setAggregationRequire();
+
+ return new AggregationFunctionCallEval(countRows, (AggFunction) countRows.newInstance(),
+ new EvalNode[] {});
+ } catch (InternalException e) {
+ throw new UndefinedFunctionException(CatalogUtil.
+ getCanonicalName(countRows.getSignature(), new TajoDataTypes.DataType[]{}));
+ }
+ }
+
+ @Override
+ public EvalNode visitGeneralSetFunction(Context ctx, Stack<Expr> stack, GeneralSetFunctionExpr setFunction)
+ throws PlanningException {
+
+ Expr[] params = setFunction.getParams();
+ EvalNode[] givenArgs = new EvalNode[params.length];
+ TajoDataTypes.DataType[] paramTypes = new TajoDataTypes.DataType[params.length];
+
+ CatalogProtos.FunctionType functionType = setFunction.isDistinct() ?
+ CatalogProtos.FunctionType.DISTINCT_AGGREGATION : CatalogProtos.FunctionType.AGGREGATION;
+ givenArgs[0] = visit(ctx, stack, params[0]);
+ if (setFunction.getSignature().equalsIgnoreCase("count")) {
+ paramTypes[0] = CatalogUtil.newSimpleDataType(TajoDataTypes.Type.ANY);
+ } else {
+ paramTypes[0] = givenArgs[0].getValueType();
+ }
+
+ if (!catalog.containFunction(setFunction.getSignature(), functionType, paramTypes)) {
+ throw new UndefinedFunctionException(CatalogUtil. getCanonicalName(setFunction.getSignature(), paramTypes));
+ }
+
+ FunctionDesc funcDesc = catalog.getFunction(setFunction.getSignature(), functionType, paramTypes);
+ if (!ctx.currentBlock.hasNode(NodeType.GROUP_BY)) {
+ ctx.currentBlock.setAggregationRequire();
+ }
+
+ try {
+ return new AggregationFunctionCallEval(funcDesc, (AggFunction) funcDesc.newInstance(), givenArgs);
+ } catch (InternalException e) {
+ throw new PlanningException(e);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Literal Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public EvalNode visitDataType(Context ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
+ return super.visitDataType(ctx, stack, expr);
+ }
+
+ @Override
+ public EvalNode visitCastExpr(Context ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+ EvalNode child = super.visitCastExpr(ctx, stack, expr);
+ return new CastEval(child, LogicalPlanner.convertDataType(expr.getTarget()));
+ }
+
+ @Override
+ public EvalNode visitLiteral(Context ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
+ switch (expr.getValueType()) {
+ case Boolean:
+ return new ConstEval(DatumFactory.createBool(((BooleanLiteral) expr).isTrue()));
+ case String:
+ return new ConstEval(DatumFactory.createText(expr.getValue()));
+ case Unsigned_Integer:
+ return new ConstEval(DatumFactory.createInt4(expr.getValue()));
+ case Unsigned_Large_Integer:
+ return new ConstEval(DatumFactory.createInt8(expr.getValue()));
+ case Unsigned_Float:
+ return new ConstEval(DatumFactory.createFloat8(expr.getValue()));
+ default:
+ throw new RuntimeException("Unsupported type: " + expr.getValueType());
+ }
+ }
+
+ @Override
+ public EvalNode visitNullLiteral(Context ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
+ return new ConstEval(NullDatum.get());
+ }
+
+ @Override
+ public EvalNode visitDateLiteral(Context context, Stack<Expr> stack, DateLiteral expr) throws PlanningException {
+ DateValue dateValue = expr.getDate();
+ int [] dates = dateToIntArray(dateValue.getYears(), dateValue.getMonths(), dateValue.getDays());
+ return new ConstEval(new DateDatum(dates[0], dates[1], dates[2]));
+ }
+
+ @Override
+ public EvalNode visitTimestampLiteral(Context ctx, Stack<Expr> stack, TimestampLiteral expr)
+ throws PlanningException {
+ DateValue dateValue = expr.getDate();
+ TimeValue timeValue = expr.getTime();
+
+ int [] dates = dateToIntArray(dateValue.getYears(),
+ dateValue.getMonths(),
+ dateValue.getDays());
+ int [] times = timeToIntArray(timeValue.getHours(),
+ timeValue.getMinutes(),
+ timeValue.getSeconds(),
+ timeValue.getSecondsFraction());
+ DateTime dateTime;
+ if (timeValue.hasSecondsFraction()) {
+ dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2], times[3]);
+ } else {
+ dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2]);
+ }
+
+ return new ConstEval(new TimestampDatum(dateTime));
+ }
+
+ @Override
+ public EvalNode visitTimeLiteral(Context ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
+ TimeValue timeValue = expr.getTime();
+ int [] times = timeToIntArray(timeValue.getHours(),
+ timeValue.getMinutes(),
+ timeValue.getSeconds(),
+ timeValue.getSecondsFraction());
+
+ TimeDatum datum;
+ if (timeValue.hasSecondsFraction()) {
+ datum = new TimeDatum(times[0], times[1], times[2], times[3]);
+ } else {
+ datum = new TimeDatum(times[0], times[1], times[2]);
+ }
+ return new ConstEval(datum);
+ }
+
+ public static int [] dateToIntArray(String years, String months, String days)
+ throws PlanningException {
+ int year = Integer.valueOf(years);
+ int month = Integer.valueOf(months);
+ int day = Integer.valueOf(days);
+
+ if (!(1 <= year && year <= 9999)) {
+ throw new PlanningException(String.format("Years (%d) must be between 1 and 9999 integer value", year));
+ }
+
+ if (!(1 <= month && month <= 12)) {
+ throw new PlanningException(String.format("Months (%d) must be between 1 and 12 integer value", month));
+ }
+
+ if (!(1<= day && day <= 31)) {
+ throw new PlanningException(String.format("Days (%d) must be between 1 and 31 integer value", day));
+ }
+
+ int [] results = new int[3];
+ results[0] = year;
+ results[1] = month;
+ results[2] = day;
+
+ return results;
+ }
+
+ public static int [] timeToIntArray(String hours, String minutes, String seconds, String fractionOfSecond)
+ throws PlanningException {
+ int hour = Integer.valueOf(hours);
+ int minute = Integer.valueOf(minutes);
+ int second = Integer.valueOf(seconds);
+ int fraction = 0;
+ if (fractionOfSecond != null) {
+ fraction = Integer.valueOf(fractionOfSecond);
+ }
+
+ if (!(0 <= hour && hour <= 23)) {
+ throw new PlanningException(String.format("Hours (%d) must be between 0 and 24 integer value", hour));
+ }
+
+ if (!(0 <= minute && minute <= 59)) {
+ throw new PlanningException(String.format("Minutes (%d) must be between 0 and 59 integer value", minute));
+ }
+
+ if (!(0 <= second && second <= 59)) {
+ throw new PlanningException(String.format("Seconds (%d) must be between 0 and 59 integer value", second));
+ }
+
+ if (fraction != 0) {
+ if (!(0 <= fraction && fraction <= 999)) {
+ throw new PlanningException(String.format("Seconds (%d) must be between 0 and 999 integer value", fraction));
+ }
+ }
+
+ int [] results = new int[4];
+ results[0] = hour;
+ results[1] = minute;
+ results[2] = second;
+ results[3] = fraction;
+
+ return results;
+ }
+}
[04/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java
index 74ef38a..9d66dd5 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/join/JoinGraph.java
@@ -24,45 +24,92 @@ import org.apache.tajo.engine.eval.AlgebraicUtil;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.eval.EvalTreeUtil;
import org.apache.tajo.engine.planner.LogicalPlan;
+import org.apache.tajo.engine.planner.NamedExprsManager;
import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.PlanningException;
import org.apache.tajo.engine.planner.graph.SimpleUndirectedGraph;
import org.apache.tajo.engine.planner.logical.JoinNode;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
public class JoinGraph extends SimpleUndirectedGraph<String, JoinEdge> {
+
+ private String [] guessRelationsFromJoinQual(LogicalPlan.QueryBlock block, EvalNode joinCondition)
+ throws PlanningException {
+
+ // Note that we can guarantee that each join qual used here is a singleton.
+ // This is because we use dissect a join qual into conjunctive normal forms.
+ // In other words, each join qual has a form 'col1 = col2'.
+ Column leftExpr = EvalTreeUtil.findAllColumnRefs(joinCondition.getLeftExpr()).get(0);
+ Column rightExpr = EvalTreeUtil.findAllColumnRefs(joinCondition.getRightExpr()).get(0);
+
+ // 0 - left table, 1 - right table
+ String [] relationNames = new String[2];
+
+ NamedExprsManager namedExprsMgr = block.getNamedExprsManager();
+ if (leftExpr.hasQualifier()) {
+ relationNames[0] = leftExpr.getQualifier();
+ } else {
+ if (namedExprsMgr.isAliasedName(leftExpr.getColumnName())) {
+ String columnName = namedExprsMgr.getOriginalName(leftExpr.getColumnName());
+ String [] parts = columnName.split("\\.");
+
+ if (parts.length != 2) {
+ throw new PlanningException("Cannot expect a referenced relation: " + leftExpr);
+ }
+
+ relationNames[0] = parts[0];
+ } else {
+ throw new PlanningException("Cannot expect a referenced relation: " + leftExpr);
+ }
+ }
+
+ if (rightExpr.hasQualifier()) {
+ relationNames[1] = rightExpr.getQualifier();
+ } else {
+ if (namedExprsMgr.isAliasedName(rightExpr.getColumnName())) {
+ String columnName = namedExprsMgr.getOriginalName(rightExpr.getColumnName());
+ String [] parts = columnName.split("\\.");
+ if (parts.length != 2) {
+ throw new PlanningException("Cannot expect a referenced relation: " + leftExpr);
+ }
+ relationNames[1] = parts[0];
+ } else {
+ throw new PlanningException("Cannot expect a referenced relation: " + rightExpr);
+ }
+ }
+
+ return relationNames;
+ }
public Collection<EvalNode> addJoin(LogicalPlan plan, LogicalPlan.QueryBlock block,
JoinNode joinNode) throws PlanningException {
Set<EvalNode> cnf = Sets.newHashSet(AlgebraicUtil.toConjunctiveNormalFormArray(joinNode.getJoinQual()));
Set<EvalNode> nonJoinQuals = Sets.newHashSet();
for (EvalNode singleQual : cnf) {
if (PlannerUtil.isJoinQual(singleQual)) {
- List<Column> leftExpr = EvalTreeUtil.findAllColumnRefs(singleQual.getLeftExpr());
- List<Column> rightExpr = EvalTreeUtil.findAllColumnRefs(singleQual.getRightExpr());
- String leftExprRelation = leftExpr.get(0).getQualifier();
- String rightExprRelName = rightExpr.get(0).getQualifier();
+ String [] relations = guessRelationsFromJoinQual(block, singleQual);
+ String leftExprRelName = relations[0];
+ String rightExprRelName = relations[1];
Collection<String> leftLineage = PlannerUtil.getRelationLineageWithinQueryBlock(plan, joinNode.getLeftChild());
- boolean isLeftExprForLeftTable = leftLineage.contains(leftExprRelation);
+ boolean isLeftExprForLeftTable = leftLineage.contains(leftExprRelName);
JoinEdge edge;
- edge = getEdge(leftExprRelation, rightExprRelName);
+ edge = getEdge(leftExprRelName, rightExprRelName);
if (edge != null) {
edge.addJoinQual(singleQual);
} else {
if (isLeftExprForLeftTable) {
edge = new JoinEdge(joinNode.getJoinType(),
- block.getRelation(leftExprRelation), block.getRelation(rightExprRelName), singleQual);
- addEdge(leftExprRelation, rightExprRelName, edge);
+ block.getRelation(leftExprRelName), block.getRelation(rightExprRelName), singleQual);
+ addEdge(leftExprRelName, rightExprRelName, edge);
} else {
edge = new JoinEdge(joinNode.getJoinType(),
- block.getRelation(rightExprRelName), block.getRelation(leftExprRelation), singleQual);
- addEdge(rightExprRelName, leftExprRelation, edge);
+ block.getRelation(rightExprRelName), block.getRelation(leftExprRelName), singleQual);
+ addEdge(rightExprRelName, leftExprRelName, edge);
}
}
} else {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
index e0f5f4c..ed82cef 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/AggregationExec.java
@@ -19,7 +19,6 @@
package org.apache.tajo.engine.planner.physical;
import com.google.common.collect.Sets;
-import org.apache.tajo.worker.TaskAttemptContext;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.datum.DatumFactory;
@@ -29,8 +28,11 @@ import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.eval.EvalType;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.engine.planner.logical.GroupbyNode;
+import org.apache.tajo.util.TUtil;
+import org.apache.tajo.worker.TaskAttemptContext;
import java.io.IOException;
+import java.util.List;
import java.util.Set;
public abstract class AggregationExec extends UnaryPhysicalExec {
@@ -43,24 +45,12 @@ public abstract class AggregationExec extends UnaryPhysicalExec {
protected EvalContext evalContexts [];
protected Schema evalSchema;
- protected EvalNode havingQual;
- protected EvalContext havingContext;
-
public AggregationExec(final TaskAttemptContext context, GroupbyNode plan,
PhysicalExec child) throws IOException {
super(context, plan.getInSchema(), plan.getOutSchema(), child);
this.plan = plan;
- if (plan.hasHavingCondition()) {
- this.havingQual = plan.getHavingCondition();
- this.havingContext = plan.getHavingCondition().newContext();
- }
-
- if (plan.getHavingSchema() != null) {
- this.evalSchema = plan.getHavingSchema();
- } else {
- this.evalSchema = plan.getOutSchema();
- }
+ evalSchema = plan.getOutSchema();
nonNullGroupingFields = Sets.newHashSet();
// keylist will contain a list of IDs of grouping column
@@ -72,27 +62,25 @@ public abstract class AggregationExec extends UnaryPhysicalExec {
nonNullGroupingFields.add(col);
}
- // measureList will contain a list of IDs of measure fields
- int valueIdx = 0;
- measureList = new int[plan.getTargets().length - keylist.length];
- if (measureList.length > 0) {
- search: for (int inputIdx = 0; inputIdx < plan.getTargets().length; inputIdx++) {
- for (int key : keylist) { // eliminate key field
- if (plan.getTargets()[inputIdx].getColumnSchema().getColumnName()
- .equals(inSchema.getColumn(key).getColumnName())) {
- continue search;
- }
- }
- measureList[valueIdx] = inputIdx;
- valueIdx++;
+ // measureList will contain a list of measure field indexes against the target list.
+ List<Integer> measureIndexes = TUtil.newList();
+ for (int i = 0; i < plan.getTargets().length; i++) {
+ Target target = plan.getTargets()[i];
+ if (target.getEvalTree().getType() == EvalType.AGG_FUNCTION) {
+ measureIndexes.add(i);
}
}
+ measureList = new int[measureIndexes.size()];
+ for (int i = 0; i < measureIndexes.size(); i++) {
+ measureList[i] = measureIndexes.get(i);
+ }
+
evals = new EvalNode[plan.getTargets().length];
evalContexts = new EvalContext[plan.getTargets().length];
for (int i = 0; i < plan.getTargets().length; i++) {
Target t = plan.getTargets()[i];
- if (t.getEvalTree().getType() == EvalType.FIELD && !nonNullGroupingFields.contains(t.getColumnSchema())) {
+ if (t.getEvalTree().getType() == EvalType.FIELD && !nonNullGroupingFields.contains(t.getNamedColumn())) {
evals[i] = new ConstEval(DatumFactory.createNullDatum());
evalContexts[i] = evals[i].newContext();
} else {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BNLJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BNLJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BNLJoinExec.java
index b2737b7..cf56200 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BNLJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BNLJoinExec.java
@@ -18,13 +18,13 @@
package org.apache.tajo.engine.planner.physical;
+import org.apache.tajo.engine.planner.PlannerUtil;
+import org.apache.tajo.engine.planner.Projector;
import org.apache.tajo.worker.TaskAttemptContext;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.logical.JoinNode;
-import org.apache.tajo.engine.utils.SchemaUtil;
import org.apache.tajo.storage.FrameTuple;
-import org.apache.tajo.storage.RowStoreUtil;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
@@ -35,46 +35,57 @@ import java.util.List;
public class BNLJoinExec extends BinaryPhysicalExec {
// from logical plan
- private JoinNode plan;
- private EvalNode joinQual;
- private EvalContext qualCtx;
+ private final JoinNode plan;
+ private final boolean hasJoinQual;
+ private final EvalNode joinQual;
+ private final EvalContext qualCtx;
- private final List<Tuple> outerTupleSlots;
- private final List<Tuple> innerTupleSlots;
- private Iterator<Tuple> outerIterator;
- private Iterator<Tuple> innerIterator;
+ private final List<Tuple> leftTupleSlots;
+ private final List<Tuple> rightTupleSlots;
+ private Iterator<Tuple> leftIterator;
+ private Iterator<Tuple> rightIterator;
- private boolean innerEnd;
- private boolean outerEnd;
+ private boolean leftEnd;
+ private boolean rightEnd;
// temporal tuples and states for nested loop join
private FrameTuple frameTuple;
- private Tuple outerTuple = null;
+ private Tuple leftTuple = null;
private Tuple outputTuple = null;
- private Tuple innext = null;
+ private Tuple rightNext = null;
private final int TUPLE_SLOT_SIZE = 10000;
// projection
- private final int[] targetIds;
+ private final Projector projector;
+ private final EvalContext [] evalContexts;
public BNLJoinExec(final TaskAttemptContext context, final JoinNode plan,
- final PhysicalExec outer, PhysicalExec inner) {
- super(context, SchemaUtil.merge(outer.getSchema(), inner.getSchema()), plan.getOutSchema(), outer, inner);
+ final PhysicalExec leftExec, PhysicalExec rightExec) {
+ super(context, plan.getInSchema(), plan.getOutSchema(), leftExec, rightExec);
this.plan = plan;
this.joinQual = plan.getJoinQual();
if (joinQual != null) { // if join type is not 'cross join'
+ hasJoinQual = true;
this.qualCtx = this.joinQual.newContext();
+ } else {
+ hasJoinQual = false;
+ this.qualCtx = null;
}
- this.outerTupleSlots = new ArrayList<Tuple>(TUPLE_SLOT_SIZE);
- this.innerTupleSlots = new ArrayList<Tuple>(TUPLE_SLOT_SIZE);
- this.outerIterator = outerTupleSlots.iterator();
- this.innerIterator = innerTupleSlots.iterator();
- this.innerEnd = false;
- this.outerEnd = false;
+ this.leftTupleSlots = new ArrayList<Tuple>(TUPLE_SLOT_SIZE);
+ this.rightTupleSlots = new ArrayList<Tuple>(TUPLE_SLOT_SIZE);
+ this.leftIterator = leftTupleSlots.iterator();
+ this.rightIterator = rightTupleSlots.iterator();
+ this.rightEnd = false;
+ this.leftEnd = false;
// for projection
- targetIds = RowStoreUtil.getTargetIds(inSchema, outSchema);
+ if (!plan.hasTargets()) {
+ plan.setTargets(PlannerUtil.schemaToTargets(outSchema));
+ }
+
+ projector = new Projector(inSchema, outSchema, plan.getTargets());
+ evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
@@ -87,106 +98,108 @@ public class BNLJoinExec extends BinaryPhysicalExec {
public Tuple next() throws IOException {
- if (outerTupleSlots.isEmpty()) {
+ if (leftTupleSlots.isEmpty()) {
for (int k = 0; k < TUPLE_SLOT_SIZE; k++) {
Tuple t = leftChild.next();
if (t == null) {
- outerEnd = true;
+ leftEnd = true;
break;
}
- outerTupleSlots.add(t);
+ leftTupleSlots.add(t);
}
- outerIterator = outerTupleSlots.iterator();
- outerTuple = outerIterator.next();
+ leftIterator = leftTupleSlots.iterator();
+ leftTuple = leftIterator.next();
}
- if (innerTupleSlots.isEmpty()) {
+ if (rightTupleSlots.isEmpty()) {
for (int k = 0; k < TUPLE_SLOT_SIZE; k++) {
Tuple t = rightChild.next();
if (t == null) {
- innerEnd = true;
+ rightEnd = true;
break;
}
- innerTupleSlots.add(t);
+ rightTupleSlots.add(t);
}
- innerIterator = innerTupleSlots.iterator();
+ rightIterator = rightTupleSlots.iterator();
}
- if((innext = rightChild.next()) == null){
- innerEnd = true;
+ if((rightNext = rightChild.next()) == null){
+ rightEnd = true;
}
while (true) {
- if (!innerIterator.hasNext()) { // if inneriterator ended
- if (outerIterator.hasNext()) { // if outertupleslot remains
- outerTuple = outerIterator.next();
- innerIterator = innerTupleSlots.iterator();
+ if (!rightIterator.hasNext()) { // if leftIterator ended
+ if (leftIterator.hasNext()) { // if rightTupleslot remains
+ leftTuple = leftIterator.next();
+ rightIterator = rightTupleSlots.iterator();
} else {
- if (innerEnd) {
+ if (rightEnd) {
rightChild.rescan();
- innerEnd = false;
+ rightEnd = false;
- if (outerEnd) {
+ if (leftEnd) {
return null;
}
- outerTupleSlots.clear();
+ leftTupleSlots.clear();
for (int k = 0; k < TUPLE_SLOT_SIZE; k++) {
Tuple t = leftChild.next();
if (t == null) {
- outerEnd = true;
+ leftEnd = true;
break;
}
- outerTupleSlots.add(t);
+ leftTupleSlots.add(t);
}
- if (outerTupleSlots.isEmpty()) {
+ if (leftTupleSlots.isEmpty()) {
return null;
}
- outerIterator = outerTupleSlots.iterator();
- outerTuple = outerIterator.next();
+ leftIterator = leftTupleSlots.iterator();
+ leftTuple = leftIterator.next();
} else {
- outerIterator = outerTupleSlots.iterator();
- outerTuple = outerIterator.next();
+ leftIterator = leftTupleSlots.iterator();
+ leftTuple = leftIterator.next();
}
- innerTupleSlots.clear();
- if (innext != null) {
- innerTupleSlots.add(innext);
- for (int k = 1; k < TUPLE_SLOT_SIZE; k++) { // fill inner
+ rightTupleSlots.clear();
+ if (rightNext != null) {
+ rightTupleSlots.add(rightNext);
+ for (int k = 1; k < TUPLE_SLOT_SIZE; k++) { // fill right
Tuple t = rightChild.next();
if (t == null) {
- innerEnd = true;
+ rightEnd = true;
break;
}
- innerTupleSlots.add(t);
+ rightTupleSlots.add(t);
}
} else {
- for (int k = 0; k < TUPLE_SLOT_SIZE; k++) { // fill inner
+ for (int k = 0; k < TUPLE_SLOT_SIZE; k++) { // fill right
Tuple t = rightChild.next();
if (t == null) {
- innerEnd = true;
+ rightEnd = true;
break;
}
- innerTupleSlots.add(t);
+ rightTupleSlots.add(t);
}
}
- if ((innext = rightChild.next()) == null) {
- innerEnd = true;
+ if ((rightNext = rightChild.next()) == null) {
+ rightEnd = true;
}
- innerIterator = innerTupleSlots.iterator();
+ rightIterator = rightTupleSlots.iterator();
}
}
- frameTuple.set(outerTuple, innerIterator.next());
- if (joinQual != null) {
+ frameTuple.set(leftTuple, rightIterator.next());
+ if (hasJoinQual) {
joinQual.eval(qualCtx, inSchema, frameTuple);
if (joinQual.terminate(qualCtx).asBool()) {
- RowStoreUtil.project(frameTuple, outputTuple, targetIds);
+ projector.eval(evalContexts, frameTuple);
+ projector.terminate(evalContexts, outputTuple);
return outputTuple;
}
} else {
- RowStoreUtil.project(frameTuple, outputTuple, targetIds);
+ projector.eval(evalContexts, frameTuple);
+ projector.terminate(evalContexts, outputTuple);
return outputTuple;
}
}
@@ -195,10 +208,10 @@ public class BNLJoinExec extends BinaryPhysicalExec {
@Override
public void rescan() throws IOException {
super.rescan();
- innerEnd = false;
- innerTupleSlots.clear();
- outerTupleSlots.clear();
- innerIterator = innerTupleSlots.iterator();
- outerIterator = outerTupleSlots.iterator();
+ rightEnd = false;
+ rightTupleSlots.clear();
+ leftTupleSlots.clear();
+ rightIterator = rightTupleSlots.iterator();
+ leftIterator = leftTupleSlots.iterator();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BSTIndexScanExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BSTIndexScanExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BSTIndexScanExec.java
index 5de6634..30c1fa7 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BSTIndexScanExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BSTIndexScanExec.java
@@ -65,7 +65,7 @@ public class BSTIndexScanExec extends PhysicalExec {
scanNode.getTableDesc().getMeta(), scanNode.getInSchema(), fragment, outSchema);
this.fileScanner.init();
this.projector = new Projector(inSchema, outSchema, scanNode.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
this.reader = new BSTIndex(sm.getFileSystem().getConf()).
getIndexReader(fileName, keySchema, comparator);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BasicPhysicalExecutorVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BasicPhysicalExecutorVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BasicPhysicalExecutorVisitor.java
index 4723ecc..67d6baa 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BasicPhysicalExecutorVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/BasicPhysicalExecutorVisitor.java
@@ -22,37 +22,72 @@ import java.util.Stack;
public class BasicPhysicalExecutorVisitor<CONTEXT, RESULT> implements PhysicalExecutorVisitor<CONTEXT, RESULT> {
- @Override
- public RESULT visitChild(PhysicalExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visit(PhysicalExec exec, Stack<PhysicalExec> stack, CONTEXT context)
throws PhysicalPlanningException {
- if (exec instanceof SeqScanExec) {
- return visitSeqScan((SeqScanExec) exec, stack, context);
- } else if (exec instanceof SelectionExec) {
- return visitSelection((SelectionExec) exec, stack, context);
- } else if (exec instanceof SortExec) {
- return visitSort((SortExec) exec, stack, context);
- } else if (exec instanceof SortAggregateExec) {
- return visitSortAggregation((SortAggregateExec) exec, stack, context);
- } else if (exec instanceof ProjectionExec) {
- return visitProjection((ProjectionExec) exec, stack, context);
+ // Please keep all physical executors except for abstract class.
+ // They should be ordered in an lexicography order of their names for easy code maintenance.
+ if (exec instanceof BNLJoinExec) {
+ return visitBNLJoin(context, (BNLJoinExec) exec, stack);
+ } else if (exec instanceof BSTIndexScanExec) {
+ return visitBSTIndexScan(context, (BSTIndexScanExec) exec, stack);
+ } else if (exec instanceof ColumnPartitionedTableStoreExec) {
+ return visitColumnPartitionedTableStore(context, (ColumnPartitionedTableStoreExec) exec, stack);
+ } else if (exec instanceof EvalExprExec) {
+ return visitEvalExpr(context, (EvalExprExec) exec, stack);
+ } else if (exec instanceof ExternalSortExec) {
+ return visitExternalSort(context, (ExternalSortExec) exec, stack);
+ } else if (exec instanceof HashAggregateExec) {
+ return visitHashAggregate(context, (HashAggregateExec) exec, stack);
+ } else if (exec instanceof HashFullOuterJoinExec) {
+ return visitHashFullOuterJoin(context, (HashFullOuterJoinExec) exec, stack);
} else if (exec instanceof HashJoinExec) {
- return visitHashJoin((HashJoinExec) exec, stack, context);
+ return visitHashJoin(context, (HashJoinExec) exec, stack);
} else if (exec instanceof HashLeftAntiJoinExec) {
- return visitHashAntiJoin((HashLeftAntiJoinExec) exec, stack, context);
+ return visitHashLeftAntiJoin(context, (HashLeftAntiJoinExec) exec, stack);
+ } else if (exec instanceof HashLeftOuterJoinExec) {
+ return visitHashLeftOuterJoin(context, (HashLeftOuterJoinExec) exec, stack);
} else if (exec instanceof HashLeftSemiJoinExec) {
- return visitHashSemiJoin((HashLeftSemiJoinExec) exec, stack, context);
+ return visitLeftHashSemiJoin(context, (HashLeftSemiJoinExec) exec, stack);
+ } else if (exec instanceof HashShuffleFileWriteExec) {
+ return visitHashShuffleFileWrite(context, (HashShuffleFileWriteExec) exec, stack);
+ } else if (exec instanceof HavingExec) {
+ return visitHaving(context, (HavingExec) exec, stack);
} else if (exec instanceof LimitExec) {
- return visitLimit((LimitExec) exec, stack, context);
- } else {
- throw new PhysicalPlanningException("Unsupported Type: " + exec.getClass().getSimpleName());
+ return visitLimit(context, (LimitExec) exec, stack);
+ } else if (exec instanceof MemSortExec) {
+ return visitMemSort(context, (MemSortExec) exec, stack);
+ } else if (exec instanceof MergeFullOuterJoinExec) {
+ return visitMergeFullOuterJoin(context, (MergeFullOuterJoinExec) exec, stack);
+ } else if (exec instanceof MergeJoinExec) {
+ return visitMergeJoin(context, (MergeJoinExec) exec, stack);
+ } else if (exec instanceof NLJoinExec) {
+ return visitNLJoin(context, (NLJoinExec) exec, stack);
+ } else if (exec instanceof NLLeftOuterJoinExec) {
+ return visitNLLeftOuterJoin(context, (NLLeftOuterJoinExec) exec, stack);
+ } else if (exec instanceof ProjectionExec) {
+ return visitProjection(context, (ProjectionExec) exec, stack);
+ } else if (exec instanceof RangeShuffleFileWriteExec) {
+ return visitRangeShuffleFileWrite(context, (RangeShuffleFileWriteExec) exec, stack);
+ } else if (exec instanceof RightOuterMergeJoinExec) {
+ return visitRightOuterMergeJoin(context, (RightOuterMergeJoinExec) exec, stack);
+ } else if (exec instanceof SelectionExec) {
+ return visitSelection(context, (SelectionExec) exec, stack);
+ } else if (exec instanceof SeqScanExec) {
+ return visitSeqScan(context, (SeqScanExec) exec, stack);
+ } else if (exec instanceof SortAggregateExec) {
+ return visitSortAggregate(context, (SortAggregateExec) exec, stack);
+ } else if (exec instanceof StoreTableExec) {
+ return visitStoreTable(context, (StoreTableExec) exec, stack);
}
+
+ throw new PhysicalPlanningException("Unsupported Type: " + exec.getClass().getSimpleName());
}
private RESULT visitUnaryExecutor(UnaryPhysicalExec exec, Stack<PhysicalExec> stack, CONTEXT context)
throws PhysicalPlanningException {
stack.push(exec);
- RESULT r = visitChild(exec.getChild(), stack, context);
+ RESULT r = visit(exec.getChild(), stack, context);
stack.pop();
return r;
}
@@ -60,68 +95,162 @@ public class BasicPhysicalExecutorVisitor<CONTEXT, RESULT> implements PhysicalEx
private RESULT visitBinaryExecutor(BinaryPhysicalExec exec, Stack<PhysicalExec> stack, CONTEXT context)
throws PhysicalPlanningException {
stack.push(exec);
- RESULT r = visitChild(exec.getLeftChild(), stack, context);
- visitChild(exec.getRightChild(), stack, context);
+ RESULT r = visit(exec.getLeftChild(), stack, context);
+ visit(exec.getRightChild(), stack, context);
stack.pop();
return r;
}
@Override
- public RESULT visitSortAggregation(SortAggregateExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitBNLJoin(CONTEXT context, BNLJoinExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
- return visitUnaryExecutor(exec, stack, context);
+ return null;
+ }
+
+ @Override
+ public RESULT visitBSTIndexScan(CONTEXT context, BSTIndexScanExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
}
@Override
- public RESULT visitSeqScan(SeqScanExec exec, Stack<PhysicalExec> stack, CONTEXT context) {
+ public RESULT visitColumnPartitionedTableStore(CONTEXT context, ColumnPartitionedTableStoreExec exec, Stack<PhysicalExec> stack) throws PhysicalPlanningException {
return null;
}
@Override
- public RESULT visitSort(SortExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitEvalExpr(CONTEXT context, EvalExprExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
- return visitUnaryExecutor(exec, stack, context);
+ return null;
}
@Override
- public RESULT visitMergeJoin(MergeJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitExternalSort(CONTEXT context, ExternalSortExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
- return visitBinaryExecutor(exec, stack, context);
+ return null;
}
@Override
- public RESULT visitSelection(SelectionExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitHashAggregate(CONTEXT context, HashAggregateExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
- return visitUnaryExecutor(exec, stack, context);
+ return null;
}
@Override
- public RESULT visitProjection(ProjectionExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitHashFullOuterJoin(CONTEXT context, HashFullOuterJoinExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
- return visitUnaryExecutor(exec, stack, context);
+ return null;
}
@Override
- public RESULT visitHashJoin(HashJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitHashJoin(CONTEXT context, HashJoinExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
return visitBinaryExecutor(exec, stack, context);
}
@Override
- public RESULT visitHashSemiJoin(HashLeftSemiJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitHashLeftAntiJoin(CONTEXT context, HashLeftAntiJoinExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
return visitBinaryExecutor(exec, stack, context);
}
@Override
- public RESULT visitHashAntiJoin(HashLeftAntiJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitHashLeftOuterJoin(CONTEXT context, HashLeftOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitLeftHashSemiJoin(CONTEXT context, HashLeftSemiJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return visitBinaryExecutor(exec, stack, context);
+ }
+
+ @Override
+ public RESULT visitHashShuffleFileWrite(CONTEXT context, HashShuffleFileWriteExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitHaving(CONTEXT context, HavingExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitLimit(CONTEXT context, LimitExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return visitUnaryExecutor(exec, stack, context);
+ }
+
+ @Override
+ public RESULT visitMemSort(CONTEXT context, MemSortExec exec, Stack<PhysicalExec> stack) throws
+ PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitMergeFullOuterJoin(CONTEXT context, MergeFullOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitMergeJoin(CONTEXT context, MergeJoinExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
return visitBinaryExecutor(exec, stack, context);
}
@Override
- public RESULT visitLimit(LimitExec exec, Stack<PhysicalExec> stack, CONTEXT context)
+ public RESULT visitNLJoin(CONTEXT context, NLJoinExec exec, Stack<PhysicalExec> stack) throws
+ PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitNLLeftOuterJoin(CONTEXT context, NLLeftOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitProjection(CONTEXT context, ProjectionExec exec, Stack<PhysicalExec> stack)
throws PhysicalPlanningException {
return visitUnaryExecutor(exec, stack, context);
}
+
+ @Override
+ public RESULT visitRangeShuffleFileWrite(CONTEXT context, RangeShuffleFileWriteExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitRightOuterMergeJoin(CONTEXT context, RightOuterMergeJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return null;
+ }
+
+ @Override
+ public RESULT visitSelection(CONTEXT context, SelectionExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return visitUnaryExecutor(exec, stack, context);
+ }
+
+ @Override
+ public RESULT visitSeqScan(CONTEXT context, SeqScanExec exec, Stack<PhysicalExec> stack) {
+ return null;
+ }
+
+ @Override
+ public RESULT visitSortAggregate(CONTEXT context, SortAggregateExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException {
+ return visitUnaryExecutor(exec, stack, context);
+ }
+
+ @Override
+ public RESULT visitStoreTable(CONTEXT context, StoreTableExec exec, Stack<PhysicalExec> stack) throws PhysicalPlanningException {
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/EvalExprExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/EvalExprExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/EvalExprExec.java
index c1f84a3..4480747 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/EvalExprExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/EvalExprExec.java
@@ -35,9 +35,9 @@ public class EvalExprExec extends PhysicalExec {
super(context, plan.getInSchema(), plan.getOutSchema());
this.plan = plan;
- evalContexts = new EvalContext[plan.getExprs().length];
- for (int i = 0; i < plan.getExprs().length; i++) {
- evalContexts[i] = plan.getExprs()[i].getEvalTree().newContext();
+ evalContexts = new EvalContext[plan.getTargets().length];
+ for (int i = 0; i < plan.getTargets().length; i++) {
+ evalContexts[i] = plan.getTargets()[i].getEvalTree().newContext();
}
}
@@ -50,7 +50,7 @@ public class EvalExprExec extends PhysicalExec {
*/
@Override
public Tuple next() throws IOException {
- Target [] targets = plan.getExprs();
+ Target [] targets = plan.getTargets();
Tuple t = new VTuple(targets.length);
for (int i = 0; i < targets.length; i++) {
targets[i].getEvalTree().eval(evalContexts[i], inSchema, null);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
index 681e340..ed2f275 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashAggregateExec.java
@@ -18,11 +18,11 @@
package org.apache.tajo.engine.planner.physical;
-import org.apache.tajo.worker.TaskAttemptContext;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.planner.logical.GroupbyNode;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.worker.TaskAttemptContext;
import java.io.IOException;
import java.util.HashMap;
@@ -86,29 +86,15 @@ public class HashAggregateExec extends AggregationExec {
}
EvalContext [] ctx;
- if (havingQual == null) {
- if (iterator.hasNext()) {
- ctx = iterator.next().getValue();
+ if (iterator.hasNext()) {
+ ctx = iterator.next().getValue();
for (int i = 0; i < ctx.length; i++) {
tuple.put(i, evals[i].terminate(ctx[i]));
}
return tuple;
- } else {
- return null;
- }
} else {
- while(iterator.hasNext()) {
- ctx = iterator.next().getValue();
- for (int i = 0; i < ctx.length; i++) {
- tuple.put(i, evals[i].terminate(ctx[i]));
- }
- havingQual.eval(havingContext, evalSchema, tuple);
- if (havingQual.terminate(havingContext).asBool()) {
- return tuple;
- }
- }
return null;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
index 550f0ee..caea5d9 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashFullOuterJoinExec.java
@@ -95,7 +95,7 @@ public class HashFullOuterJoinExec extends BinaryPhysicalExec {
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashJoinExec.java
index 8a42cff..e08e07d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashJoinExec.java
@@ -60,32 +60,32 @@ public class HashJoinExec extends BinaryPhysicalExec {
protected final Projector projector;
protected final EvalContext [] evalContexts;
- public HashJoinExec(TaskAttemptContext context, JoinNode plan, PhysicalExec outer,
- PhysicalExec inner) {
- super(context, SchemaUtil.merge(outer.getSchema(), inner.getSchema()),
- plan.getOutSchema(), outer, inner);
+ public HashJoinExec(TaskAttemptContext context, JoinNode plan, PhysicalExec leftExec,
+ PhysicalExec rightExec) {
+ super(context, SchemaUtil.merge(leftExec.getSchema(), rightExec.getSchema()), plan.getOutSchema(),
+ leftExec, rightExec);
this.plan = plan;
this.joinQual = plan.getJoinQual();
this.qualCtx = joinQual.newContext();
this.tupleSlots = new HashMap<Tuple, List<Tuple>>(10000);
this.joinKeyPairs = PlannerUtil.getJoinKeyPairs(joinQual,
- outer.getSchema(), inner.getSchema());
+ leftExec.getSchema(), rightExec.getSchema());
leftKeyList = new int[joinKeyPairs.size()];
rightKeyList = new int[joinKeyPairs.size()];
for (int i = 0; i < joinKeyPairs.size(); i++) {
- leftKeyList[i] = outer.getSchema().getColumnId(joinKeyPairs.get(i)[0].getQualifiedName());
+ leftKeyList[i] = leftExec.getSchema().getColumnId(joinKeyPairs.get(i)[0].getQualifiedName());
}
for (int i = 0; i < joinKeyPairs.size(); i++) {
- rightKeyList[i] = inner.getSchema().getColumnId(joinKeyPairs.get(i)[1].getQualifiedName());
+ rightKeyList[i] = rightExec.getSchema().getColumnId(joinKeyPairs.get(i)[1].getQualifiedName());
}
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
index f0022cb..841ff5a 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HashLeftOuterJoinExec.java
@@ -93,7 +93,7 @@ public class HashLeftOuterJoinExec extends BinaryPhysicalExec {
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HavingExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HavingExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HavingExec.java
new file mode 100644
index 0000000..41ff7bf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/HavingExec.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner.physical;
+
+import org.apache.tajo.engine.eval.EvalContext;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.planner.logical.HavingNode;
+import org.apache.tajo.engine.planner.logical.SelectionNode;
+import org.apache.tajo.storage.RowStoreUtil;
+import org.apache.tajo.storage.Tuple;
+import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.worker.TaskAttemptContext;
+
+import java.io.IOException;
+
+public class HavingExec extends UnaryPhysicalExec {
+ private final EvalNode qual;
+ private final EvalContext qualCtx;
+ private final Tuple outputTuple;
+
+ public HavingExec(TaskAttemptContext context,
+ HavingNode plan,
+ PhysicalExec child) {
+ super(context, plan.getInSchema(), plan.getOutSchema(), child);
+
+ this.qual = plan.getQual();
+ this.qualCtx = this.qual.newContext();
+ this.outputTuple = new VTuple(outSchema.getColumnNum());
+ }
+
+ @Override
+ public Tuple next() throws IOException {
+ Tuple tuple;
+ while ((tuple = child.next()) != null) {
+ qual.eval(qualCtx, inSchema, tuple);
+ if (qual.terminate(qualCtx).asBool()) {
+ return tuple;
+ }
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeFullOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeFullOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeFullOuterJoinExec.java
index e1fe440..446755d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeFullOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeFullOuterJoinExec.java
@@ -93,7 +93,7 @@ public class MergeFullOuterJoinExec extends BinaryPhysicalExec {
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeJoinExec.java
index ebddd07..e128fea 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/MergeJoinExec.java
@@ -89,7 +89,7 @@ public class MergeJoinExec extends BinaryPhysicalExec {
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLJoinExec.java
index 67908da..055c66e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLJoinExec.java
@@ -59,7 +59,7 @@ public class NLJoinExec extends BinaryPhysicalExec {
// for projection
projector = new Projector(inSchema, outSchema, plan.getTargets());
- evalContexts = projector.renew();
+ evalContexts = projector.newContexts();
// for join
needNewOuter = true;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
index ebc78e2..305cdd2 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/NLLeftOuterJoinExec.java
@@ -62,7 +62,7 @@ public class NLLeftOuterJoinExec extends BinaryPhysicalExec {
// for projection
projector = new Projector(inSchema, outSchema, plan.getTargets());
- evalContexts = projector.renew();
+ evalContexts = projector.newContexts();
// for join
needNextRightTuple = true;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalExecutorVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalExecutorVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalExecutorVisitor.java
index f0abef5..9ede15d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalExecutorVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalExecutorVisitor.java
@@ -21,15 +21,82 @@ package org.apache.tajo.engine.planner.physical;
import java.util.Stack;
public interface PhysicalExecutorVisitor<CONTEXT, RESULT> {
- RESULT visitChild(PhysicalExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitSeqScan(SeqScanExec exec, Stack<PhysicalExec> stack, CONTEXT context);
- RESULT visitSort(SortExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitSortAggregation(SortAggregateExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitMergeJoin(MergeJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitSelection(SelectionExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitProjection(ProjectionExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitHashJoin(HashJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitHashSemiJoin(HashLeftSemiJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitHashAntiJoin(HashLeftAntiJoinExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
- RESULT visitLimit(LimitExec exec, Stack<PhysicalExec> stack, CONTEXT context) throws PhysicalPlanningException;
+
+ RESULT visitBNLJoin(CONTEXT context, BNLJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitBSTIndexScan(CONTEXT context, BSTIndexScanExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitColumnPartitionedTableStore(CONTEXT context, ColumnPartitionedTableStoreExec exec,
+ Stack<PhysicalExec> stack) throws PhysicalPlanningException;
+
+ RESULT visitEvalExpr(CONTEXT context, EvalExprExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitExternalSort(CONTEXT context, ExternalSortExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashAggregate(CONTEXT context, HashAggregateExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashFullOuterJoin(CONTEXT context, HashFullOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashJoin(CONTEXT context, HashJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashLeftAntiJoin(CONTEXT context, HashLeftAntiJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashLeftOuterJoin(CONTEXT context, HashLeftOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitLeftHashSemiJoin(CONTEXT context, HashLeftSemiJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHashShuffleFileWrite(CONTEXT context, HashShuffleFileWriteExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitHaving(CONTEXT context, HavingExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitLimit(CONTEXT context, LimitExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitMemSort(CONTEXT context, MemSortExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitMergeFullOuterJoin(CONTEXT context, MergeFullOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitMergeJoin(CONTEXT context, MergeJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitNLJoin(CONTEXT context, NLJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitNLLeftOuterJoin(CONTEXT context, NLLeftOuterJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitProjection(CONTEXT context, ProjectionExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitRangeShuffleFileWrite(CONTEXT context, RangeShuffleFileWriteExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitRightOuterMergeJoin(CONTEXT context, RightOuterMergeJoinExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitSelection(CONTEXT context, SelectionExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitSeqScan(CONTEXT context, SeqScanExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitSortAggregate(CONTEXT context, SortAggregateExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
+
+ RESULT visitStoreTable(CONTEXT context, StoreTableExec exec, Stack<PhysicalExec> stack)
+ throws PhysicalPlanningException;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalPlanUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalPlanUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalPlanUtil.java
index bd773ed..fdd1839 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalPlanUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/PhysicalPlanUtil.java
@@ -23,17 +23,16 @@ import java.util.Stack;
public class PhysicalPlanUtil {
public static <T extends PhysicalExec> T findExecutor(PhysicalExec plan, Class<? extends PhysicalExec> clazz)
throws PhysicalPlanningException {
- return (T) new FindVisitor().visitChild(plan, new Stack<PhysicalExec>(), clazz);
+ return (T) new FindVisitor().visit(plan, new Stack<PhysicalExec>(), clazz);
}
private static class FindVisitor extends BasicPhysicalExecutorVisitor<Class<? extends PhysicalExec>, PhysicalExec> {
- public PhysicalExec visitChild(PhysicalExec exec, Stack<PhysicalExec> stack, Class<? extends PhysicalExec> target)
+ public PhysicalExec visit(PhysicalExec exec, Stack<PhysicalExec> stack, Class<? extends PhysicalExec> target)
throws PhysicalPlanningException {
-
if (target.isAssignableFrom(exec.getClass())) {
return exec;
} else {
- return super.visitChild(exec, stack, target);
+ return super.visit(exec, stack, target);
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/ProjectionExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/ProjectionExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/ProjectionExec.java
index f8ec801..c57089e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/ProjectionExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/ProjectionExec.java
@@ -21,24 +21,24 @@
*/
package org.apache.tajo.engine.planner.physical;
+import org.apache.tajo.engine.planner.logical.Projectable;
import org.apache.tajo.worker.TaskAttemptContext;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.planner.Projector;
-import org.apache.tajo.engine.planner.logical.ProjectionNode;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
import java.io.IOException;
public class ProjectionExec extends UnaryPhysicalExec {
- private final ProjectionNode plan;
+ private final Projectable plan;
// for projection
private Tuple outTuple;
private EvalContext[] evalContexts;
private Projector projector;
- public ProjectionExec(TaskAttemptContext context, ProjectionNode plan,
+ public ProjectionExec(TaskAttemptContext context, Projectable plan,
PhysicalExec child) {
super(context, plan.getInSchema(), plan.getOutSchema(), child);
this.plan = plan;
@@ -49,7 +49,7 @@ public class ProjectionExec extends UnaryPhysicalExec {
this.outTuple = new VTuple(outSchema.getColumnNum());
this.projector = new Projector(inSchema, outSchema, this.plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/RightOuterMergeJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/RightOuterMergeJoinExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/RightOuterMergeJoinExec.java
index 8c99215..2f1d33d 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/RightOuterMergeJoinExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/RightOuterMergeJoinExec.java
@@ -91,7 +91,7 @@ public class RightOuterMergeJoinExec extends BinaryPhysicalExec {
// for projection
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
// for join
frameTuple = new FrameTuple();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SelectionExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SelectionExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SelectionExec.java
index 0e6640c..5158dc0 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SelectionExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SelectionExec.java
@@ -18,36 +18,24 @@
package org.apache.tajo.engine.planner.physical;
-import org.apache.tajo.worker.TaskAttemptContext;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.logical.SelectionNode;
-import org.apache.tajo.storage.RowStoreUtil;
import org.apache.tajo.storage.Tuple;
-import org.apache.tajo.storage.VTuple;
+import org.apache.tajo.worker.TaskAttemptContext;
import java.io.IOException;
public class SelectionExec extends UnaryPhysicalExec {
private final EvalNode qual;
private final EvalContext qualCtx;
- private final Tuple outputTuple;
- // projection
- private int [] targetIds;
public SelectionExec(TaskAttemptContext context,
SelectionNode plan,
PhysicalExec child) {
super(context, plan.getInSchema(), plan.getOutSchema(), child);
-
this.qual = plan.getQual();
this.qualCtx = this.qual.newContext();
- // for projection
- if (!inSchema.equals(outSchema)) {
- targetIds = RowStoreUtil.getTargetIds(inSchema, outSchema);
- }
-
- this.outputTuple = new VTuple(outSchema.getColumnNum());
}
@Override
@@ -55,13 +43,8 @@ public class SelectionExec extends UnaryPhysicalExec {
Tuple tuple;
while ((tuple = child.next()) != null) {
qual.eval(qualCtx, inSchema, tuple);
- if (qual.terminate(qualCtx).asBool()) {
- if (targetIds != null) {
- RowStoreUtil.project(tuple, outputTuple, targetIds);
- return outputTuple;
- } else {
+ if (qual.terminate(qualCtx).isTrue()) {
return tuple;
- }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
index 3de75a9..6d3d6b1 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/physical/SeqScanExec.java
@@ -151,7 +151,7 @@ public class SeqScanExec extends PhysicalExec {
}
this.projector = new Projector(inSchema, outSchema, plan.getTargets());
- this.evalContexts = projector.renew();
+ this.evalContexts = projector.newContexts();
if (fragments.length > 1) {
this.scanner = new MergeScanner(context.getConf(), plan.getTableSchema(), plan.getTableDesc().getMeta(),
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/FilterPushDownRule.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/FilterPushDownRule.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/FilterPushDownRule.java
index 44af891..ddcdd03 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/FilterPushDownRule.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/FilterPushDownRule.java
@@ -43,7 +43,7 @@ public class FilterPushDownRule extends BasicLogicalPlanVisitor<Set<EvalNode>, L
@Override
public boolean isEligible(LogicalPlan plan) {
for (LogicalPlan.QueryBlock block : plan.getQueryBlocks()) {
- if (block.hasSelectionNode() || block.hasJoinNode()) {
+ if (block.hasNode(NodeType.SELECTION) || block.hasNode(NodeType.JOIN)) {
return true;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/PartitionedTableRewriter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/PartitionedTableRewriter.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/PartitionedTableRewriter.java
index 4a7a324..72ff67c 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/PartitionedTableRewriter.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/PartitionedTableRewriter.java
@@ -20,8 +20,8 @@ package org.apache.tajo.engine.planner.rewrite;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.sun.org.apache.commons.logging.Log;
-import com.sun.org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.*;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
@@ -359,7 +359,8 @@ public class PartitionedTableRewriter implements RewriteRule {
try {
Path [] filteredPaths = findFilteredPartitionPaths(scanNode);
plan.addHistory("PartitionTableRewriter chooses " + filteredPaths.length + " of partitions");
- PartitionedTableScanNode rewrittenScanNode = new PartitionedTableScanNode(plan.newPID(), scanNode, filteredPaths);
+ PartitionedTableScanNode rewrittenScanNode =
+ new PartitionedTableScanNode(plan.newPID(), scanNode, filteredPaths);
updateTableStat(rewrittenScanNode);
PlannerUtil.replaceNode(plan, stack.peek(), scanNode, rewrittenScanNode);
} catch (IOException e) {
[06/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
index be24112..e27cc04 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanner.java
@@ -18,8 +18,8 @@
package org.apache.tajo.engine.planner;
-import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
@@ -34,66 +34,59 @@ import org.apache.tajo.catalog.partition.PartitionDesc;
import org.apache.tajo.catalog.partition.Specifier;
import org.apache.tajo.catalog.proto.CatalogProtos;
import org.apache.tajo.common.TajoDataTypes;
-import org.apache.tajo.common.TajoDataTypes.DataType;
-import org.apache.tajo.datum.Datum;
-import org.apache.tajo.datum.DatumFactory;
-import org.apache.tajo.datum.NullDatum;
-import org.apache.tajo.datum.TimestampDatum;
-import org.apache.tajo.datum.TimeDatum;
-import org.apache.tajo.datum.DateDatum;
import org.apache.tajo.engine.eval.*;
import org.apache.tajo.engine.exception.InvalidQueryException;
-import org.apache.tajo.engine.exception.UndefinedFunctionException;
import org.apache.tajo.engine.exception.VerifyException;
-import org.apache.tajo.engine.function.AggFunction;
-import org.apache.tajo.engine.function.GeneralFunction;
import org.apache.tajo.engine.planner.LogicalPlan.QueryBlock;
import org.apache.tajo.engine.planner.logical.*;
import org.apache.tajo.engine.utils.SchemaUtil;
-import org.apache.tajo.exception.InternalException;
import org.apache.tajo.util.TUtil;
-import org.joda.time.DateTime;
-import java.util.Collection;
-import java.util.List;
-import java.util.Stack;
+import java.util.*;
import static org.apache.tajo.algebra.Aggregation.GroupType;
import static org.apache.tajo.algebra.CreateTable.ColumnPartition;
import static org.apache.tajo.algebra.CreateTable.PartitionType;
-
-import org.apache.tajo.algebra.DateValue;
-import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType;
+import static org.apache.tajo.engine.planner.ExprNormalizer.ExprNormalizedResult;
import static org.apache.tajo.engine.planner.LogicalPlan.BlockType;
+import static org.apache.tajo.engine.planner.LogicalPlanPreprocessor.PreprocessContext;
/**
- * This class creates a logical plan from a parse tree ({@link org.apache.tajo.engine.parser.SQLAnalyzer})
- * generated by {@link org.apache.tajo.engine.parser.SQLAnalyzer}.
- *
- * Relational operators can be divided into two categories as follows:
- * <oi>
- * <li>General operator: this type operators do not affect the tuple schema.
- * Selection, Sort, and Limit belong to this type.</li>
- * <li>Projectable operator: this type operators affects the tuple schema.
- * Scan, Groupby, and Join belong to this type.
- * </li>
- * </oi>
+ * This class creates a logical plan from a nested tajo algebra expression ({@link org.apache.tajo.algebra})
*/
public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContext, LogicalNode> {
private static Log LOG = LogFactory.getLog(LogicalPlanner.class);
private final CatalogService catalog;
+ private final LogicalPlanPreprocessor preprocessor;
+ private final ExprAnnotator exprAnnotator;
+ private final ExprNormalizer normalizer;
public LogicalPlanner(CatalogService catalog) {
this.catalog = catalog;
+ this.exprAnnotator = new ExprAnnotator(catalog);
+ this.preprocessor = new LogicalPlanPreprocessor(catalog, exprAnnotator);
+ this.normalizer = new ExprNormalizer();
}
- public static class PlanContext {
+ public class PlanContext {
LogicalPlan plan;
- QueryBlock block;
+
+ // transient data for each query block
+ QueryBlock queryBlock;
public PlanContext(LogicalPlan plan, QueryBlock block) {
this.plan = plan;
- this.block = block;
+ this.queryBlock = block;
+ }
+
+ public PlanContext(PlanContext context, QueryBlock block) {
+ this.plan = context.plan;
+ this.queryBlock = block;
+ }
+
+ public String toString() {
+ return "block=" + queryBlock.getName() + ", relNum=" + queryBlock.getRelations().size() + ", "+
+ queryBlock.namedExprsMgr.toString();
}
}
@@ -106,328 +99,399 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
public LogicalPlan createPlan(Expr expr) throws PlanningException {
LogicalPlan plan = new LogicalPlan(this);
- LogicalNode subroot;
-
- Stack<OpType> stack = new Stack<OpType>();
QueryBlock rootBlock = plan.newAndGetBlock(LogicalPlan.ROOT_BLOCK);
- PlanContext context = new PlanContext(plan, rootBlock);
- subroot = visit(context, stack, expr);
+ PreprocessContext preProcessorCtx = new PreprocessContext(plan, rootBlock);
+ preprocessor.visit(preProcessorCtx, new Stack<Expr>(), expr);
+
+ PlanContext context = new PlanContext(plan, plan.getRootBlock());
+ LogicalNode topMostNode = this.visit(context, new Stack<Expr>(), expr);
+ // Add Root Node
LogicalRootNode root = new LogicalRootNode(plan.newPID());
- root.setInSchema(subroot.getOutSchema());
- root.setOutSchema(subroot.getOutSchema());
- root.setChild(subroot);
+ root.setInSchema(topMostNode.getOutSchema());
+ root.setOutSchema(topMostNode.getOutSchema());
+ root.setChild(topMostNode);
plan.getRootBlock().setRoot(root);
return plan;
}
- public void preHook(PlanContext context, Stack<OpType> stack, Expr expr) {
- context.block = checkIfNewBlockOrGet(context.plan, context.block.getName());
- context.block.setAlgebraicExpr(expr);
- }
-
- public LogicalNode postHook(PlanContext context, Stack<OpType> stack, Expr expr, LogicalNode current)
- throws PlanningException {
- // Post work
- if ((expr.getType() == OpType.RelationList && ((RelationList) expr).size() == 1)
- || expr.getType() == OpType.Having) {
- return current;
- }
-
- // mark the node as the visited node and do post work for each operator
- context.block.postVisit(current, stack);
- if (current instanceof Projectable) {
- // check and set evaluated targets and update in/out schemas
- context.block.checkAndResolveTargets(current);
- }
-
- return current;
+ public ExprAnnotator getExprAnnotator() {
+ return this.exprAnnotator;
}
- /**
- * It checks if the first node in this query block. If not, it creates and adds a new query block.
- * In addition, it always returns the query block corresponding to the block name.
- */
- private QueryBlock checkIfNewBlockOrGet(LogicalPlan plan, String blockName) {
- QueryBlock block = plan.getBlock(blockName);
- if (block == null) {
- return plan.newAndGetBlock(blockName);
- } else {
- return block;
- }
+ public void preHook(PlanContext context, Stack<Expr> stack, Expr expr) throws PlanningException {
+ context.queryBlock.updateCurrentNode(expr);
}
- public TableSubQueryNode visitTableSubQuery(PlanContext context, Stack<OpType> stack, TablePrimarySubQuery expr)
+ public LogicalNode postHook(PlanContext context, Stack<Expr> stack, Expr expr, LogicalNode current)
throws PlanningException {
- QueryBlock newBlock = context.plan.newAndGetBlock(expr.getName());
- PlanContext newContext = new PlanContext(context.plan, newBlock);
- Stack<OpType> newStack = new Stack<OpType>();
- LogicalNode child = visit(newContext, newStack, expr.getSubQuery());
- context.plan.connectBlocks(newContext.block, context.block, BlockType.TableSubQuery);
- return new TableSubQueryNode(context.plan.newPID(), expr.getName(), child);
- }
-
- @Override
- public ScanNode visitRelation(PlanContext context, Stack<OpType> stack, Relation expr)
- throws VerifyException {
- // 1. init phase
- // 2. build child plans
- // 3. build scan plan
- Relation relation = expr;
- TableDesc desc = catalog.getTableDesc(relation.getName());
- if (!desc.hasStats()) {
- updatePhysicalInfo(desc);
+ // This checking determines whether current logical node is already visited or not.
+ // generated logical nodes (e.g., implicit aggregation) without exprs will pass NULL as a expr parameter.
+ // We should skip them.
+ if (expr != null) {
+ // A relation list including a single ScanNode will return a ScanNode instance that already passed postHook.
+ // So, it skips the already-visited ScanNode instance.
+ if (expr.getType() == OpType.RelationList && current.getType() == NodeType.SCAN) {
+ return current;
+ }
}
- ScanNode scanNode;
- if (relation.hasAlias()) {
- scanNode = new ScanNode(context.plan.newPID(), desc, relation.getAlias());
- } else {
- scanNode = new ScanNode(context.plan.newPID(), desc);
+ QueryBlock queryBlock = context.queryBlock;
+ queryBlock.updateLatestNode(current);
+ if (current.getType() == NodeType.GROUP_BY) {
+ queryBlock.unsetAggregationRequire();
}
- return scanNode;
- }
+ // if this node is the topmost
+ if (stack.size() == 0) {
+ queryBlock.setRoot(current);
+ }
- private void updatePhysicalInfo(TableDesc desc) {
- if (desc.getPath() != null) {
- try {
- FileSystem fs = desc.getPath().getFileSystem(new Configuration());
- FileStatus status = fs.getFileStatus(desc.getPath());
- if (desc.getStats() != null && (status.isDirectory() || status.isFile())) {
- ContentSummary summary = fs.getContentSummary(desc.getPath());
- if (summary != null) {
- long volume = summary.getLength();
- desc.getStats().setNumBytes(volume);
- }
- }
- } catch (Throwable t) {
- LOG.warn(t);
- }
+ if (!stack.empty()) {
+ queryBlock.updateCurrentNode(stack.peek());
}
+ return current;
}
/*===============================================================================================
- JOIN SECTION
+ Data Manupulation Language (DML) SECTION
+ ===============================================================================================*/
+
+
+ /*===============================================================================================
+ PROJECTION SECTION
===============================================================================================*/
@Override
- public LogicalNode visitRelationList(PlanContext context, Stack<OpType> stack, RelationList relations)
+ public LogicalNode visitProjection(PlanContext context, Stack<Expr> stack, Projection projection)
throws PlanningException {
- LogicalNode current = visit(context, stack, relations.getRelations()[0]);
- LogicalNode left;
- LogicalNode right;
- if (relations.size() > 1) {
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
- for (int i = 1; i < relations.size(); i++) {
- left = current;
- right = visit(context, stack, relations.getRelations()[i]);
- current = createCatasianProduct(context.plan, left, right);
- }
+ // If a non-from statement is given
+ if (!projection.hasChild()) {
+ return buildPlanForNoneFromStatement(context, stack, projection);
}
- return current;
- }
-
- @Override
- public LogicalNode visitJoin(PlanContext context, Stack<OpType> stack, Join join)
- throws PlanningException {
- // Phase 1: Init
- LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ String [] referenceNames;
+ if (projection.isAllProjected()) {
+ referenceNames = null;
+ } else {
+ // in prephase, insert all target list into NamedExprManagers.
+ // Then it gets reference names, each of which points an expression in target list.
+ referenceNames = doProjectionPrephase(context, projection);
+ }
- // Phase 2: build child plans
- stack.push(OpType.Join);
- LogicalNode left = visit(context, stack, join.getLeft());
- LogicalNode right = visit(context, stack, join.getRight());
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(projection);
+ LogicalNode child = visit(context, stack, projection.getChild());
+ // check if it is aggregation query without group-by clause. If so, it inserts group-by node to its child.
+ child = insertGroupbyNodeIfUnresolved(context, child, stack);
stack.pop();
+ ////////////////////////////////////////////////////////
- // Phase 3: build this plan
- JoinNode joinNode = new JoinNode(plan.newPID(), join.getJoinType(), left, right);
-
- // Set A merged input schema
- Schema merged;
- if (join.isNatural()) {
- merged = getNaturalJoin(left, right);
+ ProjectionNode projectionNode;
+ Target [] targets;
+ if (projection.isAllProjected()) {
+ // should takes all columns except for generated columns whose names are prefixed with '$'.
+ targets = PlannerUtil.schemaToTargetsWithGeneratedFields(child.getOutSchema());
} else {
- merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
+ targets = buildTargets(plan, block, referenceNames);
}
- joinNode.setInSchema(merged);
- joinNode.setOutSchema(merged);
- // Determine join conditions
- if (join.isNatural()) { // if natural join, it should have the equi-join conditions by common column names
- Schema leftSchema = joinNode.getLeftChild().getInSchema();
- Schema rightSchema = joinNode.getRightChild().getInSchema();
- Schema commons = SchemaUtil.getCommons(leftSchema, rightSchema);
- EvalNode njCond = getNaturalJoinCondition(leftSchema, rightSchema, commons);
- joinNode.setJoinQual(njCond);
- } else if (join.hasQual()) { // otherwise, the given join conditions are set
- joinNode.setJoinQual(createEvalTree(plan, block, join.getQual()));
+ // Set ProjectionNode
+ projectionNode = context.queryBlock.getNodeFromExpr(projection);
+ projectionNode.setTargets(targets);
+ projectionNode.setOutSchema(PlannerUtil.targetToSchema(projectionNode.getTargets()));
+ projectionNode.setInSchema(child.getOutSchema());
+ projectionNode.setChild(child);
+
+ if (projection.isDistinct() && block.hasNode(NodeType.GROUP_BY)) {
+ throw new VerifyException("Cannot support grouping and distinct at the same time yet");
+ } else {
+ if (projection.isDistinct()) {
+ insertDistinctOperator(context, projectionNode, child);
+ }
}
- return joinNode;
+ // It's for debugging and unit tests purpose.
+ // It sets raw targets, all of them are raw expressions instead of references.
+ setRawTargets(context, targets, referenceNames, projection);
+
+ return projectionNode;
}
- private static EvalNode getNaturalJoinCondition(Schema outer, Schema inner, Schema commons) {
- EvalNode njQual = null;
- EvalNode equiQual;
+ private void setRawTargets(PlanContext context, Target[] targets, String[] referenceNames,
+ Projection projection) throws PlanningException {
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
- Column leftJoinKey;
- Column rightJoinKey;
- for (Column common : commons.getColumns()) {
- leftJoinKey = outer.getColumnByName(common.getColumnName());
- rightJoinKey = inner.getColumnByName(common.getColumnName());
- equiQual = new BinaryEval(EvalType.EQUAL,
- new FieldEval(leftJoinKey), new FieldEval(rightJoinKey));
- if (njQual == null) {
- njQual = equiQual;
- } else {
- njQual = new BinaryEval(EvalType.AND,
- njQual, equiQual);
+ if (projection.isAllProjected()) {
+ block.setUnresolvedTargets(targets);
+ } else {
+ // It's for debugging or unit tests.
+ Target [] unresolvedTargets = new Target[projection.getNamedExprs().length];
+ for (int i = 0; i < targets.length; i++) {
+ NamedExpr namedExpr = projection.getNamedExprs()[i];
+ EvalNode evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
+ unresolvedTargets[i] = new Target(evalNode, referenceNames[i]);
}
+ // it's for debugging or unit testing
+ block.setUnresolvedTargets(unresolvedTargets);
}
-
- return njQual;
}
- private static LogicalNode createCatasianProduct(LogicalPlan plan, LogicalNode left, LogicalNode right) {
- JoinNode join = new JoinNode(plan.newPID(), JoinType.CROSS, left, right);
- Schema joinSchema = SchemaUtil.merge(
- join.getLeftChild().getOutSchema(),
- join.getRightChild().getOutSchema());
- join.setInSchema(joinSchema);
- join.setOutSchema(joinSchema);
+ private void insertDistinctOperator(PlanContext context, ProjectionNode projectionNode, LogicalNode child) {
+ LogicalPlan plan = context.plan;
- return join;
+ Schema outSchema = projectionNode.getOutSchema();
+ GroupbyNode dupRemoval = new GroupbyNode(plan.newPID());
+ dupRemoval.setGroupingColumns(outSchema.toArray());
+ dupRemoval.setTargets(PlannerUtil.schemaToTargets(outSchema));
+ dupRemoval.setInSchema(projectionNode.getInSchema());
+ dupRemoval.setOutSchema(outSchema);
+ dupRemoval.setChild(child);
+ projectionNode.setChild(dupRemoval);
+ projectionNode.setInSchema(dupRemoval.getOutSchema());
}
- private static Schema getNaturalJoin(LogicalNode outer, LogicalNode inner) {
- Schema joinSchema = new Schema();
- Schema commons = SchemaUtil.getCommons(outer.getOutSchema(),
- inner.getOutSchema());
- joinSchema.addColumns(commons);
- for (Column c : outer.getOutSchema().getColumns()) {
- for (Column common : commons.getColumns()) {
- if (!common.getColumnName().equals(c.getColumnName())) {
- joinSchema.addColumn(c);
- }
+ private String [] doProjectionPrephase(PlanContext context, Projection projection) throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ int finalTargetNum = projection.size();
+ String [] referenceNames = new String[finalTargetNum];
+ ExprNormalizedResult [] normalizedExprList = new ExprNormalizedResult[finalTargetNum];
+ NamedExpr namedExpr;
+ for (int i = 0; i < finalTargetNum; i++) {
+ namedExpr = projection.getNamedExprs()[i];
+
+ if (PlannerUtil.existsAggregationFunction(namedExpr)) {
+ block.setAggregationRequire();
}
+ // dissect an expression into multiple parts (at most dissected into three parts)
+ normalizedExprList[i] = normalizer.normalize(context, namedExpr.getExpr());
}
- for (Column c : inner.getOutSchema().getColumns()) {
- for (Column common : commons.getColumns()) {
- if (!common.getColumnName().equals(c.getColumnName())) {
- joinSchema.addColumn(c);
- }
+ // Note: Why separate normalization and add(Named)Expr?
+ //
+ // ExprNormalizer internally makes use of the named exprs in NamedExprsManager.
+ // If we don't separate normalization work and addExprWithName, addExprWithName will find named exprs evaluated
+ // the same logical node. It will cause impossible evaluation in physical executors.
+ for (int i = 0; i < finalTargetNum; i++) {
+ namedExpr = projection.getNamedExprs()[i];
+ // Get all projecting references
+ if (namedExpr.hasAlias()) {
+ NamedExpr aliasedExpr = new NamedExpr(normalizedExprList[i].baseExpr, namedExpr.getAlias());
+ referenceNames[i] = block.namedExprsMgr.addNamedExpr(aliasedExpr);
+ } else {
+ referenceNames[i] = block.namedExprsMgr.addExpr(normalizedExprList[i].baseExpr);
}
- }
- return joinSchema;
- }
- /*===============================================================================================
- SET OPERATION SECTION
- ===============================================================================================*/
+ // Add sub-expressions (i.e., aggregation part and scalar part) from dissected parts.
+ block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].aggExprs);
+ block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].scalarExprs);
+ }
- @Override
- public LogicalNode visitUnion(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
- throws PlanningException {
- return buildSetPlan(context, stack, setOperation);
+ return referenceNames;
}
- @Override
- public LogicalNode visitExcept(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+ /**
+ * It builds non-from statement (only expressions) like '<code>SELECT 1+3 as plus</code>'.
+ */
+ private EvalExprNode buildPlanForNoneFromStatement(PlanContext context, Stack<Expr> stack, Projection projection)
throws PlanningException {
- return buildSetPlan(context, stack, setOperation);
- }
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
- @Override
- public LogicalNode visitIntersect(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
- throws PlanningException {
- return buildSetPlan(context, stack, setOperation);
+ int finalTargetNum = projection.getNamedExprs().length;
+ Target [] targets = new Target[finalTargetNum];
+
+ for (int i = 0; i < targets.length; i++) {
+ NamedExpr namedExpr = projection.getNamedExprs()[i];
+ EvalNode evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
+ if (namedExpr.hasAlias()) {
+ targets[i] = new Target(evalNode, namedExpr.getAlias());
+ } else {
+ targets[i] = new Target(evalNode, context.plan.newGeneratedFieldName(namedExpr.getExpr()));
+ }
+ }
+ EvalExprNode evalExprNode = context.queryBlock.getNodeFromExpr(projection);
+ evalExprNode.setTargets(targets);
+ evalExprNode.setOutSchema(PlannerUtil.targetToSchema(targets));
+ // it's for debugging or unit testing
+ block.setUnresolvedTargets(targets);
+ return evalExprNode;
}
- private LogicalNode buildSetPlan(PlanContext context, Stack<OpType> stack, SetOperation setOperation)
+ private Target [] buildTargets(LogicalPlan plan, QueryBlock block, String[] referenceNames)
throws PlanningException {
+ Target [] targets = new Target[referenceNames.length];
+ for (int i = 0; i < referenceNames.length; i++) {
+ if (block.namedExprsMgr.isResolved(referenceNames[i])) {
+ targets[i] = block.namedExprsMgr.getTarget(referenceNames[i]);
+ } else {
+ NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referenceNames[i]);
+ EvalNode evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
+ block.namedExprsMgr.resolveExpr(referenceNames[i], evalNode);
+ targets[i] = new Target(evalNode, referenceNames[i]);
+ }
+ }
+ return targets;
+ }
- // 1. Init Phase
+ /**
+ * Insert a group-by operator before a sort or a projection operator.
+ * It is used only when a group-by clause is not given.
+ */
+ private LogicalNode insertGroupbyNodeIfUnresolved(PlanContext context,
+ LogicalNode child,
+ Stack<Expr> stack) throws PlanningException {
LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ QueryBlock block = context.queryBlock;
- // 2. Build Child Plans
- PlanContext leftContext = new PlanContext(plan, plan.newNoNameBlock());
- Stack<OpType> leftStack = new Stack<OpType>();
- LogicalNode left = visit(leftContext, leftStack, setOperation.getLeft());
- TableSubQueryNode leftSubQuery = new TableSubQueryNode(plan.newPID(), leftContext.block.getName(), left);
- context.plan.connectBlocks(leftContext.block, context.block, BlockType.TableSubQuery);
+ if (!block.isAggregationRequired()) {
+ GroupbyNode groupbyNode = new GroupbyNode(plan.newPID());
+ groupbyNode.setGroupingColumns(new Column[] {});
- PlanContext rightContext = new PlanContext(plan, plan.newNoNameBlock());
- Stack<OpType> rightStack = new Stack<OpType>();
- LogicalNode right = visit(rightContext, rightStack, setOperation.getRight());
- TableSubQueryNode rightSubQuery = new TableSubQueryNode(plan.newPID(), rightContext.block.getName(), right);
- context.plan.connectBlocks(rightContext.block, context.block, BlockType.TableSubQuery);
+ Set<Target> evaluatedTargets = new LinkedHashSet<Target>();
+ boolean includeDistinctFunction = false;
+ for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+ NamedExpr rawTarget = it.next();
+ try {
+ includeDistinctFunction = PlannerUtil.existsDistinctAggregationFunction(rawTarget.getExpr());
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
+ if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) {
+ block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+ evaluatedTargets.add(new Target(evalNode, rawTarget.getAlias()));
+ }
+ } catch (VerifyException ve) {
+ }
+ }
+ groupbyNode.setDistinct(includeDistinctFunction);
+ groupbyNode.setTargets(evaluatedTargets.toArray(new Target[evaluatedTargets.size()]));
+ groupbyNode.setChild(child);
+ groupbyNode.setInSchema(child.getOutSchema());
- BinaryNode setOp;
- if (setOperation.getType() == OpType.Union) {
- setOp = new UnionNode(plan.newPID(), leftSubQuery, rightSubQuery);
- } else if (setOperation.getType() == OpType.Except) {
- setOp = new ExceptNode(plan.newPID(), leftSubQuery, rightSubQuery);
- } else if (setOperation.getType() == OpType.Intersect) {
- setOp = new IntersectNode(plan.newPID(), leftSubQuery, rightSubQuery);
+ block.registerNode(groupbyNode); // this inserted group-by node doesn't pass through preprocessor. So manually added.
+ postHook(context, stack, null, groupbyNode);
+ return groupbyNode;
} else {
- throw new VerifyException("Invalid Type: " + setOperation.getType());
+ return child;
}
+ }
- // Strip the table names from the targets of the both blocks
- // in order to check the equivalence the schemas of both blocks.
- Target [] leftStrippedTargets = PlannerUtil.stripTarget(leftContext.block.getCurrentTargets());
+ /*===============================================================================================
+ SORT SECTION
+ ===============================================================================================*/
+ @Override
+ public LimitNode visitLimit(PlanContext context, Stack<Expr> stack, Limit limit) throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ EvalNode firstFetNum;
+ LogicalNode child;
+ if (limit.getFetchFirstNum().getType() == OpType.Literal) {
+ firstFetNum = exprAnnotator.createEvalNode(context.plan, block, limit.getFetchFirstNum());
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(limit);
+ child = visit(context, stack, limit.getChild());
+ stack.pop();
+ ////////////////////////////////////////////////////////
+ } else {
+ ExprNormalizedResult normalizedResult = normalizer.normalize(context, limit.getFetchFirstNum());
+ String referName = block.namedExprsMgr.addExpr(normalizedResult.baseExpr);
+ block.namedExprsMgr.addNamedExprArray(normalizedResult.aggExprs);
+ block.namedExprsMgr.addNamedExprArray(normalizedResult.scalarExprs);
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(limit);
+ child = visit(context, stack, limit.getChild());
+ stack.pop();
+ ////////////////////////////////////////////////////////
- Schema outSchema = PlannerUtil.targetToSchema(leftStrippedTargets);
- setOp.setInSchema(leftSubQuery.getOutSchema());
- setOp.setOutSchema(outSchema);
- if (isNoUpperProjection(stack)) {
- block.targetListManager = new TargetListManager(plan, leftStrippedTargets);
- block.targetListManager.resolveAll();
- block.setSchema(block.targetListManager.getUpdatedSchema());
+ // Consider the following query:
+ //
+ // SELECT one + two AS total ... FROM ... LIMIT total + 10;
+ //
+ // "total + 10" cannot be resolved in ScanNode. "total + 10" should be resolved in some of the upper nodes.
+ // So, we have to check if the reference is resolved. If not, it annotates the expression here.
+ if (block.namedExprsMgr.isResolved(referName)) {
+ firstFetNum = block.namedExprsMgr.getTarget(referName).getEvalTree();
+ } else {
+ NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referName);
+ firstFetNum = exprAnnotator.createEvalNode(context.plan, block, namedExpr.getExpr());
+ block.namedExprsMgr.resolveExpr(referName, firstFetNum);
+ }
}
- return setOp;
+ LimitNode limitNode = block.getNodeFromExpr(limit);
+ limitNode.setFetchFirst(firstFetNum.terminate(null).asInt8());
+ limitNode.setChild(child);
+ limitNode.setInSchema(child.getOutSchema());
+ limitNode.setOutSchema(child.getOutSchema());
+ return limitNode;
}
@Override
- public SelectionNode visitFilter(PlanContext context, Stack<OpType> stack, Selection selection)
- throws PlanningException {
- // 1. init phase:
- LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ public SortNode visitSort(PlanContext context, Stack<Expr> stack, Sort sort) throws PlanningException {
+ QueryBlock block = context.queryBlock;
- // 1.1 finding pushable expressions from search condition
+ int sortKeyNum = sort.getSortSpecs().length;
+ Sort.SortSpec[] sortSpecs = sort.getSortSpecs();
+ String [] referNames = new String[sortKeyNum];
- // 2. build child plans:
- stack.push(OpType.Filter);
- LogicalNode child = visit(context, stack, selection.getChild());
+ ExprNormalizedResult [] normalizedExprList = new ExprNormalizedResult[sortKeyNum];
+ for (int i = 0; i < sortKeyNum; i++) {
+ normalizedExprList[i] = normalizer.normalize(context, sortSpecs[i].getKey());
+ }
+ for (int i = 0; i < sortKeyNum; i++) {
+ referNames[i] = block.namedExprsMgr.addExpr(normalizedExprList[i].baseExpr);
+ block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].aggExprs);
+ block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].scalarExprs);
+ }
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(sort);
+ LogicalNode child = visit(context, stack, sort.getChild());
+ child = insertGroupbyNodeIfUnresolved(context, child, stack);
stack.pop();
+ ////////////////////////////////////////////////////////
- // 3. build this plan:
- EvalNode searchCondition = createEvalTree(plan, block, selection.getQual());
- EvalNode simplified = AlgebraicUtil.eliminateConstantExprs(searchCondition);
- SelectionNode selectionNode = new SelectionNode(plan.newPID(), simplified);
+ // Building sort keys
+ Column column;
+ SortSpec [] annotatedSortSpecs = new SortSpec[sortKeyNum];
+ for (int i = 0; i < sortKeyNum; i++) {
+ if (block.namedExprsMgr.isResolved(referNames[i])) {
+ column = block.namedExprsMgr.getTarget(referNames[i]).getNamedColumn();
+ } else {
+ throw new IllegalStateException("Unexpected State: " + TUtil.arrayToString(sortSpecs));
+ }
+ annotatedSortSpecs[i] = new SortSpec(column, sortSpecs[i].isAscending(), sortSpecs[i].isNullFirst());
+ }
- // 4. set child plan, update input/output schemas:
- selectionNode.setChild(child);
- selectionNode.setInSchema(child.getOutSchema());
- selectionNode.setOutSchema(child.getOutSchema());
+ SortNode sortNode = block.getNodeFromExpr(sort);
+ sortNode.setSortSpecs(annotatedSortSpecs);
- // 5. update block information:
- block.setSelectionNode(selectionNode);
+ // 4. Set Child Plan, Update Input/Output Schemas:
+ sortNode.setChild(child);
+ sortNode.setInSchema(child.getOutSchema());
+ sortNode.setOutSchema(child.getOutSchema());
- return selectionNode;
+ return sortNode;
}
/*===============================================================================================
@@ -435,133 +499,130 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
===============================================================================================*/
@Override
- public LogicalNode visitGroupBy(PlanContext context, Stack<OpType> stack, Aggregation aggregation)
+ public LogicalNode visitHaving(PlanContext context, Stack<Expr> stack, Having expr) throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ ExprNormalizedResult normalizedResult = normalizer.normalize(context, expr.getQual());
+ String referName = block.namedExprsMgr.addExpr(normalizedResult.baseExpr);
+ block.namedExprsMgr.addNamedExprArray(normalizedResult.aggExprs);
+ block.namedExprsMgr.addNamedExprArray(normalizedResult.scalarExprs);
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(expr);
+ LogicalNode child = visit(context, stack, expr.getChild());
+ stack.pop();
+ ////////////////////////////////////////////////////////
+
+ // Consider the following query:
+ //
+ // SELECT sum(avg) AS total ... FROM ... WHERE total > 2;
+ //
+ // "total" cannot be resolved in GroupByNode. "total" should be resolved in the upper nodes.
+ // So, we have to check if the reference is resolved. If not, it annotates the expression here.
+ EvalNode havingCondition;
+ if (block.namedExprsMgr.isResolved(referName)) {
+ havingCondition = block.namedExprsMgr.getTarget(referName).getEvalTree();
+ } else {
+ NamedExpr namedExpr = block.namedExprsMgr.getNamedExpr(referName);
+ havingCondition = exprAnnotator.createEvalNode(context.plan, block, namedExpr.getExpr());
+ block.namedExprsMgr.resolveExpr(referName, havingCondition);
+ }
+
+ HavingNode having = new HavingNode(context.plan.newPID());
+ having.setQual(havingCondition);
+ having.setInSchema(child.getOutSchema());
+ having.setOutSchema(child.getOutSchema());
+ having.setChild(child);
+ return having;
+ }
+
+ @Override
+ public LogicalNode visitGroupBy(PlanContext context, Stack<Expr> stack, Aggregation aggregation)
throws PlanningException {
- // 1. Initialization Phase:
+ // Initialization Phase:
LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ QueryBlock block = context.queryBlock;
+
+ // Normalize grouping keys and add normalized grouping keys to NamedExprManager
+ int groupingKeyNum = aggregation.getGroupSet()[0].getGroupingSets().length;
+ ExprNormalizedResult [] normalizedResults = new ExprNormalizedResult[groupingKeyNum];
+ for (int i = 0; i < groupingKeyNum; i++) {
+ Expr groupingKey = aggregation.getGroupSet()[0].getGroupingSets()[i];
+ normalizedResults[i] = normalizer.normalize(context, groupingKey);
+ }
+ String [] groupingKeyRefNames = new String[groupingKeyNum];
+ for (int i = 0; i < groupingKeyNum; i++) {
+ groupingKeyRefNames[i] = block.namedExprsMgr.addExpr(normalizedResults[i].baseExpr);
+ block.namedExprsMgr.addNamedExprArray(normalizedResults[i].aggExprs);
+ block.namedExprsMgr.addNamedExprArray(normalizedResults[i].scalarExprs);
+ }
- // 2. Build Child Plan Phase:
- stack.push(OpType.Aggregation);
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(aggregation);
LogicalNode child = visit(context, stack, aggregation.getChild());
stack.pop();
+ ////////////////////////////////////////////////////////
+
+ Set<Target> evaluatedTargets = new LinkedHashSet<Target>();
+ boolean includeDistinctFunction = false;
+ for (NamedExpr rawTarget : block.namedExprsMgr.getAllNamedExprs()) {
+ try {
+ includeDistinctFunction = PlannerUtil.existsDistinctAggregationFunction(rawTarget.getExpr());
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
+ if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) {
+ block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+ evaluatedTargets.add(new Target(evalNode, rawTarget.getAlias()));
+ }
+ } catch (VerifyException ve) {
+ }
+ }
// 3. Build This Plan:
Aggregation.GroupElement [] groupElements = aggregation.getGroupSet();
if (groupElements[0].getType() == GroupType.OrdinaryGroup) { // for group-by
- GroupElement annotatedElements [] = new GroupElement[groupElements.length];
- for (int i = 0; i < groupElements.length; i++) {
- annotatedElements[i] = new GroupElement(
- groupElements[i].getType(),
- annotateGroupingColumn(plan, block, groupElements[i].getColumns(), null));
+ Column [] groupingColumns = new Column[aggregation.getGroupSet()[0].getGroupingSets().length];
+ for (int i = 0; i < groupingColumns.length; i++) {
+ if (block.namedExprsMgr.isResolved(groupingKeyRefNames[i])) {
+ groupingColumns[i] = block.namedExprsMgr.getTarget(groupingKeyRefNames[i]).getNamedColumn();
+ } else {
+ throw new PlanningException("Each grouping column expression must be a scalar expression.");
+ }
}
- GroupbyNode groupingNode = new GroupbyNode(plan.newPID(), annotatedElements[0].getColumns());
- if (aggregation.hasHavingCondition()) {
- groupingNode.setHavingCondition(
- createEvalTree(plan, block, aggregation.getHavingCondition()));
+
+ GroupbyNode groupingNode = context.queryBlock.getNodeFromExpr(aggregation);
+ groupingNode.setGroupingColumns(groupingColumns);
+ groupingNode.setDistinct(includeDistinctFunction);
+
+ List<Target> targets = new ArrayList<Target>();
+
+ for (Column column : groupingColumns) {
+ if (child.getOutSchema().contains(column)) {
+ targets.add(new Target(new FieldEval(child.getOutSchema().getColumn(column))));
+ }
}
+ targets.addAll(evaluatedTargets);
+ groupingNode.setTargets(targets.toArray(new Target[targets.size()]));
// 4. Set Child Plan and Update Input Schemes Phase
groupingNode.setChild(child);
- block.setGroupbyNode(groupingNode);
+ block.registerNode(groupingNode);
groupingNode.setInSchema(child.getOutSchema());
// 5. Update Output Schema and Targets for Upper Plan
return groupingNode;
- } else if (groupElements[0].getType() == GroupType.Cube) { // for cube by
- List<Column[]> cuboids = generateCuboids(annotateGroupingColumn(plan, block,
- groupElements[0].getColumns(), null));
- UnionNode topUnion = createGroupByUnion(plan, block, child, cuboids, 0);
- block.resolveGroupingRequired();
- block.getTargetListManager().resolveAll();
-
- return topUnion;
} else {
throw new InvalidQueryException("Not support grouping");
}
}
- private UnionNode createGroupByUnion(final LogicalPlan plan,
- final QueryBlock block,
- final LogicalNode subNode,
- final List<Column[]> cuboids,
- final int idx) {
- UnionNode union;
- try {
- if ((cuboids.size() - idx) > 2) {
- GroupbyNode g1 = new GroupbyNode(plan.newPID(), cuboids.get(idx));
- Target[] clone = cloneTargets(block.getCurrentTargets());
-
- g1.setTargets(clone);
- g1.setChild((LogicalNode) subNode.clone());
- g1.setInSchema(g1.getChild().getOutSchema());
- Schema outSchema = getProjectedSchema(plan, block.getCurrentTargets());
- g1.setOutSchema(outSchema);
-
- LogicalNode right = createGroupByUnion(plan, block, subNode, cuboids, idx+1);
- union = new UnionNode(plan.newPID(), g1, right);
- union.setInSchema(g1.getOutSchema());
- union.setOutSchema(g1.getOutSchema());
-
- return union;
- } else {
- GroupbyNode g1 = new GroupbyNode(plan.newPID(), cuboids.get(idx));
- Target[] clone = cloneTargets(block.getCurrentTargets());
- g1.setTargets(clone);
- g1.setChild((LogicalNode) subNode.clone());
- g1.setInSchema(g1.getChild().getOutSchema());
- Schema outSchema = getProjectedSchema(plan, clone);
- g1.setOutSchema(outSchema);
-
- GroupbyNode g2 = new GroupbyNode(plan.newPID(), cuboids.get(idx+1));
- clone = cloneTargets(block.getCurrentTargets());
- g2.setTargets(clone);
- g2.setChild((LogicalNode) subNode.clone());
- g2.setInSchema(g1.getChild().getOutSchema());
- outSchema = getProjectedSchema(plan, clone);
- g2.setOutSchema(outSchema);
- union = new UnionNode(plan.newPID(), g1, g2);
- union.setInSchema(g1.getOutSchema());
- union.setOutSchema(g1.getOutSchema());
-
- return union;
- }
- } catch (CloneNotSupportedException cnse) {
- LOG.error(cnse);
- throw new InvalidQueryException(cnse);
- }
- }
-
- /**
- * It transforms a list of column references into a list of annotated columns with considering aliased expressions.
- */
- private Column[] annotateGroupingColumn(LogicalPlan plan, QueryBlock block,
- ColumnReferenceExpr[] columnRefs, LogicalNode child)
- throws PlanningException {
-
- Column[] columns = new Column[columnRefs.length];
- for (int i = 0; i < columnRefs.length; i++) {
- columns[i] = plan.resolveColumn(block, null, columnRefs[i]);
- columns[i] = plan.getColumnOrAliasedColumn(block, columns[i]);
- }
-
- return columns;
- }
-
- private static Target[] cloneTargets(Target[] sourceTargets)
- throws CloneNotSupportedException {
- Target[] clone = new Target[sourceTargets.length];
- for (int i = 0; i < sourceTargets.length; i++) {
- clone[i] = (Target) sourceTargets[i].clone();
- }
-
- return clone;
- }
-
public static final Column[] ALL= Lists.newArrayList().toArray(new Column[0]);
public static List<Column[]> generateCuboids(Column[] columns) {
@@ -585,160 +646,460 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
return cube;
}
+ @Override
+ public SelectionNode visitFilter(PlanContext context, Stack<Expr> stack, Selection selection)
+ throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ ExprNormalizedResult normalizedResult = normalizer.normalize(context, selection.getQual());
+ block.namedExprsMgr.addReferences(normalizedResult.baseExpr);
+ if (normalizedResult.aggExprs.size() > 0 || normalizedResult.scalarExprs.size() > 0) {
+ throw new VerifyException("Filter condition cannot include aggregation function");
+ }
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(selection);
+ LogicalNode child = visit(context, stack, selection.getChild());
+ stack.pop();
+ ////////////////////////////////////////////////////////
+
+ // Create EvalNode for a search condition.
+ EvalNode searchCondition = exprAnnotator.createEvalNode(context.plan, block, selection.getQual());
+ EvalNode simplified = AlgebraicUtil.eliminateConstantExprs(searchCondition);
+
+ SelectionNode selectionNode = context.queryBlock.getNodeFromExpr(selection);
+ selectionNode.setQual(simplified);
+ selectionNode.setChild(child);
+ selectionNode.setInSchema(child.getOutSchema());
+ selectionNode.setOutSchema(child.getOutSchema());
+
+ // 5. update block information:
+ block.registerNode(selectionNode);
+
+ return selectionNode;
+ }
+
/*===============================================================================================
- SORT SECTION
+ JOIN SECTION
===============================================================================================*/
@Override
- public SortNode visitSort(PlanContext context, Stack<OpType> stack, Sort sort) throws PlanningException {
-
- // 1. Initialization Phase:
+ public LogicalNode visitJoin(PlanContext context, Stack<Expr> stack, Join join)
+ throws PlanningException {
+ // Phase 1: Init
LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ QueryBlock block = context.queryBlock;
- // 2. Build Child Plans:
- stack.push(OpType.Sort);
- LogicalNode child = visit(context, stack, sort.getChild());
- child = insertGroupbyNodeIfUnresolved(plan, block, child, stack);
+ if (join.hasQual()) {
+ ExprNormalizedResult normalizedResult = normalizer.normalize(context, join.getQual());
+ block.namedExprsMgr.addReferences(normalizedResult.baseExpr);
+ if (normalizedResult.aggExprs.size() > 0 || normalizedResult.scalarExprs.size() > 0) {
+ throw new VerifyException("Filter condition cannot include aggregation function");
+ }
+ }
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Child Plan
+ ////////////////////////////////////////////////////////
+ stack.push(join);
+ LogicalNode left = visit(context, stack, join.getLeft());
+ LogicalNode right = visit(context, stack, join.getRight());
stack.pop();
+ ////////////////////////////////////////////////////////
- // 3. Build this plan:
- SortSpec[] annotatedSortSpecs = new SortSpec[sort.getSortSpecs().length];
- Column column;
- Sort.SortSpec[] sortSpecs = sort.getSortSpecs();
- for (int i = 0; i < sort.getSortSpecs().length; i++) {
- column = plan.resolveColumn(block, null, sortSpecs[i].getKey());
- column = plan.getColumnOrAliasedColumn(block, column);
- annotatedSortSpecs[i] = new SortSpec(column, sortSpecs[i].isAscending(), sortSpecs[i].isNullFirst());
+
+ JoinNode joinNode = context.queryBlock.getNodeFromExpr(join);
+ joinNode.setJoinType(join.getJoinType());
+ joinNode.setLeftChild(left);
+ joinNode.setRightChild(right);
+
+ // Set A merged input schema
+ Schema merged;
+ if (join.isNatural()) {
+ merged = getNaturalJoinSchema(left, right);
+ } else {
+ merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
}
- SortNode sortNode = new SortNode(context.plan.newPID(), annotatedSortSpecs);
+ joinNode.setInSchema(merged);
- // 4. Set Child Plan, Update Input/Output Schemas:
- sortNode.setChild(child);
- sortNode.setInSchema(child.getOutSchema());
- sortNode.setOutSchema(child.getOutSchema());
+ // Create EvalNode for a search condition.
+ EvalNode joinCondition = null;
+ if (join.hasQual()) {
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, block, join.getQual());
+ joinCondition = AlgebraicUtil.eliminateConstantExprs(evalNode);
+ }
- return sortNode;
+ EvalNode evalNode;
+ List<Expr> newlyEvaluatedExprs = TUtil.newList();
+ for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+ NamedExpr namedExpr = it.next();
+ try {
+ evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
+ if (LogicalPlanner.checkIfBeEvaluatedAtJoin(block, evalNode, joinNode, stack.peek().getType() != OpType.Join)) {
+ block.namedExprsMgr.resolveExpr(namedExpr.getAlias(), evalNode);
+ newlyEvaluatedExprs.add(namedExpr.getExpr());
+ }
+ } catch (VerifyException ve) {}
+ }
+
+ List<Target> targets = TUtil.newList(PlannerUtil.schemaToTargets(merged));
+
+ for (Expr newAddedExpr : newlyEvaluatedExprs) {
+ targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
+ }
+ joinNode.setTargets(targets.toArray(new Target[targets.size()]));
+
+ // Determine join conditions
+ if (join.isNatural()) { // if natural join, it should have the equi-join conditions by common column names
+ Schema leftSchema = joinNode.getLeftChild().getInSchema();
+ Schema rightSchema = joinNode.getRightChild().getInSchema();
+ Schema commons = SchemaUtil.getNaturalJoinColumns(leftSchema, rightSchema);
+ EvalNode njCond = getNaturalJoinCondition(leftSchema, rightSchema, commons);
+ joinNode.setJoinQual(njCond);
+ } else if (join.hasQual()) { // otherwise, the given join conditions are set
+ joinNode.setJoinQual(joinCondition);
+ }
+
+ return joinNode;
+ }
+
+ private static Schema getNaturalJoinSchema(LogicalNode left, LogicalNode right) {
+ Schema joinSchema = new Schema();
+ Schema commons = SchemaUtil.getNaturalJoinColumns(left.getOutSchema(), right.getOutSchema());
+ joinSchema.addColumns(commons);
+ for (Column c : left.getOutSchema().getColumns()) {
+ if (!joinSchema.contains(c.getQualifiedName())) {
+ joinSchema.addColumn(c);
+ }
+ }
+
+ for (Column c : right.getOutSchema().getColumns()) {
+ if (!joinSchema.contains(c.getQualifiedName())) {
+ joinSchema.addColumn(c);
+ }
+ }
+ return joinSchema;
+ }
+
+ private static EvalNode getNaturalJoinCondition(Schema outer, Schema inner, Schema commons) {
+ EvalNode njQual = null;
+ EvalNode equiQual;
+
+ Column leftJoinKey;
+ Column rightJoinKey;
+ for (Column common : commons.getColumns()) {
+ leftJoinKey = outer.getColumnByName(common.getColumnName());
+ rightJoinKey = inner.getColumnByName(common.getColumnName());
+ equiQual = new BinaryEval(EvalType.EQUAL,
+ new FieldEval(leftJoinKey), new FieldEval(rightJoinKey));
+ if (njQual == null) {
+ njQual = equiQual;
+ } else {
+ njQual = new BinaryEval(EvalType.AND, njQual, equiQual);
+ }
+ }
+
+ return njQual;
+ }
+
+ private LogicalNode createCartesianProduct(PlanContext context, LogicalNode left, LogicalNode right)
+ throws PlanningException {
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
+
+ EvalNode evalNode;
+ List<Expr> newlyEvaluatedExprs = TUtil.newList();
+ for (Iterator<NamedExpr> it = block.namedExprsMgr.getUnresolvedExprs(); it.hasNext();) {
+ NamedExpr namedExpr = it.next();
+ try {
+ evalNode = exprAnnotator.createEvalNode(plan, block, namedExpr.getExpr());
+ if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() == 0) {
+ block.namedExprsMgr.resolveExpr(namedExpr.getAlias(), evalNode);
+ newlyEvaluatedExprs.add(namedExpr.getExpr());
+ }
+ } catch (VerifyException ve) {}
+ }
+
+ Schema merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
+ List<Target> targets = TUtil.newList(PlannerUtil.schemaToTargets(merged));
+ for (Expr newAddedExpr : newlyEvaluatedExprs) {
+ targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
+ }
+
+ JoinNode join = new JoinNode(plan.newPID(), JoinType.CROSS, left, right);
+ join.setTargets(targets.toArray(new Target[targets.size()]));
+ join.setInSchema(merged);
+ return join;
+ }
+
+ @Override
+ public LogicalNode visitRelationList(PlanContext context, Stack<Expr> stack, RelationList relations)
+ throws PlanningException {
+
+ LogicalNode current = visit(context, stack, relations.getRelations()[0]);
+
+ LogicalNode left;
+ LogicalNode right;
+ if (relations.size() > 1) {
+
+ for (int i = 1; i < relations.size(); i++) {
+ left = current;
+ right = visit(context, stack, relations.getRelations()[i]);
+ current = createCartesianProduct(context, left, right);
+ }
+ }
+ context.queryBlock.registerNode(current);
+
+ return current;
+ }
+
+ @Override
+ public ScanNode visitRelation(PlanContext context, Stack<Expr> stack, Relation expr)
+ throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ ScanNode scanNode = block.getNodeFromExpr(expr);
+ updatePhysicalInfo(scanNode.getTableDesc());
+
+ // Add additional expressions required in upper nodes.
+ Set<Expr> newlyEvaluatedExprs = new LinkedHashSet<Expr>();
+ for (NamedExpr rawTarget : block.namedExprsMgr.getAllNamedExprs()) {
+ try {
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
+ if (checkIfBeEvaluatedAtRelation(block, evalNode, scanNode)) {
+ block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+ newlyEvaluatedExprs.add(rawTarget.getExpr()); // newly added exr
+ }
+ } catch (VerifyException ve) {
+ }
+ }
+
+ // Assume that each unique expr is evaluated once.
+ List<Target> targets = new ArrayList<Target>();
+ for (Column column : scanNode.getInSchema().getColumns()) {
+ ColumnReferenceExpr columnRef = new ColumnReferenceExpr(column.getQualifier(), column.getColumnName());
+ if (block.namedExprsMgr.contains(columnRef)) {
+ String referenceName = block.namedExprsMgr.getName(columnRef);
+ targets.add(new Target(new FieldEval(column), referenceName));
+ newlyEvaluatedExprs.remove(columnRef);
+ } else {
+ targets.add(new Target(new FieldEval(column)));
+ }
+ }
+
+ for (Expr newAddedExpr : newlyEvaluatedExprs) {
+ targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
+ }
+
+ scanNode.setTargets(targets.toArray(new Target[targets.size()]));
+
+ return scanNode;
+ }
+
+ private void updatePhysicalInfo(TableDesc desc) {
+ if (desc.getPath() != null) {
+ try {
+ FileSystem fs = desc.getPath().getFileSystem(new Configuration());
+ FileStatus status = fs.getFileStatus(desc.getPath());
+ if (desc.getStats() != null && (status.isDirectory() || status.isFile())) {
+ ContentSummary summary = fs.getContentSummary(desc.getPath());
+ if (summary != null) {
+ long volume = summary.getLength();
+ desc.getStats().setNumBytes(volume);
+ }
+ }
+ } catch (Throwable t) {
+ LOG.warn(t);
+ }
+ }
}
- @Override
- public LimitNode visitLimit(PlanContext context, Stack<OpType> stack, Limit limit) throws PlanningException {
- // 1. Init Phase:
- LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ public TableSubQueryNode visitTableSubQuery(PlanContext context, Stack<Expr> stack, TablePrimarySubQuery expr)
+ throws PlanningException {
+ QueryBlock block = context.queryBlock;
+
+ QueryBlock childBlock = context.plan.getBlock(context.plan.getBlockNameByExpr(expr.getSubQuery()));
+ PlanContext newContext = new PlanContext(context, childBlock);
+ LogicalNode child = visit(newContext, new Stack<Expr>(), expr.getSubQuery());
+ TableSubQueryNode subQueryNode = context.queryBlock.getNodeFromExpr(expr);
+ context.plan.connectBlocks(childBlock, context.queryBlock, BlockType.TableSubQuery);
+ subQueryNode.setSubQuery(child);
+
+ // Add additional expressions required in upper nodes.
+ Set<Expr> newlyEvaluatedExprs = new LinkedHashSet<Expr>();
+ for (NamedExpr rawTarget : block.namedExprsMgr.getAllNamedExprs()) {
+ try {
+ EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, rawTarget.getExpr());
+ if (checkIfBeEvaluatedAtRelation(block, evalNode, subQueryNode)) {
+ block.namedExprsMgr.resolveExpr(rawTarget.getAlias(), evalNode);
+ newlyEvaluatedExprs.add(rawTarget.getExpr()); // newly added exr
+ }
+ } catch (VerifyException ve) {
+ }
+ }
- // build child plans
- stack.push(OpType.Limit);
- LogicalNode child = visit(context, stack, limit.getChild());
- stack.pop();
+ // Assume that each unique expr is evaluated once.
+ List<Target> targets = new ArrayList<Target>();
+ for (Column column : subQueryNode.getInSchema().getColumns()) {
+ ColumnReferenceExpr columnRef = new ColumnReferenceExpr(column.getQualifier(), column.getColumnName());
+ if (block.namedExprsMgr.contains(columnRef)) {
+ String referenceName = block.namedExprsMgr.getName(columnRef);
+ targets.add(new Target(new FieldEval(column), referenceName));
+ newlyEvaluatedExprs.remove(columnRef);
+ } else {
+ targets.add(new Target(new FieldEval(column)));
+ }
+ }
- // build limit plan
- EvalNode firstFetchNum = createEvalTree(plan, block, limit.getFetchFirstNum());
- firstFetchNum.eval(null, null, null);
- LimitNode limitNode = new LimitNode(context.plan.newPID(), firstFetchNum.terminate(null).asInt8());
+ for (Expr newAddedExpr : newlyEvaluatedExprs) {
+ targets.add(block.namedExprsMgr.getTarget(newAddedExpr, true));
+ }
- // set child plan and update input/output schemas.
- limitNode.setChild(child);
- limitNode.setInSchema(child.getOutSchema());
- limitNode.setOutSchema(child.getOutSchema());
- return limitNode;
+ subQueryNode.setTargets(targets.toArray(new Target[targets.size()]));
+
+ return subQueryNode;
}
- /*===============================================================================================
- PROJECTION SECTION
+ /*===============================================================================================
+ SET OPERATION SECTION
===============================================================================================*/
@Override
- public LogicalNode visitProjection(PlanContext context, Stack<OpType> stack, Projection projection)
+ public LogicalNode visitUnion(PlanContext context, Stack<Expr> stack, SetOperation setOperation)
throws PlanningException {
+ return buildSetPlan(context, stack, setOperation);
+ }
- //1: init Phase
- LogicalPlan plan = context.plan;
- QueryBlock block = context.block;
+ @Override
+ public LogicalNode visitExcept(PlanContext context, Stack<Expr> stack, SetOperation setOperation)
+ throws PlanningException {
+ return buildSetPlan(context, stack, setOperation);
+ }
- if (!projection.isAllProjected()) {
- block.targetListManager = new TargetListManager(plan, projection);
- }
+ @Override
+ public LogicalNode visitIntersect(PlanContext context, Stack<Expr> stack, SetOperation setOperation)
+ throws PlanningException {
+ return buildSetPlan(context, stack, setOperation);
+ }
- if (!projection.hasChild()) {
- EvalExprNode evalOnly =
- new EvalExprNode(context.plan.newPID(), annotateTargets(plan, block, projection.getTargets()));
- evalOnly.setOutSchema(getProjectedSchema(plan, evalOnly.getExprs()));
- block.setProjectionNode(evalOnly);
- for (int i = 0; i < evalOnly.getTargets().length; i++) {
- block.targetListManager.fill(i, evalOnly.getTargets()[i]);
- }
- return evalOnly;
- }
+ private LogicalNode buildSetPlan(PlanContext context, Stack<Expr> stack, SetOperation setOperation)
+ throws PlanningException {
- // 2: Build Child Plans
- stack.push(OpType.Projection);
- LogicalNode child = visit(context, stack, projection.getChild());
- child = insertGroupbyNodeIfUnresolved(plan, block, child, stack);
+ // 1. Init Phase
+ LogicalPlan plan = context.plan;
+ QueryBlock block = context.queryBlock;
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Left Child Plan
+ ////////////////////////////////////////////////////////
+ QueryBlock leftBlock = context.plan.getBlockByExpr(setOperation.getLeft());
+ PlanContext leftContext = new PlanContext(context, leftBlock);
+ stack.push(setOperation);
+ LogicalNode leftChild = visit(leftContext, new Stack<Expr>(), setOperation.getLeft());
stack.pop();
+ // Connect left child and current blocks
+ context.plan.connectBlocks(leftContext.queryBlock, context.queryBlock, BlockType.TableSubQuery);
+
+ ////////////////////////////////////////////////////////
+ // Visit and Build Right Child Plan
+ ////////////////////////////////////////////////////////
+ QueryBlock rightBlock = context.plan.getBlockByExpr(setOperation.getRight());
+ PlanContext rightContext = new PlanContext(context, rightBlock);
+ stack.push(setOperation);
+ LogicalNode rightChild = visit(rightContext, new Stack<Expr>(), setOperation.getRight());
+ stack.pop();
+ // Connect right child and current blocks
+ context.plan.connectBlocks(rightContext.queryBlock, context.queryBlock, BlockType.TableSubQuery);
- // All targets must be evaluable before the projection.
- Preconditions.checkState(block.getTargetListManager().isAllResolved(),
- "Some targets cannot be evaluated in the query block \"%s\"", block.getName());
-
- ProjectionNode projectionNode;
- if (projection.isAllProjected()) {
- projectionNode = new ProjectionNode(context.plan.newPID(), PlannerUtil.schemaToTargets(child.getOutSchema()));
+ BinaryNode setOp;
+ if (setOperation.getType() == OpType.Union) {
+ setOp = new UnionNode(plan.newPID());
+ } else if (setOperation.getType() == OpType.Except) {
+ setOp = new ExceptNode(plan.newPID(), leftChild, rightChild);
+ } else if (setOperation.getType() == OpType.Intersect) {
+ setOp = new IntersectNode(plan.newPID(), leftChild, rightChild);
} else {
- projectionNode = new ProjectionNode(context.plan.newPID(), block.getCurrentTargets());
+ throw new VerifyException("Invalid Type: " + setOperation.getType());
}
+ setOp.setLeftChild(leftChild);
+ setOp.setRightChild(rightChild);
- block.setProjectionNode(projectionNode);
- projectionNode.setOutSchema(getProjectedSchema(plan, projectionNode.getTargets()));
- projectionNode.setInSchema(child.getOutSchema());
- projectionNode.setChild(child);
+ // An union statement can be derived from two query blocks.
+ // For one union statement between both relations, we can ensure that each corresponding data domain of both
+ // relations are the same. However, if necessary, the schema of left query block will be used as a base schema.
+ Target [] leftStrippedTargets = PlannerUtil.stripTarget(
+ PlannerUtil.schemaToTargets(leftBlock.getRoot().getOutSchema()));
- if (projection.isDistinct() && block.hasGrouping()) {
- throw new VerifyException("Cannot support grouping and distinct at the same time");
- } else {
- if (projection.isDistinct()) {
- Schema outSchema = projectionNode.getOutSchema();
- GroupbyNode dupRemoval = new GroupbyNode(plan.newPID(), outSchema.toArray());
- dupRemoval.setTargets(block.getTargetListManager().getTargets());
- dupRemoval.setInSchema(child.getOutSchema());
- dupRemoval.setOutSchema(outSchema);
- dupRemoval.setChild(child);
- projectionNode.setChild(dupRemoval);
- }
- }
+ Schema outSchema = PlannerUtil.targetToSchema(leftStrippedTargets);
+ setOp.setInSchema(leftChild.getOutSchema());
+ setOp.setOutSchema(outSchema);
- return projectionNode;
+ return setOp;
}
- /**
- * Insert a group-by operator before a sort or a projection operator.
- * It is used only when a group-by clause is not given.
- */
- private LogicalNode insertGroupbyNodeIfUnresolved(LogicalPlan plan, QueryBlock block,
- LogicalNode child, Stack<OpType> stack) throws PlanningException {
+ /*===============================================================================================
+ INSERT SECTION
+ ===============================================================================================*/
- if (!block.isGroupingResolved()) {
- GroupbyNode groupbyNode = new GroupbyNode(plan.newPID(), new Column[] {});
- groupbyNode.setTargets(block.getCurrentTargets());
- groupbyNode.setChild(child);
- groupbyNode.setInSchema(child.getOutSchema());
+ public LogicalNode visitInsert(PlanContext context, Stack<Expr> stack, Insert expr) throws PlanningException {
+ stack.push(expr);
+ QueryBlock newQueryBlock = context.plan.getBlockByExpr(expr.getSubQuery());
+ PlanContext newContext = new PlanContext(context, newQueryBlock);
+ Stack<Expr> subStack = new Stack<Expr>();
+ LogicalNode subQuery = visit(newContext, subStack, expr.getSubQuery());
+ context.plan.connectBlocks(newQueryBlock, context.queryBlock, BlockType.TableSubQuery);
+ stack.pop();
- block.postVisit(groupbyNode, stack);
- block.checkAndResolveTargets(groupbyNode);
- return groupbyNode;
- } else {
- return child;
+ InsertNode insertNode = null;
+ if (expr.hasTableName()) {
+ TableDesc desc = catalog.getTableDesc(expr.getTableName());
+ context.queryBlock.addRelation(new ScanNode(context.plan.newPID(), desc));
+
+ Schema targetSchema = new Schema();
+ if (expr.hasTargetColumns()) {
+ // INSERT OVERWRITE INTO TABLE tbl(col1 type, col2 type) SELECT ...
+ String [] targetColumnNames = expr.getTargetColumns();
+ for (int i = 0; i < targetColumnNames.length; i++) {
+ Column targetColumn = context.plan.resolveColumn(context.queryBlock,
+ new ColumnReferenceExpr(targetColumnNames[i]));
+ targetSchema.addColumn(targetColumn);
+ }
+ } else {
+ // use the output schema of select clause as target schema
+ // if didn't specific target columns like the way below,
+ // INSERT OVERWRITE INTO TABLE tbl SELECT ...
+ Schema targetTableSchema = desc.getSchema();
+ for (int i = 0; i < subQuery.getOutSchema().getColumnNum(); i++) {
+ targetSchema.addColumn(targetTableSchema.getColumn(i));
+ }
+ }
+
+ insertNode = context.queryBlock.getNodeFromExpr(expr);
+ insertNode.setTargetTableDesc(desc);
+ insertNode.setSubQuery(subQuery);
+ insertNode.setTargetSchema(targetSchema);
+ insertNode.setOutSchema(targetSchema);
}
- }
- private boolean isNoUpperProjection(Stack<OpType> stack) {
- for (OpType node : stack) {
- if (!( (node == OpType.Projection) || (node == OpType.Aggregation) || (node == OpType.Join) )) {
- return false;
+ if (expr.hasLocation()) {
+ insertNode = context.queryBlock.getNodeFromExpr(expr);
+ insertNode.setTargetLocation(new Path(expr.getLocation()));
+ insertNode.setSubQuery(subQuery);
+ if (expr.hasStorageType()) {
+ insertNode.setStorageType(CatalogUtil.getStoreType(expr.getStorageType()));
+ }
+ if (expr.hasParams()) {
+ Options options = new Options();
+ options.putAll(expr.getParams());
+ insertNode.setOptions(options);
}
}
- return true;
+ insertNode.setOverwrite(expr.isOverwrite());
+
+ return insertNode;
}
/*===============================================================================================
@@ -746,13 +1107,13 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
===============================================================================================*/
@Override
- public LogicalNode visitCreateTable(PlanContext context, Stack<OpType> stack, CreateTable expr)
+ public LogicalNode visitCreateTable(PlanContext context, Stack<Expr> stack, CreateTable expr)
throws PlanningException {
String tableName = expr.getTableName();
if (expr.hasSubQuery()) {
- stack.add(OpType.CreateTable);
+ stack.add(expr);
LogicalNode subQuery = visit(context, stack, expr.getSubQuery());
stack.pop();
StoreTableNode storeNode = new StoreTableNode(context.plan.newPID(), tableName);
@@ -794,23 +1155,22 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
mergedPartition = true;
}
} else {
- throw new PlanningException(String.format("Not supported PartitonType: %s",
- expr.getPartition().getPartitionType()));
+ throw new PlanningException(String.format("Not supported PartitonType: %s",
+ expr.getPartition().getPartitionType()));
}
}
if (mergedPartition) {
ColumnDefinition [] merged = TUtil.concat(expr.getTableElements(),
- ((ColumnPartition)expr.getPartition()).getColumns());
+ ((ColumnPartition)expr.getPartition()).getColumns());
tableSchema = convertTableElementsSchema(merged);
} else {
tableSchema = convertTableElementsSchema(expr.getTableElements());
}
- CreateTableNode createTableNode = new CreateTableNode(
- context.plan.newPID(),
- expr.getTableName(),
- tableSchema);
+ CreateTableNode createTableNode = context.queryBlock.getNodeFromExpr(expr);
+ createTableNode.setTableName(expr.getTableName());
+ createTableNode.setSchema(tableSchema);
if (expr.isExternal()) {
createTableNode.setExternal(true);
@@ -834,12 +1194,12 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
createTableNode.setPath(new Path(expr.getLocation()));
}
- if (expr.hasPartition()) {
+ if (expr.hasPartition()) {
if (expr.getPartition().getPartitionType().equals(PartitionType.COLUMN)) {
createTableNode.setPartitions(convertTableElementsPartition(context, expr));
} else {
- throw new PlanningException(String.format("Not supported PartitonType: %s",
- expr.getPartition().getPartitionType()));
+ throw new PlanningException(String.format("Not supported PartitonType: %s",
+ expr.getPartition().getPartitionType()));
}
}
@@ -856,7 +1216,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
* @throws PlanningException
*/
private PartitionDesc convertTableElementsPartition(PlanContext context,
- CreateTable expr) throws PlanningException {
+ CreateTable expr) throws PlanningException {
Schema schema = convertTableElementsSchema(expr.getTableElements());
PartitionDesc partitionDesc = null;
List<Specifier> specifiers = null;
@@ -909,8 +1269,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
Specifier specifier = new Specifier(eachSpec.getName());
sb.delete(0, sb.length());
for(Expr eachExpr : eachSpec.getValueList().getValues()) {
- context.block.setSchema(schema);
- EvalNode eval = createEvalTree(context.plan, context.block, eachExpr);
+ context.queryBlock.setSchema(schema);
+ EvalNode eval = exprAnnotator.createEvalNode(context.plan, context.queryBlock, eachExpr);
if(sb.length() > 1)
sb.append(",");
@@ -936,8 +1296,8 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
specifier.setName(eachSpec.getName());
if (eachSpec.getEnd() != null) {
- context.block.setSchema(schema);
- EvalNode eval = createEvalTree(context.plan, context.block, eachSpec.getEnd());
+ context.queryBlock.setSchema(schema);
+ EvalNode eval = exprAnnotator.createEvalNode(context.plan, context.queryBlock, eachSpec.getEnd());
specifier.setExpressions(eval.toString());
}
@@ -988,7 +1348,7 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
}
private Collection<Column> convertTableElementsColumns(CreateTable.ColumnDefinition [] elements,
- ColumnReferenceExpr[] references) {
+ ColumnReferenceExpr[] references) {
List<Column> columnList = TUtil.newList();
for(CreateTable.ColumnDefinition columnDefinition: elements) {
@@ -1002,10 +1362,14 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
return columnList;
}
- private DataType convertDataType(DataTypeExpr dataType) {
+ private Column convertColumn(ColumnDefinition columnDefinition) {
+ return new Column(columnDefinition.getColumnName(), convertDataType(columnDefinition));
+ }
+
+ static TajoDataTypes.DataType convertDataType(DataTypeExpr dataType) {
TajoDataTypes.Type type = TajoDataTypes.Type.valueOf(dataType.getTypeName());
- DataType.Builder builder = DataType.newBuilder();
+ TajoDataTypes.DataType.Builder builder = TajoDataTypes.DataType.newBuilder();
builder.setType(type);
if (dataType.hasLengthOrPrecision()) {
builder.setLength(dataType.getLengthOrPrecision());
@@ -1013,486 +1377,99 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
return builder.build();
}
- private Column convertColumn(ColumnDefinition columnDefinition) {
- return new Column(columnDefinition.getColumnName(), convertDataType(columnDefinition));
- }
-
- public LogicalNode visitInsert(PlanContext context, Stack<OpType> stack, Insert expr) throws PlanningException {
- stack.push(expr.getType());
- QueryBlock newQueryBlock = context.plan.newNoNameBlock();
- PlanContext newContext = new PlanContext(context.plan, newQueryBlock);
- Stack<OpType> subStack = new Stack<OpType>();
- LogicalNode subQuery = visit(newContext, subStack, expr.getSubQuery());
- context.plan.connectBlocks(newQueryBlock, context.block, BlockType.TableSubQuery);
- stack.pop();
-
- InsertNode insertNode = null;
- if (expr.hasTableName()) {
- TableDesc desc = catalog.getTableDesc(expr.getTableName());
- context.block.addRelation(new ScanNode(context.plan.newPID(), desc));
-
- Schema targetSchema = new Schema();
- if (expr.hasTargetColumns()) {
- // INSERT OVERWRITE INTO TABLE tbl(col1 type, col2 type) SELECT ...
- String [] targetColumnNames = expr.getTargetColumns();
- for (int i = 0; i < targetColumnNames.length; i++) {
- Column targetColumn = context.plan.resolveColumn(context.block, null, new ColumnReferenceExpr(targetColumnNames[i]));
- targetSchema.addColumn(targetColumn);
- }
- } else {
- // use the output schema of select clause as target schema
- // if didn't specific target columns like the way below,
- // INSERT OVERWRITE INTO TABLE tbl SELECT ...
- Schema targetTableSchema = desc.getSchema();
- for (int i = 0; i < subQuery.getOutSchema().getColumnNum(); i++) {
- targetSchema.addColumn(targetTableSchema.getColumn(i));
- }
- }
-
- insertNode = new InsertNode(context.plan.newPID(), desc, subQuery);
- insertNode.setTargetSchema(targetSchema);
- insertNode.setOutSchema(targetSchema);
- }
-
- if (expr.hasLocation()) {
- insertNode = new InsertNode(context.plan.newPID(), new Path(expr.getLocation()), subQuery);
- if (expr.hasStorageType()) {
- insertNode.setStorageType(CatalogUtil.getStoreType(expr.getStorageType()));
- }
- if (expr.hasParams()) {
- Options options = new Options();
- options.putAll(expr.getParams());
- insertNode.setOptions(options);
- }
- }
-
- insertNode.setOverwrite(expr.isOverwrite());
-
- return insertNode;
- }
@Override
- public LogicalNode visitDropTable(PlanContext context, Stack<OpType> stack, DropTable dropTable) {
- DropTableNode dropTableNode = new DropTableNode(context.plan.newPID(), dropTable.getTableName(),
- dropTable.isPurge());
+ public LogicalNode visitDropTable(PlanContext context, Stack<Expr> stack, DropTable dropTable) {
+ DropTableNode dropTableNode = context.queryBlock.getNodeFromExpr(dropTable);
+ dropTableNode.set(dropTable.getTableName(), dropTable.isPurge());
return dropTableNode;
}
- public static int [] dateToIntArray(String years, String months, String days)
- throws PlanningException {
- int year = Integer.valueOf(years);
- int month = Integer.valueOf(months);
- int day = Integer.valueOf(days);
+ /*===============================================================================================
+ Util SECTION
+ ===============================================================================================*/
- if (!(1 <= year && year <= 9999)) {
- throw new PlanningException(String.format("Years (%d) must be between 1 and 9999 integer value", year));
- }
+ public static boolean checkIfBeEvaluatedAtGroupBy(EvalNode evalNode, GroupbyNode groupbyNode) {
+ Set<Column> columnRefs = EvalTreeUtil.findDistinctRefColumns(evalNode);
- if (!(1 <= month && month <= 12)) {
- throw new PlanningException(String.format("Months (%d) must be between 1 and 12 integer value", month));
+ if (!groupbyNode.getInSchema().containsAll(columnRefs)) {
+ return false;
}
- if (!(1<= day && day <= 31)) {
- throw new PlanningException(String.format("Days (%d) must be between 1 and 31 integer value", day));
+ Set<String> tableIds = Sets.newHashSet();
+ // getting distinct table references
+ for (Column col : columnRefs) {
+ if (!tableIds.contains(col.getQualifier())) {
+ tableIds.add(col.getQualifier());
+ }
}
- int [] results = new int[3];
- results[0] = year;
- results[1] = month;
- results[2] = day;
+ if (tableIds.size() > 1) {
+ return false;
+ }
- return results;
+ return true;
}
- public static int [] timeToIntArray(String hours, String minutes, String seconds, String fractionOfSecond)
- throws PlanningException {
- int hour = Integer.valueOf(hours);
- int minute = Integer.valueOf(minutes);
- int second = Integer.valueOf(seconds);
- int fraction = 0;
- if (fractionOfSecond != null) {
- fraction = Integer.valueOf(fractionOfSecond);
- }
-
- if (!(0 <= hour && hour <= 23)) {
- throw new PlanningException(String.format("Hours (%d) must be between 0 and 24 integer value", hour));
- }
+ public static boolean checkIfBeEvaluatedAtJoin(QueryBlock block, EvalNode evalNode, JoinNode joinNode,
+ boolean isTopMostJoin) {
+ Set<Column> columnRefs = EvalTreeUtil.findDistinctRefColumns(evalNode);
- if (!(0 <= minute && minute <= 59)) {
- throw new PlanningException(String.format("Minutes (%d) must be between 0 and 59 integer value", minute));
+ if (EvalTreeUtil.findDistinctAggFunction(evalNode).size() > 0) {
+ return false;
}
- if (!(0 <= second && second <= 59)) {
- throw new PlanningException(String.format("Seconds (%d) must be between 0 and 59 integer value", second));
+ if (!joinNode.getInSchema().containsAll(columnRefs)) {
+ return false;
}
- if (fraction != 0) {
- if (!(0 <= fraction && fraction <= 999)) {
- throw new PlanningException(String.format("Seconds (%d) must be between 0 and 999 integer value", fraction));
- }
+ // When a 'case-when' is used with outer join, the case-when expression must be evaluated
+ // at the topmost join operator.
+ // TODO - It's also valid that case-when is evalauted at the topmost outer operator.
+ // But, how can we know there is no further outer join operator after this node?
+ if (checkCaseWhenWithOuterJoin(block, evalNode, isTopMostJoin)) {
+ return true;
+ } else {
+ return false;
}
-
- int [] results = new int[4];
- results[0] = hour;
- results[1] = minute;
- results[2] = second;
- results[3] = fraction;
-
- return results;
}
-
- /*===============================================================================================
- Expression SECTION
- ===============================================================================================*/
-
- public EvalNode createEvalTree(LogicalPlan plan, QueryBlock block, final Expr expr)throws PlanningException {
-
- switch(expr.getType()) {
- // constants
- case NullLiteral:
- return new ConstEval(NullDatum.get());
-
- case Literal:
- LiteralValue literal = (LiteralValue) expr;
- switch (literal.getValueType()) {
- case Boolean:
- return new ConstEval(DatumFactory.createBool(((BooleanLiteral)literal).isTrue()));
- case String:
- return new ConstEval(DatumFactory.createText(literal.getValue()));
- case Unsigned_Integer:
- return new ConstEval(DatumFactory.createInt4(literal.getValue()));
- case Unsigned_Large_Integer:
- return new ConstEval(DatumFactory.createInt8(literal.getValue()));
- case Unsigned_Float:
- return new ConstEval(DatumFactory.createFloat8(literal.getValue()));
- default:
- throw new RuntimeException("Unsupported type: " + literal.getValueType());
- }
-
- case TimeLiteral: {
- TimeLiteral timeLiteral = (TimeLiteral) expr;
- TimeValue timeValue = timeLiteral.getTime();
- int [] times = LogicalPlanner.timeToIntArray(timeValue.getHours(),
- timeValue.getMinutes(),
- timeValue.getSeconds(),
- timeValue.getSecondsFraction());
-
- TimeDatum datum;
- if (timeValue.hasSecondsFraction()) {
- datum = new TimeDatum(times[0], times[1], times[2], times[3]);
- } else {
- datum = new TimeDatum(times[0], times[1], times[2]);
- }
- return new ConstEval(datum);
- }
-
- case DateLiteral: {
- DateLiteral dateLiteral = (DateLiteral) expr;
- DateValue dateValue = dateLiteral.getDate();
- int [] dates = LogicalPlanner.dateToIntArray(dateValue.getYears(),
- dateValue.getMonths(),
- dateValue.getDays());
-
- DateDatum datum;
- datum = new DateDatum(dates[0], dates[1], dates[2]);
- return new ConstEval(datum);
- }
-
- case TimestampLiteral: {
- TimestampLiteral timestampLiteral = (TimestampLiteral) expr;
- DateValue dateValue = timestampLiteral.getDate();
- TimeValue timeValue = timestampLiteral.getTime();
-
- int [] dates = LogicalPlanner.dateToIntArray(dateValue.getYears(),
- dateValue.getMonths(),
- dateValue.getDays());
- int [] times = LogicalPlanner.timeToIntArray(timeValue.getHours(),
- timeValue.getMinutes(),
- timeValue.getSeconds(),
- timeValue.getSecondsFraction());
- DateTime dateTime;
- if (timeValue.hasSecondsFraction()) {
- dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2], times[3]);
- } else {
- dateTime = new DateTime(dates[0], dates[1], dates[2], times[0], times[1], times[2]);
- }
-
- return new ConstEval(new TimestampDatum(dateTime));
- }
-
- case Sign:
- SignedExpr signedExpr = (SignedExpr) expr;
- EvalNode numericExpr = createEvalTree(plan, block, signedExpr.getChild());
- if (signedExpr.isNegative()) {
- return new SignedEval(signedExpr.isNegative(), numericExpr);
- } else {
- return numericExpr;
- }
-
- case Cast:
- CastExpr cast = (CastExpr) expr;
- return new CastEval(createEvalTree(plan, block, cast.getOperand()),
- convertDataType(cast.getTarget()));
-
- case ValueList: {
- ValueListExpr valueList = (ValueListExpr) expr;
- Datum[] values = new Datum[valueList.getValues().length];
- ConstEval [] constEvals = new ConstEval[valueList.getValues().length];
- for (int i = 0; i < valueList.getValues().length; i++) {
- constEvals[i] = (ConstEval) createEvalTree(plan, block, valueList.getValues()[i]);
- values[i] = constEvals[i].getValue();
- }
- return new RowConstantEval(values);
- }
-
- // unary expression
- case Not:
- NotExpr notExpr = (NotExpr) expr;
- return new NotEval(createEvalTree(plan, block, notExpr.getChild()));
-
- case Between: {
- BetweenPredicate between = (BetweenPredicate) expr;
- BetweenPredicateEval betweenEval = new BetweenPredicateEval(between.isNot(), between.isSymmetric(),
- createEvalTree(plan, block, between.predicand()), createEvalTree(plan, block, between.begin()),
- createEvalTree(plan, block, between.end()));
- return betweenEval;
- }
- // pattern matching predicates
- case LikePredicate:
- case SimilarToPredicate:
- case Regexp:
- PatternMatchPredicate patternMatch = (PatternMatchPredicate) expr;
- EvalNode field = createEvalTree(plan, block, patternMatch.getPredicand());
- ConstEval pattern = (ConstEval) createEvalTree(plan, block, patternMatch.getPattern());
-
- // A pattern is a const value in pattern matching predicates.
- // In a binary expression, the result is always null if a const value in left or right side is null.
- if (pattern.getValue() instanceof NullDatum) {
- return new ConstEval(NullDatum.get());
- } else {
- if (expr.getType() == OpType.LikePredicate) {
- return new LikePredicateEval(patternMatch.isNot(), field, pattern, patternMatch.isCaseInsensitive());
- } else if (expr.getType() == OpType.SimilarToPredicate) {
- return new SimilarToPredicateEval(patternMatch.isNot(), field, pattern);
- } else {
- return new RegexPredicateEval(patternMatch.isNot(), field, pattern, patternMatch.isCaseInsensitive());
- }
- }
-
- case InPredicate: {
- InPredicate inPredicate = (InPredicate) expr;
- FieldEval predicand =
- new FieldEval(plan.resolveColumn(block, null, (ColumnReferenceExpr) inPredicate.getPredicand()));
- RowConstantEval rowConstantEval = (RowConstantEval) createEvalTree(plan, block, inPredicate.getInValue());
- return new InEval(predicand, rowConstantEval, inPredicate.isNot());
- }
-
- case And:
- case Or:
- case Equals:
- case NotEquals:
- case LessThan:
- case LessThanOrEquals:
- case GreaterThan:
- case GreaterThanOrEquals:
- case Plus:
- case Minus:
- case Multiply:
- case Divide:
- case Modular:
- case Concatenate:
- BinaryOperator bin = (BinaryOperator) expr;
- return new BinaryEval(exprTypeToEvalType(expr.getType()),
- createEvalTree(plan, block, bin.getLeft()),
- createEvalTree(plan, block, bin.getRight()));
-
- // others
- case Column:
- return createFieldEval(plan, block, (ColumnReferenceExpr) expr);
-
- case CountRowsFunction: {
- FunctionDesc countRows = catalog.getFunction("count", FunctionType.AGGREGATION, new DataType[] {});
-
- try {
- block.setHasGrouping();
-
- return new AggregationFunctionCallEval(countRows, (AggFunction) countRows.newInstance(),
- new EvalNode[] {});
- } catch (InternalException e) {
- throw new UndefinedFunctionException(CatalogUtil.
- getCanonicalName(countRows.getSignature(), new DataType[]{}));
- }
- }
- case GeneralSetFunction: {
- GeneralSetFunctionExpr setFunction = (GeneralSetFunctionExpr) expr;
<TRUNCATED>
[05/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
new file mode 100644
index 0000000..05ba036
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/NamedExprsManager.java
@@ -0,0 +1,271 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import org.apache.tajo.algebra.ColumnReferenceExpr;
+import org.apache.tajo.algebra.Expr;
+import org.apache.tajo.algebra.NamedExpr;
+import org.apache.tajo.algebra.OpType;
+import org.apache.tajo.annotation.Nullable;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.eval.FieldEval;
+import org.apache.tajo.util.TUtil;
+
+import java.util.*;
+
+import static java.util.Map.Entry;
+
+/**
+ * NamedExprsManager manages an expressions to be evaluated in a query block.
+ * NamedExprsManager uses a reference name to identify one expression or one
+ * EvalNode (annotated expression).
+ */
+public class NamedExprsManager {
+ /** Map; Reference name -> EvalNode */
+ private Map<String, EvalNode> nameToEvalMap = new LinkedHashMap<String, EvalNode>();
+ /** Map: EvalNode -> String */
+ private Map<EvalNode, String> evalToNameMap = new LinkedHashMap<EvalNode, String>();
+ /** Map; Reference name -> Expr */
+ private LinkedHashMap<String, Expr> nameToExprMap = new LinkedHashMap<String, Expr>();
+ /** Map; Expr -> Reference Name */
+ private LinkedHashMap<Expr, String> exprToNameMap = new LinkedHashMap<Expr, String>();
+ /** Map; Reference Name -> Boolean (if it is resolved or not) */
+ private LinkedHashMap<String, Boolean> resolvedFlags = new LinkedHashMap<String, Boolean>();
+
+ private BiMap<String, String> aliasedColumnMap = HashBiMap.create();
+
+ private LogicalPlan plan;
+
+ public NamedExprsManager(LogicalPlan plan) {
+ this.plan = plan;
+ }
+
+ /**
+ * Check whether the expression corresponding to a given name was resolved.
+ *
+ * @param name The name of a certain expression to be checked
+ * @return true if resolved. Otherwise, false.
+ */
+ public boolean isResolved(String name) {
+ String normalized = name.toLowerCase();
+ return resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized);
+ }
+
+ public boolean contains(String name) {
+ return nameToExprMap.containsKey(name);
+ }
+
+ public boolean contains(Expr expr) {
+ return exprToNameMap.containsKey(expr);
+ }
+
+ public String getName(Expr expr) {
+ return exprToNameMap.get(expr);
+ }
+
+ public NamedExpr getNamedExpr(String name) {
+ String normalized = name.toLowerCase();
+ return new NamedExpr(nameToExprMap.get(normalized), normalized);
+ }
+
+ public boolean isAliased(String name) {
+ return aliasedColumnMap.containsKey(name);
+ }
+
+ public String getAlias(String originalName) {
+ return aliasedColumnMap.get(originalName);
+ }
+
+ public boolean isAliasedName(String aliasName) {
+ return aliasedColumnMap.inverse().containsKey(aliasName);
+ }
+
+ public String getOriginalName(String aliasName) {
+ return aliasedColumnMap.inverse().get(aliasName);
+ }
+
+ public String addExpr(Expr expr, String alias) {
+ if (exprToNameMap.containsKey(expr)) {
+ return exprToNameMap.get(expr);
+ } else {
+ String normalized = alias.toLowerCase();
+ nameToExprMap.put(normalized, expr);
+ exprToNameMap.put(expr, normalized);
+ resolvedFlags.put(normalized, false);
+ return normalized;
+ }
+ }
+
+ public String [] addReferences(Expr expr) throws PlanningException {
+ Set<ColumnReferenceExpr> foundSet = ExprFinder.finds(expr, OpType.Column);
+ String [] names = new String[foundSet.size()];
+ int i = 0;
+ for (ColumnReferenceExpr column : foundSet) {
+ addExpr(column);
+ names[i++] = column.getCanonicalName();
+ }
+ return names;
+ }
+
+ public String addExpr(Expr expr) {
+ String name;
+
+ // all columns are projected automatically. BTW, should we add column reference to this list?
+ if (expr.getType() == OpType.Column) {
+ name = ((ColumnReferenceExpr)expr).getCanonicalName();
+ if (nameToExprMap.containsKey(name)) { // if it is column and another one already exists, skip.
+ return name;
+ }
+ } else {
+ name = plan.newGeneratedFieldName(expr);
+ }
+ return addExpr(expr, name);
+ }
+
+ public String addNamedExpr(NamedExpr namedExpr) {
+ if (namedExpr.hasAlias()) {
+ return addExpr(namedExpr.getExpr(), namedExpr.getAlias());
+ } else {
+ return addExpr(namedExpr.getExpr());
+ }
+ }
+
+ public String [] addNamedExprArray(@Nullable Collection<NamedExpr> targets) {
+ if (targets != null || targets.size() > 0) {
+ String [] names = new String[targets.size()];
+ int i = 0;
+ for (NamedExpr target : targets) {
+ names[i++] = addNamedExpr(target);
+ }
+ return names;
+ } else {
+ return null;
+ }
+ }
+
+ public Collection<NamedExpr> getAllNamedExprs() {
+ List<NamedExpr> namedExprList = new ArrayList<NamedExpr>();
+ for (Entry<String, Expr> entry: nameToExprMap.entrySet()) {
+ namedExprList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+ }
+ return namedExprList;
+ }
+
+ public void resolveExpr(String name, EvalNode evalNode) throws PlanningException {
+ String normalized = name.toLowerCase();
+ nameToEvalMap.put(normalized, evalNode);
+ evalToNameMap.put(evalNode, normalized);
+ resolvedFlags.put(normalized, true);
+
+ String originalName = checkAndGetIfAliasedColumn(normalized);
+ if (originalName != null) {
+ aliasedColumnMap.put(originalName, normalized);
+ }
+ }
+
+ /**
+ * It returns an original column name if it is aliased column reference.
+ * Otherwise, it will return NULL.
+ */
+ private String checkAndGetIfAliasedColumn(String name) {
+ Expr expr = nameToExprMap.get(name);
+ if (expr.getType() == OpType.Column) {
+ ColumnReferenceExpr column = (ColumnReferenceExpr) expr;
+ if (!column.getCanonicalName().equals(name)) {
+ return column.getCanonicalName();
+ }
+ }
+ return null;
+ }
+
+ public Target getTarget(Expr expr, boolean unresolved) {
+ String name = exprToNameMap.get(expr);
+ return getTarget(name, unresolved);
+ }
+
+ public Target getTarget(String name) {
+ return getTarget(name, false);
+ }
+
+ public Target getTarget(String name, boolean unresolved) {
+ String normalized = name;
+ if (!unresolved && resolvedFlags.containsKey(normalized) && resolvedFlags.get(normalized)) {
+ return new Target(new FieldEval(normalized, nameToEvalMap.get(normalized).getValueType()));
+ } else {
+ if (nameToEvalMap.containsKey(normalized)) {
+ return new Target(nameToEvalMap.get(normalized), name);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public String toString() {
+ return "unresolved=" + nameToExprMap.size() + ", resolved=" + nameToEvalMap.size()
+ + ", renamed=" + aliasedColumnMap.size();
+ }
+
+ /**
+ * It returns an iterator for unresolved NamedExprs.
+ */
+ public Iterator<NamedExpr> getUnresolvedExprs() {
+ return new UnresolvedIterator();
+ }
+
+ public class UnresolvedIterator implements Iterator<NamedExpr> {
+ private final Iterator<NamedExpr> iterator;
+
+ public UnresolvedIterator() {
+ List<NamedExpr> unresolvedList = TUtil.newList();
+ for (Entry<String,Expr> entry : nameToExprMap.entrySet()) {
+ if (!isResolved(entry.getKey())) {
+ unresolvedList.add(new NamedExpr(entry.getValue(), entry.getKey()));
+ }
+ }
+ if (unresolvedList.size() == 0) {
+ iterator = null;
+ } else {
+ iterator = unresolvedList.iterator();
+ }
+ }
+
+
+ @Override
+ public boolean hasNext() {
+ return iterator != null && iterator.hasNext();
+ }
+
+ @Override
+ public NamedExpr next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ }
+ }
+
+ public void reset() {
+ for (String name : resolvedFlags.keySet()) {
+ resolvedFlags.put(name, false);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
index d6d518c..d9689aa 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PhysicalPlannerImpl.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ObjectArrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.fs.Path;
+import org.apache.tajo.algebra.Projection;
import org.apache.tajo.engine.planner.global.DataChannel;
import org.apache.tajo.storage.fragment.FileFragment;
import org.apache.tajo.storage.fragment.FragmentConvertor;
@@ -133,7 +134,8 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
case TABLE_SUBQUERY: {
TableSubQueryNode subQueryNode = (TableSubQueryNode) logicalNode;
leftExec = createPlanRecursive(ctx, subQueryNode.getSubQuery());
- return leftExec;
+ ProjectionExec projectionExec = new ProjectionExec(ctx, subQueryNode, leftExec);
+ return projectionExec;
}
case PARTITIONS_SCAN:
@@ -146,6 +148,11 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
leftExec = createPlanRecursive(ctx, grpNode.getChild());
return createGroupByPlan(ctx, grpNode, leftExec);
+ case HAVING:
+ HavingNode havingNode = (HavingNode) logicalNode;
+ leftExec = createPlanRecursive(ctx, havingNode.getChild());
+ return new HavingExec(ctx, havingNode, leftExec);
+
case SORT:
SortNode sortNode = (SortNode) logicalNode;
leftExec = createPlanRecursive(ctx, sortNode.getChild());
@@ -327,12 +334,18 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
PhysicalExec leftExec, PhysicalExec rightExec) throws IOException {
SortSpec[][] sortSpecs = PlannerUtil.getSortKeysFromJoinQual(
plan.getJoinQual(), leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID, sortSpecs[0], leftExec.getSchema(), leftExec.getSchema()),
- leftExec);
- ExternalSortExec innerSort = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID, sortSpecs[1], rightExec.getSchema(), rightExec.getSchema()),
- rightExec);
+
+ SortNode leftSortNode = new SortNode(UNGENERATED_PID);
+ leftSortNode.setSortSpecs(sortSpecs[0]);
+ leftSortNode.setInSchema(leftExec.getSchema());
+ leftSortNode.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort = new ExternalSortExec(context, sm, leftSortNode, leftExec);
+
+ SortNode rightSortNode = new SortNode(UNGENERATED_PID);
+ rightSortNode.setSortSpecs(sortSpecs[1]);
+ rightSortNode.setInSchema(rightExec.getSchema());
+ rightSortNode.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort = new ExternalSortExec(context, sm, rightSortNode, rightExec);
LOG.info("Join (" + plan.getPID() +") chooses [Merge Join]");
return new MergeJoinExec(context, plan, outerSort, innerSort, sortSpecs[0], sortSpecs[1]);
@@ -399,10 +412,19 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
LOG.info("Right Outer Join (" + plan.getPID() +") chooses [Merge Join].");
SortSpec[][] sortSpecs2 = PlannerUtil.getSortKeysFromJoinQual(
plan.getJoinQual(), leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort2 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs2[0], leftExec.getSchema(), leftExec.getSchema()), leftExec);
- ExternalSortExec innerSort2 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs2[1], rightExec.getSchema(), rightExec.getSchema()), rightExec);
+
+ SortNode leftSortNode2 = new SortNode(UNGENERATED_PID);
+ leftSortNode2.setSortSpecs(sortSpecs2[0]);
+ leftSortNode2.setInSchema(leftExec.getSchema());
+ leftSortNode2.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort2 = new ExternalSortExec(context, sm, leftSortNode2, leftExec);
+
+ SortNode rightSortNode2 = new SortNode(UNGENERATED_PID);
+ rightSortNode2.setSortSpecs(sortSpecs2[1]);
+ rightSortNode2.setInSchema(rightExec.getSchema());
+ rightSortNode2.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort2 = new ExternalSortExec(context, sm, rightSortNode2, rightExec);
+
return new RightOuterMergeJoinExec(context, plan, outerSort2, innerSort2, sortSpecs2[0], sortSpecs2[1]);
}
@@ -481,10 +503,18 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
LOG.info("Full Outer Join (" + plan.getPID() +") chooses [Merge Join]");
SortSpec[][] sortSpecs3 = PlannerUtil.getSortKeysFromJoinQual(plan.getJoinQual(),
leftExec.getSchema(), rightExec.getSchema());
- ExternalSortExec outerSort3 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs3[0], leftExec.getSchema(), leftExec.getSchema()), leftExec);
- ExternalSortExec innerSort3 = new ExternalSortExec(context, sm,
- new SortNode(UNGENERATED_PID,sortSpecs3[1], rightExec.getSchema(), rightExec.getSchema()), rightExec);
+
+ SortNode leftSortNode = new SortNode(UNGENERATED_PID);
+ leftSortNode.setSortSpecs(sortSpecs3[0]);
+ leftSortNode.setInSchema(leftExec.getSchema());
+ leftSortNode.setOutSchema(leftExec.getSchema());
+ ExternalSortExec outerSort3 = new ExternalSortExec(context, sm, leftSortNode, leftExec);
+
+ SortNode rightSortNode = new SortNode(UNGENERATED_PID);
+ rightSortNode.setSortSpecs(sortSpecs3[1]);
+ rightSortNode.setInSchema(rightExec.getSchema());
+ rightSortNode.setOutSchema(rightExec.getSchema());
+ ExternalSortExec innerSort3 = new ExternalSortExec(context, sm, rightSortNode, rightExec);
return new MergeFullOuterJoinExec(context, plan, outerSort3, innerSort3, sortSpecs3[0], sortSpecs3[1]);
}
@@ -706,7 +736,8 @@ public class PhysicalPlannerImpl implements PhysicalPlanner {
sortSpecs = ObjectArrays.concat(sortSpecs, enforcedSortSpecs, SortSpec.class);
}
- SortNode sortNode = new SortNode(-1, sortSpecs);
+ SortNode sortNode = new SortNode(-1);
+ sortNode.setSortSpecs(sortSpecs);
sortNode.setInSchema(subOp.getSchema());
sortNode.setOutSchema(subOp.getSchema());
// SortExec sortExec = new SortExec(sortNode, child);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
index 4e2441b..66358d5 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/PlannerUtil.java
@@ -22,7 +22,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
-import org.apache.tajo.algebra.JoinType;
+import org.apache.tajo.algebra.*;
import org.apache.tajo.annotation.Nullable;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
@@ -33,6 +33,7 @@ import org.apache.tajo.engine.eval.*;
import org.apache.tajo.engine.planner.logical.*;
import org.apache.tajo.engine.exception.InvalidQueryException;
import org.apache.tajo.storage.TupleComparator;
+import org.apache.tajo.util.TUtil;
import java.util.*;
@@ -139,12 +140,17 @@ public class PlannerUtil {
public static void replaceNode(LogicalPlan plan, LogicalNode startNode, LogicalNode oldNode, LogicalNode newNode) {
LogicalNodeReplaceVisitor replacer = new LogicalNodeReplaceVisitor(oldNode, newNode);
try {
- replacer.visit(null, plan, null, startNode, new Stack<LogicalNode>());
+ replacer.visit(new ReplacerContext(), plan, null, startNode, new Stack<LogicalNode>());
} catch (PlanningException e) {
e.printStackTrace();
}
}
- public static class LogicalNodeReplaceVisitor extends BasicLogicalPlanVisitor<Object, LogicalNode> {
+
+ static class ReplacerContext {
+ boolean updateSchemaFlag = false;
+ }
+
+ public static class LogicalNodeReplaceVisitor extends BasicLogicalPlanVisitor<ReplacerContext, LogicalNode> {
private LogicalNode target;
private LogicalNode tobeReplaced;
@@ -154,9 +160,9 @@ public class PlannerUtil {
}
@Override
- public LogicalNode visit(Object context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block, LogicalNode node,
- Stack<LogicalNode> stack) throws PlanningException {
- super.visit(context, plan, null, node, stack);
+ public LogicalNode visit(ReplacerContext context, LogicalPlan plan, @Nullable LogicalPlan.QueryBlock block,
+ LogicalNode node, Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visit(context, plan, null, node, stack);
if (node.deepEquals(target)) {
LogicalNode parent = stack.peek();
@@ -173,6 +179,18 @@ public class PlannerUtil {
UnaryNode unaryParent = (UnaryNode) parent;
unaryParent.setChild(tobeReplaced);
}
+
+ context.updateSchemaFlag = true;
+ }
+
+ if (context.updateSchemaFlag && !node.deepEquals(target)) {
+ if (node instanceof Projectable) {
+ node.setInSchema(child.getOutSchema());
+ context.updateSchemaFlag = false;
+ } else {
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ }
}
return node;
}
@@ -241,10 +259,8 @@ public class PlannerUtil {
new Column(targetName, newTarget.getEvalTree().getValueType()))});
} else {
func.setFirstPhase();
- newTarget = new Target(func);
String targetName = "column_" + (targetId++);
- newTarget.setAlias(targetName);
-
+ newTarget = new Target(func, targetName);
AggregationFunctionCallEval secondFunc = null;
for (AggregationFunctionCallEval sf : secondStepFunctions) {
if (func.equals(sf)) {
@@ -264,14 +280,13 @@ public class PlannerUtil {
Schema targetSchema = PlannerUtil.targetToSchema(targetArray);
List<Target> newTarget = Lists.newArrayList();
for (Column column : groupBy.getGroupingColumns()) {
- if (!targetSchema.contains(column.getQualifiedName())) {
+ if (!targetSchema.containsByQualifiedName(column.getQualifiedName())) {
newTarget.add(new Target(new FieldEval(column)));
}
}
targetArray = ObjectArrays.concat(targetArray, newTarget.toArray(new Target[newTarget.size()]), Target.class);
child.setTargets(targetArray);
- child.setOutSchema(PlannerUtil.targetToSchema(targetArray));
// set the groupby chaining
groupBy.setChild(child);
groupBy.setInSchema(child.getOutSchema());
@@ -409,7 +424,7 @@ public class PlannerUtil {
} else {
for (Column col : columnRefs) {
- if (!node.getInSchema().contains(col.getQualifiedName())) {
+ if (!node.getInSchema().containsByQualifiedName(col.getQualifiedName())) {
return false;
}
}
@@ -506,6 +521,21 @@ public class PlannerUtil {
return targets;
}
+ public static Target[] schemaToTargetsWithGeneratedFields(Schema schema) {
+ List<Target> targets = TUtil.newList();
+
+ FieldEval eval;
+ Column column;
+ for (int i = 0; i < schema.getColumnNum(); i++) {
+ column = schema.getColumn(i);
+ if (column.getColumnName().charAt(0) != LogicalPlan.NONAMED_COLUMN_PREFIX) {
+ eval = new FieldEval(schema.getColumn(i));
+ targets.add(new Target(eval));
+ }
+ }
+ return targets.toArray(new Target[targets.size()]);
+ }
+
public static SortSpec[] schemaToSortSpecs(Schema schema) {
return schemaToSortSpecs(schema.toArray());
}
@@ -619,7 +649,7 @@ public class PlannerUtil {
for (int j = 0; j < schemas.length; j++) {
// check whether the column is for either outer or inner
// 0 is outer, and 1 is inner
- if (schemas[j].contains(column.getQualifiedName())) {
+ if (schemas[j].containsByQualifiedName(column.getQualifiedName())) {
pair[j] = column;
}
}
@@ -637,6 +667,10 @@ public class PlannerUtil {
}
}
+ public static Schema targetToSchema(Collection<Target> targets) {
+ return targetToSchema(targets.toArray(new Target[targets.size()]));
+ }
+
public static Schema targetToSchema(Target[] targets) {
Schema schema = new Schema();
for(Target t : targets) {
@@ -647,7 +681,9 @@ public class PlannerUtil {
} else {
name = t.getEvalTree().getName();
}
- schema.addColumn(name, type);
+ if (!schema.containsByQualifiedName(name)) {
+ schema.addColumn(name, type);
+ }
}
return schema;
@@ -668,7 +704,7 @@ public class PlannerUtil {
throw new InternalError(e.getMessage());
}
if (copy[i].getEvalTree().getType() == EvalType.FIELD) {
- FieldEval fieldEval = (FieldEval) copy[i].getEvalTree();
+ FieldEval fieldEval = copy[i].getEvalTree();
if (fieldEval.getColumnRef().hasQualifier()) {
fieldEval.getColumnRef().setName(fieldEval.getColumnName());
}
@@ -706,4 +742,51 @@ public class PlannerUtil {
return schema;
}
+ public static boolean existsAggregationFunction(Expr expr) throws PlanningException {
+ AggregationFunctionFinder finder = new AggregationFunctionFinder();
+ AggFunctionFoundResult result = new AggFunctionFoundResult();
+ finder.visit(result, new Stack<Expr>(), expr);
+ return result.generalSetFunction;
+ }
+
+ public static boolean existsDistinctAggregationFunction(Expr expr) throws PlanningException {
+ AggregationFunctionFinder finder = new AggregationFunctionFinder();
+ AggFunctionFoundResult result = new AggFunctionFoundResult();
+ finder.visit(result, new Stack<Expr>(), expr);
+ return result.distinctSetFunction;
+ }
+
+ static class AggFunctionFoundResult {
+ boolean generalSetFunction;
+ boolean distinctSetFunction;
+ }
+ static class AggregationFunctionFinder extends SimpleAlgebraVisitor<AggFunctionFoundResult, Object> {
+ @Override
+ public Object visitCountRowsFunction(AggFunctionFoundResult ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+ throws PlanningException {
+ ctx.generalSetFunction = true;
+ return super.visitCountRowsFunction(ctx, stack, expr);
+ }
+
+ @Override
+ public Object visitGeneralSetFunction(AggFunctionFoundResult ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
+ throws PlanningException {
+ ctx.generalSetFunction = true;
+ ctx.distinctSetFunction = expr.isDistinct();
+ return super.visitGeneralSetFunction(ctx, stack, expr);
+ }
+ }
+
+ public static Collection<String> toQualifiedFieldNames(Collection<String> fieldNames, String qualifier) {
+ List<String> names = TUtil.newList();
+ for (String n : fieldNames) {
+ String [] parts = n.split("\\.");
+ if (parts.length == 1) {
+ names.add(qualifier + "." + parts[0]);
+ } else {
+ names.add(qualifier + "." + parts[1]);
+ }
+ }
+ return names;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
index 12e4978..8d6db22 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Projector.java
@@ -18,7 +18,6 @@
package org.apache.tajo.engine.planner;
-import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.eval.EvalContext;
import org.apache.tajo.engine.eval.EvalNode;
@@ -29,59 +28,21 @@ public class Projector {
// for projection
private final int targetNum;
- private final int [] inMap;
- private final int [] outMap;
- private int [] evalOutMap; // target list?
- private EvalNode[] evals;
- private Tuple prevTuple;
+ private final EvalNode[] evals;
public Projector(Schema inSchema, Schema outSchema, Target [] targets) {
this.inSchema = inSchema;
-
- this.targetNum = targets != null ? targets.length : 0;
-
- inMap = new int[outSchema.getColumnNum() - targetNum];
- outMap = new int[outSchema.getColumnNum() - targetNum];
- int mapId = 0;
- Column col;
-
- if (targetNum > 0) {
- evalOutMap = new int[targetNum];
- evals = new EvalNode[targetNum];
- for (int i = 0; i < targetNum; i++) {
- // TODO - is it always correct?
- if (targets[i].hasAlias()) {
- evalOutMap[i] = outSchema.getColumnId(targets[i].getAlias());
- } else {
- evalOutMap[i] = outSchema.getColumnId(targets[i].getEvalTree().getName());
- }
- evals[i] = targets[i].getEvalTree();
- }
-
- outer:
- for (int targetId = 0; targetId < outSchema.getColumnNum(); targetId ++) {
- for (int j = 0; j < evalOutMap.length; j++) {
- if (evalOutMap[j] == targetId)
- continue outer;
- }
-
- col = inSchema.getColumnByFQN(outSchema.getColumn(targetId).getQualifiedName());
- outMap[mapId] = targetId;
- inMap[mapId] = inSchema.getColumnId(col.getQualifiedName());
- mapId++;
- }
- } else {
- for (int targetId = 0; targetId < outSchema.getColumnNum(); targetId ++) {
- col = inSchema.getColumnByFQN(outSchema.getColumn(targetId).getQualifiedName());
- outMap[mapId] = targetId;
- inMap[mapId] = inSchema.getColumnId(col.getQualifiedName());
- mapId++;
- }
+ if (targets == null) {
+ targets = PlannerUtil.schemaToTargets(outSchema);
+ }
+ this.targetNum = targets.length;
+ evals = new EvalNode[targetNum];
+ for (int i = 0; i < targetNum; i++) {
+ evals[i] = targets[i].getEvalTree();
}
}
public void eval(EvalContext[] evalContexts, Tuple in) {
- this.prevTuple = in;
if (targetNum > 0) {
for (int i = 0; i < evals.length; i++) {
evals[i].eval(evalContexts[i], inSchema, in);
@@ -90,17 +51,12 @@ public class Projector {
}
public void terminate(EvalContext [] evalContexts, Tuple out) {
- for (int i = 0; i < inMap.length; i++) {
- out.put(outMap[i], prevTuple.get(inMap[i]));
- }
- if (targetNum > 0) {
- for (int i = 0; i < evals.length; i++) {
- out.put(evalOutMap[i], evals[i].terminate(evalContexts[i]));
- }
+ for (int i = 0; i < targetNum; i++) {
+ out.put(i, evals[i].terminate(evalContexts[i]));
}
}
- public EvalContext [] renew() {
+ public EvalContext [] newContexts() {
EvalContext [] evalContexts = new EvalContext[targetNum];
for (int i = 0; i < targetNum; i++) {
evalContexts[i] = evals[i].newContext();
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
index e25903f..35d7743 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/RangePartitionAlgorithm.java
@@ -60,6 +60,9 @@ public abstract class RangePartitionAlgorithm {
BigDecimal columnCard;
switch (dataType.getType()) {
+ case BOOLEAN:
+ columnCard = new BigDecimal(2);
+ break;
case CHAR:
columnCard = new BigDecimal(end.asChar() - start.asChar());
break;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
new file mode 100644
index 0000000..dc7b7a2
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/SimpleAlgebraVisitor.java
@@ -0,0 +1,210 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import org.apache.tajo.algebra.*;
+
+import java.util.Stack;
+
+/**
+ * <code>SimpleAlgebraVisitor</code> provides a simple and fewer visit methods. It makes building concrete class easier.
+ */
+public abstract class SimpleAlgebraVisitor<CONTEXT, RESULT> extends BaseAlgebraVisitor<CONTEXT, RESULT> {
+
+ public RESULT visit(CONTEXT ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
+ RESULT result = null;
+ if (expr instanceof UnaryOperator) {
+ preHook(ctx, stack, expr);
+ result = visitUnaryOperator(ctx, stack, (UnaryOperator) expr);
+ postHook(ctx, stack, expr, result);
+ } else if (expr instanceof BinaryOperator) {
+ preHook(ctx, stack, expr);
+ result = visitBinaryOperator(ctx, stack, (BinaryOperator) expr);
+ postHook(ctx, stack, expr, result);
+ } else {
+ result = super.visit(ctx, stack, expr);
+ }
+
+ return result;
+ }
+
+ public RESULT visitUnaryOperator(CONTEXT ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ RESULT result = visit(ctx, stack, expr.getChild());
+ stack.pop();
+ return result;
+ }
+
+ public RESULT visitBinaryOperator(CONTEXT ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ stack.push(expr);
+ visit(ctx, stack, expr.getLeft());
+ RESULT result = visit(ctx, stack, expr.getRight());
+ stack.pop();
+ return result;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Relational Operator Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitProjection(CONTEXT ctx, Stack<Expr> stack, Projection expr) throws PlanningException {
+ return super.visitProjection(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitLimit(CONTEXT ctx, Stack<Expr> stack, Limit expr) throws PlanningException {
+ return super.visitLimit(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitSort(CONTEXT ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
+ return super.visitSort(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitHaving(CONTEXT ctx, Stack<Expr> stack, Having expr) throws PlanningException {
+ return super.visitHaving(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitGroupBy(CONTEXT ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
+ return super.visitGroupBy(ctx, stack, expr);
+ }
+
+ public RESULT visitFilter(CONTEXT ctx, Stack<Expr> stack, Selection expr) throws PlanningException {
+ return super.visitFilter(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitJoin(CONTEXT ctx, Stack<Expr> stack, Join expr) throws PlanningException {
+ return super.visitJoin(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitTableSubQuery(CONTEXT ctx, Stack<Expr> stack, TablePrimarySubQuery expr) throws PlanningException {
+ return super.visitTableSubQuery(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitRelationList(CONTEXT ctx, Stack<Expr> stack, RelationList expr) throws PlanningException {
+ return super.visitRelationList(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Data Definition Language Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitCreateTable(CONTEXT ctx, Stack<Expr> stack, CreateTable expr) throws PlanningException {
+ return super.visitCreateTable(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitDropTable(CONTEXT ctx, Stack<Expr> stack, DropTable expr) throws PlanningException {
+ return super.visitDropTable(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Insert or Update Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws PlanningException {
+ return super.visitInsert(ctx, stack, expr);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Other Predicates Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitBetween(CONTEXT ctx, Stack<Expr> stack, BetweenPredicate expr) throws PlanningException {
+ return super.visitBetween(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitCaseWhen(CONTEXT ctx, Stack<Expr> stack, CaseWhenPredicate expr) throws PlanningException {
+ return super.visitCaseWhen(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitValueListExpr(CONTEXT ctx, Stack<Expr> stack, ValueListExpr expr) throws PlanningException {
+ return super.visitValueListExpr(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Other Expressions
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitFunction(CONTEXT ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+ return super.visitFunction(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // General Set Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitCountRowsFunction(CONTEXT ctx, Stack<Expr> stack, CountRowsFunctionExpr expr)
+ throws PlanningException {
+ return super.visitCountRowsFunction(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitGeneralSetFunction(CONTEXT ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
+ throws PlanningException {
+ return super.visitGeneralSetFunction(ctx, stack, expr);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Literal Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public RESULT visitDataType(CONTEXT ctx, Stack<Expr> stack, DataTypeExpr expr) throws PlanningException {
+ return super.visitDataType(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitCastExpr(CONTEXT ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+ return super.visitCastExpr(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitLiteral(CONTEXT ctx, Stack<Expr> stack, LiteralValue expr) throws PlanningException {
+ return super.visitLiteral(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitNullLiteral(CONTEXT ctx, Stack<Expr> stack, NullLiteral expr) throws PlanningException {
+ return super.visitNullLiteral(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitTimestampLiteral(CONTEXT ctx, Stack<Expr> stack, TimestampLiteral expr) throws PlanningException {
+ return super.visitTimestampLiteral(ctx, stack, expr);
+ }
+
+ @Override
+ public RESULT visitTimeLiteral(CONTEXT ctx, Stack<Expr> stack, TimeLiteral expr) throws PlanningException {
+ return super.visitTimeLiteral(ctx, stack, expr);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
index ac50c46..d83a394 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/Target.java
@@ -22,6 +22,7 @@ import com.google.gson.annotations.Expose;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.common.TajoDataTypes.DataType;
import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.eval.FieldEval;
import org.apache.tajo.engine.json.CoreGsonHelper;
import org.apache.tajo.json.GsonObject;
import org.apache.tajo.util.TUtil;
@@ -34,14 +35,23 @@ public class Target implements Cloneable, GsonObject {
@Expose private Column column;
@Expose private String alias = null;
- public Target(EvalNode expr) {
- this.expr = expr;
- this.column = new Column(expr.getName(), expr.getValueType());
+ public Target(FieldEval fieldEval) {
+ this.expr = fieldEval;
+ this.column = fieldEval.getColumnRef();
}
public Target(final EvalNode eval, final String alias) {
- this(eval);
- setAlias(alias);
+ this.expr = eval;
+ // force lower case
+ String normalized = alias.toLowerCase();
+
+ // If an expr is a column reference and its alias is equivalent to column name, ignore a given alias.
+ if (eval instanceof FieldEval && eval.getName().equals(normalized)) {
+ column = ((FieldEval) eval).getColumnRef();
+ } else {
+ column = new Column(normalized, eval.getValueType());
+ setAlias(alias);
+ }
}
public String getCanonicalName() {
@@ -73,7 +83,7 @@ public class Target implements Cloneable, GsonObject {
return (T) this.expr;
}
- public Column getColumnSchema() {
+ public Column getNamedColumn() {
return this.column;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
deleted file mode 100644
index 4e1427e..0000000
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/TargetListManager.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tajo.engine.planner;
-
-import com.google.common.collect.Maps;
-import org.apache.tajo.algebra.Projection;
-import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.EvalNode;
-import org.apache.tajo.engine.eval.EvalTreeUtil;
-import org.apache.tajo.engine.eval.EvalType;
-import org.apache.tajo.engine.eval.FieldEval;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * It manages a list of targets.
- */
-public class TargetListManager {
- private final LogicalPlan plan;
- private boolean [] resolvedFlags;
- private Projection projection;
- private Target[] targets;
- private Target[] unresolvedTargets;
- private Map<Column, Integer> targetColumnToId = Maps.newHashMap();
-
- public TargetListManager(LogicalPlan plan, Projection projection) {
- this.plan = plan;
- int targetNum = projection.size();
- if (projection.size() == 0) {
- resolvedFlags = new boolean[0];
- } else {
- resolvedFlags = new boolean[targetNum];
- }
- this.targets = new Target[targetNum];
- this.unresolvedTargets = new Target[targetNum];
- }
-
- public TargetListManager(LogicalPlan plan, Target[] unresolvedTargets) {
- this.plan = plan;
-
- this.targets = new Target[unresolvedTargets.length];
- this.unresolvedTargets = new Target[unresolvedTargets.length];
- for (int i = 0; i < unresolvedTargets.length; i++) {
- try {
- this.targets[i] = (Target) unresolvedTargets[i].clone();
- this.unresolvedTargets[i] = (Target) unresolvedTargets[i].clone();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- }
- resolvedFlags = new boolean[unresolvedTargets.length];
- }
-
- public TargetListManager(LogicalPlan plan, String blockName) {
- this(plan, plan.getBlock(blockName).getTargetListManager().getUnresolvedTargets());
- }
-
- public Target getTarget(int id) {
- return targets[id];
- }
-
- public Target[] getTargets() {
- return this.targets;
- }
-
- public Target[] getUnresolvedTargets() {
- return this.unresolvedTargets;
- }
-
- public void fill(int id, Target target) {
- this.targets[id] = target;
- this.unresolvedTargets[id] = target;
-
- EvalNode evalNode = target.getEvalTree();
- if (evalNode.getType() == EvalType.FIELD) {
- if (target.hasAlias()) {
- FieldEval fieldEval = (FieldEval) evalNode;
- targetColumnToId.put(fieldEval.getColumnRef(), id);
- }
- }
- targetColumnToId.put(target.getColumnSchema(), id);
- }
-
- public int size() {
- return targets.length;
- }
-
- public void resolve(int id) {
- resolvedFlags[id] = true;
- }
-
- public void resolveAll() {
- for (int i = 0; i < resolvedFlags.length; i++) {
- resolvedFlags[i] = true;
- }
- }
-
- public boolean isResolved(int id) {
- return resolvedFlags[id];
- }
-
- /**
- * It checks whether only column reference is resolve or not.
- * Note that this method doesn't know if an expression is resolved.
- *
- * @param targetColumn A column to be checked
- * @return True if a column reference belong to a target list and is already resolved. Otherwise, false.
- */
- public boolean isResolve(Column targetColumn) throws PlanningException {
- Integer targetId = targetColumnToId.get(targetColumn);
- if (targetId == null) {
- return false;
- }
- return resolvedFlags[targetId];
- }
-
- public Column getResolvedColumn(Column targetColumn) throws PlanningException {
- Integer targetId = targetColumnToId.get(targetColumn);
- if (targetId == null) {
- throw new PlanningException("Unknown target column: " + targetColumn);
- }
- return getResolvedTargetToColumn(targetId);
- }
-
- public Target [] getUpdatedTarget(Set<Integer> exclude) throws PlanningException {
- Target [] updated = new Target[targets.length];
-
- for (int i = 0; i < targets.length; i++) {
- if (targets[i] == null) { // if it is not created
- continue;
- }
-
- if (!exclude.contains(i) && resolvedFlags[i]) { // if this target was evaluated, it becomes a column target.
- Column col = getResolvedTargetToColumn(i);
- updated[i] = new Target(new FieldEval(col));
- } else {
- try {
- updated[i] = (Target) targets[i].clone();
- } catch (CloneNotSupportedException e) {
- throw new PlanningException(e);
- }
- }
- }
- return updated;
- }
-
- public Target [] getUpdatedTarget() throws PlanningException {
- Target [] updated = new Target[targets.length];
-
- for (int i = 0; i < targets.length; i++) {
- if (targets[i] == null) { // if it is not created
- continue;
- }
-
- if (resolvedFlags[i]) { // if this target was evaluated, it becomes a column target.
- Column col = getResolvedTargetToColumn(i);
- updated[i] = new Target(new FieldEval(col));
- } else {
- try {
- updated[i] = (Target) targets[i].clone();
- } catch (CloneNotSupportedException e) {
- throw new PlanningException(e);
- }
- }
- }
- targets = updated;
- return updated;
- }
-
- public Schema getUpdatedSchema() {
- Schema schema = new Schema();
- for (int i = 0; i < resolvedFlags.length; i++) {
- if (resolvedFlags[i]) {
- Column col = getResolvedTargetToColumn(i);
- if (!schema.contains(col.getQualifiedName()))
- schema.addColumn(col);
- } else {
- Collection<Column> cols = getColumnRefs(i);
- for (Column col : cols) {
- if (!schema.contains(col.getQualifiedName())) {
- schema.addColumn(col);
- }
- }
- }
- }
- return schema;
- }
-
- public Collection<Column> getColumnRefs(int id) {
- return EvalTreeUtil.findDistinctRefColumns(targets[id].getEvalTree());
- }
-
- public Column getResolvedTargetToColumn(int id) {
- Target t = targets[id];
- String name;
- if (t.hasAlias() || t.getEvalTree().getType() == EvalType.FIELD) {
- name = t.getCanonicalName();
- } else { // if alias name is not given or target is an expression
- t.setAlias(plan.newNonameColumnName(t.getEvalTree().getName()));
- name = t.getCanonicalName();
- }
- return new Column(name, t.getEvalTree().getValueType());
- }
-
- public boolean isAllResolved() {
- for (boolean resolved : resolvedFlags) {
- if (!resolved) {
- return false;
- }
- }
-
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
index d05ac46..58ad73c 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/global/GlobalPlanner.java
@@ -50,8 +50,7 @@ public class GlobalPlanner {
private TajoConf conf;
private CatalogProtos.StoreType storeType;
- public GlobalPlanner(final TajoConf conf, final AbstractStorageManager sm)
- throws IOException {
+ public GlobalPlanner(final TajoConf conf, final AbstractStorageManager sm) throws IOException {
this.conf = conf;
this.storeType = CatalogProtos.StoreType.valueOf(conf.getVar(TajoConf.ConfVars.SHUFFLE_FILE_FORMAT).toUpperCase());
Preconditions.checkArgument(storeType != null);
@@ -249,8 +248,7 @@ public class GlobalPlanner {
}
private ExecutionBlock buildGroupBy(GlobalPlanContext context, ExecutionBlock childBlock,
- GroupbyNode groupbyNode)
- throws PlanningException {
+ GroupbyNode groupbyNode) throws PlanningException {
MasterPlan masterPlan = context.plan;
ExecutionBlock currentBlock;
@@ -259,7 +257,6 @@ public class GlobalPlanner {
return buildDistinctGroupBy(context, childBlock, groupbyNode);
} else {
GroupbyNode firstPhaseGroupBy = PlannerUtil.transformGroupbyTo2P(groupbyNode);
- firstPhaseGroupBy.setHavingCondition(null);
if (firstPhaseGroupBy.getChild().getType() == NodeType.TABLE_SUBQUERY &&
((TableSubQueryNode)firstPhaseGroupBy.getChild()).getSubQuery().getType() == NodeType.UNION) {
@@ -365,10 +362,20 @@ public class GlobalPlanner {
// if result table is not a partitioned table, directly store it
if(partitionDesc == null) {
- currentNode.setChild(childBlock.getPlan());
- currentNode.setInSchema(childBlock.getPlan().getOutSchema());
- childBlock.setPlan(currentNode);
- return childBlock;
+
+ if (childBlock.getPlan() == null) { // when the below is union
+ for (ExecutionBlock grandChildBlock : context.plan.getChilds(childBlock)) {
+ StoreTableNode copy = PlannerUtil.clone(context.plan.getLogicalPlan(), currentNode);
+ copy.setChild(grandChildBlock.getPlan());
+ grandChildBlock.setPlan(copy);
+ }
+ return childBlock;
+ } else {
+ currentNode.setChild(childBlock.getPlan());
+ currentNode.setInSchema(childBlock.getPlan().getOutSchema());
+ childBlock.setPlan(currentNode);
+ return childBlock;
+ }
}
// if result table is a partitioned table
@@ -419,9 +426,23 @@ public class GlobalPlanner {
ExecutionBlock execBlock = context.execBlockMap.remove(child.getPID());
- node.setChild(execBlock.getPlan());
- node.setInSchema(execBlock.getPlan().getOutSchema());
- execBlock.setPlan(node);
+ if (child.getType() == NodeType.TABLE_SUBQUERY &&
+ ((TableSubQueryNode)child).getSubQuery().getType() == NodeType.UNION) {
+ MasterPlan masterPlan = context.plan;
+ for (DataChannel dataChannel : masterPlan.getIncomingChannels(execBlock.getId())) {
+ ExecutionBlock subBlock = masterPlan.getExecBlock(dataChannel.getSrcId());
+
+ ProjectionNode copy = PlannerUtil.clone(plan, node);
+ copy.setChild(subBlock.getPlan());
+ subBlock.setPlan(copy);
+ }
+ execBlock.setPlan(null);
+ } else {
+ node.setChild(execBlock.getPlan());
+ node.setInSchema(execBlock.getPlan().getOutSchema());
+ execBlock.setPlan(node);
+ }
+
context.execBlockMap.put(node.getPID(), execBlock);
return node;
}
@@ -481,6 +502,20 @@ public class GlobalPlanner {
}
@Override
+ public LogicalNode visitHaving(GlobalPlanContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ HavingNode node, Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visitHaving(context, plan, block, node, stack);
+
+ // Don't separate execution block. Having is pushed to the second grouping execution block.
+ ExecutionBlock childBlock = context.execBlockMap.remove(child.getPID());
+ node.setChild(childBlock.getPlan());
+ childBlock.setPlan(node);
+ context.execBlockMap.put(node.getPID(), childBlock);
+
+ return node;
+ }
+
+ @Override
public LogicalNode visitGroupBy(GlobalPlanContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
GroupbyNode node, Stack<LogicalNode> stack) throws PlanningException {
LogicalNode child = super.visitGroupBy(context, plan, block, node, stack);
@@ -553,9 +588,9 @@ public class GlobalPlanner {
}
for (ExecutionBlock childBlocks : unionBlocks) {
- UnionNode union = (UnionNode) childBlocks.getPlan();
- queryBlockBlocks.add(context.execBlockMap.get(union.getLeftChild().getPID()));
- queryBlockBlocks.add(context.execBlockMap.get(union.getRightChild().getPID()));
+ for (ExecutionBlock grandChildBlock : context.plan.getChilds(childBlocks)) {
+ queryBlockBlocks.add(grandChildBlock);
+ }
}
for (ExecutionBlock childBlocks : queryBlockBlocks) {
@@ -596,7 +631,20 @@ public class GlobalPlanner {
LogicalPlan.QueryBlock queryBlock,
TableSubQueryNode node, Stack<LogicalNode> stack) throws PlanningException {
LogicalNode child = super.visitTableSubQuery(context, plan, queryBlock, node, stack);
- return handleUnaryNode(context, child, node);
+
+ ExecutionBlock currentBlock = context.execBlockMap.remove(child.getPID());
+
+ if (child.getType() == NodeType.UNION) {
+ for (ExecutionBlock childBlock : context.plan.getChilds(currentBlock.getId())) {
+ TableSubQueryNode copy = PlannerUtil.clone(plan, node);
+ copy.setSubQuery(childBlock.getPlan());
+ childBlock.setPlan(copy);
+ }
+ } else {
+ currentBlock.setPlan(node);
+ }
+ context.execBlockMap.put(node.getPID(), currentBlock);
+ return node;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
index d0c8373..3dc5655 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/CreateTableNode.java
@@ -38,15 +38,21 @@ public class CreateTableNode extends LogicalNode implements Cloneable {
@Expose private boolean external;
@Expose private PartitionDesc partitionDesc;
- public CreateTableNode(int pid, String tableName, Schema schema) {
+ public CreateTableNode(int pid) {
super(pid, NodeType.CREATE_TABLE);
- this.tableName = tableName;
- this.schema = schema;
+ }
+
+ public void setTableName(String name) {
+ this.tableName = name;
}
public final String getTableName() {
return this.tableName;
}
+
+ public void setSchema(Schema schema) {
+ this.schema = schema;
+ }
public Schema getSchema() {
return this.schema;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
index 6510925..4dda7af 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/DropTableNode.java
@@ -24,8 +24,11 @@ public class DropTableNode extends LogicalNode {
private String tableName;
private boolean purge;
- public DropTableNode(int pid, String tableName, boolean purge) {
+ public DropTableNode(int pid) {
super(pid, NodeType.DROP_TABLE);
+ }
+
+ public void set(String tableName, boolean purge) {
this.tableName = tableName;
this.purge = purge;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
index 5bc41bf..ed63bbc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/EvalExprNode.java
@@ -29,9 +29,8 @@ import org.apache.tajo.util.TUtil;
public class EvalExprNode extends LogicalNode implements Projectable {
@Expose private Target[] exprs;
- public EvalExprNode(int pid, Target[] exprs) {
+ public EvalExprNode(int pid) {
super(pid, NodeType.EXPRS);
- this.exprs = exprs;
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
index 352780a..41f1e88 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/GroupbyNode.java
@@ -20,33 +20,28 @@ package org.apache.tajo.engine.planner.logical;
import com.google.gson.annotations.Expose;
import org.apache.tajo.catalog.Column;
-import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
@Expose private Column [] columns;
- @Expose private Schema havingSchema;
- @Expose private EvalNode havingCondition = null;
@Expose private Target [] targets;
@Expose private boolean hasDistinct = false;
-
- public GroupbyNode(int pid, final Column [] columns) {
- super(pid, NodeType.GROUP_BY);
- this.columns = columns;
- }
-
- public GroupbyNode(int pid, final Column [] columns, final EvalNode havingCondition) {
- this(pid, columns);
- this.havingCondition = havingCondition;
+
+ public GroupbyNode(int pid) {
+ super(pid, NodeType.GROUP_BY);
}
public final boolean isEmptyGrouping() {
return columns == null || columns.length == 0;
}
+ public void setGroupingColumns(Column [] groupingColumns) {
+ this.columns = groupingColumns;
+ }
+
public final Column [] getGroupingColumns() {
return this.columns;
}
@@ -58,26 +53,6 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
public void setDistinct(boolean distinct) {
hasDistinct = distinct;
}
-
- public final boolean hasHavingCondition() {
- return this.havingCondition != null;
- }
-
- public final EvalNode getHavingCondition() {
- return this.havingCondition;
- }
-
- public final void setHavingCondition(final EvalNode evalTree) {
- this.havingCondition = evalTree;
- }
-
- public final void setHavingSchema(Schema schema) {
- this.havingSchema = schema;
- }
-
- public Schema getHavingSchema() {
- return this.havingSchema;
- }
@Override
public boolean hasTargets() {
@@ -87,6 +62,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -105,10 +81,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
if(i < columns.length - 1)
sb.append(",");
}
-
- if(hasHavingCondition()) {
- sb.append("], \"having qual\": \"").append(havingCondition).append("\"");
- }
+
if(hasTargets()) {
sb.append(", \"target\": [");
for (int i = 0; i < targets.length; i++) {
@@ -132,7 +105,6 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
GroupbyNode other = (GroupbyNode) obj;
boolean eq = super.equals(other);
eq = eq && TUtil.checkEquals(columns, other.columns);
- eq = eq && TUtil.checkEquals(havingCondition, other.havingCondition);
eq = eq && TUtil.checkEquals(targets, other.targets);
return eq;
} else {
@@ -149,8 +121,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
grp.columns[i] = (Column) columns[i].clone();
}
}
- grp.havingCondition = (EvalNode) (havingCondition != null
- ? havingCondition.clone() : null);
+
if (targets != null) {
grp.targets = new Target[targets.length];
for (int i = 0; i < targets.length; i++) {
@@ -183,7 +154,7 @@ public class GroupbyNode extends UnaryNode implements Projectable, Cloneable {
for (int i = 0; i < targets.length; i++) {
sb.append(targets[i]);
if( i < targets.length - 1) {
- sb.append(",");
+ sb.append(", ");
}
}
planStr.addExplan(sb.toString());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
new file mode 100644
index 0000000..f4eafd0
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/HavingNode.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner.logical;
+
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.planner.PlanString;
+
+public class HavingNode extends UnaryNode implements Cloneable {
+ @Expose private EvalNode qual;
+
+ public HavingNode(int pid) {
+ super(pid, NodeType.HAVING);
+ }
+
+ public EvalNode getQual() {
+ return this.qual;
+ }
+
+ public void setQual(EvalNode qual) {
+ this.qual = qual;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof HavingNode) {
+ HavingNode other = (HavingNode) obj;
+ return super.equals(other)
+ && this.qual.equals(other.qual);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ HavingNode selNode = (HavingNode) super.clone();
+ selNode.qual = (EvalNode) this.qual.clone();
+
+ return selNode;
+ }
+
+ @Override
+ public PlanString getPlanString() {
+ return new PlanString("Having: ").appendTitle(qual.toString());
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\"Having\": {\"qual\": \"").append(qual.toString()).append("\",");
+ sb.append("\n \"out schema\": ").append(getOutSchema()).append(",");
+ sb.append("\n \"in schema\": ").append(getInSchema()).append("}");
+
+ return sb.toString()+"\n"
+ + getChild().toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
index 7272630..e82cc3e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/IndexScanNode.java
@@ -35,7 +35,6 @@ public class IndexScanNode extends ScanNode {
super(pid, scanNode.getTableDesc());
setQual(scanNode.getQual());
setInSchema(scanNode.getInSchema());
- setOutSchema(scanNode.getOutSchema());
setTargets(scanNode.getTargets());
setType(NodeType.BST_INDEX_SCAN);
this.sortKeys = sortKeys;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
index 23a79df..2628c3b 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/JoinNode.java
@@ -25,6 +25,7 @@ import com.google.gson.annotations.Expose;
import org.apache.tajo.algebra.JoinType;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
@@ -87,6 +88,7 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ this.setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -97,8 +99,21 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
planStr.addExplan("Join Cond: " + joinQual.toString());
}
- planStr.addDetail("in schema: " + getInSchema());
+ if (hasTargets()) {
+ planStr.addExplan("target list: ");
+ boolean first = true;
+ for (Target target : targets) {
+ if (!first) {
+ planStr.appendExplain(", ");
+ }
+ planStr.appendExplain(target.toString());
+ first = false;
+ }
+ }
+
planStr.addDetail("out schema: " + getOutSchema());
+ planStr.addDetail("in schema: " + getInSchema());
+
return planStr;
}
@@ -108,14 +123,8 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
JoinNode other = (JoinNode) obj;
boolean eq = this.joinType.equals(other.joinType);
eq &= TUtil.checkEquals(this.targets, other.targets);
- if (this.joinQual != null && other.joinQual != null) {
- eq &= this.joinQual.equals(other.joinQual);
- } else if (this.joinQual == null && other.joinQual == null) {
-
- } else {
- eq = false;
- }
- return eq;
+ eq &= TUtil.checkEquals(joinQual, other.joinQual);
+ return eq && leftChild.equals(other.leftChild) && rightChild.equals(other.rightChild);
} else {
return false;
}
@@ -126,6 +135,12 @@ public class JoinNode extends BinaryNode implements Projectable, Cloneable {
JoinNode join = (JoinNode) super.clone();
join.joinType = this.joinType;
join.joinQual = this.joinQual == null ? null : (EvalNode) this.joinQual.clone();
+ if (hasTargets()) {
+ join.targets = new Target[targets.length];
+ for (int i = 0; i < targets.length; i++) {
+ join.targets[i] = (Target) targets[i].clone();
+ }
+ }
return join;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
index b604fac..197a5bc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/LimitNode.java
@@ -24,9 +24,12 @@ import org.apache.tajo.engine.planner.PlanString;
public final class LimitNode extends UnaryNode implements Cloneable {
@Expose private long fetchFirstNum;
- public LimitNode(int pid, long fetchFirstNum) {
+ public LimitNode(int pid) {
super(pid, NodeType.LIMIT);
- this.fetchFirstNum = fetchFirstNum;
+ }
+
+ public void setFetchFirst(long num) {
+ this.fetchFirstNum = num;
}
public long getFetchFirstNum() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
index 4c0dd11..32b9bc6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/NodeType.java
@@ -32,6 +32,7 @@ public enum NodeType {
PROJECTION(ProjectionNode.class),
LIMIT(LimitNode.class),
SORT(SortNode.class),
+ HAVING(HavingNode.class),
GROUP_BY(GroupbyNode.class),
SELECTION(SelectionNode.class),
JOIN(JoinNode.class),
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
index c2807fe..d72b31e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/Projectable.java
@@ -18,10 +18,17 @@
package org.apache.tajo.engine.planner.logical;
+import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.planner.Target;
public interface Projectable {
boolean hasTargets();
+
void setTargets(Target[] targets);
+
Target [] getTargets();
+
+ public Schema getInSchema();
+
+ public Schema getOutSchema();
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
index 8ef2bda..1a219a6 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ProjectionNode.java
@@ -20,6 +20,7 @@ package org.apache.tajo.engine.planner.logical;
import com.google.gson.annotations.Expose;
import org.apache.tajo.engine.planner.PlanString;
+import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
import org.apache.tajo.util.TUtil;
@@ -32,12 +33,8 @@ public class ProjectionNode extends UnaryNode implements Projectable {
@Expose private Target [] targets;
@Expose private boolean distinct = false;
- /**
- * @param targets they should be all evaluated ones.
- */
- public ProjectionNode(int pid, Target [] targets) {
+ public ProjectionNode(int pid) {
super(pid, NodeType.PROJECTION);
- this.targets = targets;
}
public boolean hasTargets() {
@@ -47,6 +44,7 @@ public class ProjectionNode extends UnaryNode implements Projectable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ this.setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
index 5ea61b4..8ed247e 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/RelationNode.java
@@ -20,6 +20,16 @@ package org.apache.tajo.engine.planner.logical;
import org.apache.tajo.catalog.Schema;
+/**
+ * It provides a logical view of a relation. Regarding a table, the main difference between a logical view and a
+ * physical view is as follows:
+ *
+ * <ul>
+ * <li>In logical view, each column in the table has qualified name by table alias name. In addition, the schema of
+ * logical view will includes partition columns if we use column-partitioned tables.</li>
+ * <li>In contrast, in physical view: each column in the table has qualified name by the original table.</li>
+ * </ul>
+ */
public abstract class RelationNode extends LogicalNode {
public RelationNode(int pid, NodeType nodeType) {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
index cd9c1f1..165e1e8 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/ScanNode.java
@@ -90,6 +90,7 @@ public class ScanNode extends RelationNode implements Projectable {
@Override
public void setTargets(Target [] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
index 699a561..b39ade3 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SelectionNode.java
@@ -24,11 +24,10 @@ import org.apache.tajo.engine.planner.PlanString;
public class SelectionNode extends UnaryNode implements Cloneable {
@Expose private EvalNode qual;
-
- public SelectionNode(int pid, EvalNode qual) {
- super(pid, NodeType.SELECTION);
- setQual(qual);
- }
+
+ public SelectionNode(int pid) {
+ super(pid, NodeType.SELECTION);
+ }
public EvalNode getQual() {
return this.qual;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
index 46ceea8..00c8485 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/SortNode.java
@@ -20,7 +20,6 @@ package org.apache.tajo.engine.planner.logical;
import com.google.common.base.Preconditions;
import com.google.gson.annotations.Expose;
-import org.apache.tajo.catalog.Schema;
import org.apache.tajo.catalog.SortSpec;
import org.apache.tajo.engine.planner.PlanString;
import org.apache.tajo.util.TUtil;
@@ -28,17 +27,13 @@ import org.apache.tajo.util.TUtil;
public final class SortNode extends UnaryNode implements Cloneable {
@Expose private SortSpec [] sortKeys;
- public SortNode(int pid, SortSpec[] sortKeys) {
+ public SortNode(int pid) {
super(pid, NodeType.SORT);
- Preconditions.checkArgument(sortKeys.length > 0,
- "At least one sort key must be specified");
- this.sortKeys = sortKeys;
}
- public SortNode(int pid, SortSpec[] sortKeys, Schema inSchema, Schema outSchema) {
- this(pid, sortKeys);
- this.setInSchema(inSchema);
- this.setOutSchema(outSchema);
+ public void setSortSpecs(SortSpec[] sortSpecs) {
+ Preconditions.checkArgument(sortSpecs.length > 0, "At least one sort key must be specified");
+ this.sortKeys = sortSpecs;
}
public SortSpec[] getSortKeys() {
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
index 335d12f..25e5d07 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/TableSubQueryNode.java
@@ -24,6 +24,7 @@ import org.apache.tajo.catalog.Schema;
import org.apache.tajo.engine.planner.PlanString;
import org.apache.tajo.engine.planner.PlannerUtil;
import org.apache.tajo.engine.planner.Target;
+import org.apache.tajo.util.TUtil;
public class TableSubQueryNode extends RelationNode implements Projectable {
@Expose private String tableName;
@@ -33,10 +34,13 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public TableSubQueryNode(int pid, String tableName, LogicalNode subQuery) {
super(pid, NodeType.TABLE_SUBQUERY);
this.tableName = PlannerUtil.normalizeTableName(tableName);
- this.subQuery = subQuery;
- setOutSchema((Schema) this.subQuery.getOutSchema().clone());
- getOutSchema().setQualifier(this.tableName);
- setInSchema((Schema) this.subQuery.getInSchema().clone());
+ if (subQuery != null) {
+ this.subQuery = subQuery;
+ setOutSchema((Schema) this.subQuery.getOutSchema().clone());
+ setInSchema((Schema) this.subQuery.getOutSchema().clone());
+ getInSchema().setQualifier(this.tableName);
+ getOutSchema().setQualifier(this.tableName);
+ }
}
public String getTableName() {
@@ -55,7 +59,10 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public void setSubQuery(LogicalNode node) {
this.subQuery = node;
- setInSchema(subQuery.getInSchema());
+ setInSchema((Schema) this.subQuery.getOutSchema().clone());
+ getInSchema().setQualifier(this.tableName);
+ setOutSchema((Schema) this.subQuery.getOutSchema().clone());
+ getOutSchema().setQualifier(this.tableName);
}
public LogicalNode getSubQuery() {
@@ -70,6 +77,7 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
@Override
public void setTargets(Target[] targets) {
this.targets = targets;
+ setOutSchema(PlannerUtil.targetToSchema(targets));
}
@Override
@@ -81,6 +89,24 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public PlanString getPlanString() {
PlanString planStr = new PlanString("TablePrimarySubQuery");
planStr.appendTitle(" as ").appendTitle(tableName);
+
+ if (hasTargets()) {
+ StringBuilder sb = new StringBuilder("Targets: ");
+ for (int i = 0; i < targets.length; i++) {
+ sb.append(targets[i]);
+ if( i < targets.length - 1) {
+ sb.append(", ");
+ }
+ }
+ planStr.addExplan(sb.toString());
+ if (getOutSchema() != null) {
+ planStr.addExplan("out schema: " + getOutSchema().toString());
+ }
+ if (getInSchema() != null) {
+ planStr.addExplan("in schema: " + getInSchema().toString());
+ }
+ }
+
return planStr;
}
@@ -103,6 +129,13 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
public Object clone() throws CloneNotSupportedException {
TableSubQueryNode newTableSubQueryNode = (TableSubQueryNode) super.clone();
newTableSubQueryNode.tableName = tableName;
+ newTableSubQueryNode.subQuery = (LogicalNode) subQuery.clone();
+ if (hasTargets()) {
+ newTableSubQueryNode.targets = new Target[targets.length];
+ for (int i = 0; i < targets.length; i++) {
+ newTableSubQueryNode.targets[i] = (Target) targets[i].clone();
+ }
+ }
return newTableSubQueryNode;
}
@@ -119,6 +152,14 @@ public class TableSubQueryNode extends RelationNode implements Projectable {
}
public String toString() {
- return "(" + getPID() + ") Table Subquery (alias = " + tableName + ")\n" + subQuery.toString();
+ StringBuilder sb = new StringBuilder();
+ sb.append("(").append(getPID()).append(") Table Subquery (alias=").append(tableName).append(")\n");
+ if (hasTargets()) {
+ sb.append(" targets: ").append(TUtil.arrayToString(targets)).append("\n");
+ }
+ sb.append(" out schema:").append(getOutSchema()).append("\n");
+ sb.append(" input schema:").append(getInSchema()).append("\n");
+ sb.append(subQuery.toString());
+ return sb.toString();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
index d0e8b02..56ca146 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/logical/UnionNode.java
@@ -25,19 +25,13 @@ import org.apache.tajo.engine.planner.PlanString;
public class UnionNode extends BinaryNode {
- public UnionNode(int pid, LogicalNode outer, LogicalNode inner) {
+ public UnionNode(int pid) {
super(pid, NodeType.UNION);
- setLeftChild(outer);
- setRightChild(inner);
}
-
@Override
public PlanString getPlanString() {
PlanString planStr = new PlanString("Union");
- planStr.appendTitle(" (L - " + ((TableSubQueryNode)getLeftChild()).getTableName());
- planStr.appendTitle(", R - " + ((TableSubQueryNode)getRightChild()).getTableName());
- planStr.appendTitle(")");
return planStr;
}
[10/12] git commit: Merge branch 'master' of
https://git-wip-us.apache.org/repos/asf/incubator-tajo into TAJO-502
Posted by hy...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-tajo into TAJO-502
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/70323804
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/70323804
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/70323804
Branch: refs/heads/master
Commit: 70323804292a5c837564eeefec0bc74044a71647
Parents: 8e1f989 568c523
Author: Hyunsik Choi <hy...@apache.org>
Authored: Fri Jan 17 16:33:35 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Fri Jan 17 16:33:35 2014 +0900
----------------------------------------------------------------------
CHANGES.txt | 3 +
request-patch-review.py | 163 ++++++++++++++++
.../src/site/markdown/review-request-tool.md | 191 +++++++++++++++++++
tajo-project/src/site/site.xml | 1 +
4 files changed, 358 insertions(+)
----------------------------------------------------------------------
[03/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java
index 94dc476..1bd2928 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/rewrite/ProjectionPushDownRule.java
@@ -18,8 +18,6 @@
package org.apache.tajo.engine.planner.rewrite;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Sets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tajo.catalog.Column;
@@ -28,14 +26,16 @@ import org.apache.tajo.catalog.SortSpec;
import org.apache.tajo.engine.eval.EvalNode;
import org.apache.tajo.engine.eval.EvalTreeUtil;
import org.apache.tajo.engine.eval.EvalType;
+import org.apache.tajo.engine.eval.FieldEval;
import org.apache.tajo.engine.planner.*;
import org.apache.tajo.engine.planner.logical.*;
import org.apache.tajo.engine.utils.SchemaUtil;
+import org.apache.tajo.util.TUtil;
import java.util.*;
public class ProjectionPushDownRule extends
- BasicLogicalPlanVisitor<ProjectionPushDownRule.PushDownContext, LogicalNode> implements RewriteRule {
+ BasicLogicalPlanVisitor<ProjectionPushDownRule.Context, LogicalNode> implements RewriteRule {
/** Class Logger */
private final Log LOG = LogFactory.getLog(ProjectionPushDownRule.class);
private static final String name = "ProjectionPushDown";
@@ -65,404 +65,684 @@ public class ProjectionPushDownRule extends
// skip a non-table-expression block.
if (plan.getRootBlock().getRootType() == NodeType.INSERT) {
- topmostBlock = plan.getChildBlocks(rootBlock).iterator().next();
+ topmostBlock = plan.getChildBlocks(rootBlock).get(0);
} else {
topmostBlock = rootBlock;
}
Stack<LogicalNode> stack = new Stack<LogicalNode>();
- PushDownContext context = new PushDownContext();
- context.plan = plan;
+ Context context = new Context(plan);
+ visit(context, plan, topmostBlock, topmostBlock.getRoot(), stack);
- if (topmostBlock.getProjection() != null && topmostBlock.getProjection().isAllProjected()) {
- context.targetListManager = new TargetListManager(plan, topmostBlock.getProjectionNode().getTargets());
- } else {
- context.targetListManager= new TargetListManager(plan, topmostBlock.getName());
+ return plan;
+ }
+
+ public static class TargetListManager {
+ private LinkedHashMap<String, EvalNode> nameToEvalMap;
+ private LinkedHashMap<EvalNode, String> evalToNameMap;
+ private LinkedHashMap<String, Boolean> resolvedFlags;
+ private LogicalPlan plan;
+
+ public TargetListManager(LogicalPlan plan) {
+ this.plan = plan;
+ nameToEvalMap = new LinkedHashMap<String, EvalNode>();
+ evalToNameMap = new LinkedHashMap<EvalNode, String>();
+ resolvedFlags = new LinkedHashMap<String, Boolean>();
}
- visit(context, plan, topmostBlock, topmostBlock.getRoot(), stack);
+ public TargetListManager(TargetListManager targetListMgr) {
+ this.plan = targetListMgr.plan;
+ nameToEvalMap = new LinkedHashMap<String, EvalNode>(targetListMgr.nameToEvalMap);
+ evalToNameMap = new LinkedHashMap<EvalNode, String>(targetListMgr.evalToNameMap);
+ resolvedFlags = new LinkedHashMap<String, Boolean>(targetListMgr.resolvedFlags);
+ }
- return plan;
+ private String add(String name, EvalNode evalNode) throws PlanningException {
+ if (evalToNameMap.containsKey(evalNode)) {
+ name = evalToNameMap.get(evalNode);
+ } else {
+
+ // Name can be conflicts between a column reference and an aliased EvalNode.
+ // Example, a SQL statement 'select l_orderkey + l_partkey as total ...' leads to
+ // two EvalNodes: a column reference total and an EvalNode (+, l_orderkey, l_partkey)
+ // If they are inserted into here, their names are conflict to each other, and one of them is removed.
+ // In this case, we just keep an original eval node instead of a column reference.
+ // This is because a column reference that points to an aliased EvalNode can be restored from the given alias.
+ if (nameToEvalMap.containsKey(name)) {
+ EvalNode storedEvalNode = nameToEvalMap.get(name);
+ if (!storedEvalNode.equals(evalNode)) {
+ if (storedEvalNode.getType() != EvalType.FIELD && evalNode.getType() != EvalType.FIELD) {
+ throw new PlanningException("Duplicate alias: " + evalNode);
+ }
+ if (storedEvalNode.getType() == EvalType.FIELD) {
+ nameToEvalMap.put(name, evalNode);
+ }
+ }
+ } else {
+ nameToEvalMap.put(name, evalNode);
+ }
+
+ evalToNameMap.put(evalNode, name);
+ resolvedFlags.put(name, false);
+
+ for (Column column : EvalTreeUtil.findDistinctRefColumns(evalNode)) {
+ add(new FieldEval(column));
+ }
+ }
+ return name;
+ }
+
+ public Collection<String> getNames() {
+ return nameToEvalMap.keySet();
+ }
+
+ public String add(Target target) throws PlanningException {
+ return add(target.getCanonicalName(), target.getEvalTree());
+ }
+
+ public String add(EvalNode evalNode) throws PlanningException {
+ String name;
+ if (evalToNameMap.containsKey(evalNode)) {
+ name = evalToNameMap.get(evalNode);
+ } else {
+ if (evalNode.getType() == EvalType.FIELD) {
+ FieldEval fieldEval = (FieldEval) evalNode;
+ name = fieldEval.getName();
+ } else {
+ name = plan.newGeneratedFieldName(evalNode);
+ }
+ add(name, evalNode);
+ }
+ return name;
+ }
+
+ public Target getTarget(String name) {
+ if (!nameToEvalMap.containsKey(name)) {
+ throw new RuntimeException("No Such target name: " + name);
+ }
+ EvalNode evalNode = nameToEvalMap.get(name);
+ if (evalNode.getType() == EvalType.FIELD && evalNode.getName().equals(name)) {
+ return new Target((FieldEval)evalNode);
+ } else {
+ return new Target(evalNode, name);
+ }
+ }
+
+ public boolean isResolved(String name) {
+ if (!nameToEvalMap.containsKey(name)) {
+ throw new RuntimeException("No Such target name: " + name);
+ }
+
+ return resolvedFlags.get(name);
+ }
+
+ public void resolve(Target target) {
+ EvalNode evalNode = target.getEvalTree();
+ if (!evalToNameMap.containsKey(evalNode)) {
+ throw new RuntimeException("No such eval: " + evalNode);
+ }
+ String name = evalToNameMap.get(evalNode);
+ resolvedFlags.put(name, true);
+ }
+
+ public Iterator<Target> getFilteredTargets(Set<String> required) {
+ return new FilteredTargetIterator(required);
+ }
+
+ class FilteredTargetIterator implements Iterator<Target> {
+ List<Target> filtered = TUtil.newList();
+
+ public FilteredTargetIterator(Set<String> required) {
+ for (Map.Entry<String,EvalNode> entry : nameToEvalMap.entrySet()) {
+ if (required.contains(entry.getKey())) {
+ filtered.add(getTarget(entry.getKey()));
+ }
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public Target next() {
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ }
+ }
+
+ public String toString() {
+ int resolved = 0;
+ for (Boolean flag: resolvedFlags.values()) {
+ if (flag) {
+ resolved++;
+ }
+ }
+ return "eval=" + resolvedFlags.size() + ", resolved=" + resolved;
+ }
}
- public static class PushDownContext {
- LogicalPlan plan;
- TargetListManager targetListManager;
- Set<Column> upperRequired;
+ static class Context {
+ TargetListManager targetListMgr;
+ Set<String> requiredSet;
+
+ public Context(LogicalPlan plan) {
+ requiredSet = new LinkedHashSet<String>();
+ targetListMgr = new TargetListManager(plan);
+ }
+
+ public Context(LogicalPlan plan, Collection<String> requiredSet) {
+ this.requiredSet = new LinkedHashSet<String>(requiredSet);
+ targetListMgr = new TargetListManager(plan);
+ }
+
+ public Context(Context upperContext) {
+ this.requiredSet = new LinkedHashSet<String>(upperContext.requiredSet);
+ targetListMgr = upperContext.targetListMgr;
+ }
- public PushDownContext() {}
+ public String addExpr(Target target) throws PlanningException {
+ String reference = targetListMgr.add(target);
+ addNecessaryReferences(target.getEvalTree());
+ return reference;
+ }
- public PushDownContext(ProjectionPushDownRule.PushDownContext context) {
- this.plan = context.plan;
- this.targetListManager = context.targetListManager;
- this.upperRequired = context.upperRequired;
+ public String addExpr(EvalNode evalNode) throws PlanningException {
+ String reference = targetListMgr.add(evalNode);
+ addNecessaryReferences(evalNode);
+ return reference;
+ }
+
+ private void addNecessaryReferences(EvalNode evalNode) {
+ for (Column column : EvalTreeUtil.findDistinctRefColumns(evalNode)) {
+ requiredSet.add(column.getQualifiedName());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "required=" + requiredSet.size() + "," + targetListMgr.toString();
}
}
@Override
- public LogicalNode visitRoot(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- LogicalRootNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownCommonPost(context, block, node, stack);
+ public LogicalNode visitRoot(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, LogicalRootNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visitRoot(context, plan, block, node, stack);
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ return node;
}
@Override
- public LogicalNode visitProjection(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ public LogicalNode visitProjection(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
ProjectionNode node, Stack<LogicalNode> stack) throws PlanningException {
- if (context.upperRequired == null) { // all projected
- context.upperRequired = new HashSet<Column>();
- for (Target target : node.getTargets()) {
- context.upperRequired.add(target.getColumnSchema());
- }
- } else {
- List<Target> projectedTarget = new ArrayList<Target>();
- for (Target target : node.getTargets()) {
- if (context.upperRequired.contains(target.getColumnSchema())) {
- projectedTarget.add(target);
- }
- }
- node.setTargets(projectedTarget.toArray(new Target[projectedTarget.size()]));
+ Context newContext = new Context(context);
+ String [] referenceNames = new String[node.getTargets().length];
+ for (int i = 0; i < node.getTargets().length; i++) {
+ referenceNames[i] = newContext.addExpr(node.getTargets()[i]);
+ }
+
+ LogicalNode child = super.visitProjection(newContext, plan, block, node, stack);
- context.upperRequired = new HashSet<Column>();
- for (Target target : node.getTargets()) {
- context.upperRequired.add(target.getColumnSchema());
+ int resolvingCount = 0;
+ List<Target> finalTargets = TUtil.newList();
+ for (String referenceName : referenceNames) {
+ Target target = context.targetListMgr.getTarget(referenceName);
+
+ if (context.targetListMgr.isResolved(referenceName)) {
+ finalTargets.add(new Target(new FieldEval(target.getNamedColumn())));
+ } else if (LogicalPlanner.checkIfBeEvaluateAtThis(target.getEvalTree(), node)) {
+ finalTargets.add(target);
+ context.targetListMgr.resolve(target);
+ resolvingCount++;
}
}
- stack.push(node);
- LogicalNode child = visit(context, plan, block, node.getChild(), stack);
- stack.pop();
-
- LogicalNode childNode = node.getChild();
-
- // If all expressions are evaluated in the child operators and the last operator is projectable,
- // ProjectionNode will not be necessary. It eliminates ProjectionNode.
- if (context.targetListManager.isAllResolved() && (childNode instanceof Projectable)) {
- child.setOutSchema(context.targetListManager.getUpdatedSchema());
- if (stack.isEmpty()) {
- // update the child node's output schemas
- block.setRoot(child);
- } else if (stack.peek().getType() == NodeType.TABLE_SUBQUERY) {
- ((TableSubQueryNode)stack.peek()).setSubQuery(childNode);
- } else {
- LogicalNode parent = stack.peek();
- PlannerUtil.deleteNode(parent, node);
+ // Removing ProjectionNode
+ // TODO - Consider INSERT and CTAS statement, and then remove the check of stack.empty.
+ if (resolvingCount == 0 && !stack.empty() &&
+ PlannerUtil.targetToSchema(finalTargets).equals(child.getOutSchema())) {
+ LogicalNode parentNode = stack.peek();
+ switch (parentNode.getType()) {
+ case ROOT:
+ LogicalRootNode rootNode = (LogicalRootNode) parentNode;
+ rootNode.setChild(child);
+ rootNode.setInSchema(child.getOutSchema());
+ rootNode.setOutSchema(child.getOutSchema());
+ break;
+ case TABLE_SUBQUERY:
+ TableSubQueryNode tableSubQueryNode = (TableSubQueryNode) parentNode;
+ tableSubQueryNode.setSubQuery(child);
+ break;
+ case STORE:
+ StoreTableNode storeTableNode = (StoreTableNode) parentNode;
+ storeTableNode.setChild(child);
+ storeTableNode.setInSchema(child.getOutSchema());
+ break;
+ case INSERT:
+ InsertNode insertNode = (InsertNode) parentNode;
+ insertNode.setSubQuery(child);
+
+ default:
+ throw new PlanningException("Unexpected Parent Node: " + parentNode.getType());
}
- return child;
+ plan.addHistory("ProjectionNode is eliminated.");
} else {
node.setInSchema(child.getOutSchema());
- node.setTargets(context.targetListManager.getUpdatedTarget());
- return node;
+ node.setTargets(finalTargets.toArray(new Target[finalTargets.size()]));
}
+
+ return node;
}
- @Override
- public LogicalNode visitLimit(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- LimitNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownCommonPost(context, block, node, stack);
+ public LogicalNode visitLimit(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, LimitNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ LogicalNode child = super.visitLimit(context, plan, block, node, stack);
+
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ return node;
}
@Override
- public LogicalNode visitSort(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ public LogicalNode visitSort(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
SortNode node, Stack<LogicalNode> stack) throws PlanningException {
- for (SortSpec spec : node.getSortKeys()) {
- context.upperRequired.add(spec.getSortKey());
+ Context newContext = new Context(context);
+
+ final int sortKeyNum = node.getSortKeys().length;
+ String [] keyNames = new String[sortKeyNum];
+ for (int i = 0; i < sortKeyNum; i++) {
+ SortSpec sortSpec = node.getSortKeys()[i];
+ keyNames[i] = newContext.addExpr(new FieldEval(sortSpec.getSortKey()));
}
- return pushDownCommonPost(context, block, node, stack);
+ LogicalNode child = super.visitSort(newContext, plan, block, node, stack);
+
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ return node;
}
@Override
- public LogicalNode visitGroupBy(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- GroupbyNode node, Stack<LogicalNode> stack) throws PlanningException {
- Set<Column> currentRequired = new HashSet<Column>(context.upperRequired);
+ public LogicalNode visitHaving(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ Context newContext = new Context(context);
+ String referenceName = newContext.targetListMgr.add(node.getQual());
+ newContext.addNecessaryReferences(node.getQual());
- for (Target target : node.getTargets()) {
- currentRequired.addAll(EvalTreeUtil.findDistinctRefColumns(target.getEvalTree()));
- }
+ LogicalNode child = super.visitHaving(newContext, plan, block, node, stack);
- for (Column column : node.getGroupingColumns()) {
- currentRequired.add(column);
+ Target target = context.targetListMgr.getTarget(referenceName);
+ if (newContext.targetListMgr.isResolved(referenceName)) {
+ node.setQual(new FieldEval(target.getNamedColumn()));
+ } else {
+ node.setQual(target.getEvalTree());
+ newContext.targetListMgr.resolve(target);
}
- PushDownContext groupByContext = new PushDownContext(context);
- groupByContext.upperRequired = currentRequired;
- return pushDownCommonPost(groupByContext, block, node, stack);
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+ return node;
}
- @Override
- public LogicalNode visitFilter(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- SelectionNode node, Stack<LogicalNode> stack) throws PlanningException {
- if (node.getQual() != null) {
- context.upperRequired.addAll(EvalTreeUtil.findDistinctRefColumns(node.getQual()));
+ public LogicalNode visitGroupBy(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ Context newContext = new Context(context);
+
+ // Getting grouping key names
+ final int groupingKeyNum = node.getGroupingColumns().length;
+ String [] groupingKeyNames = null;
+ if (groupingKeyNum > 0) {
+ groupingKeyNames = new String[groupingKeyNum];
+ for (int i = 0; i < groupingKeyNum; i++) {
+ FieldEval fieldEval = new FieldEval(node.getGroupingColumns()[i]);
+ groupingKeyNames[i] = newContext.addExpr(fieldEval);
+ }
}
- return pushDownCommonPost(context, block, node, stack);
- }
-
- @Override
- public LogicalNode visitJoin(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
- Stack<LogicalNode> stack) throws PlanningException {
- Set<Column> currentRequired = Sets.newHashSet(context.upperRequired);
+ // Getting target names
+ final int targetNum = node.getTargets().length;
+ final String [] targetNames = new String[targetNum];
+ for (int i = 0; i < targetNum; i++) {
+ Target target = node.getTargets()[i];
+ targetNames[i] = newContext.addExpr(target);
+ }
- if (node.hasTargets()) {
- EvalNode expr;
- for (Target target : node.getTargets()) {
- expr = target.getEvalTree();
- if (expr.getType() != EvalType.FIELD) {
- currentRequired.addAll(EvalTreeUtil.findDistinctRefColumns(target.getEvalTree()));
+ // visit a child node
+ LogicalNode child = super.visitGroupBy(newContext, plan, block, node, stack);
+
+ if (groupingKeyNum > 0) {
+ // Restoring grouping key columns
+ final Column [] groupingColumns = new Column[groupingKeyNum];
+ for (int i = 0; i < groupingKeyNum; i++) {
+ String groupingKey = groupingKeyNames[i];
+
+ Target target = context.targetListMgr.getTarget(groupingKey);
+ if (context.targetListMgr.isResolved(groupingKey)) {
+ groupingColumns[i] = target.getNamedColumn();
+ } else {
+ if (target.getEvalTree().getType() == EvalType.FIELD) {
+ groupingColumns[i] = target.getNamedColumn();
+ } else {
+ throw new PlanningException("Cannot evaluate this expression in grouping keys: " + target.getEvalTree());
+ }
}
}
+ node.setGroupingColumns(groupingColumns);
+ }
+
+ // Getting projected targets
+ List<Target> projectedTargets = TUtil.newList();
+ for (Iterator<String> it = getFilteredReferences(targetNames, context.requiredSet); it.hasNext();) {
+ String referenceName = it.next();
+ Target target = context.targetListMgr.getTarget(referenceName);
+
+ if (context.targetListMgr.isResolved(referenceName)) {
+ projectedTargets.add(new Target(new FieldEval(target.getNamedColumn())));
+ } else if (LogicalPlanner.checkIfBeEvaluatedAtGroupBy(target.getEvalTree(), node)) {
+ projectedTargets.add(target);
+ context.targetListMgr.resolve(target);
+ }
}
+ node.setInSchema(child.getOutSchema());
+ node.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
+
+ node.setInSchema(child.getOutSchema());
+ return node;
+ }
+
+ public LogicalNode visitFilter(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ SelectionNode node, Stack<LogicalNode> stack) throws PlanningException {
+ Context newContext = new Context(context);
+ String referenceName = newContext.targetListMgr.add(node.getQual());
+ newContext.addNecessaryReferences(node.getQual());
+
+ LogicalNode child = super.visitFilter(newContext, plan, block, node, stack);
+ Target target = context.targetListMgr.getTarget(referenceName);
+ if (newContext.targetListMgr.isResolved(referenceName)) {
+ node.setQual(new FieldEval(target.getNamedColumn()));
+ } else {
+ node.setQual(target.getEvalTree());
+ newContext.targetListMgr.resolve(target);
+ }
+
+ node.setInSchema(child.getOutSchema());
+ node.setOutSchema(child.getOutSchema());
+
+ return node;
+ }
+
+ public LogicalNode visitJoin(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
+ Context newContext = new Context(context);
+
+ String joinQualReference = null;
if (node.hasJoinQual()) {
- currentRequired.addAll(EvalTreeUtil.findDistinctRefColumns(node.getJoinQual()));
+ joinQualReference = newContext.addExpr(node.getJoinQual());
}
- PushDownContext leftContext = new PushDownContext(context);
- PushDownContext rightContext = new PushDownContext(context);
- leftContext.upperRequired = currentRequired;
- rightContext.upperRequired = currentRequired;
+ String [] referenceNames = null;
+ if (node.hasTargets()) {
+ referenceNames = new String[node.getTargets().length];
+ int i = 0;
+ for (Iterator<Target> it = getFilteredTarget(node.getTargets(), context.requiredSet); it.hasNext();) {
+ Target target = it.next();
+ referenceNames[i++] = newContext.addExpr(target);
+ }
+ }
stack.push(node);
- LogicalNode outer = visit(leftContext, plan, block, node.getLeftChild(), stack);
- LogicalNode inner = visit(rightContext, plan, block, node.getRightChild(), stack);
+ LogicalNode left = visit(newContext, plan, block, node.getLeftChild(), stack);
+ LogicalNode right = visit(newContext, plan, block, node.getRightChild(), stack);
stack.pop();
- Schema merged = SchemaUtil.merge(outer.getOutSchema(), inner.getOutSchema());
+ Schema merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
node.setInSchema(merged);
- pushDownProjectablePost(context, node, isTopmostProjectable(stack));
+
+ if (node.hasJoinQual()) {
+ Target target = context.targetListMgr.getTarget(joinQualReference);
+ if (newContext.targetListMgr.isResolved(joinQualReference)) {
+ throw new PlanningException("Join condition must be evaluated in the proper Join Node: " + joinQualReference);
+ } else {
+ node.setJoinQual(target.getEvalTree());
+ newContext.targetListMgr.resolve(target);
+ }
+ }
+
+ List<Target> projectedTargets = TUtil.newList();
+ for (Iterator<String> it = getFilteredReferences(context.targetListMgr.getNames(),
+ context.requiredSet); it.hasNext();) {
+ String referenceName = it.next();
+ Target target = context.targetListMgr.getTarget(referenceName);
+
+ if (context.targetListMgr.isResolved(referenceName)) {
+ Target fieldReference = new Target(new FieldEval(target.getNamedColumn()));
+ if (LogicalPlanner.checkIfBeEvaluatedAtJoin(block, fieldReference.getEvalTree(), node,
+ stack.peek().getType() != NodeType.JOIN)) {
+ projectedTargets.add(fieldReference);
+ }
+ } else if (LogicalPlanner.checkIfBeEvaluatedAtJoin(block, target.getEvalTree(), node,
+ stack.peek().getType() != NodeType.JOIN)) {
+ projectedTargets.add(target);
+ context.targetListMgr.resolve(target);
+ }
+ }
+
+ node.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
return node;
}
- @Override
- public LogicalNode visitUnion(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- UnionNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownSetNode(plan, block, node, stack, context);
+ static Iterator<String> getFilteredReferences(Collection<String> targetNames, Set<String> required) {
+ return new FilteredStringsIterator(targetNames, required);
}
- @Override
- public LogicalNode visitExcept(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- ExceptNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownSetNode(plan, block, node, stack, context);
+ static Iterator<String> getFilteredReferences(String [] targetNames, Set<String> required) {
+ return new FilteredStringsIterator(targetNames, required);
}
- @Override
- public LogicalNode visitIntersect(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- IntersectNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownSetNode(plan, block, node, stack, context);
- }
+ static class FilteredStringsIterator implements Iterator<String> {
+ Iterator<String> iterator;
- @Override
- public LogicalNode visitTableSubQuery(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- TableSubQueryNode node, Stack<LogicalNode> stack) throws PlanningException {
- LogicalPlan.QueryBlock subBlock = plan.getBlock(node.getSubQuery());
- LogicalNode subRoot = subBlock.getRoot();
+ FilteredStringsIterator(Collection<String> targetNames, Set<String> required) {
+ List<String> filtered = TUtil.newList();
+ for (String name : targetNames) {
+ if (required.contains(name)) {
+ filtered.add(name);
+ }
+ }
- Stack<LogicalNode> newStack = new Stack<LogicalNode>();
- newStack.push(node);
- PushDownContext newContext = new PushDownContext();
+ iterator = filtered.iterator();
+ }
- newContext.upperRequired = new HashSet<Column>();
+ FilteredStringsIterator(String [] targetNames, Set<String> required) {
+ this(TUtil.newList(targetNames), required);
+ }
- if (subBlock.hasProjection() && subBlock.getProjection().isAllProjected()
- && context.upperRequired.size() == 0) {
- newContext.targetListManager = new TargetListManager(plan, subBlock.getProjectionNode().getTargets());
- } else {
- if (!subBlock.hasGrouping()) {
- List<Target> projectedTarget = new ArrayList<Target>();
- for (Target target : subBlock.getTargetListManager().getUnresolvedTargets()) {
- for (Column column : context.upperRequired) {
- if (column.hasQualifier() && !node.getTableName().equals(column.getQualifier())) {
- continue;
- }
- if (target.getColumnSchema().getColumnName().equalsIgnoreCase(column.getColumnName())) {
- projectedTarget.add(target);
- }
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public String next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ }
+ }
+
+ static Iterator<Target> getFilteredTarget(Target[] targets, Set<String> required) {
+ return new FilteredIterator(targets, required);
+ }
+
+ static class FilteredIterator implements Iterator<Target> {
+ Iterator<Target> iterator;
+
+ FilteredIterator(Target [] targets, Set<String> requiredReferences) {
+ List<Target> filtered = TUtil.newList();
+ Map<String, Target> targetSet = new HashMap<String, Target>();
+ for (Target t : targets) {
+ // Only should keep an raw target instead of field reference.
+ if (targetSet.containsKey(t.getCanonicalName())) {
+ Target targetInSet = targetSet.get(t.getCanonicalName());
+ EvalNode evalNode = targetInSet.getEvalTree();
+ if (evalNode.getType() == EvalType.FIELD && t.getEvalTree().getType() != EvalType.FIELD) {
+ targetSet.put(t.getCanonicalName(), t);
}
+ } else {
+ targetSet.put(t.getCanonicalName(), t);
}
- newContext.targetListManager = new TargetListManager(plan,
- projectedTarget.toArray(new Target[projectedTarget.size()]));
+ }
- } else {
- newContext.targetListManager = new TargetListManager(plan,
- subBlock.getTargetListManager().getUnresolvedTargets());
+ for (String name : requiredReferences) {
+ if (targetSet.containsKey(name)) {
+ filtered.add(targetSet.get(name));
+ }
}
+
+ iterator = filtered.iterator();
+ }
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
}
- newContext.upperRequired.addAll(PlannerUtil.targetToSchema(newContext.targetListManager.getTargets()).getColumns());
+ @Override
+ public Target next() {
+ return iterator.next();
+ }
- LogicalNode child = visit(newContext, plan, subBlock, subRoot, newStack);
- newStack.pop();
- Schema inSchema = (Schema) child.getOutSchema().clone();
- inSchema.setQualifier(node.getCanonicalName());
- node.setInSchema(inSchema);
- return pushDownProjectablePost(context, node, isTopmostProjectable(stack));
+ @Override
+ public void remove() {
+ }
}
@Override
- public LogicalNode visitScan(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- ScanNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownProjectablePost(context, node, isTopmostProjectable(stack));
- }
+ public LogicalNode visitUnion(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, UnionNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
- @Override
- public LogicalNode visitStoreTable(PushDownContext context, LogicalPlan plan, LogicalPlan.QueryBlock block,
- StoreTableNode node, Stack<LogicalNode> stack) throws PlanningException {
- return pushDownCommonPost(context, block, node, stack);
- }
+ LogicalPlan.QueryBlock leftBlock = plan.getBlock(node.getLeftChild());
+ LogicalPlan.QueryBlock rightBlock = plan.getBlock(node.getRightChild());
- private LogicalNode pushDownCommonPost(PushDownContext context, LogicalPlan.QueryBlock block,
- UnaryNode node, Stack<LogicalNode> stack) throws PlanningException {
+ Context leftContext = new Context(plan, PlannerUtil.toQualifiedFieldNames(context.requiredSet,
+ leftBlock.getName()));
+ Context rightContext = new Context(plan, PlannerUtil.toQualifiedFieldNames(context.requiredSet,
+ rightBlock.getName()));
stack.push(node);
- LogicalNode child = visit(context, context.plan, block, node.getChild(), stack);
+ LogicalNode leftChild = visit(leftContext, plan, leftBlock, node.getLeftChild(), new Stack<LogicalNode>());
+ LogicalNode rightChild = visit(rightContext, plan, rightBlock, node.getRightChild(), new Stack<LogicalNode>());
stack.pop();
- node.setInSchema(child.getOutSchema());
- node.setOutSchema(child.getOutSchema());
-
- if (node instanceof Projectable) {
- pushDownProjectablePost(context, node, isTopmostProjectable(stack));
- }
return node;
}
- private static LogicalNode pushDownProjectablePost(PushDownContext context, LogicalNode node, boolean last)
- throws PlanningException {
- TargetListManager targetListManager = context.targetListManager;
- EvalNode expr;
-
- List<Integer> newEvaluatedTargetIds = new ArrayList<Integer>();
+ public LogicalNode visitScan(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block, ScanNode node,
+ Stack<LogicalNode> stack) throws PlanningException {
- for (int i = 0; i < targetListManager.size(); i++) {
- expr = targetListManager.getTarget(i).getEvalTree();
+ Context newContext = new Context(context);
- if (!targetListManager.isResolved(i) && PlannerUtil.canBeEvaluated(expr, node)) {
-
- if (node instanceof RelationNode) { // For ScanNode
+ Target [] targets;
+ if (node.hasTargets()) {
+ targets = node.getTargets();
+ } else {
+ targets = PlannerUtil.schemaToTargets(node.getOutSchema());
+ }
- if (expr.getType() == EvalType.FIELD && !targetListManager.getTarget(i).hasAlias()) {
- targetListManager.resolve(i);
- } else if (EvalTreeUtil.findDistinctAggFunction(expr).size() == 0) {
- targetListManager.resolve(i);
- newEvaluatedTargetIds.add(i);
- }
+ List<Target> projectedTargets = TUtil.newList();
+ for (Iterator<Target> it = getFilteredTarget(targets, newContext.requiredSet); it.hasNext();) {
+ Target target = it.next();
+ newContext.addExpr(target);
+ }
- } else if (node instanceof GroupbyNode) { // For GroupBy
- if (EvalTreeUtil.findDistinctAggFunction(expr).size() > 0 && expr.getType() != EvalType.FIELD) {
- targetListManager.resolve(i);
- newEvaluatedTargetIds.add(i);
- }
+ for (Iterator<Target> it = getFilteredTarget(targets, context.requiredSet); it.hasNext();) {
+ Target target = it.next();
- } else if (node instanceof JoinNode) {
- if (expr.getType() != EvalType.FIELD && EvalTreeUtil.findDistinctAggFunction(expr).size() == 0) {
- targetListManager.resolve(i);
- newEvaluatedTargetIds.add(i);
- }
- }
+ if (LogicalPlanner.checkIfBeEvaluatedAtRelation(block, target.getEvalTree(), node)) {
+ projectedTargets.add(target);
+ newContext.targetListMgr.resolve(target);
}
}
- Projectable projectable = (Projectable) node;
- if (last) {
- Preconditions.checkState(targetListManager.isAllResolved(), "Not all targets are evaluated");
- if (node.getType() != NodeType.GROUP_BY) {
- projectable.setTargets(targetListManager.getTargets());
- }
- node.setOutSchema(targetListManager.getUpdatedSchema());
- } else {
- // Preparing targets regardless of that the node has targets or not.
- // This part is required because some node does not have any targets,
- // if the node has the same input and output schemas.
-
- Target[] checkingTargets;
- if (!projectable.hasTargets()) {
- Schema outSchema = node.getOutSchema();
- checkingTargets = new Target[outSchema.getColumnNum() + newEvaluatedTargetIds.size()];
- PlannerUtil.schemaToTargets(outSchema, checkingTargets);
- int baseIdx = outSchema.getColumnNum();
- for (int i = 0; i < newEvaluatedTargetIds.size(); i++) {
- checkingTargets[baseIdx + i] = targetListManager.getTarget(newEvaluatedTargetIds.get(i));
- }
- } else {
- checkingTargets = projectable.getTargets();
- }
+ node.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
+ return node;
+ }
- List<Target> projectedTargets = new ArrayList<Target>();
- for (Target target : checkingTargets) {
- for (Column column : context.upperRequired) {
- if (target.hasAlias() && target.getAlias().equalsIgnoreCase(column.getQualifiedName())) {
- projectedTargets.add(target);
- } else {
+ @Override
+ public LogicalNode visitPartitionedTableScan(Context context, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ PartitionedTableScanNode node, Stack<LogicalNode> stack)
+ throws PlanningException {
- if (target.getColumnSchema().equals(column)) {
- projectedTargets.add(target);
- }
- }
- }
- }
+ Context newContext = new Context(context);
- projectable.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
- targetListManager.getUpdatedTarget();
- node.setOutSchema(PlannerUtil.targetToSchema(projectable.getTargets()));
+ Target [] targets;
+ if (node.hasTargets()) {
+ targets = node.getTargets();
+ } else {
+ targets = PlannerUtil.schemaToTargets(node.getOutSchema());
}
- return node;
- }
-
- private static boolean isTopmostProjectable(Stack<LogicalNode> stack) {
- for (LogicalNode node : stack) {
- if (node.getType() == NodeType.JOIN || node.getType() == NodeType.GROUP_BY) {
- return false;
- }
+ List<Target> projectedTargets = TUtil.newList();
+ for (Iterator<Target> it = getFilteredTarget(targets, newContext.requiredSet); it.hasNext();) {
+ Target target = it.next();
+ newContext.addExpr(target);
}
- return true;
- }
+ for (Iterator<Target> it = getFilteredTarget(targets, context.requiredSet); it.hasNext();) {
+ Target target = it.next();
- private TargetListManager buildSubBlockTargetList(LogicalPlan plan,
- LogicalPlan.QueryBlock subQueryBlock, TableSubQueryNode subQueryNode, Set<Column> upperRequired) {
- TargetListManager subBlockTargetList;
- List<Target> projectedTarget = new ArrayList<Target>();
- for (Target target : subQueryBlock.getTargetListManager().getUnresolvedTargets()) {
- for (Column column : upperRequired) {
- if (!subQueryNode.getTableName().equals(column.getQualifier())) {
- continue;
- }
- if (target.getColumnSchema().getColumnName().equalsIgnoreCase(column.getColumnName())) {
- projectedTarget.add(target);
- }
+ if (LogicalPlanner.checkIfBeEvaluatedAtRelation(block, target.getEvalTree(), node)) {
+ projectedTargets.add(target);
+ newContext.targetListMgr.resolve(target);
}
}
- subBlockTargetList = new TargetListManager(plan, projectedTarget.toArray(new Target[projectedTarget.size()]));
- return subBlockTargetList;
+
+ node.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
+ return node;
}
- private BinaryNode pushDownSetNode(LogicalPlan plan, LogicalPlan.QueryBlock block, BinaryNode setNode,
- Stack<LogicalNode> stack, PushDownContext context) throws PlanningException {
+ @Override
+ public LogicalNode visitTableSubQuery(Context upperContext, LogicalPlan plan, LogicalPlan.QueryBlock block,
+ TableSubQueryNode node, Stack<LogicalNode> stack) throws PlanningException {
+ Context childContext = new Context(plan, upperContext.requiredSet);
+ stack.push(node);
+ LogicalNode child = visit(childContext, plan, plan.getBlock(node.getSubQuery()), node.getSubQuery(), stack);
+ stack.pop();
- LogicalPlan.QueryBlock leftBlock = plan.getChildBlocks(block).get(0);
- LogicalPlan.QueryBlock rightBlock = plan.getChildBlocks(block).get(1);
+ Context newContext = new Context(upperContext);
- PushDownContext leftContext = new PushDownContext(context);
- leftContext.targetListManager = buildSubBlockTargetList(plan, leftBlock,
- (TableSubQueryNode) setNode.getLeftChild(), context.upperRequired);
+ Target [] targets;
+ if (node.hasTargets()) {
+ targets = node.getTargets();
+ } else {
+ targets = PlannerUtil.schemaToTargets(node.getOutSchema());
+ }
- PushDownContext rightContext = new PushDownContext(context);
- rightContext.targetListManager = buildSubBlockTargetList(plan, rightBlock,
- (TableSubQueryNode) setNode.getRightChild(), context.upperRequired);
+ List<Target> projectedTargets = TUtil.newList();
+ for (Iterator<Target> it = getFilteredTarget(targets, newContext.requiredSet); it.hasNext();) {
+ Target target = it.next();
+ childContext.addExpr(target);
+ }
- stack.push(setNode);
- visit(leftContext, plan, leftBlock, setNode.getLeftChild(), stack);
- visit(rightContext, plan, rightBlock, setNode.getRightChild(), stack);
- stack.pop();
+ for (Iterator<Target> it = getFilteredTarget(targets, upperContext.requiredSet); it.hasNext();) {
+ Target target = it.next();
- // if this is the final union, we assume that all targets are evalauted.
- // TODO - is it always correct?
- if (stack.peek().getType() != NodeType.UNION) {
- context.targetListManager.resolveAll();
+ if (LogicalPlanner.checkIfBeEvaluatedAtRelation(block, target.getEvalTree(), node)) {
+ projectedTargets.add(target);
+ childContext.targetListMgr.resolve(target);
+ }
}
- return setNode;
+ node.setTargets(projectedTargets.toArray(new Target[projectedTargets.size()]));
+
+ return node;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/utils/SchemaUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/utils/SchemaUtil.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/utils/SchemaUtil.java
index 0c215a3..df49503 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/utils/SchemaUtil.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/utils/SchemaUtil.java
@@ -20,41 +20,35 @@ package org.apache.tajo.engine.utils;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.common.TajoDataTypes.DataType;
public class SchemaUtil {
public static Schema merge(Schema left, Schema right) {
Schema merged = new Schema();
for(Column col : left.getColumns()) {
- if (!merged.contains(col.getQualifiedName())) {
+ if (!merged.containsByQualifiedName(col.getQualifiedName())) {
merged.addColumn(col);
}
}
for(Column col : right.getColumns()) {
- if (!merged.contains(col.getQualifiedName())) {
+ if (!merged.containsByQualifiedName(col.getQualifiedName())) {
merged.addColumn(col);
}
}
return merged;
}
-
- public static Schema getCommons(Schema left, Schema right) {
+
+ /**
+ * Get common columns to be used as join keys of natural joins.
+ */
+ public static Schema getNaturalJoinColumns(Schema left, Schema right) {
Schema common = new Schema();
for (Column outer : left.getColumns()) {
- for (Column inner : right.getColumns()) {
- if (outer.getColumnName().equals(inner.getColumnName()) &&
- outer.getDataType().equals(inner.getDataType())) {
- common.addColumn(outer.getColumnName(), outer.getDataType());
- }
+ if (!common.containsByName(outer.getColumnName()) && right.containsByName(outer.getColumnName())) {
+ common.addColumn(new Column(outer.getColumnName(), outer.getDataType()));
}
}
return common;
}
-
- public static DataType[] newNoNameSchema(DataType... types) {
- DataType [] dataTypes = types.clone();
- return dataTypes;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
index 5bd2924..8c40810 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GlobalEngine.java
@@ -370,8 +370,9 @@ public class GlobalEngine extends AbstractService {
@Override
public boolean isEligible(QueryContext queryContext, LogicalPlan plan) {
- if (plan.getRootBlock().hasStoreTableNode()) {
- StoreTableNode storeTableNode = plan.getRootBlock().getStoreTableNode();
+ LogicalRootNode rootNode = plan.getRootBlock().getRoot();
+ if (rootNode.getChild().getType() == NodeType.STORE) {
+ StoreTableNode storeTableNode = rootNode.getChild();
return storeTableNode.isCreatedTable();
} else {
return false;
@@ -380,7 +381,8 @@ public class GlobalEngine extends AbstractService {
@Override
public void hook(QueryContext queryContext, LogicalPlan plan) throws Exception {
- StoreTableNode storeTableNode = plan.getRootBlock().getStoreTableNode();
+ LogicalRootNode rootNode = plan.getRootBlock().getRoot();
+ StoreTableNode storeTableNode = rootNode.getChild();
String tableName = storeTableNode.getTableName();
queryContext.setOutputTable(tableName);
queryContext.setOutputPath(new Path(TajoConf.getWarehouseDir(context.getConf()), tableName));
@@ -402,7 +404,7 @@ public class GlobalEngine extends AbstractService {
public void hook(QueryContext queryContext, LogicalPlan plan) throws Exception {
queryContext.setInsert();
- InsertNode insertNode = plan.getRootBlock().getInsertNode();
+ InsertNode insertNode = plan.getRootBlock().getNode(NodeType.INSERT);
StoreTableNode storeNode;
// Set QueryContext settings, such as output table name and output path.
@@ -489,9 +491,9 @@ public class GlobalEngine extends AbstractService {
}
- ProjectionNode projectionNode = new ProjectionNode(plan.newPID(), targets);
+ ProjectionNode projectionNode = new ProjectionNode(plan.newPID());
+ projectionNode.setTargets(targets);
projectionNode.setInSchema(insertNode.getSubQuery().getOutSchema());
- projectionNode.setOutSchema(PlannerUtil.targetToSchema(targets));
List<LogicalPlan.QueryBlock> blocks = plan.getChildBlocks(plan.getRootBlock());
projectionNode.setChild(blocks.get(0).getRoot());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GreedyFragmentScheduleAlgorithm.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GreedyFragmentScheduleAlgorithm.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GreedyFragmentScheduleAlgorithm.java
index 39448bd..82fd6fc 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GreedyFragmentScheduleAlgorithm.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/GreedyFragmentScheduleAlgorithm.java
@@ -20,8 +20,8 @@ package org.apache.tajo.master;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
-import com.sun.org.apache.commons.logging.Log;
-import com.sun.org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.yarn.util.RackResolver;
import org.apache.tajo.master.DefaultFragmentScheduleAlgorithm.FragmentsPerDisk;
import org.apache.tajo.util.NetUtils;
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
index 0093ff7..d871608 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/master/TajoMaster.java
@@ -1026,8 +1026,6 @@ public class TajoMaster extends CompositeService {
break;
}
- System.out.println(line);
-
int indexStart = line.indexOf(" on /");
int indexEnd = line.indexOf(" ", indexStart + 4);
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
index 092a5bc..67782ff 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java
@@ -77,7 +77,7 @@ public class ExprTestBase {
private static Target[] getRawTargets(String query) throws PlanningException {
Expr expr = analyzer.parse(query);
LogicalPlan plan = planner.createPlan(expr);
- Target [] targets = plan.getRootBlock().getTargetListManager().getUnresolvedTargets();
+ Target [] targets = plan.getRootBlock().getUnresolvedTargets();
if (targets == null) {
throw new PlanningException("Wrong query statement or query plan: " + query);
}
@@ -125,29 +125,29 @@ public class ExprTestBase {
CommonTestingUtil.getTestDir()));
}
- Target [] targets = null;
+ Target [] targets;
try {
targets = getRawTargets(query);
- } catch (PlanningException e) {
- assertFalse(e.getMessage(), true);
- }
- EvalContext [] evalContexts = new EvalContext[targets.length];
- Tuple outTuple = new VTuple(targets.length);
- for (int i = 0; i < targets.length; i++) {
- EvalNode eval = targets[i].getEvalTree();
- evalContexts[i] = eval.newContext();
- eval.eval(evalContexts[i], inputSchema, vtuple);
- outTuple.put(i, eval.terminate(evalContexts[i]));
- }
-
- if (schema != null) {
- cat.deleteTable(tableName);
- }
+ EvalContext [] evalContexts = new EvalContext[targets.length];
+ Tuple outTuple = new VTuple(targets.length);
+ for (int i = 0; i < targets.length; i++) {
+ EvalNode eval = targets[i].getEvalTree();
+ evalContexts[i] = eval.newContext();
+ eval.eval(evalContexts[i], inputSchema, vtuple);
+ outTuple.put(i, eval.terminate(evalContexts[i]));
+ }
- for (int i = 0; i < expected.length; i++) {
- assertEquals(query, expected[i], outTuple.get(i).asChars());
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(query, expected[i], outTuple.get(i).asChars());
+ }
+ } catch (PlanningException e) {
+ assertFalse(e.getMessage(), true);
+ } finally {
+ if (schema != null) {
+ cat.deleteTable(tableName);
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
index b99dcce..34ba1ca 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTree.java
@@ -33,6 +33,8 @@ import org.apache.tajo.engine.planner.LogicalPlan;
import org.apache.tajo.engine.planner.LogicalPlanner;
import org.apache.tajo.engine.planner.PlanningException;
import org.apache.tajo.engine.planner.Target;
+import org.apache.tajo.engine.planner.logical.NodeType;
+import org.apache.tajo.engine.planner.logical.SelectionNode;
import org.apache.tajo.master.TajoMaster;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
@@ -41,14 +43,14 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.io.IOException;
+
import static org.apache.tajo.common.TajoDataTypes.Type.*;
import static org.junit.Assert.*;
-public class TestEvalTree {
+public class TestEvalTree extends ExprTestBase{
private static TajoTestingCluster util;
private static CatalogService cat;
- private static SQLAnalyzer analyzer;
- private static LogicalPlanner planner;
private static Tuple [] tuples = new Tuple[3];
@BeforeClass
@@ -73,9 +75,6 @@ public class TestEvalTree {
CatalogUtil.newSimpleDataType(INT4),
CatalogUtil.newSimpleDataTypeArray(INT4, INT4));
cat.createFunction(funcMeta);
-
- analyzer = new SQLAnalyzer();
- planner = new LogicalPlanner(cat);
tuples[0] = new VTuple(3);
tuples[0].put(new Datum[] {
@@ -124,81 +123,6 @@ public class TestEvalTree {
"select sum(score) from people", // 4
"select name from people where NOT (20 > 30)", // 5
};
-
- public static Target[] getRawTargets(String query) throws PlanningException {
- Expr expr = analyzer.parse(query);
- LogicalPlan plan = planner.createPlan(expr);
- Target [] targets = plan.getRootBlock().getTargetListManager().getUnresolvedTargets();
- for (Target t : targets) {
- assertJsonSerDer(t.getEvalTree());
- }
- return targets;
- }
-
- public static EvalNode getRootSelection(String query) {
- Expr block = analyzer.parse(query);
- LogicalPlan plan = null;
- try {
- plan = planner.createPlan(block);
- } catch (PlanningException e) {
- e.printStackTrace();
- }
- EvalNode qual = plan.getRootBlock().getSelectionNode().getQual();
- assertJsonSerDer(qual);
- return qual;
- }
-
- @Test
- public final void testFunctionEval() throws Exception {
- Tuple tuple = new VTuple(3);
- tuple.put(
- new Datum[] {
- DatumFactory.createText("hyunsik"),
- DatumFactory.createInt4(500),
- DatumFactory.createInt4(30)});
-
- EvalNode expr;
-
- Schema peopleSchema = cat.getTableDesc("people").getSchema();
- EvalContext evalCtx;
- expr = getRootSelection(QUERIES[0]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuple);
- assertEquals(true, expr.terminate(evalCtx).asBool());
-
- expr = getRootSelection(QUERIES[1]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuple);
- assertEquals(15000, expr.terminate(evalCtx).asInt4());
- assertCloneEqual(expr);
-
- expr = getRootSelection(QUERIES[2]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuple);
- assertEquals(15050, expr.terminate(evalCtx).asInt4());
- assertCloneEqual(expr);
-
- // Aggregation function test
- expr = getRawTargets(QUERIES[4])[0].getEvalTree();
- evalCtx = expr.newContext();
-
- final int tuplenum = 10;
- Tuple [] tuples = new Tuple[tuplenum];
- for (int i=0; i < tuplenum; i++) {
- tuples[i] = new VTuple(3);
- tuples[i].put(0, DatumFactory.createText("hyunsik"));
- tuples[i].put(1, DatumFactory.createInt4(i + 1));
- tuples[i].put(2, DatumFactory.createInt4(30));
- }
-
- int sum = 0;
- for (int i=0; i < tuplenum; i++) {
- expr.eval(evalCtx, peopleSchema, tuples[i]);
- sum = sum + (i+1);
- assertEquals(sum, expr.terminate(evalCtx).asInt4());
- }
- }
-
@Test
public void testTupleEval() throws CloneNotSupportedException {
@@ -558,165 +482,4 @@ public class TestEvalTree {
assertEquals(eval, copy);
assertFalse(eval == copy);
}
-
- static String[] NOT = {
- "select name, score, age from people where not (score >= 200)", // 0"
- };
-
- @Test
- public final void testNot() throws CloneNotSupportedException {
- ConstEval e1;
- ConstEval e2;
- EvalNode expr;
-
- // Constant
- e1 = new ConstEval(DatumFactory.createInt4(9));
- e2 = new ConstEval(DatumFactory.createInt4(34));
- expr = new BinaryEval(EvalType.LTH, e1, e2);
- EvalContext evalCtx = expr.newContext();
- expr.eval(evalCtx, null, null);
- assertTrue(expr.terminate(evalCtx).asBool());
- NotEval not = new NotEval(expr);
- evalCtx = not .newContext();
- not.eval(evalCtx, null, null);
- assertFalse(not.terminate(evalCtx).asBool());
-
- expr = new BinaryEval(EvalType.LEQ, e1, e2);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, null, null);
- assertTrue(expr.terminate(evalCtx).asBool());
- not = new NotEval(expr);
- evalCtx = not.newContext();
- not.eval(evalCtx, null, null);
- assertFalse(not.terminate(evalCtx).asBool());
-
- expr = new BinaryEval(EvalType.LTH, e2, e1);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, null, null);
- assertFalse(expr.terminate(evalCtx).asBool());
- not = new NotEval(expr);
- evalCtx = not.newContext();
- not.eval(evalCtx, null, null);
- assertTrue(not.terminate(evalCtx).asBool());
-
- expr = new BinaryEval(EvalType.LEQ, e2, e1);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, null, null);
- assertFalse(expr.terminate(evalCtx).asBool());
- not = new NotEval(expr);
- evalCtx = not.newContext();
- not.eval(evalCtx, null, null);
- assertTrue(not.terminate(evalCtx).asBool());
-
- // Evaluation Test
- Schema peopleSchema = cat.getTableDesc("people").getSchema();
- expr = getRootSelection(NOT[0]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuples[0]);
- assertTrue(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[1]);
- assertFalse(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[2]);
- assertFalse(expr.terminate(evalCtx).asBool());
- }
-
- static String[] LIKE = {
- "select name, score, age from people where name like '%bc'", // 0"
- "select name, score, age from people where name like 'aa%'", // 1"
- "select name, score, age from people where name not like '%bc'", // 2"
- "select name, score, age from people where name like '.*b_'", // 3"
- };
-
- @Test
- public final void testLike() {
- EvalNode expr;
-
- Schema peopleSchema = cat.getTableDesc("people").getSchema();
- // prefix
- expr = getRootSelection(LIKE[0]);
- EvalContext evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuples[0]);
- assertTrue(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[1]);
- assertFalse(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[2]);
- assertTrue(expr.terminate(evalCtx).asBool());
-
- // suffix
- expr = getRootSelection(LIKE[1]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuples[0]);
- assertTrue(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[1]);
- assertTrue(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[2]);
- assertFalse(expr.terminate(evalCtx).asBool());
-
- // Not Test
- expr = getRootSelection(LIKE[2]);
- evalCtx = expr.newContext();
- expr.eval(evalCtx, peopleSchema, tuples[0]);
- assertFalse(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[1]);
- assertTrue(expr.terminate(evalCtx).asBool());
- expr.eval(evalCtx, peopleSchema, tuples[2]);
- assertFalse(expr.terminate(evalCtx).asBool());
- }
-
- static String[] IS_NULL = {
- "select name, score, age from people where name is null", // 0"
- "select name, score, age from people where name is not null", // 1"
- };
-
- @Test
- public void testIsNullEval() {
- EvalNode expr;
-
- expr = getRootSelection(IS_NULL[0]);
-
- assertIsNull(expr);
-
- expr = getRootSelection(IS_NULL[1]);
-
- IsNullEval nullEval = (IsNullEval) expr;
- assertTrue(nullEval.isNot());
- assertIsNull(expr);
- }
-
- static String[] IN_PREDICATE = {
- "select name, score, age from people where name in ('abc', 'def', 'ghi')", // 0
- "select name, score, age from people where score in (1, 2, 3)", // 1
- "select name, score, age from people where score not in (1, 2, 3)", // 2
- };
-
- @Test
- public void testInEval() {
- EvalNode expr;
-
- expr = getRootSelection(IN_PREDICATE[0]);
- assertEquals(EvalType.IN, expr.getType());
- InEval inEval = (InEval) expr;
-
- expr = getRootSelection(IN_PREDICATE[1]);
- assertEquals(EvalType.IN, expr.getType());
-
- expr = getRootSelection(IN_PREDICATE[2]);
- assertEquals(EvalType.IN, expr.getType());
- inEval = (InEval) expr;
- assertTrue(inEval.isNot());
- }
-
- private void assertIsNull(EvalNode isNullEval) {
- assertEquals(EvalType.IS_NULL, isNullEval.getType());
- assertEquals(EvalType.FIELD, isNullEval.getLeftExpr().getType());
- FieldEval left = (FieldEval) isNullEval.getLeftExpr();
- assertEquals("name", left.getColumnName());
- assertEquals(EvalType.CONST, isNullEval.getRightExpr().getType());
- }
-
- private static void assertJsonSerDer(EvalNode expr) {
- String json = expr.toJson();
- EvalNode fromJson = CoreGsonHelper.fromJson(json, EvalNode.class);
- assertEquals(expr, fromJson);
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java
index 3c67068..9c01fdf 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestEvalTreeUtil.java
@@ -21,6 +21,8 @@ package org.apache.tajo.engine.eval;
import com.google.common.collect.Sets;
import org.apache.tajo.TajoTestingCluster;
import org.apache.tajo.algebra.Expr;
+import org.apache.tajo.algebra.OpType;
+import org.apache.tajo.algebra.Selection;
import org.apache.tajo.catalog.*;
import org.apache.tajo.catalog.proto.CatalogProtos.FunctionType;
import org.apache.tajo.catalog.proto.CatalogProtos.StoreType;
@@ -32,7 +34,7 @@ import org.apache.tajo.engine.planner.LogicalPlan;
import org.apache.tajo.engine.planner.LogicalPlanner;
import org.apache.tajo.engine.planner.PlanningException;
import org.apache.tajo.engine.planner.Target;
-import org.apache.tajo.engine.planner.logical.EvalExprNode;
+import org.apache.tajo.engine.planner.logical.GroupbyNode;
import org.apache.tajo.engine.planner.logical.NodeType;
import org.apache.tajo.exception.InternalException;
import org.apache.tajo.master.TajoMaster;
@@ -41,6 +43,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -103,14 +106,11 @@ public class TestEvalTreeUtil {
} catch (PlanningException e) {
e.printStackTrace();
}
- if (plan.getRootBlock().getRoot().getType() == NodeType.EXPRS) {
- return ((EvalExprNode)plan.getRootBlock().getRoot()).getExprs();
- } else {
- return plan.getRootBlock().getTargetListManager().getUnresolvedTargets();
- }
+
+ return plan.getRootBlock().getUnresolvedTargets();
}
- public static EvalNode getRootSelection(String query) {
+ public static EvalNode getRootSelection(String query) throws PlanningException {
Expr block = analyzer.parse(query);
LogicalPlan plan = null;
try {
@@ -118,7 +118,9 @@ public class TestEvalTreeUtil {
} catch (PlanningException e) {
e.printStackTrace();
}
- return plan.getRootBlock().getSelectionNode().getQual();
+
+ Selection selection = plan.getRootBlock().getSingletonExpr(OpType.Filter);
+ return planner.getExprAnnotator().createEvalNode(plan, plan.getRootBlock(), selection.getQual());
}
@Test
@@ -128,14 +130,14 @@ public class TestEvalTreeUtil {
Set<Column> set = EvalTreeUtil.findDistinctRefColumns(copy);
assertEquals(1, set.size());
assertTrue(set.contains(new Column("newscore", TajoDataTypes.Type.INT4)));
-
+
copy = (EvalNode)expr2.clone();
EvalTreeUtil.changeColumnRef(copy, "people.age", "sum_age");
set = EvalTreeUtil.findDistinctRefColumns(copy);
assertEquals(2, set.size());
assertTrue(set.contains(new Column("people.score", TajoDataTypes.Type.INT4)));
assertTrue(set.contains(new Column("sum_age", TajoDataTypes.Type.INT4)));
-
+
copy = (EvalNode)expr3.clone();
EvalTreeUtil.changeColumnRef(copy, "people.age", "sum_age");
set = EvalTreeUtil.findDistinctRefColumns(copy);
@@ -183,12 +185,12 @@ public class TestEvalTreeUtil {
assertEquals("mul", col2.getColumnName());
assertEquals(TajoDataTypes.Type.FLOAT8, col2.getDataType().getType());
}
-
+
@Test
public final void testGetContainExprs() throws CloneNotSupportedException, PlanningException {
Expr expr = analyzer.parse(QUERIES[1]);
LogicalPlan plan = planner.createPlan(expr);
- Target [] targets = plan.getRootBlock().getTargetListManager().getUnresolvedTargets();
+ Target [] targets = plan.getRootBlock().getUnresolvedTargets();
Column col1 = new Column("people.score", TajoDataTypes.Type.INT4);
Collection<EvalNode> exprs =
EvalTreeUtil.getContainExpr(targets[0].getEvalTree(), col1);
@@ -196,7 +198,7 @@ public class TestEvalTreeUtil {
assertEquals(EvalType.LTH, node.getType());
assertEquals(EvalType.PLUS, node.getLeftExpr().getType());
assertEquals(new ConstEval(DatumFactory.createInt4(4)), node.getRightExpr());
-
+
Column col2 = new Column("people.age", TajoDataTypes.Type.INT4);
exprs = EvalTreeUtil.getContainExpr(targets[1].getEvalTree(), col2);
node = exprs.iterator().next();
@@ -206,7 +208,7 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testGetCNF() {
+ public final void testGetCNF() throws PlanningException {
// "select score from people where score < 10 and 4 < score "
EvalNode node = getRootSelection(QUERIES[5]);
EvalNode [] cnf = AlgebraicUtil.toConjunctiveNormalFormArray(node);
@@ -233,7 +235,7 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testTransformCNF2Singleton() {
+ public final void testTransformCNF2Singleton() throws PlanningException {
// "select score from people where score < 10 and 4 < score "
EvalNode node = getRootSelection(QUERIES[6]);
EvalNode [] cnf1 = AlgebraicUtil.toConjunctiveNormalFormArray(node);
@@ -248,14 +250,14 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testGetDNF() {
+ public final void testGetDNF() throws PlanningException {
// "select score from people where score > 1 and score < 3 or score > 7 and score < 10", // 7
EvalNode node = getRootSelection(QUERIES[7]);
EvalNode [] cnf = AlgebraicUtil.toDisjunctiveNormalFormArray(node);
assertEquals(2, cnf.length);
- assertEquals("people.score (INT4(0)) > 1 AND people.score (INT4(0)) < 3", cnf[0].toString());
- assertEquals("7 < people.score (INT4(0)) AND people.score (INT4(0)) < 10", cnf[1].toString());
+ assertEquals("people.score (INT4) > 1 AND people.score (INT4) < 3", cnf[0].toString());
+ assertEquals("7 < people.score (INT4) AND people.score (INT4) < 10", cnf[1].toString());
}
@Test
@@ -274,7 +276,7 @@ public class TestEvalTreeUtil {
Expr expr = analyzer.parse(QUERIES[1]);
LogicalPlan plan = planner.createPlan(expr);
- targets = plan.getRootBlock().getTargetListManager().getUnresolvedTargets();
+ targets = plan.getRootBlock().getUnresolvedTargets();
Column col1 = new Column("people.score", TajoDataTypes.Type.INT4);
Collection<EvalNode> exprs =
EvalTreeUtil.getContainExpr(targets[0].getEvalTree(), col1);
@@ -282,7 +284,7 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testConatainSingleVar() {
+ public final void testConatainSingleVar() throws PlanningException {
EvalNode node = getRootSelection(QUERIES[2]);
assertEquals(true, AlgebraicUtil.containSingleVar(node));
node = getRootSelection(QUERIES[3]);
@@ -290,16 +292,13 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testTranspose() {
- //EvalNode node = getRootSelection(QUERIES[2]);
- //assertEquals(true, AlgebraicUtil.containSingleVar(node));
-
+ public final void testTranspose() throws PlanningException {
Column col1 = new Column("people.score", TajoDataTypes.Type.INT4);
EvalNode node = getRootSelection(QUERIES[3]);
// we expect that score < 3
EvalNode transposed = AlgebraicUtil.transpose(node, col1);
assertEquals(EvalType.GTH, transposed.getType());
- FieldEval field = (FieldEval) transposed.getLeftExpr();
+ FieldEval field = transposed.getLeftExpr();
assertEquals(col1, field.getColumnRef());
EvalContext evalCtx = transposed.getRightExpr().newContext();
transposed.getRightExpr().eval(evalCtx, null, null);
@@ -309,7 +308,7 @@ public class TestEvalTreeUtil {
// we expect that score < 3
transposed = AlgebraicUtil.transpose(node, col1);
assertEquals(EvalType.LTH, transposed.getType());
- field = (FieldEval) transposed.getLeftExpr();
+ field = transposed.getLeftExpr();
assertEquals(col1, field.getColumnRef());
evalCtx = transposed.getRightExpr().newContext();
transposed.getRightExpr().eval(evalCtx, null, null);
@@ -317,12 +316,19 @@ public class TestEvalTreeUtil {
}
@Test
- public final void testFindDistinctAggFunctions() {
+ public final void testFindDistinctAggFunctions() throws PlanningException {
String query = "select sum(score) + max(age) from people";
- Target [] targets = getRawTargets(query);
- List<AggregationFunctionCallEval> list = EvalTreeUtil.
- findDistinctAggFunction(targets[0].getEvalTree());
+ Expr expr = analyzer.parse(query);
+ LogicalPlan plan = planner.createPlan(expr);
+ GroupbyNode groupByNode = plan.getRootBlock().getNode(NodeType.GROUP_BY);
+ Target [] targets = groupByNode.getTargets();
+
+ List<AggregationFunctionCallEval> list = new ArrayList<AggregationFunctionCallEval>();
+ for (int i = 0; i < targets.length; i++) {
+ list.addAll(EvalTreeUtil.findDistinctAggFunction(targets[i].getEvalTree()));
+ }
assertEquals(2, list.size());
+
Set<String> result = Sets.newHashSet("max", "sum");
for (AggregationFunctionCallEval eval : list) {
assertTrue(result.contains(eval.getName()));
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestPredicates.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestPredicates.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestPredicates.java
index 9005b42..86b921f 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestPredicates.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/eval/TestPredicates.java
@@ -28,29 +28,191 @@ import static org.apache.tajo.common.TajoDataTypes.Type.INT4;
import static org.apache.tajo.common.TajoDataTypes.Type.TEXT;
public class TestPredicates extends ExprTestBase {
+
+ //////////////////////////////////////////////////////////////////
+ // Logical Operator
+ //////////////////////////////////////////////////////////////////
+
@Test
- public void testIsNullPredicate() throws IOException {
+ public void testAnd() throws IOException {
+ testSimpleEval("select true;", new String[] {"t"});
+
+ testSimpleEval("select true and true;", new String[] {"t"});
+ testSimpleEval("select true and false;", new String[] {"f"});
+ testSimpleEval("select false and true;", new String[] {"f"});
+ testSimpleEval("select false and false;", new String[] {"f"});
+ }
+
+ @Test
+ public void testOr() throws IOException {
+ testSimpleEval("select true or true;", new String[] {"t"});
+ testSimpleEval("select true or false;", new String[] {"t"});
+ testSimpleEval("select false or true;", new String[] {"t"});
+ testSimpleEval("select false or false;", new String[] {"f"});
+ }
+
+ @Test
+ public void testLogicalOperatorPrecedence() throws IOException {
+ testSimpleEval("select true or (false or false) or false;", new String[] {"t"});
+ testSimpleEval("select false or (true or false) or false;", new String[] {"t"});
+ testSimpleEval("select false or (false or true) or false;", new String[] {"t"});
+ testSimpleEval("select false or (false or false) or true;", new String[] {"t"});
+
+ testSimpleEval("select true and (false or false) or false;", new String[] {"f"});
+ testSimpleEval("select false and (true or false) or false;", new String[] {"f"});
+ testSimpleEval("select false and (false or true) or false;", new String[] {"f"});
+ testSimpleEval("select false and (false or false) or true;", new String[] {"t"});
+
+ testSimpleEval("select true or (false and false) or false;", new String[] {"t"});
+ testSimpleEval("select false or (true and false) or false;", new String[] {"f"});
+ testSimpleEval("select false or (false and true) or false;", new String[] {"f"});
+ testSimpleEval("select false or (false and true) or true;", new String[] {"t"});
+
+ testSimpleEval("select true or (false or false) and false;", new String[] {"t"});
+ testSimpleEval("select false or (true or false) and false;", new String[] {"f"});
+ testSimpleEval("select false or (false or true) and false;", new String[] {"f"});
+ testSimpleEval("select false or (false or false) and true;", new String[] {"f"});
+ }
+
+ @Test
+ public void testNot() throws IOException {
+
+ testSimpleEval("select true;", new String[] {"t"});
+ testSimpleEval("select not true;", new String[] {"f"});
+ testSimpleEval("select (true);", new String[] {"t"});
+ testSimpleEval("select not (true);", new String[] {"f"});
+ testSimpleEval("select not (not (true));", new String[] {"t"});
+
+ testSimpleEval("select (not (1 > null)) is null;", new String[] {"t"});
+
Schema schema1 = new Schema();
schema1.addColumn("col1", INT4);
schema1.addColumn("col2", INT4);
- testEval(schema1, "table1", "123,", "select col1 is null, col2 is null as a from table1",
- new String[]{"f", "t"});
- testEval(schema1, "table1", "123,", "select col1 is not null, col2 is not null as a from table1",
+ schema1.addColumn("col3", INT4);
+
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 = col2, col1 = col3 from table1",
new String[]{"t", "f"});
}
@Test
- public void testIsNullPredicateWithFunction() throws IOException {
- Schema schema2 = new Schema();
- schema2.addColumn("col1", TEXT);
- schema2.addColumn("col2", TEXT);
- testEval(schema2, "table1", "_123,", "select ltrim(col1, '_') is null, upper(col2) is null as a from table1",
- new String[]{"f", "t"});
+ public void testParenthesizedValues() throws IOException {
+ testSimpleEval("select ((true));", new String[] {"t"});
+ testSimpleEval("select ((((true))));", new String[] {"t"});
+ testSimpleEval("select not(not(not(false)));", new String[] {"t"});
+ }
- testEval(schema2, "table1", "_123,",
- "select ltrim(col1, '_') is not null, upper(col2) is not null as a from table1", new String[]{"t", "f"});
+ //////////////////////////////////////////////////////////////////
+ // Comparison Predicate
+ //////////////////////////////////////////////////////////////////
+
+ @Test
+ public void testComparisonEqual() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 = col2, col1 = col3, col1 = col4 from table1",
+ new String[]{"t", "f", "f"});
+ testEval(schema1,
+ "table1", "123,123,,",
+ "select col1 = col2, (col1 = col3) is null, (col3 = col2) is null from table1",
+ new String[]{"t", "t", "t"});
+ }
+
+ @Test
+ public void testComparisonNotEqual() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 <> col2, col1 <> col3, col1 <> col4 from table1",
+ new String[]{"f", "t", "t"});
+ testEval(schema1,
+ "table1", "123,123,,",
+ "select col1 <> col2, (col1 <> col3) is null, (col3 <> col2) is null from table1",
+ new String[]{"f", "t", "t"});
+ }
+
+ @Test
+ public void testComparisonLessThan() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 < col2, col1 < col3, col1 < col4 from table1",
+ new String[]{"f", "t", "f"});
+ testEval(schema1,
+ "table1", "123,456,,",
+ "select col1 < col2, (col1 = col3) is null, (col4 = col1) is null from table1",
+ new String[]{"t", "t", "t"});
+ }
+
+ @Test
+ public void testComparisonLessThanEqual() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 <= col2, col1 <= col3, col1 <= col4 from table1",
+ new String[]{"t", "t", "f"});
+ testEval(schema1,
+ "table1", "123,456,,",
+ "select col1 <= col2, (col1 <= col3) is null, (col4 <= col1) is null from table1",
+ new String[]{"t", "t", "t"});
+ }
+
+ @Test
+ public void testComparisonGreaterThan() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 > col2, col3 > col2, col1 > col4 from table1",
+ new String[]{"f", "t", "t"});
+ testEval(schema1,
+ "table1", "123,456,,",
+ "select col2 > col1, col1 > col2, (col1 > col3) is null, (col4 > col1) is null from table1",
+ new String[]{"t", "f", "t", "t"});
+ }
+
+ @Test
+ public void testComparisonGreaterThanEqual() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ schema1.addColumn("col3", INT4);
+ schema1.addColumn("col4", INT4);
+ testEval(schema1,
+ "table1", "123,123,456,-123",
+ "select col1 >= col2, col3 >= col2, col1 >= col4 from table1",
+ new String[]{"t", "t", "t"});
+ testEval(schema1,
+ "table1", "123,456,,",
+ "select col2 >= col1, col1 >= col2, (col1 >= col3) is null, (col4 >= col1) is null from table1",
+ new String[]{"t", "f", "t", "t"});
}
+ //////////////////////////////////////////////////////////////////
+ // Between Predicate
+ //////////////////////////////////////////////////////////////////
+
@Test
public void testBetween() throws IOException {
Schema schema2 = new Schema();
@@ -110,6 +272,53 @@ public class TestPredicates extends ExprTestBase {
testEval(schema3, "table1", "20130715,20100102,20120525,20130705", query, new String [] {"0"});
}
+ //////////////////////////////////////////////////////////////////
+ // In Predicate
+ //////////////////////////////////////////////////////////////////
+
+ @Test
+ public void testInPredicate() throws IOException {
+ Schema schema2 = new Schema();
+ schema2.addColumn("col1", TEXT);
+ schema2.addColumn("col2", TEXT);
+ schema2.addColumn("col3", TEXT);
+
+ testEval(schema2, "table1", "a,b,c", "select col1 in ('a'), col2 in ('a', 'c') from table1", new String[]{"t","f"});
+ testEval(schema2, "table1", "a,,c", "select col1 in ('a','b','c'), (col2 in ('a', 'c')) is null from table1",
+ new String[]{"t","t"});
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // Null Predicate
+ //////////////////////////////////////////////////////////////////
+
+ @Test
+ public void testIsNullPredicate() throws IOException {
+ Schema schema1 = new Schema();
+ schema1.addColumn("col1", INT4);
+ schema1.addColumn("col2", INT4);
+ testEval(schema1, "table1", "123,", "select col1 is null, col2 is null as a from table1",
+ new String[]{"f", "t"});
+ testEval(schema1, "table1", "123,", "select col1 is not null, col2 is not null as a from table1",
+ new String[]{"t", "f"});
+ }
+
+ @Test
+ public void testIsNullPredicateWithFunction() throws IOException {
+ Schema schema2 = new Schema();
+ schema2.addColumn("col1", TEXT);
+ schema2.addColumn("col2", TEXT);
+ testEval(schema2, "table1", "_123,", "select ltrim(col1, '_') is null, upper(col2) is null as a from table1",
+ new String[]{"f", "t"});
+
+ testEval(schema2, "table1", "_123,",
+ "select ltrim(col1, '_') is not null, upper(col2) is not null as a from table1", new String[]{"t", "f"});
+ }
+
+ //////////////////////////////////////////////////////////////////
+ // Boolean Test
+ //////////////////////////////////////////////////////////////////
+
@Test
public void testBooleanTest() throws IOException {
testSimpleEval("select 1 < 3 is true", new String [] {"t"});
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/parser/TestHiveConverter.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/parser/TestHiveConverter.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/parser/TestHiveConverter.java
index 2573391..2e4221d 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/parser/TestHiveConverter.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/parser/TestHiveConverter.java
@@ -71,18 +71,6 @@ public class TestHiveConverter {
}
}
- public static Expr parseExpr(String sql) {
- ANTLRInputStream input = new ANTLRInputStream(sql);
- SQLLexer lexer = new SQLLexer(input);
- CommonTokenStream tokens = new CommonTokenStream(lexer);
- SQLParser parser = new SQLParser(tokens);
- parser.setBuildParseTree(true);
- SQLAnalyzer visitor = new SQLAnalyzer();
- Boolean_value_expressionContext context = parser.boolean_value_expression();
- System.out.println(context.toStringTree(parser));
- return visitor.visitBoolean_value_expression(context);
- }
-
@Test
public void testSelect1() throws IOException {
String sql = FileUtil.readTextFile(new File("src/test/resources/queries/default/select_1.sql"));
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalNode.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalNode.java
index 596ce1e..b540868 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalNode.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalNode.java
@@ -45,11 +45,13 @@ public class TestLogicalNode {
schema.addColumn("id", Type.INT4);
schema.addColumn("name", Type.TEXT);
schema.addColumn("age", Type.INT2);
- GroupbyNode groupbyNode = new GroupbyNode(0, new Column[]{schema.getColumn(1), schema.getColumn(2)});
+ GroupbyNode groupbyNode = new GroupbyNode(0);
+ groupbyNode.setGroupingColumns(new Column[]{schema.getColumn(1), schema.getColumn(2)});
ScanNode scanNode = new ScanNode(0,
CatalogUtil.newTableDesc("in", schema, CatalogUtil.newTableMeta(StoreType.CSV), new Path("in")));
- GroupbyNode groupbyNode2 = new GroupbyNode(0, new Column[]{schema.getColumn(1), schema.getColumn(2)});
+ GroupbyNode groupbyNode2 = new GroupbyNode(0);
+ groupbyNode2.setGroupingColumns(new Column[]{schema.getColumn(1), schema.getColumn(2)});
JoinNode joinNode = new JoinNode(0);
ScanNode scanNode2 = new ScanNode(0,
CatalogUtil.newTableDesc("in2", schema, CatalogUtil.newTableMeta(StoreType.CSV), new Path("in2")));
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlan.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlan.java b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlan.java
index 1d9df14..208b18d 100644
--- a/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlan.java
+++ b/tajo-core/tajo-core-backend/src/test/java/org/apache/tajo/engine/planner/TestLogicalPlan.java
@@ -83,7 +83,7 @@ public class TestLogicalPlan {
@Test
public final void testQueryBlockGraph() {
- LogicalPlan plan = new LogicalPlan(new LogicalPlanner(catalog));
+ LogicalPlan plan = new LogicalPlan(planner);
LogicalPlan.QueryBlock root = plan.newAndGetBlock(LogicalPlan.ROOT_BLOCK);
LogicalPlan.QueryBlock new1 = plan.newAndGetBlock("@new1");
LogicalPlan.QueryBlock new2 = plan.newAndGetBlock("@new2");
[11/12] git commit: Removed java.util.objects.
Posted by hy...@apache.org.
Removed java.util.objects.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/63ac233a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/63ac233a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/63ac233a
Branch: refs/heads/master
Commit: 63ac233a52b072560c580fca0fff26e9e1d6bd73
Parents: 7032380
Author: Hyunsik Choi <hy...@apache.org>
Authored: Fri Jan 17 16:34:35 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Fri Jan 17 16:34:35 2014 +0900
----------------------------------------------------------------------
.../src/main/java/org/apache/tajo/algebra/BetweenPredicate.java | 4 ++--
.../src/main/java/org/apache/tajo/algebra/DataTypeExpr.java | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/63ac233a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
index f504994..4409f4e 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/BetweenPredicate.java
@@ -18,7 +18,7 @@
package org.apache.tajo.algebra;
-import java.util.Objects;
+import com.google.common.base.Objects;
public class BetweenPredicate extends Expr {
private boolean not;
@@ -60,7 +60,7 @@ public class BetweenPredicate extends Expr {
@Override
public int hashCode() {
- return Objects.hash(not, symmetric, predicand, begin, end);
+ return Objects.hashCode(not, symmetric, predicand, begin, end);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/63ac233a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
index 15d6d7e..044a372 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
@@ -18,10 +18,9 @@
package org.apache.tajo.algebra;
+import com.google.common.base.Objects;
import org.apache.tajo.util.TUtil;
-import java.util.Objects;
-
public class DataTypeExpr extends Expr {
String typeName;
Integer lengthOrPrecision;
@@ -62,7 +61,7 @@ public class DataTypeExpr extends Expr {
@Override
public int hashCode() {
- return Objects.hash(typeName, lengthOrPrecision, scale);
+ return Objects.hashCode(typeName, lengthOrPrecision, scale);
}
@Override
[12/12] git commit: Fixed union10.
Posted by hy...@apache.org.
Fixed union10.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tajo/commit/ebb12b7d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tajo/tree/ebb12b7d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tajo/diff/ebb12b7d
Branch: refs/heads/master
Commit: ebb12b7dc6777321c8f5482cd698522522745617
Parents: 63ac233
Author: Hyunsik Choi <hy...@apache.org>
Authored: Fri Jan 17 17:30:17 2014 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Fri Jan 17 17:30:17 2014 +0900
----------------------------------------------------------------------
.../queries/TestUnionQuery/testUnion10.sql | 214 ++++++++++---------
.../results/TestUnionQuery/testUnion10.result | 16 +-
2 files changed, 119 insertions(+), 111 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/ebb12b7d/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
index b4f01d9..d644a44 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestUnionQuery/testUnion10.sql
@@ -1,149 +1,157 @@
-SELECT
- *
-FROM (
+SELECT * FROM (
SELECT
- n_nationkey,
- n_name
-
+ *
FROM (
SELECT
n_nationkey,
n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
-
-
- UNION ALL
- SELECT
- n_nationkey,
- n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
- ) T1
- GROUP BY
- n_nationkey,
- n_name
- ORDER BY
- n_nationkey desc,
- n_name desc
- UNION
+ UNION ALL
- SELECT
- n_nationkey,
- n_name
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
- FROM (
- SELECT
+ ) T1
+ GROUP BY
n_nationkey,
n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
- UNION ALL
+ UNION
- SELECT
- n_nationkey,
- n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
- ) T2
+ SELECT
+ n_nationkey,
+ n_name
- GROUP BY
- n_nationkey,
- n_name
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
- ORDER BY
- n_nationkey desc,
- n_name desc
+ UNION ALL
-) TABLE1
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+ ) T2
-ORDER BY
- n_nationkey desc
+ GROUP BY
+ n_nationkey,
+ n_name
-UNION
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
-SELECT
- *
-FROM (
- SELECT
+ ) TABLE1
+
+ ORDER BY
n_nationkey,
n_name
+ UNION
+
+ SELECT
+ *
FROM (
SELECT
n_nationkey,
n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
- UNION ALL
- SELECT
+ UNION ALL
+
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+
+ ) T3
+ GROUP BY
n_nationkey,
n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
+
+ UNION
- ) T3
- GROUP BY
+ SELECT
n_nationkey,
n_name
- ORDER BY
- n_nationkey desc,
- n_name desc
- UNION
+ FROM (
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
- SELECT
- n_nationkey,
- n_name
+ UNION ALL
- FROM (
- SELECT
- n_nationkey,
- n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
+ SELECT
+ n_nationkey,
+ n_name
+ FROM
+ nation
+ WHERE
+ n_regionkey = 0
+ ) T4
- UNION ALL
+ GROUP BY
+ n_nationkey,
+ n_name
- SELECT
- n_nationkey,
- n_name
- FROM
- nation
- WHERE
- n_regionkey = 0
- ) T4
+ ORDER BY
+ n_nationkey desc,
+ n_name desc
- GROUP BY
- n_nationkey,
- n_name
+ ) TABLE2
- ORDER BY
- n_nationkey desc,
- n_name desc
+ ORDER BY
+ n_nationkey,
+ n_name
-) TABLE2
+) TABLE3
ORDER BY
n_nationkey,
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/ebb12b7d/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
index 83e693d..effe340 100644
--- a/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestUnionQuery/testUnion10.result
@@ -1,22 +1,22 @@
n_nationkey,n_name
-------------------------------
-16,MOZAMBIQUE
-16,MOZAMBIQUE
-15,MOROCCO
-15,MOROCCO
-14,KENYA
-14,KENYA
-5,ETHIOPIA
-5,ETHIOPIA
0,ALGERIA
0,ALGERIA
0,ALGERIA
0,ALGERIA
5,ETHIOPIA
5,ETHIOPIA
+5,ETHIOPIA
+5,ETHIOPIA
+14,KENYA
+14,KENYA
14,KENYA
14,KENYA
15,MOROCCO
15,MOROCCO
+15,MOROCCO
+15,MOROCCO
+16,MOZAMBIQUE
+16,MOZAMBIQUE
16,MOZAMBIQUE
16,MOZAMBIQUE
\ No newline at end of file
[07/12] TAJO-501: Rewrite the projection part of logical planning.
Posted by hy...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
new file mode 100644
index 0000000..c97a30a
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprFinder.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import org.apache.tajo.algebra.*;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+class ExprFinder extends SimpleAlgebraVisitor<ExprFinder.Context, Object> {
+
+ static class Context {
+ Set<Expr> set = new HashSet<Expr>();
+ OpType targetType;
+
+ Context(OpType type) {
+ this.targetType = type;
+ }
+ }
+
+ public static <T extends Expr> Set<T> finds(Expr expr, OpType type) {
+ Context context = new Context(type);
+ ExprFinder finder = new ExprFinder();
+ Stack<Expr> stack = new Stack<Expr>();
+ stack.push(expr);
+ try {
+ finder.visit(context, new Stack<Expr>(), expr);
+ } catch (PlanningException e) {
+ throw new RuntimeException(e);
+ }
+ stack.pop();
+ return (Set<T>) context.set;
+ }
+
+ public Object visit(Context ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
+ if (expr instanceof UnaryOperator) {
+ preHook(ctx, stack, expr);
+ visitUnaryOperator(ctx, stack, (UnaryOperator) expr);
+ postHook(ctx, stack, expr, null);
+ } else if (expr instanceof BinaryOperator) {
+ preHook(ctx, stack, expr);
+ visitBinaryOperator(ctx, stack, (BinaryOperator) expr);
+ postHook(ctx, stack, expr, null);
+ } else {
+ super.visit(ctx, stack, expr);
+ }
+
+ if (ctx.targetType == expr.getType()) {
+ ctx.set.add(expr);
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
new file mode 100644
index 0000000..ca509c4
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/ExprNormalizer.java
@@ -0,0 +1,259 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import org.apache.tajo.algebra.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * ExprNormalizer performs two kinds of works:
+ *
+ * <h3>1. Duplication Removal.</h3>
+ *
+ * For example, assume a simple query as follows:
+ * <pre>
+ * select price * rate as total_price, ..., order by price * rate
+ * </pre>
+ *
+ * The expression <code>price * rate</code> is duplicated in both select list and order by clause.
+ * Against those cases, ExprNormalizer removes duplicated expressions and replaces one with one reference.
+ * In the case, ExprNormalizer replaces price * rate with total_price reference.
+ *
+ * <h3>2. Dissection of Expression</h3>
+ *
+ * A expression can be a complex expressions, including a mixed of scalar and aggregation expressions.
+ * For example, assume an aggregation query as follows:
+ * <pre>
+ * select sum(price * rate) * (1 - avg(discount_rate))), ...
+ * </pre>
+ *
+ * In this case, ExprNormalizer dissects the expression 'sum(price * rate) * (1 - avg(discount_rate)))'
+ * into the following expressions:
+ * <ul>
+ * <li>$1 = price * rage</li>
+ * <li>$2 = sum($1)</li>
+ * <li>$3 = avg(discount_rate)</li>
+ * <li>$4 = $3 * (1 - $3)</li>
+ * </ul>
+ *
+ * It mainly two advantages. Firstly, it makes complex expression evaluations easier across multiple physical executors.
+ * Second, it gives move opportunities to remove duplicated expressions.
+ *
+ * <h3>3. Name Normalization</h3>
+ *
+ * Users can use qualified column names, unqualified column names or aliased column references.
+ *
+ * Consider the following example:
+ *
+ * <pre>
+ * select rate_a as total_rate, rate_a * 100, table1.rate_a, ... WHERE total_rate * 100
+ * </pre>
+ *
+ * <code>total_rate</code>, <code>rate_a</code>, and <code>table1.rate_a</code> are all the same references. But,
+ * they have different forms. Due to their different forms, duplication removal can be hard.
+ *
+ * In order to solve this problem, ExprNormalizer normalizes all column references as qualified names while it keeps
+ * its points..
+ */
+class ExprNormalizer extends SimpleAlgebraVisitor<ExprNormalizer.ExprNormalizedResult, Object> {
+
+ public static class ExprNormalizedResult {
+ private final LogicalPlan plan;
+ private final LogicalPlan.QueryBlock block;
+
+ Expr baseExpr; // outmost expressions, which can includes one or more references of the results of aggregation
+ // function.
+ List<NamedExpr> aggExprs = new ArrayList<NamedExpr>(); // aggregation functions
+ List<NamedExpr> scalarExprs = new ArrayList<NamedExpr>(); // scalar expressions which can be referred
+
+ private ExprNormalizedResult(LogicalPlanner.PlanContext context) {
+ this.plan = context.plan;
+ this.block = context.queryBlock;
+ }
+
+ @Override
+ public String toString() {
+ return baseExpr.toString() + ", agg=" + aggExprs.size() + ", scalar=" + scalarExprs.size();
+ }
+ }
+
+ public ExprNormalizedResult normalize(LogicalPlanner.PlanContext context, Expr expr) throws PlanningException {
+ ExprNormalizedResult exprNormalizedResult = new ExprNormalizedResult(context);
+ Stack<Expr> stack = new Stack<Expr>();
+ stack.push(expr);
+ visit(exprNormalizedResult, new Stack<Expr>(), expr);
+ exprNormalizedResult.baseExpr = stack.pop();
+ return exprNormalizedResult;
+ }
+
+ private boolean isAggregationFunction(Expr expr) {
+ return expr.getType() == OpType.GeneralSetFunction || expr.getType() == OpType.CountRowsFunction;
+ }
+
+ @Override
+ public Object visitCaseWhen(ExprNormalizedResult ctx, Stack<Expr> stack, CaseWhenPredicate expr)
+ throws PlanningException {
+ stack.push(expr);
+ for (CaseWhenPredicate.WhenExpr when : expr.getWhens()) {
+ visit(ctx, stack, when.getCondition());
+ visit(ctx, stack, when.getResult());
+
+ if (isAggregationFunction(when.getCondition())) {
+ String referenceName = ctx.block.namedExprsMgr.addExpr(when.getCondition());
+ ctx.aggExprs.add(new NamedExpr(when.getCondition(), referenceName));
+ when.setCondition(new ColumnReferenceExpr(referenceName));
+ }
+
+ if (isAggregationFunction(when.getResult())) {
+ String referenceName = ctx.block.namedExprsMgr.addExpr(when.getResult());
+ ctx.aggExprs.add(new NamedExpr(when.getResult(), referenceName));
+ when.setResult(new ColumnReferenceExpr(referenceName));
+ }
+ }
+
+ if (expr.hasElseResult()) {
+ visit(ctx, stack, expr.getElseResult());
+ if (isAggregationFunction(expr.getElseResult())) {
+ String referenceName = ctx.block.namedExprsMgr.addExpr(expr.getElseResult());
+ ctx.aggExprs.add(new NamedExpr(expr.getElseResult(), referenceName));
+ expr.setElseResult(new ColumnReferenceExpr(referenceName));
+ }
+ }
+ stack.pop();
+ return expr;
+ }
+
+ @Override
+ public Expr visitUnaryOperator(ExprNormalizedResult ctx, Stack<Expr> stack, UnaryOperator expr) throws PlanningException {
+ super.visitUnaryOperator(ctx, stack, expr);
+ if (isAggregationFunction(expr.getChild())) {
+ // Get an anonymous column name and replace the aggregation function by the column name
+ String refName = ctx.block.namedExprsMgr.addExpr(expr.getChild());
+ ctx.aggExprs.add(new NamedExpr(expr.getChild(), refName));
+ expr.setChild(new ColumnReferenceExpr(refName));
+ }
+
+ return expr;
+ }
+
+ @Override
+ public Expr visitBinaryOperator(ExprNormalizedResult ctx, Stack<Expr> stack, BinaryOperator expr) throws PlanningException {
+ super.visitBinaryOperator(ctx, stack, expr);
+
+ ////////////////////////
+ // For Left Term
+ ////////////////////////
+
+ if (isAggregationFunction(expr.getLeft())) {
+ String leftRefName = ctx.block.namedExprsMgr.addExpr(expr.getLeft());
+ ctx.aggExprs.add(new NamedExpr(expr.getLeft(), leftRefName));
+ expr.setLeft(new ColumnReferenceExpr(leftRefName));
+ }
+
+
+ ////////////////////////
+ // For Right Term
+ ////////////////////////
+ if (isAggregationFunction(expr.getRight())) {
+ String rightRefName = ctx.block.namedExprsMgr.addExpr(expr.getRight());
+ ctx.aggExprs.add(new NamedExpr(expr.getRight(), rightRefName));
+ expr.setRight(new ColumnReferenceExpr(rightRefName));
+ }
+
+ return expr;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Function Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public Expr visitFunction(ExprNormalizedResult ctx, Stack<Expr> stack, FunctionExpr expr) throws PlanningException {
+ stack.push(expr);
+
+ Expr param;
+ for (int i = 0; i < expr.getParams().length; i++) {
+ param = expr.getParams()[i];
+ visit(ctx, stack, param);
+
+ if (isAggregationFunction(param)) {
+ String referenceName = ctx.plan.newGeneratedFieldName(param);
+ ctx.aggExprs.add(new NamedExpr(param, referenceName));
+ expr.getParams()[i] = new ColumnReferenceExpr(referenceName);
+ }
+ }
+
+ stack.pop();
+
+ return expr;
+ }
+
+ @Override
+ public Expr visitGeneralSetFunction(ExprNormalizedResult ctx, Stack<Expr> stack, GeneralSetFunctionExpr expr)
+ throws PlanningException {
+ stack.push(expr);
+
+ Expr param;
+ for (int i = 0; i < expr.getParams().length; i++) {
+ param = expr.getParams()[i];
+ visit(ctx, stack, param);
+
+ String referenceName = ctx.block.namedExprsMgr.addExpr(param);
+ ctx.scalarExprs.add(new NamedExpr(param, referenceName));
+ expr.getParams()[i] = new ColumnReferenceExpr(referenceName);
+ }
+ stack.pop();
+ return expr;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Literal Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public Expr visitCastExpr(ExprNormalizedResult ctx, Stack<Expr> stack, CastExpr expr) throws PlanningException {
+ super.visitCastExpr(ctx, stack, expr);
+ if (expr.getChild().getType() == OpType.GeneralSetFunction
+ || expr.getChild().getType() == OpType.CountRowsFunction) {
+ String referenceName = ctx.block.namedExprsMgr.addExpr(expr.getChild());
+ ctx.aggExprs.add(new NamedExpr(expr.getChild(), referenceName));
+ expr.setChild(new ColumnReferenceExpr(referenceName));
+ }
+ return expr;
+ }
+
+ @Override
+ public Expr visitColumnReference(ExprNormalizedResult ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+ throws PlanningException {
+ // normalize column references.
+ if (!expr.hasQualifier()) {
+ if (ctx.block.namedExprsMgr.contains(expr.getCanonicalName())) {
+ NamedExpr namedExpr = ctx.block.namedExprsMgr.getNamedExpr(expr.getCanonicalName());
+ return new ColumnReferenceExpr(namedExpr.getAlias());
+ } else {
+ String normalized = ctx.plan.getNormalizedColumnName(ctx.block, expr);
+ expr.setName(normalized);
+ }
+ }
+ return expr;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/GroupElement.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
index 3c8ee5c..3fb05c2 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/GroupElement.java
@@ -22,29 +22,28 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import org.apache.tajo.algebra.Aggregation;
-import org.apache.tajo.catalog.Column;
+import org.apache.tajo.engine.eval.EvalNode;
public class GroupElement implements Cloneable {
- @Expose
- private Aggregation.GroupType type;
- @Expose private Column[] columns;
+ @Expose private Aggregation.GroupType type;
+ @Expose private EvalNode [] groupingSets;
@SuppressWarnings("unused")
public GroupElement() {
// for gson
}
- public GroupElement(Aggregation.GroupType type, Column[] columns) {
+ public GroupElement(Aggregation.GroupType type, EvalNode [] groupingSets) {
this.type = type;
- this.columns = columns;
+ this.groupingSets = groupingSets;
}
public Aggregation.GroupType getType() {
return this.type;
}
- public Column [] getColumns() {
- return this.columns;
+ public EvalNode [] getGroupingSets() {
+ return this.groupingSets;
}
public String toString() {
@@ -56,9 +55,9 @@ public class GroupElement implements Cloneable {
public Object clone() throws CloneNotSupportedException {
GroupElement groups = (GroupElement) super.clone();
groups.type = type;
- groups.columns = new Column[columns.length];
- for (int i = 0; i < columns.length; i++) {
- groups.columns[i++] = (Column) columns[i].clone();
+ groups.groupingSets = new EvalNode [groupingSets.length];
+ for (int i = 0; i < groupingSets.length; i++) {
+ groups.groupingSets[i++] = (EvalNode) groupingSets[i].clone();
}
return groups;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
index 4a3e479..ecba05a 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/InsertNode.java
@@ -38,18 +38,19 @@ public class InsertNode extends LogicalNode implements Cloneable {
@Expose private Options options;
@Expose private LogicalNode subQuery;
-
- public InsertNode(int pid, TableDesc desc, LogicalNode subQuery) {
+ public InsertNode(int pid) {
super(pid, NodeType.INSERT);
+ }
+
+ public void setTargetTableDesc(TableDesc desc) {
this.targetTableDesc = desc;
- this.subQuery = subQuery;
- this.setInSchema(subQuery.getOutSchema());
- this.setOutSchema(subQuery.getOutSchema());
}
- public InsertNode(int pid, Path location, LogicalNode subQuery) {
- super(pid, NodeType.INSERT);
- this.path = location;
+ public void setTargetLocation(Path path) {
+ this.path = path;
+ }
+
+ public void setSubQuery(LogicalNode subQuery) {
this.subQuery = subQuery;
this.setInSchema(subQuery.getOutSchema());
this.setOutSchema(subQuery.getOutSchema());
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
index acbace0..b462a30 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalOptimizer.java
@@ -36,6 +36,7 @@ import org.apache.tajo.engine.planner.rewrite.FilterPushDownRule;
import org.apache.tajo.engine.planner.rewrite.PartitionedTableRewriter;
import org.apache.tajo.engine.planner.rewrite.ProjectionPushDownRule;
+import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Stack;
@@ -77,7 +78,7 @@ public class LogicalOptimizer {
private void optimizeJoinOrder(LogicalPlan plan, String blockName) throws PlanningException {
LogicalPlan.QueryBlock block = plan.getBlock(blockName);
- if (block.hasJoinNode()) {
+ if (block.hasNode(NodeType.JOIN)) {
String originalOrder = JoinOrderStringBuilder.buildJoinOrderString(plan, block);
double nonOptimizedJoinCost = JoinCostComputer.computeCost(plan, block);
@@ -87,12 +88,39 @@ public class LogicalOptimizer {
// finding join order and restore remain filter order
FoundJoinOrder order = joinOrderAlgorithm.findBestOrder(plan, block,
joinGraphContext.joinGraph, joinGraphContext.relationsForProduct);
- block.setJoinNode(order.getOrderedJoin());
+ JoinNode newJoinNode = order.getOrderedJoin();
+ JoinNode old = block.getNode(NodeType.JOIN);
+ JoinTargetCollector collector = new JoinTargetCollector();
+ Set<Target> targets = new LinkedHashSet<Target>();
+ collector.visitJoin(targets, plan, block, old, new Stack<LogicalNode>());
+
+ if (targets.size() == 0) {
+ newJoinNode.setTargets(PlannerUtil.schemaToTargets(old.getOutSchema()));
+ } else {
+ newJoinNode.setTargets(targets.toArray(new Target[targets.size()]));
+ }
+
+ PlannerUtil.replaceNode(plan, block.getRoot(), old, newJoinNode);
String optimizedOrder = JoinOrderStringBuilder.buildJoinOrderString(plan, block);
+ block.addPlanHistory("Non-optimized join order: " + originalOrder + " (cost: " + nonOptimizedJoinCost + ")");
+ block.addPlanHistory("Optimized join order : " + optimizedOrder + " (cost: " + order.getCost() + ")");
+ }
+ }
- block.addHistory("Non-optimized join order: " + originalOrder + " (cost: " + nonOptimizedJoinCost + ")");
- block.addHistory("Optimized join order : " + optimizedOrder + " (cost: " + order.getCost() + ")");
+ private static class JoinTargetCollector extends BasicLogicalPlanVisitor<Set<Target>, LogicalNode> {
+ @Override
+ public LogicalNode visitJoin(Set<Target> ctx, LogicalPlan plan, LogicalPlan.QueryBlock block, JoinNode node,
+ Stack<LogicalNode> stack)
+ throws PlanningException {
+ super.visitJoin(ctx, plan, block, node, stack);
+
+ if (node.hasTargets()) {
+ for (Target target : node.getTargets()) {
+ ctx.add(target);
+ }
+ }
+ return node;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
index 584fd6e..2519a95 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlan.java
@@ -19,12 +19,13 @@
package org.apache.tajo.engine.planner;
import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import org.apache.commons.lang.ObjectUtils;
import org.apache.tajo.algebra.*;
import org.apache.tajo.annotation.NotThreadSafe;
import org.apache.tajo.catalog.Column;
import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.engine.eval.*;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.eval.EvalTreeUtil;
import org.apache.tajo.engine.exception.NoSuchColumnException;
import org.apache.tajo.engine.exception.VerifyException;
import org.apache.tajo.engine.planner.graph.DirectedGraphCursor;
@@ -39,13 +40,12 @@ import java.util.*;
*/
@NotThreadSafe
public class LogicalPlan {
- private final LogicalPlanner planner;
-
/** the prefix character for virtual tables */
- public static final char VIRTUAL_TABLE_PREFIX='@';
+ public static final char VIRTUAL_TABLE_PREFIX='#';
+ public static final char NONAMED_COLUMN_PREFIX='?';
/** it indicates the root block */
public static final String ROOT_BLOCK = VIRTUAL_TABLE_PREFIX + "ROOT";
- public static final String NONAME_BLOCK_PREFIX = VIRTUAL_TABLE_PREFIX + "NONAME_";
+ public static final String NONAME_BLOCK_PREFIX = VIRTUAL_TABLE_PREFIX + "QB_";
private int nextPid = 0;
private Integer noNameBlockId = 0;
private Integer noNameColumnId = 0;
@@ -54,10 +54,12 @@ public class LogicalPlan {
private Map<String, QueryBlock> queryBlocks = new LinkedHashMap<String, QueryBlock>();
private Map<Integer, LogicalNode> nodeMap = new HashMap<Integer, LogicalNode>();
private Map<Integer, QueryBlock> queryBlockByPID = new HashMap<Integer, QueryBlock>();
+ private Map<String, String> exprToBlockNameMap = TUtil.newHashMap();
private SimpleDirectedGraph<String, BlockEdge> queryBlockGraph = new SimpleDirectedGraph<String, BlockEdge>();
/** planning and optimization log */
private List<String> planingHistory = Lists.newArrayList();
+ LogicalPlanner planner;
public LogicalPlan(LogicalPlanner planner) {
this.planner = planner;
@@ -79,23 +81,39 @@ public class LogicalPlan {
return nextPid++;
}
- public QueryBlock newNoNameBlock() {
+ public QueryBlock newQueryBlock() {
return newAndGetBlock(NONAME_BLOCK_PREFIX + (noNameBlockId++));
}
- public String newNonameColumnName(String prefix) {
- String suffix = noNameColumnId == 0 ? "" : String.valueOf(noNameColumnId);
- noNameColumnId++;
- return "?" + prefix + suffix;
+ private String generateFieldName(String prefix) {
+ int sequence = noNameColumnId++;
+ return NONAMED_COLUMN_PREFIX + prefix.toLowerCase() + (sequence > 0 ? "_" + sequence : "");
}
- /**
- * Check if a query block exists
- * @param blockName the query block name to be checked
- * @return true if exists. Otherwise, false
- */
- public boolean existBlock(String blockName) {
- return queryBlocks.containsKey(blockName);
+ public String newGeneratedFieldName(EvalNode evalNode) {
+ String prefix = evalNode.getName();
+ return generateFieldName(prefix);
+ }
+
+ public String newGeneratedFieldName(Expr expr) {
+ String prefix;
+
+ switch (expr.getType()) {
+ case CountRowsFunction:
+ prefix = "count";
+ break;
+ case GeneralSetFunction:
+ GeneralSetFunctionExpr setFunction = (GeneralSetFunctionExpr) expr;
+ prefix = setFunction.getSignature();
+ break;
+ case Function:
+ FunctionExpr function = (FunctionExpr) expr;
+ prefix = function.getSignature();
+ break;
+ default:
+ prefix = expr.getType().name();
+ }
+ return generateFieldName(prefix);
}
public QueryBlock getRootBlock() {
@@ -137,6 +155,18 @@ public class LogicalPlan {
return childBlocks;
}
+ public void mapExprToBlock(Expr expr, String blockName) {
+ exprToBlockNameMap.put(ObjectUtils.identityToString(expr), blockName);
+ }
+
+ public QueryBlock getBlockByExpr(Expr expr) {
+ return getBlock(exprToBlockNameMap.get(ObjectUtils.identityToString(expr)));
+ }
+
+ public String getBlockNameByExpr(Expr expr) {
+ return exprToBlockNameMap.get(ObjectUtils.identityToString(expr));
+ }
+
public Collection<QueryBlock> getQueryBlocks() {
return queryBlocks.values();
}
@@ -145,13 +175,18 @@ public class LogicalPlan {
return queryBlockGraph;
}
+ public String getNormalizedColumnName(QueryBlock block, ColumnReferenceExpr columnRef)
+ throws PlanningException {
+ Column found = resolveColumn(block, columnRef);
+ return found.getQualifiedName();
+ }
+
/**
* It resolves a column.
*/
- public Column resolveColumn(QueryBlock block, LogicalNode currentNode, ColumnReferenceExpr columnRef)
- throws PlanningException {
+ public Column resolveColumn(QueryBlock block, ColumnReferenceExpr columnRef) throws PlanningException {
- if (columnRef.hasQualifier()) { // if a column referenec is qualified
+ if (columnRef.hasQualifier()) { // if a column reference is qualified
RelationNode relationOp = block.getRelation(columnRef.getQualifier());
@@ -159,44 +194,73 @@ public class LogicalPlan {
if (relationOp == null) {
// TODO - nested query can only refer outer query block? or not?
for (QueryBlock eachBlock : queryBlocks.values()) {
- if (eachBlock.containRelation(columnRef.getQualifier())) {
+ if (eachBlock.existsRelation(columnRef.getQualifier())) {
relationOp = eachBlock.getRelation(columnRef.getQualifier());
}
}
}
+ // If we cannot find any relation against a qualified column name
if (relationOp == null) {
throw new NoSuchColumnException(columnRef.getCanonicalName());
}
Schema schema = relationOp.getTableSchema();
-
Column column = schema.getColumnByFQN(columnRef.getCanonicalName());
if (column == null) {
- throw new VerifyException("ERROR: no such a column '"+ columnRef.getCanonicalName() + "'");
+ throw new NoSuchColumnException(columnRef.getCanonicalName());
}
- return column;
+ // If code reach here, a column is found.
+ // But, it may be aliased from bottom logical node.
+ // If the column is aliased, the found name may not be used in upper node.
+
+ // Here, we try to check if column reference is already aliased.
+ // If so, it replaces the name with aliased name.
+ LogicalNode currentNode = block.getCurrentNode();
+
+ // The condition (currentNode.getInSchema().contains(column)) means
+ // the column can be used at the current node. So, we don't need to find aliase name.
+ if (currentNode != null && !currentNode.getInSchema().contains(column)) {
+ List<Column> candidates = TUtil.newList();
+ if (block.namedExprsMgr.isAliased(column.getQualifiedName())) {
+ String alias = block.namedExprsMgr.getAlias(columnRef.getCanonicalName());
+ Column found = resolveColumn(block, new ColumnReferenceExpr(alias));
+ if (found != null) {
+ candidates.add(found);
+ }
+ }
+ if (!candidates.isEmpty()) {
+ return ensureUniqueColumn(candidates);
+ }
+ }
+ return column;
} else { // if a column reference is not qualified
- // if current logical node is available
- if (currentNode != null && currentNode.getOutSchema() != null) {
- Column found = currentNode.getOutSchema().getColumnByName(columnRef.getName());
+ // Trying to find the column within the current block
+
+ if (block.getLatestNode() != null) {
+ Column found = block.getLatestNode().getOutSchema().getColumnByName(columnRef.getName());
if (found != null) {
return found;
}
}
- if (block.getLatestNode() != null) {
- Column found = block.getLatestNode().getOutSchema().getColumnByName(columnRef.getName());
+ List<Column> candidates = TUtil.newList();
+ // Trying to find columns from aliased references.
+ if (block.namedExprsMgr.isAliased(columnRef.getCanonicalName())) {
+ String originalName = block.namedExprsMgr.getAlias(columnRef.getCanonicalName());
+ Column found = resolveColumn(block, new ColumnReferenceExpr(originalName));
if (found != null) {
- return found;
+ candidates.add(found);
}
}
+ if (!candidates.isEmpty()) {
+ return ensureUniqueColumn(candidates);
+ }
// Trying to find columns from other relations in the current block
- List<Column> candidates = TUtil.newList();
for (RelationNode rel : block.getRelations()) {
Column found = rel.getOutSchema().getColumnByName(columnRef.getName());
if (found != null) {
@@ -238,16 +302,6 @@ public class LogicalPlan {
}
}
- /**
- * replace the found column if the column is renamed to an alias name
- */
- public Column getColumnOrAliasedColumn(QueryBlock block, Column column) throws PlanningException {
- if (block.targetListManager.isResolve(column)) {
- column = block.targetListManager.getResolvedColumn(column);
- }
- return column;
- }
-
private static Column ensureUniqueColumn(List<Column> candidates)
throws VerifyException {
if (candidates.size() == 1) {
@@ -282,9 +336,9 @@ public class LogicalPlan {
new DirectedGraphCursor<String, BlockEdge>(queryBlockGraph, getRootBlock().getName());
while(cursor.hasNext()) {
QueryBlock block = getBlock(cursor.nextBlock());
- if (block.getPlaningHistory().size() > 0) {
+ if (block.getPlanHistory().size() > 0) {
sb.append("\n[").append(block.getName()).append("]\n");
- for (String log : block.getPlaningHistory()) {
+ for (String log : block.getPlanHistory()) {
sb.append("> ").append(log).append("\n");
}
}
@@ -308,7 +362,7 @@ public class LogicalPlan {
ExplainLogicalPlanVisitor.printDepthString(explainContext.getMaxDepth(), explainContext.explains.pop()));
}
} catch (PlanningException e) {
- e.printStackTrace();
+ throw new RuntimeException(e);
}
return explains.toString();
@@ -366,41 +420,43 @@ public class LogicalPlan {
}
public class QueryBlock {
- private String blockName;
+ private final String blockName;
private LogicalNode rootNode;
private NodeType rootType;
- private Map<String, RelationNode> relations = new HashMap<String, RelationNode>();
- private Map<OpType, List<Expr>> algebraicExprs = TUtil.newHashMap();
- // changing states
+ // transient states
+ private final Map<String, RelationNode> nameToRelationMap = TUtil.newHashMap();
+ private final Map<OpType, List<Expr>> operatorToExprMap = TUtil.newHashMap();
+ /**
+ * It's a map between nodetype and node. node types can be duplicated. So, latest node type is only kept.
+ */
+ private final Map<NodeType, LogicalNode> nodeTypeToNodeMap = TUtil.newHashMap();
+ private final Map<String, LogicalNode> exprToNodeMap = TUtil.newHashMap();
+ final NamedExprsManager namedExprsMgr;
+
+ private LogicalNode currentNode;
private LogicalNode latestNode;
- private boolean resolvedGrouping = true;
- private boolean hasGrouping;
- private Projectable projectionNode;
- private GroupbyNode groupingNode;
- private JoinNode joinNode;
- private SelectionNode selectionNode;
- private StoreTableNode storeTableNode;
- private InsertNode insertNode;
+ private final Set<JoinType> includedJoinTypes = TUtil.newHashSet();
+ /**
+ * Set true value if this query block has either implicit or explicit aggregation.
+ */
+ private boolean aggregationRequired = true;
private Schema schema;
- TargetListManager targetListManager;
-
/** It contains a planning log for this block */
- private List<String> planingHistory = Lists.newArrayList();
+ private final List<String> planingHistory = Lists.newArrayList();
+ /** It is for debugging or unit tests */
+ private Target [] unresolvedTargets;
public QueryBlock(String blockName) {
this.blockName = blockName;
+ this.namedExprsMgr = new NamedExprsManager(LogicalPlan.this);
}
public String getName() {
return blockName;
}
- public boolean hasRoot() {
- return rootNode != null;
- }
-
public void refresh() {
setRoot(rootNode);
}
@@ -411,7 +467,6 @@ public class LogicalPlan {
LogicalRootNode rootNode = (LogicalRootNode) blockRoot;
rootType = rootNode.getChild().getType();
}
- queryBlockByPID.put(blockRoot.getPID(), this);
}
public <NODE extends LogicalNode> NODE getRoot() {
@@ -422,20 +477,32 @@ public class LogicalPlan {
return rootType;
}
- public boolean containRelation(String name) {
- return relations.containsKey(PlannerUtil.normalizeTableName(name));
+ public Target [] getUnresolvedTargets() {
+ return unresolvedTargets;
}
- public void addRelation(RelationNode relation) {
- relations.put(PlannerUtil.normalizeTableName(relation.getCanonicalName()), relation);
+ public void setUnresolvedTargets(Target [] unresolvedTargets) {
+ this.unresolvedTargets = unresolvedTargets;
+ }
+
+ public boolean existsRelation(String name) {
+ return nameToRelationMap.containsKey(PlannerUtil.normalizeTableName(name));
}
public RelationNode getRelation(String name) {
- return relations.get(PlannerUtil.normalizeTableName(name));
+ return nameToRelationMap.get(PlannerUtil.normalizeTableName(name));
+ }
+
+ public void addRelation(RelationNode relation) {
+ nameToRelationMap.put(PlannerUtil.normalizeTableName(relation.getCanonicalName()), relation);
}
public Collection<RelationNode> getRelations() {
- return this.relations.values();
+ return this.nameToRelationMap.values();
+ }
+
+ public boolean hasTableExpression() {
+ return this.nameToRelationMap.size() > 0;
}
public void setSchema(Schema schema) {
@@ -446,8 +513,22 @@ public class LogicalPlan {
return schema;
}
- public boolean hasTableExpression() {
- return this.relations.size() > 0;
+ public NamedExprsManager getNamedExprsManager() {
+ return namedExprsMgr;
+ }
+
+ public void updateCurrentNode(Expr expr) throws PlanningException {
+
+ if (expr.getType() != OpType.RelationList) { // skip relation list because it is a virtual expr.
+ this.currentNode = exprToNodeMap.get(ObjectUtils.identityToString(expr));
+ if (currentNode == null) {
+ throw new PlanningException("Unregistered Algebra Expression: " + expr.getType());
+ }
+ }
+ }
+
+ public <T extends LogicalNode> T getCurrentNode() {
+ return (T) this.currentNode;
}
public void updateLatestNode(LogicalNode node) {
@@ -459,384 +540,94 @@ public class LogicalPlan {
}
public void setAlgebraicExpr(Expr expr) {
- TUtil.putToNestedList(algebraicExprs, expr.getType(), expr);
+ TUtil.putToNestedList(operatorToExprMap, expr.getType(), expr);
}
public boolean hasAlgebraicExpr(OpType opType) {
- return algebraicExprs.containsKey(opType);
+ return operatorToExprMap.containsKey(opType);
}
public <T extends Expr> List<T> getAlgebraicExpr(OpType opType) {
- return (List<T>) algebraicExprs.get(opType);
+ return (List<T>) operatorToExprMap.get(opType);
}
public <T extends Expr> T getSingletonExpr(OpType opType) {
if (hasAlgebraicExpr(opType)) {
- return (T) algebraicExprs.get(opType).get(0);
+ return (T) operatorToExprMap.get(opType).get(0);
} else {
return null;
}
}
- public boolean hasProjection() {
- return hasAlgebraicExpr(OpType.Projection);
- }
-
- public Projection getProjection() {
- return getSingletonExpr(OpType.Projection);
- }
-
- public boolean hasHaving() {
- return hasAlgebraicExpr(OpType.Having);
- }
-
- public Having getHaving() {
- return getSingletonExpr(OpType.Having);
- }
-
- public void setProjectionNode(Projectable node) {
- this.projectionNode = node;
- }
-
- public Projectable getProjectionNode() {
- return this.projectionNode;
+ public boolean hasNode(NodeType nodeType) {
+ return nodeTypeToNodeMap.containsKey(nodeType);
}
- public boolean isGroupingResolved() {
- return this.resolvedGrouping;
- }
-
- public void resolveGroupingRequired() {
- this.resolvedGrouping = true;
- }
-
- public void setHasGrouping() {
- hasGrouping = true;
- resolvedGrouping = false;
- }
+ public void registerNode(LogicalNode node) {
+ // id -> node
+ nodeMap.put(node.getPID(), node);
- public boolean hasGrouping() {
- return hasGrouping || hasGroupbyNode();
- }
+ // So, this is only for filter, groupby, sort, limit, projection, which exists once at a query block.
+ nodeTypeToNodeMap.put(node.getType(), node);
- public boolean hasGroupbyNode() {
- return this.groupingNode != null;
+ queryBlockByPID.put(node.getPID(), this);
}
- public void setGroupbyNode(GroupbyNode groupingNode) {
- this.groupingNode = groupingNode;
+ public <T extends LogicalNode> T getNode(NodeType nodeType) {
+ return (T) nodeTypeToNodeMap.get(nodeType);
}
- public GroupbyNode getGroupbyNode() {
- return this.groupingNode;
+ // expr -> node
+ public void registerExprWithNode(Expr expr, LogicalNode node) {
+ exprToNodeMap.put(ObjectUtils.identityToString(expr), node);
}
- public boolean hasJoinNode() {
- return joinNode != null;
+ public <T extends LogicalNode> T getNodeFromExpr(Expr expr) {
+ return (T) exprToNodeMap.get(ObjectUtils.identityToString(expr));
}
/**
- * @return the topmost JoinNode instance
+ * This flag can be changed as a plan is generated.
+ *
+ * True value means that this query should have aggregation phase. If aggregation plan is added to this block,
+ * it becomes false because it doesn't need aggregation phase anymore. It is usually used to add aggregation
+ * phase from SELECT statement without group-by clause.
+ *
+ * @return True if aggregation is needed but this query hasn't had aggregation phase.
*/
- public JoinNode getJoinNode() {
- return joinNode;
- }
-
- public void setJoinNode(JoinNode node) {
- if (joinNode == null || latestNode == node) {
- this.joinNode = node;
- } else {
- PlannerUtil.replaceNode(LogicalPlan.this, latestNode, this.joinNode, node);
- }
- }
-
- public boolean hasSelectionNode() {
- return this.selectionNode != null;
- }
-
- public void setSelectionNode(SelectionNode selectionNode) {
- this.selectionNode = selectionNode;
+ public boolean isAggregationRequired() {
+ return this.aggregationRequired;
}
- public SelectionNode getSelectionNode() {
- return selectionNode;
- }
-
- public boolean hasStoreTableNode() {
- return this.storeTableNode != null;
- }
-
- public void setStoreTableNode(StoreTableNode storeTableNode) {
- this.storeTableNode = storeTableNode;
- }
-
- public StoreTableNode getStoreTableNode() {
- return this.storeTableNode;
+ /**
+ * Unset aggregation required flag. It has to be called after an aggregation phase is added to this block.
+ */
+ public void unsetAggregationRequire() {
+ this.aggregationRequired = true;
}
- public boolean hasInsertNode() {
- return this.insertNode != null;
+ public void setAggregationRequire() {
+ aggregationRequired = false;
}
- public InsertNode getInsertNode() {
- return this.insertNode;
+ public boolean containsJoinType(JoinType joinType) {
+ return includedJoinTypes.contains(joinType);
}
- public void setInsertNode(InsertNode insertNode) {
- this.insertNode = insertNode;
+ public void addJoinType(JoinType joinType) {
+ includedJoinTypes.add(joinType);
}
- public List<String> getPlaningHistory() {
+ public List<String> getPlanHistory() {
return planingHistory;
}
- public void addHistory(String history) {
+ public void addPlanHistory(String history) {
this.planingHistory.add(history);
}
- public boolean postVisit(LogicalNode node, Stack<OpType> path) {
- if (nodeMap.containsKey(node.getPID())) {
- return false;
- }
-
- nodeMap.put(node.getPID(), node);
- updateLatestNode(node);
-
- // if an added operator is a relation, add it to relation set.
- switch (node.getType()) {
- case STORE:
- setStoreTableNode((StoreTableNode) node);
- break;
-
- case SCAN:
- ScanNode relationOp = (ScanNode) node;
- addRelation(relationOp);
- break;
-
- case GROUP_BY:
- resolveGroupingRequired();
- setGroupbyNode((GroupbyNode) node);
- break;
-
- case JOIN:
- setJoinNode((JoinNode) node);
- break;
-
- case SELECTION:
- setSelectionNode((SelectionNode) node);
- break;
-
- case INSERT:
- setInsertNode((InsertNode) node);
- break;
-
- case TABLE_SUBQUERY:
- TableSubQueryNode tableSubQueryNode = (TableSubQueryNode) node;
- addRelation(tableSubQueryNode);
- break;
- }
-
- // if this node is the topmost
- if (path.size() == 0) {
- setRoot(node);
- }
-
- return true;
- }
-
public String toString() {
return blockName;
}
-
- ///////////////////////////////////////////////////////////////////////////
- // Target List Management Methods
- ///////////////////////////////////////////////////////////////////////////
- //
- // A target list means a list of expressions after SELECT keyword in SQL.
- //
- // SELECT rel1.col1, sum(rel1.col2), res1.col3 + res2.col2, ... FROM ...
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // TARGET LIST
- //
- ///////////////////////////////////////////////////////////////////////////
-
- public void initTargetList(Target[] original) {
- targetListManager = new TargetListManager(LogicalPlan.this, original);
- }
-
- public boolean isTargetResolved(int targetId) {
- return targetListManager.isResolved(targetId);
- }
-
- public void resolveAllTargetList() {
- targetListManager.resolveAll();
- }
-
- public void resolveTarget(int idx) {
- targetListManager.resolve(idx);
- }
-
- public boolean isAlreadyTargetCreated(int idx) {
- return getTarget(idx) != null;
- }
-
- public Target getTarget(int idx) {
- return targetListManager.getTarget(idx);
- }
-
- public int getTargetListNum() {
- return targetListManager.size();
- }
-
- public void fillTarget(int idx) throws PlanningException {
- Target target = planner.createTarget(LogicalPlan.this, this, getProjection().getTargets()[idx]);
- // below code reaches only when target is created.
- targetListManager.fill(idx, target);
- }
-
- public boolean checkIfTargetCanBeEvaluated(int targetId, LogicalNode node) {
- return isAlreadyTargetCreated(targetId)
- && PlannerUtil.canBeEvaluated(targetListManager.getTarget(targetId).getEvalTree(), node);
- }
-
- public TargetListManager getTargetListManager() {
- return targetListManager;
- }
-
- public Target [] getCurrentTargets() {
- return targetListManager.getTargets();
- }
-
- public Schema updateSchema() {
- return targetListManager.getUpdatedSchema();
- }
-
- public void fillTargets() throws PlanningException {
- for (int i = 0; i < getTargetListNum(); i++) {
- if (!isAlreadyTargetCreated(i)) {
- try {
- fillTarget(i);
- } catch (VerifyException e) {
- }
- }
- }
- }
-
- public void checkAndResolveTargets(LogicalNode node) throws PlanningException {
- // If all columns are projected and do not include any expression
- if (getProjection().isAllProjected() && node instanceof RelationNode) {
- initTargetList(PlannerUtil.schemaToTargets(node.getOutSchema()));
- resolveAllTargetList();
-
- } else {
- // fill a target if an annotated target can be created.
- // Some targets which are based on multiple relations can be created only in a join node.
- fillTargets();
-
- // add target to list if a target can be evaluated at this node
- List<Integer> newEvaluatedTargetIds = new ArrayList<Integer>();
- for (int i = 0; i < getTargetListNum(); i++) {
- if (getTarget(i) != null && !isTargetResolved(i)) {
- EvalNode expr = getTarget(i).getEvalTree();
-
- if (checkIfTargetCanBeEvaluated(i, node)) {
-
- if (node instanceof RelationNode) { // for scan node
- if (expr.getType() == EvalType.FIELD) {
- resolveTarget(i);
- if (getTarget(i).hasAlias()) {
- newEvaluatedTargetIds.add(i);
- }
- } else if (EvalTreeUtil.findDistinctAggFunction(expr).size() == 0) {
- // if this expression does no contain any aggregation function
- resolveTarget(i);
- newEvaluatedTargetIds.add(i);
- }
-
- } else if (node instanceof GroupbyNode) { // for grouping
- if (EvalTreeUtil.findDistinctAggFunction(expr).size() > 0) {
- resolveTarget(i);
- newEvaluatedTargetIds.add(i);
- }
-
- } else if (node instanceof JoinNode) { // for join
- if (EvalTreeUtil.findDistinctAggFunction(expr).size() == 0) {
- // if this expression does no contain any aggregation function,
- resolveTarget(i);
- newEvaluatedTargetIds.add(i);
- }
- }
- }
- }
- }
-
- if (node instanceof ScanNode || node instanceof JoinNode) {
-
- Schema baseSchema = null;
- if (node instanceof ScanNode) {
- baseSchema = ((ScanNode)node).getTableSchema();
- } else if (node instanceof JoinNode) {
- baseSchema = node.getInSchema(); // composite schema
- }
-
- if (newEvaluatedTargetIds.size() > 0) {
- // fill addedTargets with output columns and new expression columns (e.g., aliased column or expressions)
- Target[] addedTargets = new Target[baseSchema.getColumnNum() + newEvaluatedTargetIds.size()];
- PlannerUtil.schemaToTargets(baseSchema, addedTargets);
- int baseIdx = baseSchema.getColumnNum();
- for (int i = 0; i < newEvaluatedTargetIds.size(); i++) {
- addedTargets[baseIdx + i] = getTarget(newEvaluatedTargetIds.get(i));
- }
-
- // set targets to ScanNode because it needs to evaluate expressions
- ((Projectable)node).setTargets(addedTargets);
- // the output schema of ScanNode has to have the combination of the original output and newly-added targets.
- node.setOutSchema(LogicalPlanner.getProjectedSchema(LogicalPlan.this, addedTargets));
- } else {
- // if newEvaluatedTargetIds == 0, the original input schema will be used as the output schema.
- node.setOutSchema(node.getInSchema());
- }
- } else if (node instanceof GroupbyNode) {
- // Set the current targets to the GroupByNode because the GroupByNode is the last projection operator.
- GroupbyNode groupbyNode = (GroupbyNode) node;
- groupbyNode.setTargets(targetListManager.getUpdatedTarget(Sets.newHashSet(newEvaluatedTargetIds)));
- //groupbyNode.setTargets(getCurrentTargets());
- boolean distinct = false;
- for (Target target : groupbyNode.getTargets()) {
- for (AggregationFunctionCallEval aggrFunc : EvalTreeUtil.findDistinctAggFunction(target.getEvalTree())) {
- if (aggrFunc.isDistinct()) {
- distinct = true;
- break;
- }
- }
- }
- groupbyNode.setDistinct(distinct);
- node.setOutSchema(updateSchema());
-
- // if a having condition is given,
- if (hasHaving()) {
- EvalNode havingCondition = planner.createEvalTree(LogicalPlan.this, this, getHaving().getQual());
- List<AggregationFunctionCallEval> aggrFunctions = EvalTreeUtil.findDistinctAggFunction(havingCondition);
-
- if (aggrFunctions.size() == 0) {
- groupbyNode.setHavingCondition(havingCondition);
- } else {
- Target [] addedTargets = new Target[aggrFunctions.size()];
- for (int i = 0; i < aggrFunctions.size(); i++) {
- Target aggrFunctionTarget = new Target(aggrFunctions.get(i),
- newNonameColumnName(aggrFunctions.get(i).getName()));
- addedTargets[i] = aggrFunctionTarget;
- EvalTreeUtil.replace(havingCondition, aggrFunctions.get(i),
- new FieldEval(aggrFunctionTarget.getColumnSchema()));
- }
- Target [] updatedTargets = TUtil.concat(groupbyNode.getTargets(), addedTargets);
- groupbyNode.setTargets(updatedTargets);
- groupbyNode.setHavingCondition(havingCondition);
- groupbyNode.setHavingSchema(PlannerUtil.targetToSchema(groupbyNode.getTargets()));
- }
- }
- }
- }
- }
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
new file mode 100644
index 0000000..3ab328c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanPreprocessor.java
@@ -0,0 +1,301 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.engine.planner;
+
+import org.apache.tajo.algebra.*;
+import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.TableDesc;
+import org.apache.tajo.engine.eval.EvalNode;
+import org.apache.tajo.engine.eval.EvalType;
+import org.apache.tajo.engine.eval.FieldEval;
+import org.apache.tajo.engine.planner.logical.*;
+import org.apache.tajo.engine.utils.SchemaUtil;
+
+import java.util.Stack;
+
+/**
+ * It finds all relations for each block and builds base schema information.
+ */
+class LogicalPlanPreprocessor extends BaseAlgebraVisitor<LogicalPlanPreprocessor.PreprocessContext, LogicalNode> {
+ private ExprAnnotator annotator;
+
+ static class PreprocessContext {
+ LogicalPlan plan;
+ LogicalPlan.QueryBlock currentBlock;
+
+ public PreprocessContext(LogicalPlan plan, LogicalPlan.QueryBlock currentBlock) {
+ this.plan = plan;
+ this.currentBlock = currentBlock;
+ }
+
+ public PreprocessContext(PreprocessContext context, LogicalPlan.QueryBlock currentBlock) {
+ this.plan = context.plan;
+ this.currentBlock = currentBlock;
+ }
+ }
+
+ /** Catalog service */
+ private CatalogService catalog;
+
+ LogicalPlanPreprocessor(CatalogService catalog, ExprAnnotator annotator) {
+ this.catalog = catalog;
+ this.annotator = annotator;
+ }
+
+ @Override
+ public void preHook(PreprocessContext ctx, Stack<Expr> stack, Expr expr) throws PlanningException {
+ ctx.currentBlock.setAlgebraicExpr(expr);
+ ctx.plan.mapExprToBlock(expr, ctx.currentBlock.getName());
+ }
+
+ @Override
+ public LogicalNode postHook(PreprocessContext ctx, Stack<Expr> stack, Expr expr, LogicalNode result) throws PlanningException {
+ // If non-from statement, result can be null. It avoids that case.
+ if (result != null) {
+ // setNode method registers each node to corresponding block and plan.
+ ctx.currentBlock.registerNode(result);
+ // It makes a map between an expr and a logical node.
+ ctx.currentBlock.registerExprWithNode(expr, result);
+ }
+ return result;
+ }
+
+ @Override
+ public LogicalNode visitProjection(PreprocessContext ctx, Stack<Expr> stack, Projection expr) throws PlanningException {
+ // If Non-from statement, it immediately returns.
+ if (!expr.hasChild()) {
+ return new EvalExprNode(ctx.plan.newPID());
+ }
+
+ stack.push(expr); // <--- push
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+
+ Target [] targets;
+ if (expr.isAllProjected()) {
+ targets = PlannerUtil.schemaToTargets(child.getOutSchema());
+ } else {
+ targets = new Target[expr.getNamedExprs().length];
+
+ for (int i = 0; i < expr.getNamedExprs().length; i++) {
+ NamedExpr namedExpr = expr.getNamedExprs()[i];
+ EvalNode evalNode = annotator.createEvalNode(ctx.plan, ctx.currentBlock, namedExpr.getExpr());
+
+ if (namedExpr.hasAlias()) {
+ targets[i] = new Target(evalNode, namedExpr.getAlias());
+ } else if (evalNode.getType() == EvalType.FIELD) {
+ targets[i] = new Target((FieldEval) evalNode);
+ } else {
+ targets[i] = new Target(evalNode, "?name_" + i);
+ }
+ }
+ }
+ stack.pop(); // <--- Pop
+
+ ProjectionNode projectionNode = new ProjectionNode(ctx.plan.newPID());
+ projectionNode.setInSchema(child.getOutSchema());
+ projectionNode.setOutSchema(PlannerUtil.targetToSchema(targets));
+ return projectionNode;
+ }
+
+ @Override
+ public LogicalNode visitLimit(PreprocessContext ctx, Stack<Expr> stack, Limit expr) throws PlanningException {
+ stack.push(expr);
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+ stack.pop();
+
+ LimitNode limitNode = new LimitNode(ctx.plan.newPID());
+ limitNode.setInSchema(child.getOutSchema());
+ limitNode.setOutSchema(child.getOutSchema());
+ return limitNode;
+ }
+
+ @Override
+ public LogicalNode visitSort(PreprocessContext ctx, Stack<Expr> stack, Sort expr) throws PlanningException {
+ stack.push(expr);
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+ stack.pop();
+
+ SortNode sortNode = new SortNode(ctx.plan.newPID());
+ sortNode.setInSchema(child.getOutSchema());
+ sortNode.setOutSchema(child.getOutSchema());
+ return sortNode;
+ }
+
+ @Override
+ public LogicalNode visitHaving(PreprocessContext ctx, Stack<Expr> stack, Having expr) throws PlanningException {
+ stack.push(expr);
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+ stack.pop();
+
+ HavingNode havingNode = new HavingNode(ctx.plan.newPID());
+ havingNode.setInSchema(child.getOutSchema());
+ havingNode.setOutSchema(child.getOutSchema());
+ return havingNode;
+ }
+
+ @Override
+ public LogicalNode visitGroupBy(PreprocessContext ctx, Stack<Expr> stack, Aggregation expr) throws PlanningException {
+ stack.push(expr); // <--- push
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+
+ Projection projection = ctx.currentBlock.getSingletonExpr(OpType.Projection);
+ int finalTargetNum = projection.getNamedExprs().length;
+ Target [] targets = new Target[finalTargetNum];
+
+ for (int i = 0; i < finalTargetNum; i++) {
+ NamedExpr namedExpr = projection.getNamedExprs()[i];
+ EvalNode evalNode = annotator.createEvalNode(ctx.plan, ctx.currentBlock, namedExpr.getExpr());
+
+ if (namedExpr.hasAlias()) {
+ targets[i] = new Target(evalNode, namedExpr.getAlias());
+ } else {
+ targets[i] = new Target(evalNode, "?name_" + i);
+ }
+ }
+ stack.pop();
+
+ GroupbyNode groupByNode = new GroupbyNode(ctx.plan.newPID());
+ groupByNode.setInSchema(child.getOutSchema());
+ groupByNode.setOutSchema(PlannerUtil.targetToSchema(targets));
+ return groupByNode;
+ }
+
+ @Override
+ public LogicalNode visitUnion(PreprocessContext ctx, Stack<Expr> stack, SetOperation expr) throws PlanningException {
+ LogicalPlan.QueryBlock leftBlock = ctx.plan.newQueryBlock();
+ PreprocessContext leftContext = new PreprocessContext(ctx, leftBlock);
+ LogicalNode leftChild = visit(leftContext, new Stack<Expr>(), expr.getLeft());
+ ctx.currentBlock.registerExprWithNode(expr.getLeft(), leftChild);
+
+ LogicalPlan.QueryBlock rightBlock = ctx.plan.newQueryBlock();
+ PreprocessContext rightContext = new PreprocessContext(ctx, rightBlock);
+ LogicalNode rightChild = visit(rightContext, new Stack<Expr>(), expr.getRight());
+ ctx.currentBlock.registerExprWithNode(expr.getRight(), rightChild);
+
+ UnionNode unionNode = new UnionNode(ctx.plan.newPID());
+ unionNode.setLeftChild(leftChild);
+ unionNode.setRightChild(rightChild);
+ unionNode.setInSchema(leftChild.getOutSchema());
+ unionNode.setOutSchema(leftChild.getOutSchema());
+
+ return unionNode;
+ }
+
+ public LogicalNode visitFilter(PreprocessContext ctx, Stack<Expr> stack, Selection expr) throws PlanningException {
+ stack.push(expr);
+ LogicalNode child = visit(ctx, stack, expr.getChild());
+ stack.pop();
+
+ SelectionNode selectionNode = new SelectionNode(ctx.plan.newPID());
+ selectionNode.setInSchema(child.getOutSchema());
+ selectionNode.setOutSchema(child.getOutSchema());
+ return selectionNode;
+ }
+
+ @Override
+ public LogicalNode visitJoin(PreprocessContext ctx, Stack<Expr> stack, Join expr) throws PlanningException {
+ stack.push(expr);
+ LogicalNode left = visit(ctx, stack, expr.getLeft());
+ LogicalNode right = visit(ctx, stack, expr.getRight());
+ stack.pop();
+ JoinNode joinNode = new JoinNode(ctx.plan.newPID());
+ joinNode.setJoinType(expr.getJoinType());
+ Schema merged = SchemaUtil.merge(left.getOutSchema(), right.getOutSchema());
+ joinNode.setInSchema(merged);
+ joinNode.setOutSchema(merged);
+
+ ctx.currentBlock.addJoinType(expr.getJoinType());
+ return joinNode;
+ }
+
+ @Override
+ public LogicalNode visitRelation(PreprocessContext ctx, Stack<Expr> stack, Relation expr)
+ throws PlanningException {
+
+ Relation relation = expr;
+ TableDesc desc = catalog.getTableDesc(relation.getName());
+
+ ScanNode scanNode;
+ if (relation.hasAlias()) {
+ scanNode = new ScanNode(ctx.plan.newPID(), desc, relation.getAlias());
+ } else {
+ scanNode = new ScanNode(ctx.plan.newPID(), desc);
+ }
+ ctx.currentBlock.addRelation(scanNode);
+
+ return scanNode;
+ }
+
+ @Override
+ public LogicalNode visitTableSubQuery(PreprocessContext ctx, Stack<Expr> stack, TablePrimarySubQuery expr)
+ throws PlanningException {
+
+ PreprocessContext newContext;
+ // Note: TableSubQuery always has a table name.
+ // SELECT .... FROM (SELECT ...) TB_NAME <-
+ newContext = new PreprocessContext(ctx, ctx.plan.newAndGetBlock(expr.getName()));
+ LogicalNode child = super.visitTableSubQuery(newContext, stack, expr);
+
+ // a table subquery should be dealt as a relation.
+ TableSubQueryNode node = new TableSubQueryNode(ctx.plan.newPID(), expr.getName(), child);
+ ctx.currentBlock.addRelation(node);
+ return node;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Data Definition Language Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public LogicalNode visitCreateTable(PreprocessContext ctx, Stack<Expr> stack, CreateTable expr)
+ throws PlanningException {
+
+ CreateTableNode createTableNode = new CreateTableNode(ctx.plan.newPID());
+
+ if (expr.hasSubQuery()) {
+ stack.push(expr);
+ visit(ctx, stack, expr.getSubQuery());
+ stack.pop();
+ }
+
+ return createTableNode;
+ }
+
+ @Override
+ public LogicalNode visitDropTable(PreprocessContext ctx, Stack<Expr> stack, DropTable expr)
+ throws PlanningException {
+ DropTableNode dropTable = new DropTableNode(ctx.plan.newPID());
+ return dropTable;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Insert or Update Section
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public LogicalNode visitInsert(PreprocessContext ctx, Stack<Expr> stack, Insert expr) throws PlanningException {
+ PreprocessContext newContext = new PreprocessContext(ctx, ctx.plan.newQueryBlock());
+ LogicalNode child = super.visitInsert(newContext, stack, expr);
+
+ InsertNode insertNode = new InsertNode(ctx.plan.newPID());
+ insertNode.setInSchema(child.getOutSchema());
+ insertNode.setOutSchema(child.getOutSchema());
+ return insertNode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
index e48b655..41e42d0 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVerifier.java
@@ -71,9 +71,6 @@ public class LogicalPlanVerifier extends BasicLogicalPlanVisitor<VerificationSta
}
}
- if (node.hasHavingCondition()) {
- ExprsVerifier.verify(state, node.getHavingCondition());
- }
return node;
}
http://git-wip-us.apache.org/repos/asf/incubator-tajo/blob/8e1f989a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
index 697a8c6..bf41996 100644
--- a/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
+++ b/tajo-core/tajo-core-backend/src/main/java/org/apache/tajo/engine/planner/LogicalPlanVisitor.java
@@ -35,6 +35,9 @@ public interface LogicalPlanVisitor<CONTEXT, RESULT> {
RESULT visitSort(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, SortNode node,
Stack<LogicalNode> stack) throws PlanningException;
+ RESULT visitHaving(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, HavingNode node,
+ Stack<LogicalNode> stack) throws PlanningException;
+
RESULT visitGroupBy(CONTEXT context, LogicalPlan plan, LogicalPlan.QueryBlock block, GroupbyNode node,
Stack<LogicalNode> stack) throws PlanningException;