PHOENIX-1397 RVC combined with OR on first row key column results in NPE (Samarth Jain)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/27a52ad2 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/27a52ad2 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/27a52ad2 Branch: refs/heads/4.2 Commit: 27a52ad2cfed50bd1396a5007114d8bf2e3a0a36 Parents: c2e4e0c Author: James Taylor <[email protected]> Authored: Tue Nov 4 20:52:14 2014 -0800 Committer: James Taylor <[email protected]> Committed: Tue Nov 4 22:52:45 2014 -0800 ---------------------------------------------------------------------- .../phoenix/end2end/RowValueConstructorIT.java | 69 ++++++++++++++++++++ .../apache/phoenix/compile/WhereOptimizer.java | 21 +++--- 2 files changed, 82 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/27a52ad2/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 bf3d9db..9e3a5b0 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 @@ -1280,5 +1280,74 @@ public class RowValueConstructorIT extends BaseClientManagedTimeIT { conn.close(); } } + + // query against non-multitenant table. Salted - yes + @Test + public void testComparisonAgainstRVCCombinedWithOrAnd_1() throws Exception { + String tableDDL = "CREATE TABLE RVC1 (tenantId char(15) NOT NULL, pk2 char(15) NOT NULL, pk3 INTEGER NOT NULL, c1 INTEGER constraint pk primary key (tenantId,pk2,pk3)) SALT_BUCKETS = 4"; + createTestTable(getUrl(), tableDDL, null, nextTimestamp()); + + Connection conn = nextConnection(getUrl()); + conn.createStatement().executeUpdate("upsert into RVC1 (tenantId, pk2, pk3, c1) values ('ABC', 'helo1', 1, 1)"); + conn.createStatement().executeUpdate("upsert into RVC1 (tenantId, pk2, pk3, c1) values ('ABC', 'helo2', 2, 2)"); + conn.createStatement().executeUpdate("upsert into RVC1 (tenantId, pk2, pk3, c1) values ('DEF', 'helo3', 3, 3)"); + conn.commit(); + conn.close(); + + conn = nextConnection(getUrl()); + PreparedStatement stmt = conn.prepareStatement("select pk2, pk3 from RVC1 WHERE (tenantId = ? OR tenantId = ?) AND (tenantId, pk2, pk3) > (?, ?, ?) LIMIT 100"); + stmt.setString(1, "ABC"); + stmt.setString(2, "DEF"); + + // give back all rows after row 1 - ABC|helo1|1 + stmt.setString(3, "ABC"); + stmt.setString(4, "helo1"); + stmt.setInt(5, 1); + + ResultSet rs = stmt.executeQuery(); + assertTrue(rs.next()); + assertEquals("helo2", rs.getString(1)); + assertEquals(2, rs.getInt(2)); + assertTrue(rs.next()); + assertEquals("helo3", rs.getString(1)); + assertEquals(3, rs.getInt(2)); + assertFalse(rs.next()); + } + + // query against tenant specific view. Salted base table. + @Test + public void testComparisonAgainstRVCCombinedWithOrAnd_2() throws Exception { + String tenantId = "ABC"; + String tenantSpecificUrl = getUrl() + ";" + PhoenixRuntime.TENANT_ID_ATTRIB + '=' + tenantId; + String baseTableDDL = "CREATE TABLE RVC2 (tenant_id char(15) NOT NULL, pk2 char(15) NOT NULL, pk3 INTEGER NOT NULL, c1 INTEGER constraint pk primary key (tenant_id,pk2,pk3)) MULTI_TENANT=true, SALT_BUCKETS = 4"; + createTestTable(getUrl(), baseTableDDL, null, nextTimestamp()); + String tenantTableDDL = "CREATE VIEW t_view AS SELECT * FROM RVC2"; + createTestTable(tenantSpecificUrl, tenantTableDDL, null, nextTimestamp()); + + Connection conn = nextConnection(tenantSpecificUrl); + conn.createStatement().executeUpdate("upsert into t_view (pk2, pk3, c1) values ('helo1', 1, 1)"); + conn.createStatement().executeUpdate("upsert into t_view (pk2, pk3, c1) values ('helo2', 2, 2)"); + conn.createStatement().executeUpdate("upsert into t_view (pk2, pk3, c1) values ('helo3', 3, 3)"); + conn.commit(); + conn.close(); + + conn = nextConnection(tenantSpecificUrl); + PreparedStatement stmt = conn.prepareStatement("select pk2, pk3 from t_view WHERE (pk2 = ? OR pk2 = ?) AND (pk2, pk3) > (?, ?) LIMIT 100"); + stmt.setString(1, "helo1"); + stmt.setString(2, "helo3"); + + // return rows after helo1|1 + stmt.setString(3, "helo1"); + stmt.setInt(4, 1); + + ResultSet rs = stmt.executeQuery(); + assertTrue(rs.next()); + assertEquals("helo3", rs.getString(1)); + assertEquals(3, rs.getInt(2)); + assertFalse(rs.next()); + conn.close(); + } + + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/27a52ad2/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 5803bd2..6a46a7b 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 @@ -105,6 +105,14 @@ public class WhereOptimizer { Expression whereClause, Set<Expression> extractNodes) { PName tenantId = context.getConnection().getTenantId(); PTable table = context.getCurrentTable().getTable(); + Integer nBuckets = table.getBucketNum(); + boolean isSalted = nBuckets != null; + RowKeySchema schema = table.getRowKeySchema(); + boolean isMultiTenant = tenantId != null && table.isMultiTenant(); + if (isMultiTenant) { + tenantId = ScanUtil.padTenantIdIfNecessary(schema, isSalted, tenantId); + } + if (whereClause == null && (tenantId == null || !table.isMultiTenant()) && table.getViewIndexId() == null) { context.setScanRanges(ScanRanges.EVERYTHING); return whereClause; @@ -145,8 +153,6 @@ public class WhereOptimizer { int nPKColumns = table.getPKColumns().size(); int[] slotSpan = new int[nPKColumns]; List<Expression> removeFromExtractNodes = null; - Integer nBuckets = table.getBucketNum(); - RowKeySchema schema = table.getRowKeySchema(); List<List<KeyRange>> cnf = Lists.newArrayListWithExpectedSize(schema.getMaxFields()); KeyRange minMaxRange = keySlots.getMinMaxRange(); if (minMaxRange == null) { @@ -155,8 +161,6 @@ public class WhereOptimizer { boolean hasMinMaxRange = (minMaxRange != KeyRange.EVERYTHING_RANGE); int minMaxRangeOffset = 0; byte[] minMaxRangePrefix = null; - boolean isSalted = nBuckets != null; - boolean isMultiTenant = tenantId != null && table.isMultiTenant(); boolean hasViewIndex = table.getViewIndexId() != null; if (hasMinMaxRange) { int minMaxRangeSize = (isSalted ? SaltingUtil.NUM_SALTING_BYTES : 0) @@ -181,7 +185,6 @@ public class WhereOptimizer { // Add tenant data isolation for tenant-specific tables if (isMultiTenant) { - tenantId = ScanUtil.padTenantIdIfNecessary(schema, isSalted, tenantId); byte[] tenantIdBytes = tenantId.getBytes(); KeyRange tenantIdKeyRange = KeyRange.getKeyRange(tenantIdBytes); cnf.add(singletonList(tenantIdKeyRange)); @@ -703,9 +706,11 @@ public class WhereOptimizer { minMaxRange = minMaxRange.union(childSlot.getMinMaxRange()); thePosition = initialPos; for (KeySlot slot : childSlot) { - List<Expression> extractNodes = slot.getKeyPart().getExtractNodes(); - extractAll &= !extractNodes.isEmpty(); - slotExtractNodes.addAll(extractNodes); + if (slot != null) { + List<Expression> extractNodes = slot.getKeyPart().getExtractNodes(); + extractAll &= !extractNodes.isEmpty(); + slotExtractNodes.addAll(extractNodes); + } } } else { // TODO: Do the same optimization that we do for IN if the childSlots specify a fully qualified row key
