PHOENIX-2014 WHERE search condition ignored when also using row value constructor in view
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/14d11b13 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/14d11b13 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/14d11b13 Branch: refs/heads/json Commit: 14d11b130ca0b3726e7724a1f4a9770bc1cb2453 Parents: 8060048 Author: James Taylor <jamestay...@apache.org> Authored: Wed Jun 17 16:58:51 2015 -0700 Committer: James Taylor <jamestay...@apache.org> Committed: Wed Jun 17 16:58:51 2015 -0700 ---------------------------------------------------------------------- .../phoenix/end2end/RowValueConstructorIT.java | 28 ++++++++++++++++++++ .../apache/phoenix/compile/WhereOptimizer.java | 25 ++++++++++------- .../phoenix/compile/WhereOptimizerTest.java | 20 ++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/14d11b13/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java index 3859785..e227eb0 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java @@ -1395,4 +1395,32 @@ public class RowValueConstructorIT extends BaseClientManagedTimeIT { assertEquals(1, numRecords); } + @Test + public void testRVCInView() throws Exception { + Connection conn = nextConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE TEST_TABLE.TEST1 (\n" + + "PK1 CHAR(3) NOT NULL, \n" + + "PK2 CHAR(3) NOT NULL,\n" + + "DATA1 CHAR(10)\n" + + "CONSTRAINT PK PRIMARY KEY (PK1, PK2))"); + conn.close(); + conn = nextConnection(getUrl()); + conn.createStatement().execute("CREATE VIEW TEST_TABLE.FOO AS SELECT * FROM TEST_TABLE.TEST1 WHERE PK1 = 'FOO'"); + conn.close(); + conn = nextConnection(getUrl()); + conn.createStatement().execute("UPSERT INTO TEST_TABLE.TEST1 VALUES('FOO','001','SOMEDATA')"); + conn.createStatement().execute("UPSERT INTO TEST_TABLE.TEST1 VALUES('FOO','002','SOMEDATA')"); + conn.createStatement().execute("UPSERT INTO TEST_TABLE.TEST1 VALUES('FOO','003','SOMEDATA')"); + conn.createStatement().execute("UPSERT INTO TEST_TABLE.TEST1 VALUES('FOO','004','SOMEDATA')"); + conn.createStatement().execute("UPSERT INTO TEST_TABLE.TEST1 VALUES('FOO','005','SOMEDATA')"); + conn.commit(); + conn.close(); + + conn = nextConnection(getUrl()); + ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM TEST_TABLE.FOO WHERE PK2 < '004' AND (PK1,PK2) > ('FOO','002') LIMIT 2"); + assertTrue(rs.next()); + assertEquals("003", rs.getString("PK2")); + assertFalse(rs.next()); + conn.close(); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/14d11b13/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java index a5aef02..b7f04e0 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java @@ -647,23 +647,30 @@ public class WhereOptimizer { if (childSlot == EMPTY_KEY_SLOTS) { return EMPTY_KEY_SLOTS; } - // FIXME: get rid of this min/max range BS now that a key range can span multiple columns + // FIXME: get rid of this special-cased min/max range now that a key range can span multiple columns if (childSlot.getMinMaxRange() != null) { // Only set if in initial pk position - // TODO: potentially use KeySlot.intersect here. However, we can't intersect the key ranges in the slot - // with our minMaxRange, since it spans columns and this would mess up our skip scan. + // TODO: fix intersectSlots so that it works with RVCs. We'd just need to fill in the leading parts + // of the key with the minMaxRange and then intersect the key parts that overlap. minMaxRange = minMaxRange.intersect(childSlot.getMinMaxRange()); for (KeySlot slot : childSlot) { if (slot != null) { - minMaxExtractNodes.addAll(slot.getKeyPart().getExtractNodes()); + // We can only definitely extract the expression nodes that start from the + // leading PK column. They may get extracted at the end if we end up having + // expressions matching the leading PK columns, but otherwise we'll be forced + // to execute the expression in a filter. + if (slot.getPKPosition() == initPosition) { + minMaxExtractNodes.addAll(slot.getKeyPart().getExtractNodes()); + } else { + if (!intersectSlots(keySlot, slot)) { + return EMPTY_KEY_SLOTS; + } + } } } } else { for (KeySlot slot : childSlot) { - // We have a nested AND with nothing for this slot, so continue - if (slot == null) { - continue; - } - if (!intersectSlots(keySlot, slot)) { + // The slot will be null if we have no condition for this slot + if (slot != null && !intersectSlots(keySlot, slot)) { return EMPTY_KEY_SLOTS; } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/14d11b13/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java index f40afc3..adbd9a2 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java @@ -1780,6 +1780,26 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest { PChar.INSTANCE.toBytes(entityId2), 15)), k2.getLowerRange()); } + + @Test + public void testRVCInView() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + conn.createStatement().execute("CREATE TABLE TEST_TABLE.TEST1 (\n" + + "PK1 CHAR(3) NOT NULL, \n" + + "PK2 CHAR(3) NOT NULL,\n" + + "DATA1 CHAR(10)\n" + + "CONSTRAINT PK PRIMARY KEY (PK1, PK2))"); + conn.createStatement().execute("CREATE VIEW TEST_TABLE.FOO AS SELECT * FROM TEST_TABLE.TEST1 WHERE PK1 = 'FOO'"); + String query = "SELECT * FROM TEST_TABLE.FOO WHERE PK2 < '004' AND (PK1,PK2) > ('FOO','002') LIMIT 2"; + Scan scan = compileStatement(query, Collections.emptyList(), 2).getScan(); + byte[] startRow = ByteUtil.nextKey(ByteUtil.concat(PChar.INSTANCE.toBytes("FOO"), + PVarchar.INSTANCE.toBytes("002"))); + assertArrayEquals(startRow, scan.getStartRow()); + byte[] stopRow = ByteUtil.concat(PChar.INSTANCE.toBytes("FOO"), + PChar.INSTANCE.toBytes("004")); + assertArrayEquals(stopRow, scan.getStopRow()); + } + private static StatementContext compileStatementTenantSpecific(String tenantId, String query, List<Object> binds) throws Exception { PhoenixConnection pconn = getTenantSpecificConnection("tenantId").unwrap(PhoenixConnection.class); PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);