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

Reply via email to