PHOENIX-1610 Incorrect subquery results caused by unpaired contextStack push/pop
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/1c58f442 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/1c58f442 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/1c58f442 Branch: refs/heads/calcite Commit: 1c58f442dea6c19745a119f53e47e78ce9e2ef76 Parents: d058a41 Author: maryannxue <wei....@intel.com> Authored: Thu Jan 29 11:42:24 2015 -0500 Committer: maryannxue <wei....@intel.com> Committed: Thu Jan 29 11:42:24 2015 -0500 ---------------------------------------------------------------------- .../apache/phoenix/end2end/DerivedTableIT.java | 9 +++ .../org/apache/phoenix/end2end/HashJoinIT.java | 52 ++++++++-------- .../org/apache/phoenix/end2end/SubqueryIT.java | 10 ++-- .../end2end/SubqueryUsingSortMergeJoinIT.java | 10 ++-- phoenix-core/src/main/antlr3/PhoenixSQL.g | 6 +- .../apache/phoenix/compile/QueryCompiler.java | 12 ++-- .../apache/phoenix/execute/HashJoinPlan.java | 63 ++++---------------- .../phoenix/expression/InListExpression.java | 9 +-- .../apache/phoenix/join/HashCacheClient.java | 58 +++++++++++++++--- .../apache/phoenix/optimize/QueryOptimizer.java | 2 +- .../java/org/apache/phoenix/parse/HintNode.java | 8 +-- 11 files changed, 120 insertions(+), 119 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java index 727293f..7a418bd 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DerivedTableIT.java @@ -667,6 +667,15 @@ public class DerivedTableIT extends BaseClientManagedTimeIT { assertEquals(2,rs.getInt(1)); assertFalse(rs.next()); + + // count (subquery) + query = "SELECT count(*) FROM (SELECT * FROM aTable WHERE (organization_id, entity_id) in (SELECT organization_id, entity_id FROM aTable WHERE a_byte != 8)) AS t"; + statement = conn.prepareStatement(query); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(8,rs.getInt(1)); + + assertFalse(rs.next()); } finally { conn.close(); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java index 9a95ea4..a699d48 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/HashJoinIT.java @@ -229,7 +229,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " PARALLEL INNER-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (I2.item_id)", + " DYNAMIC SERVER FILTER BY item_id IN (I2.item_id)", /* * testSelfJoin() * SELECT i1.name, i2.name FROM joinItemTable i1 @@ -241,7 +241,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { "CLIENT MERGE SORT\n" + " PARALLEL INNER-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (I2.supplier_id)", + " DYNAMIC SERVER FILTER BY item_id IN (I2.supplier_id)", /* * testStarJoin() * SELECT order_id, c.name, i.name iname, quantity, o.date @@ -270,7 +270,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " PARALLEL INNER-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_DISPLAY_NAME + "\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (O.item_id)", + " DYNAMIC SERVER FILTER BY item_id IN (O.item_id)", /* * testSubJoin() * SELECT * FROM joinCustomerTable c @@ -415,11 +415,11 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + " PARALLEL INNER-JOIN TABLE 1(DELAYED EVALUATION)\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + - " DYNAMIC SERVER FILTER BY supplier_id BETWEEN MIN/MAX OF (I.supplier_id)\n" + + " DYNAMIC SERVER FILTER BY supplier_id IN (I.supplier_id)\n" + " JOIN-SCANNER 4 ROW LIMIT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col1 = rhs.col2 */ @@ -430,7 +430,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT MERGE SORT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col2 */ @@ -442,7 +442,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY COL0 IN (RHS.COL2)", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col1 = rhs.col2 */ @@ -454,7 +454,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY (COL0, COL1) IN ((RHS.COL1, RHS.COL2))", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col2 = rhs.col3 - 1 AND lhs.col1 = rhs.col2 */ @@ -592,7 +592,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " PARALLEL INNER-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (I2.:item_id)", + " DYNAMIC SERVER FILTER BY item_id IN (I2.:item_id)", /* * testSelfJoin() * SELECT i1.name, i2.name FROM joinItemTable i1 @@ -782,11 +782,11 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_SCHEMA + ".idx_item\n" + " PARALLEL INNER-JOIN TABLE 1(DELAYED EVALUATION)\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + - " DYNAMIC SERVER FILTER BY supplier_id BETWEEN MIN/MAX OF (I.0:supplier_id)\n" + + " DYNAMIC SERVER FILTER BY supplier_id IN (I.0:supplier_id)\n" + " JOIN-SCANNER 4 ROW LIMIT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col1 = rhs.col2 */ @@ -797,7 +797,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT MERGE SORT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col2 */ @@ -809,7 +809,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY COL0 IN (RHS.COL2)", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col1 = rhs.col2 */ @@ -821,7 +821,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY (COL0, COL1) IN ((RHS.COL1, RHS.COL2))", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col2 = rhs.col3 - 1 AND lhs.col1 = rhs.col2 */ @@ -970,7 +970,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX +""+ JOIN_ITEM_TABLE_DISPLAY_NAME +" [-32768]\n" + " SERVER FILTER BY FIRST KEY ONLY\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (I2.:item_id)", + " DYNAMIC SERVER FILTER BY item_id IN (I2.:item_id)", /* * testSelfJoin() * SELECT i1.name, i2.name FROM joinItemTable i1 @@ -984,7 +984,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " PARALLEL INNER-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX +""+ JOIN_ITEM_TABLE_DISPLAY_NAME +" [-32768]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (I2.0:supplier_id)", + " DYNAMIC SERVER FILTER BY item_id IN (I2.0:supplier_id)", /* * testStarJoin() * SELECT order_id, c.name, i.name iname, quantity, o.date @@ -1020,7 +1020,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + "" + JOIN_CUSTOMER_TABLE_DISPLAY_NAME+" [-32768]\n"+ " SERVER FILTER BY FIRST KEY ONLY\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF (O.item_id)", + " DYNAMIC SERVER FILTER BY item_id IN (O.item_id)", /* * testSubJoin() * SELECT * FROM joinCustomerTable c @@ -1172,11 +1172,11 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT MERGE SORT\n" + " PARALLEL INNER-JOIN TABLE 1(DELAYED EVALUATION)\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + - " DYNAMIC SERVER FILTER BY supplier_id BETWEEN MIN/MAX OF (I.0:supplier_id)\n" + + " DYNAMIC SERVER FILTER BY supplier_id IN (I.0:supplier_id)\n" + " JOIN-SCANNER 4 ROW LIMIT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col1 = rhs.col2 */ @@ -1187,7 +1187,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " CLIENT MERGE SORT", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col2 */ @@ -1199,7 +1199,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY COL0 IN (RHS.COL2)", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col1 = rhs.col2 */ @@ -1211,7 +1211,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { " DYNAMIC SERVER FILTER BY (COL0, COL1) IN ((RHS.COL1, RHS.COL2))", /* * testJoinWithKeyRangeOptimization() - * SELECT (*SKIP_SCAN_HASH_JOIN*) lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 + * SELECT lhs.col0, lhs.col1, lhs.col2, rhs.col0, rhs.col1, rhs.col2 * FROM TEMP_TABLE_COMPOSITE_PK lhs * JOIN TEMP_TABLE_COMPOSITE_PK rhs ON lhs.col0 = rhs.col1 AND lhs.col2 = rhs.col3 - 1 AND lhs.col1 = rhs.col2 */ @@ -3549,7 +3549,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { conn.commit(); // No leading part of PK - String query = "SELECT /*+ SKIP_SCAN_HASH_JOIN*/ lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + String query = "SELECT lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + tempTableWithCompositePK + " lhs JOIN " + tempTableWithCompositePK + " rhs ON lhs.col1 = rhs.col2"; PreparedStatement statement = conn.prepareStatement(query); @@ -3579,7 +3579,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { assertEquals(plans[21], QueryUtil.getExplainPlan(rs)); // Two parts of PK but only one leading part - query = "SELECT /*+ SKIP_SCAN_HASH_JOIN*/ lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + query = "SELECT lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + tempTableWithCompositePK + " lhs JOIN " + tempTableWithCompositePK + " rhs ON lhs.col2 = rhs.col3 AND lhs.col0 = rhs.col2"; statement = conn.prepareStatement(query); @@ -3600,7 +3600,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { assertEquals(plans[22], QueryUtil.getExplainPlan(rs)); // Two leading parts of PK - query = "SELECT /*+ SKIP_SCAN_HASH_JOIN*/ lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + query = "SELECT lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + tempTableWithCompositePK + " lhs JOIN " + tempTableWithCompositePK + " rhs ON lhs.col1 = rhs.col2 AND lhs.col0 = rhs.col1"; statement = conn.prepareStatement(query); @@ -3630,7 +3630,7 @@ public class HashJoinIT extends BaseHBaseManagedTimeIT { assertEquals(plans[23], QueryUtil.getExplainPlan(rs)); // All parts of PK - query = "SELECT /*+ SKIP_SCAN_HASH_JOIN*/ lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + query = "SELECT lhs.col0, lhs.col1, lhs.col2, lhs.col3, rhs.col0, rhs.col1, rhs.col2, rhs.col3 FROM " + tempTableWithCompositePK + " lhs JOIN " + tempTableWithCompositePK + " rhs ON lhs.col1 = rhs.col2 AND lhs.col2 = rhs.col3 - 1 AND lhs.col0 = rhs.col1"; statement = conn.prepareStatement(query); http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java index 066790c..85e562c 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryIT.java @@ -139,11 +139,11 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id, NAME\\]\n" + " CLIENT MERGE SORT\n" + - " PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" + + " SKIP-SCAN-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(\\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(\\$\\d+.\\$\\d+\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(\\$\\d+.\\$\\d+ IS NOT NULL OR \\$\\d+.\\$\\d+ IS NOT NULL\\)", "CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + @@ -165,7 +165,7 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(O.item_id\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(I.NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)\n" + " DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)" }}); @@ -289,7 +289,7 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(\\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(\\$\\d+.\\$\\d+\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(\\$\\d+.\\$\\d+ IS NOT NULL OR \\$\\d+.\\$\\d+ IS NOT NULL\\)", "CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + JOIN_ITEM_TABLE_DISPLAY_NAME + " [-32768]\n" + @@ -314,7 +314,7 @@ public class SubqueryIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(O.item_id\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)\n" + " DYNAMIC SERVER FILTER BY customer_id IN \\(\\$\\d+.\\$\\d+\\)" }}); http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryUsingSortMergeJoinIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryUsingSortMergeJoinIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryUsingSortMergeJoinIT.java index bbb84ba..82b1c68 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryUsingSortMergeJoinIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SubqueryUsingSortMergeJoinIT.java @@ -143,11 +143,11 @@ public class SubqueryUsingSortMergeJoinIT extends BaseHBaseManagedTimeIT { " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id, NAME\\]\n" + " CLIENT MERGE SORT\n" + " CLIENT SORTED BY \\[item_id, NAME\\]\n" + - " PARALLEL SEMI-JOIN TABLE 0 \\(SKIP MERGE\\)\n" + + " SKIP-SCAN-JOIN TABLE 0\n" + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(\\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(\\$\\d+.\\$\\d+\\)\n" + "CLIENT FILTER BY \\(\\$\\d+.\\$\\d+ IS NOT NULL OR \\$\\d+.\\$\\d+ IS NOT NULL\\)", "SORT-MERGE-JOIN \\(SEMI\\) TABLES\n" + @@ -163,7 +163,7 @@ public class SubqueryUsingSortMergeJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(O.item_id\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(I.NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)", }}); testCases.add(new String[][] { @@ -285,7 +285,7 @@ public class SubqueryUsingSortMergeJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(\\$\\d+.\\$\\d+\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(\\$\\d+.\\$\\d+\\)\n" + "CLIENT FILTER BY \\(\\$\\d+.\\$\\d+ IS NOT NULL OR \\$\\d+.\\$\\d+ IS NOT NULL\\)", "SORT-MERGE-JOIN \\(SEMI\\) TABLES\n" + @@ -305,7 +305,7 @@ public class SubqueryUsingSortMergeJoinIT extends BaseHBaseManagedTimeIT { " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + " SERVER AGGREGATE INTO DISTINCT ROWS BY \\[item_id\\]\n" + " CLIENT MERGE SORT\n" + - " DYNAMIC SERVER FILTER BY item_id BETWEEN MIN/MAX OF \\(O.item_id\\)\n" + + " DYNAMIC SERVER FILTER BY item_id IN \\(O.item_id\\)\n" + " AFTER-JOIN SERVER FILTER BY \\(I.0:NAME = 'T2' OR O.QUANTITY > \\$\\d+.\\$\\d+\\)", }}); return testCases; http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/antlr3/PhoenixSQL.g ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/antlr3/PhoenixSQL.g b/phoenix-core/src/main/antlr3/PhoenixSQL.g index 0a4ea7a..bcf26be 100644 --- a/phoenix-core/src/main/antlr3/PhoenixSQL.g +++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g @@ -362,8 +362,9 @@ non_select_node returns [BindableStatement ret] | s=create_sequence_node | s=drop_sequence_node | s=update_statistics_node - | s=explain_node) { contextStack.pop(); $ret = s; } + | s=explain_node) { $ret = s; } ; +finally{ contextStack.pop(); } explain_node returns [BindableStatement ret] : EXPLAIN q=oneStatement {$ret=factory.explain(q);} @@ -567,8 +568,9 @@ select_node returns [SelectStatement ret] (HAVING having=expression)? (ORDER BY order=order_by)? (LIMIT l=limit)? - { ParseContext context = contextStack.pop(); $ret = factory.select(from, null, d!=null, sel, where, group, having, order, l, getBindCount(), context.isAggregate(), context.hasSequences()); } + { ParseContext context = contextStack.peek(); $ret = factory.select(from, null, d!=null, sel, where, group, having, order, l, getBindCount(), context.isAggregate(), context.hasSequences()); } ; +finally{ contextStack.pop(); } // Parse a full select expression structure. hinted_select_node returns [SelectStatement ret] http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java index 014e73a..9642489 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java @@ -101,6 +101,7 @@ public class QueryCompiler { private final ParallelIteratorFactory parallelIteratorFactory; private final SequenceManager sequenceManager; private final boolean useSortMergeJoin; + private final boolean noChildParentJoinOptimization; public QueryCompiler(PhoenixStatement statement, SelectStatement select, ColumnResolver resolver) throws SQLException { this(statement, select, resolver, Collections.<PDatum>emptyList(), null, new SequenceManager(statement)); @@ -115,6 +116,7 @@ public class QueryCompiler { this.parallelIteratorFactory = parallelIteratorFactory; this.sequenceManager = sequenceManager; this.useSortMergeJoin = select.getHint().hasHint(Hint.USE_SORT_MERGE_JOIN); + this.noChildParentJoinOptimization = select.getHint().hasHint(Hint.NO_CHILD_PARENT_JOIN_OPTIMIZATION); if (statement.getConnection().getQueryServices().getLowestClusterHBaseVersion() >= PhoenixDatabaseMetaData.ESSENTIAL_FAMILY_VERSION_THRESHOLD) { this.scan.setAttribute(LOAD_COLUMN_FAMILIES_ON_DEMAND_ATTR, QueryConstants.TRUE); } @@ -259,16 +261,14 @@ public class QueryCompiler { joinExpressions[i] = joinConditions.getFirst(); List<Expression> hashExpressions = joinConditions.getSecond(); Pair<Expression, Expression> keyRangeExpressions = new Pair<Expression, Expression>(null, null); - boolean complete = getKeyExpressionCombinations(keyRangeExpressions, context, joinTable.getStatement(), tableRef, joinSpec.getType(), joinExpressions[i], hashExpressions); + boolean optimized = getKeyExpressionCombinations(keyRangeExpressions, context, joinTable.getStatement(), tableRef, joinSpec.getType(), joinExpressions[i], hashExpressions); Expression keyRangeLhsExpression = keyRangeExpressions.getFirst(); Expression keyRangeRhsExpression = keyRangeExpressions.getSecond(); - boolean hasFilters = joinSpec.getJoinTable().hasFilters(); - boolean optimized = complete && hasFilters; joinTypes[i] = joinSpec.getType(); if (i < count - 1) { fieldPositions[i + 1] = fieldPositions[i] + (tables[i] == null ? 0 : (tables[i].getColumns().size() - tables[i].getPKColumns().size())); } - subPlans[i] = new HashSubPlan(i, joinPlan, optimized ? null : hashExpressions, joinSpec.isSingleValueOnly(), keyRangeLhsExpression, keyRangeRhsExpression, hasFilters); + subPlans[i] = new HashSubPlan(i, joinPlan, optimized ? null : hashExpressions, joinSpec.isSingleValueOnly(), keyRangeLhsExpression, keyRangeRhsExpression); } if (needsProject) { TupleProjector.serializeProjectorIntoScan(context.getScan(), initialProjectedTable.createTupleProjector()); @@ -339,7 +339,7 @@ public class QueryCompiler { HashJoinInfo joinInfo = new HashJoinInfo(projectedTable.getTable(), joinIds, new List[] {joinExpressions}, new JoinType[] {type == JoinType.Right ? JoinType.Left : type}, new boolean[] {true}, new PTable[] {lhsTable}, new int[] {fieldPosition}, postJoinFilterExpression, limit, forceProjection); Pair<Expression, Expression> keyRangeExpressions = new Pair<Expression, Expression>(null, null); getKeyExpressionCombinations(keyRangeExpressions, context, joinTable.getStatement(), rhsTableRef, type, joinExpressions, hashExpressions); - return HashJoinPlan.create(joinTable.getStatement(), rhsPlan, joinInfo, new HashSubPlan[] {new HashSubPlan(0, lhsPlan, hashExpressions, false, keyRangeExpressions.getFirst(), keyRangeExpressions.getSecond(), lhsJoin.hasFilters())}); + return HashJoinPlan.create(joinTable.getStatement(), rhsPlan, joinInfo, new HashSubPlan[] {new HashSubPlan(0, lhsPlan, hashExpressions, false, keyRangeExpressions.getFirst(), keyRangeExpressions.getSecond())}); } JoinTable lhsJoin = joinTable.getSubJoinTableWithoutPostFilters(); @@ -395,7 +395,7 @@ public class QueryCompiler { } private boolean getKeyExpressionCombinations(Pair<Expression, Expression> combination, StatementContext context, SelectStatement select, TableRef table, JoinType type, final List<Expression> joinExpressions, final List<Expression> hashExpressions) throws SQLException { - if (type != JoinType.Inner && type != JoinType.Semi) + if ((type != JoinType.Inner && type != JoinType.Semi) || this.noChildParentJoinOptimization) return false; Scan scanCopy = ScanUtil.newScan(context.getScan()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java index db2a29d..aea075d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java @@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.client.Scan; -import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.cache.ServerCacheClient.ServerCache; import org.apache.phoenix.compile.ColumnProjector; @@ -44,8 +43,6 @@ import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.compile.WhereCompiler; import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.exception.SQLExceptionInfo; -import org.apache.phoenix.expression.AndExpression; -import org.apache.phoenix.expression.ComparisonExpression; import org.apache.phoenix.expression.Determinism; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.InListExpression; @@ -58,7 +55,6 @@ import org.apache.phoenix.job.JobManager.JobCallable; import org.apache.phoenix.join.HashCacheClient; import org.apache.phoenix.join.HashJoinInfo; import org.apache.phoenix.parse.FilterableStatement; -import org.apache.phoenix.parse.HintNode.Hint; import org.apache.phoenix.parse.ParseNode; import org.apache.phoenix.parse.SQLParser; import org.apache.phoenix.parse.SelectStatement; @@ -82,8 +78,6 @@ public class HashJoinPlan extends DelegateQueryPlan { private final HashJoinInfo joinInfo; private final SubPlan[] subPlans; private final boolean recompileWhereClause; - private final boolean forceHashJoinRangeScan; - private final boolean forceHashJoinSkipScan; private List<SQLCloseable> dependencies; private HashCacheClient hashClient; private int maxServerCacheTimeToLive; @@ -115,8 +109,6 @@ public class HashJoinPlan extends DelegateQueryPlan { this.joinInfo = joinInfo; this.subPlans = subPlans; this.recompileWhereClause = recompileWhereClause; - this.forceHashJoinRangeScan = plan.getStatement().getHint().hasHint(Hint.RANGE_SCAN_HASH_JOIN); - this.forceHashJoinSkipScan = plan.getStatement().getHint().hasHint(Hint.SKIP_SCAN_HASH_JOIN); } @Override @@ -200,39 +192,14 @@ public class HashJoinPlan extends DelegateQueryPlan { } private Expression createKeyRangeExpression(Expression lhsExpression, - Expression rhsExpression, List<ImmutableBytesWritable> rhsValues, - ImmutableBytesWritable ptr, boolean hasFilters) throws SQLException { + Expression rhsExpression, List<Expression> rhsValues, + ImmutableBytesWritable ptr) throws SQLException { if (rhsValues.isEmpty()) - return LiteralExpression.newConstant(false, PBoolean.INSTANCE, Determinism.ALWAYS); + return LiteralExpression.newConstant(false, PBoolean.INSTANCE, Determinism.ALWAYS); - PDataType type = rhsExpression.getDataType(); - if (!useInClause(hasFilters)) { - ImmutableBytesWritable minValue = rhsValues.get(0); - ImmutableBytesWritable maxValue = rhsValues.get(0); - for (ImmutableBytesWritable value : rhsValues) { - if (value.compareTo(minValue) < 0) { - minValue = value; - } - if (value.compareTo(maxValue) > 0) { - maxValue = value; - } - } - - return AndExpression.create(Lists.newArrayList( - ComparisonExpression.create(CompareOp.GREATER_OR_EQUAL, Lists.newArrayList(lhsExpression, LiteralExpression.newConstant(type.toObject(minValue), type)), ptr), - ComparisonExpression.create(CompareOp.LESS_OR_EQUAL, Lists.newArrayList(lhsExpression, LiteralExpression.newConstant(type.toObject(maxValue), type)), ptr))); - } + rhsValues.add(0, lhsExpression); - List<Expression> children = Lists.newArrayList(lhsExpression); - for (ImmutableBytesWritable value : rhsValues) { - children.add(LiteralExpression.newConstant(type.toObject(value), type)); - } - - return InListExpression.create(children, false, ptr, false); - } - - private boolean useInClause(boolean hasFilters) { - return this.forceHashJoinSkipScan || (!this.forceHashJoinRangeScan && hasFilters); + return InListExpression.create(rhsValues, false, ptr); } @Override @@ -345,29 +312,26 @@ public class HashJoinPlan extends DelegateQueryPlan { private final boolean singleValueOnly; private final Expression keyRangeLhsExpression; private final Expression keyRangeRhsExpression; - private final boolean hasFilters; public HashSubPlan(int index, QueryPlan subPlan, List<Expression> hashExpressions, boolean singleValueOnly, Expression keyRangeLhsExpression, - Expression keyRangeRhsExpression, - boolean hasFilters) { + Expression keyRangeRhsExpression) { this.index = index; this.plan = subPlan; this.hashExpressions = hashExpressions; this.singleValueOnly = singleValueOnly; this.keyRangeLhsExpression = keyRangeLhsExpression; this.keyRangeRhsExpression = keyRangeRhsExpression; - this.hasFilters = hasFilters; } @Override public Object execute(HashJoinPlan parent) throws SQLException { ScanRanges ranges = parent.delegate.getContext().getScanRanges(); - List<ImmutableBytesWritable> keyRangeRhsValues = null; + List<Expression> keyRangeRhsValues = null; if (keyRangeRhsExpression != null) { - keyRangeRhsValues = Lists.<ImmutableBytesWritable>newArrayList(); + keyRangeRhsValues = Lists.<Expression>newArrayList(); } ServerCache cache = null; if (hashExpressions != null) { @@ -383,15 +347,11 @@ public class HashJoinPlan extends DelegateQueryPlan { ResultIterator iterator = plan.iterator(); for (Tuple result = iterator.next(); result != null; result = iterator.next()) { // Evaluate key expressions for hash join key range optimization. - ImmutableBytesWritable value = new ImmutableBytesWritable(); - keyRangeRhsExpression.reset(); - if (keyRangeRhsExpression.evaluate(result, value)) { - keyRangeRhsValues.add(value); - } + keyRangeRhsValues.add(HashCacheClient.evaluateKeyExpression(keyRangeRhsExpression, result, plan.getContext().getTempPtr())); } } if (keyRangeRhsValues != null) { - parent.keyRangeExpressions.add(parent.createKeyRangeExpression(keyRangeLhsExpression, keyRangeRhsExpression, keyRangeRhsValues, plan.getContext().getTempPtr(), hasFilters)); + parent.keyRangeExpressions.add(parent.createKeyRangeExpression(keyRangeLhsExpression, keyRangeRhsExpression, keyRangeRhsValues, plan.getContext().getTempPtr())); } return cache; } @@ -430,8 +390,7 @@ public class HashJoinPlan extends DelegateQueryPlan { return Collections.<String> emptyList(); String step = " DYNAMIC SERVER FILTER BY " + keyRangeLhsExpression.toString() - + (parent.useInClause(hasFilters) ? " IN " : " BETWEEN MIN/MAX OF ") - + "(" + keyRangeRhsExpression.toString() + ")"; + + " IN (" + keyRangeRhsExpression.toString() + ")"; return Collections.<String> singletonList(step); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java index 772db97..63178db 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java @@ -58,19 +58,12 @@ public class InListExpression extends BaseSingleExpression { private List<Expression> keyExpressions; // client side only public static Expression create (List<Expression> children, boolean isNegate, ImmutableBytesWritable ptr) throws SQLException { - return create(children, isNegate, ptr, true); - } - - public static Expression create (List<Expression> children, boolean isNegate, ImmutableBytesWritable ptr, boolean allowShortcut) throws SQLException { Expression firstChild = children.get(0); if (firstChild.isStateless() && (!firstChild.evaluate(null, ptr) || ptr.getLength() == 0)) { return LiteralExpression.newConstant(null, PBoolean.INSTANCE, firstChild.getDeterminism()); } - // We set allowShortcut to false for child/parent join optimization since we - // compare RVC expressions with literal expressions and we want to avoid - // RVC-rewrite operation in ComparisonExpression.create(). - if (allowShortcut && children.size() == 2) { + if (children.size() == 2) { return ComparisonExpression.create(isNegate ? CompareOp.NOT_EQUAL : CompareOp.EQUAL, children, ptr); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java b/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java index 6494603..f13b28e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java @@ -30,18 +30,22 @@ import org.apache.phoenix.cache.ServerCacheClient.ServerCache; import org.apache.phoenix.compile.ScanRanges; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.ExpressionType; +import org.apache.phoenix.expression.LiteralExpression; +import org.apache.phoenix.expression.RowValueConstructorExpression; import org.apache.phoenix.iterate.ResultIterator; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.schema.TableRef; import org.apache.phoenix.schema.tuple.Tuple; +import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.util.ServerUtil; import org.apache.phoenix.util.TrustedByteArrayOutputStream; import org.apache.phoenix.util.TupleUtil; - import org.iq80.snappy.Snappy; +import com.google.common.collect.Lists; + /** * * Client for adding cache of one side of a join to region servers @@ -70,7 +74,7 @@ public class HashCacheClient { * @throws MaxServerCacheSizeExceededException if size of hash cache exceeds max allowed * size */ - public ServerCache addHashCache(ScanRanges keyRanges, ResultIterator iterator, long estimatedSize, List<Expression> onExpressions, boolean singleValueOnly, TableRef cacheUsingTableRef, Expression keyRangeRhsExpression, List<ImmutableBytesWritable> keyRangeRhsValues) throws SQLException { + public ServerCache addHashCache(ScanRanges keyRanges, ResultIterator iterator, long estimatedSize, List<Expression> onExpressions, boolean singleValueOnly, TableRef cacheUsingTableRef, Expression keyRangeRhsExpression, List<Expression> keyRangeRhsValues) throws SQLException { /** * Serialize and compress hashCacheTable */ @@ -79,7 +83,7 @@ public class HashCacheClient { return serverCache.addServerCache(keyRanges, ptr, new HashCacheFactory(), cacheUsingTableRef); } - private void serialize(ImmutableBytesWritable ptr, ResultIterator iterator, long estimatedSize, List<Expression> onExpressions, boolean singleValueOnly, Expression keyRangeRhsExpression, List<ImmutableBytesWritable> keyRangeRhsValues) throws SQLException { + private void serialize(ImmutableBytesWritable ptr, ResultIterator iterator, long estimatedSize, List<Expression> onExpressions, boolean singleValueOnly, Expression keyRangeRhsExpression, List<Expression> keyRangeRhsValues) throws SQLException { long maxSize = serverCache.getConnection().getQueryServices().getProps().getLong(QueryServices.MAX_SERVER_CACHE_SIZE_ATTRIB, QueryServicesOptions.DEFAULT_MAX_SERVER_CACHE_SIZE); estimatedSize = Math.min(estimatedSize, maxSize); if (estimatedSize > Integer.MAX_VALUE) { @@ -98,6 +102,7 @@ public class HashCacheClient { out.writeInt(exprSize * (singleValueOnly ? -1 : 1)); int nRows = 0; out.writeInt(nRows); // In the end will be replaced with total number of rows + ImmutableBytesWritable tempPtr = new ImmutableBytesWritable(); for (Tuple result = iterator.next(); result != null; result = iterator.next()) { TupleUtil.write(result, out); if (baOut.size() > maxSize) { @@ -105,11 +110,7 @@ public class HashCacheClient { } // Evaluate key expressions for hash join key range optimization. if (keyRangeRhsExpression != null) { - ImmutableBytesWritable value = new ImmutableBytesWritable(); - keyRangeRhsExpression.reset(); - if (keyRangeRhsExpression.evaluate(result, value)) { - keyRangeRhsValues.add(value); - } + keyRangeRhsValues.add(evaluateKeyExpression(keyRangeRhsExpression, result, tempPtr)); } nRows++; } @@ -136,4 +137,45 @@ public class HashCacheClient { iterator.close(); } } + + /** + * Evaluate the RHS key expression and wrap the result as a new Expression. + * Unlike other types of Expression which will be evaluated and wrapped as a + * single LiteralExpression, RowValueConstructorExpression should be handled + * differently. We should evaluate each child of RVC and wrap them into a new + * RVC Expression, in order to make sure that the later coercion between the + * LHS key expression and this RHS key expression will be successful. + * + * @param keyExpression the RHS key expression + * @param tuple the input tuple + * @param ptr the temporary pointer + * @return the Expression containing the evaluated result + * @throws SQLException + */ + public static Expression evaluateKeyExpression(Expression keyExpression, Tuple tuple, ImmutableBytesWritable ptr) throws SQLException { + if (!(keyExpression instanceof RowValueConstructorExpression)) { + PDataType type = keyExpression.getDataType(); + keyExpression.reset(); + if (keyExpression.evaluate(tuple, ptr)) { + return LiteralExpression.newConstant(type.toObject(ptr), type); + } + + return LiteralExpression.newConstant(null, type); + } + + List<Expression> children = keyExpression.getChildren(); + List<Expression> values = Lists.newArrayListWithExpectedSize(children.size()); + for (Expression child : children) { + PDataType type = child.getDataType(); + child.reset(); + if (child.evaluate(tuple, ptr)) { + values.add(LiteralExpression.newConstant(type.toObject(ptr), type)); + } else { + values.add(LiteralExpression.newConstant(null, type)); + } + } + // The early evaluation of this constant expression is not necessary, for it + // might be coerced later. + return new RowValueConstructorExpression(values, false); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java index 7a2d313..9c5c2cd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java @@ -291,7 +291,7 @@ public class QueryOptimizer { if (extractedCondition != null) { outerWhere = FACTORY.and(Lists.newArrayList(outerWhere, extractedCondition)); } - HintNode hint = HintNode.combine(HintNode.subtract(indexSelect.getHint(), new Hint[] {Hint.INDEX, Hint.RANGE_SCAN_HASH_JOIN}), FACTORY.hint("NO_INDEX SKIP_SCAN_HASH_JOIN")); + HintNode hint = HintNode.combine(HintNode.subtract(indexSelect.getHint(), new Hint[] {Hint.INDEX, Hint.NO_CHILD_PARENT_JOIN_OPTIMIZATION}), FACTORY.hint("NO_INDEX")); SelectStatement query = FACTORY.select(dataSelect, hint, outerWhere); ColumnResolver queryResolver = FromCompiler.getResolverForQuery(query, statement.getConnection()); query = SubqueryRewriter.transform(query, queryResolver, statement.getConnection()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/1c58f442/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java index 5ee8016..94f9bfb 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java @@ -47,13 +47,9 @@ public class HintNode { */ SKIP_SCAN, /** - * Forces a range scan when full or partial primary key is used as join keys. + * Prevents the usage of child-parent-join optimization. */ - RANGE_SCAN_HASH_JOIN, - /** - * Forces a skip scan when full or partial primary key is used as join keys. - */ - SKIP_SCAN_HASH_JOIN, + NO_CHILD_PARENT_JOIN_OPTIMIZATION, /** * Prevents the usage of indexes, forcing usage * of the data table for a query.