You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by go...@apache.org on 2022/03/04 00:49:10 UTC

[phoenix] branch 4.x updated: PHOENIX-6659 RVC query fix for variable column + fixed column

This is an automated email from the ASF dual-hosted git repository.

gokcen pushed a commit to branch 4.x
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/4.x by this push:
     new 425bfe8  PHOENIX-6659 RVC query fix for variable column + fixed column
425bfe8 is described below

commit 425bfe878bd54dfd359c7675f6fb5014f3b88082
Author: Gokcen Iskender <gi...@salesforce.com>
AuthorDate: Wed Mar 2 19:30:11 2022 -0800

    PHOENIX-6659 RVC query fix for variable column + fixed column
    
    Signed-off-by: Gokcen Iskender <go...@gmail.com>
---
 .../phoenix/end2end/RowValueConstructorIT.java     |  2 +-
 .../apache/phoenix/end2end/SkipScanQueryIT.java    | 97 ++++++++++++++++++++++
 .../org/apache/phoenix/compile/WhereOptimizer.java | 13 +--
 3 files changed, 106 insertions(+), 6 deletions(-)

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 f03e436..47d6327 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
@@ -369,7 +369,7 @@ public class RowValueConstructorIT extends ParallelStatsDisabledIT {
                 count++;
             }
             // we have key values (7,5) (8,4) and (9,3) present in aTable. So the query should return the 3 records.
-            assertTrue(count == 3); 
+            assertEquals(3, count);
         } finally {
             conn.close();
         }
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SkipScanQueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SkipScanQueryIT.java
index db9d23c..69b0b44 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SkipScanQueryIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SkipScanQueryIT.java
@@ -41,8 +41,10 @@ import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.filter.Filter;
 import org.apache.hadoop.hbase.filter.FilterList;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.compile.ExplainPlan;
 import org.apache.phoenix.compile.QueryPlan;
 import org.apache.phoenix.filter.SkipScanFilter;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
 import org.apache.phoenix.jdbc.PhoenixStatement;
 import org.apache.phoenix.util.TestUtil;
 import org.apache.phoenix.util.SchemaUtil;
@@ -716,6 +718,101 @@ public class SkipScanQueryIT extends ParallelStatsDisabledIT {
     }
 
     @Test
+    public void testRVCBug6659() throws Exception {
+        String tableName = generateUniqueName();
+        String ddl = "CREATE TABLE " + tableName + " (PK1 VARCHAR NOT NULL, PK2 INTEGER NOT NULL, " +
+                "PK3 BIGINT NOT NULL CONSTRAINT PK PRIMARY KEY (PK1,PK2,PK3))";
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',0,1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',1,1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',2,1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',3,1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',3,2)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a',4,1)");
+            conn.commit();
+            String query = "SELECT * FROM " + tableName +
+                    " WHERE (PK1 = 'a') AND (PK1,PK2,PK3) <= ('a',3,1)";
+            ResultSet rs = conn.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            int rowCnt = 0;
+            do {
+                rowCnt++;
+            } while (rs.next());
+            assertEquals(4, rowCnt);
+        }
+    }
+
+    @Test
+    public void testRVCBug6659_Delete() throws Exception {
+        String tableName = generateUniqueName();
+        String ddl = "CREATE TABLE " + tableName + " (PK1 DOUBLE NOT NULL, PK2 INTEGER NOT NULL, " +
+                " CONSTRAINT PK PRIMARY KEY (PK1,PK2))";
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(10.0,10)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(20.0,20)");
+            conn.commit();
+            String query = "DELETE FROM " + tableName +
+                    " WHERE (PK1,PK2) IN ((10.0, 10),(20.0, 20))";
+            conn.createStatement().execute(query);
+            conn.commit();
+            ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName);
+            assertFalse(rs.next());
+        }
+    }
+
+    @Test
+    public void testRVCBug6659_AllVarchar() throws Exception {
+        String tableName = generateUniqueName();
+        String ddl = "CREATE TABLE " + tableName + " (PK1 VARCHAR NOT NULL, PK2 VARCHAR NOT NULL, " +
+                "PK3 BIGINT NOT NULL CONSTRAINT PK PRIMARY KEY (PK1,PK2,PK3))";
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a','0',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a','1',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a','3',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a','3',2)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('a','4',1)");
+            conn.commit();
+            String query = "SELECT * FROM " + tableName +
+                    " WHERE (PK1 = 'a') AND (PK1,PK2,PK3) <= ('a','3',1)";
+            ResultSet rs = conn.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            int rowCnt = 0;
+            do {
+                rowCnt++;
+            } while (rs.next());
+            assertEquals(3, rowCnt);
+        }
+    }
+
+    @Test
+    public void testRVCBug6659_IntVarcharBigint() throws Exception {
+        String tableName = generateUniqueName();
+        String ddl = "CREATE TABLE " + tableName + " (PK1 INTEGER NOT NULL, PK2 VARCHAR NOT NULL, " +
+                "PK3 BIGINT NOT NULL CONSTRAINT PK PRIMARY KEY (PK1,PK2,PK3))";
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1,'0',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1,'1',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1,'3',1)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1,'3',2)");
+            conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1,'4',1)");
+            conn.commit();
+            String query = "SELECT * FROM " + tableName +
+                    " WHERE (PK1 = 1) AND (PK1,PK2,PK3) <= (1,'3',1)";
+            ResultSet rs = conn.createStatement().executeQuery(query);
+            assertTrue(rs.next());
+            int rowCnt = 0;
+            do {
+                rowCnt++;
+            } while (rs.next());
+            assertEquals(3, rowCnt);
+        }
+    }
+
+    @Test
     public void testKeyRangesContainsAllValues() throws Exception {
         String tableName = generateUniqueName();
         String ddl = "CREATE TABLE IF NOT EXISTS " + tableName + "(" +
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 65bbbfd..e0f5da3 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
@@ -29,6 +29,7 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
+import org.apache.phoenix.expression.DelegateExpression;
 import org.apache.phoenix.thirdparty.com.google.common.base.Optional;
 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -361,8 +362,10 @@ public class WhereOptimizer {
         }
     }
     
-    private static KeyRange getTrailingRange(RowKeySchema rowKeySchema, int pkPos, KeyRange range, KeyRange clippedResult, ImmutableBytesWritable ptr) {
-        int separatorLength = rowKeySchema.getField(pkPos).getDataType().isFixedWidth() ? 0 : 1;
+    private static KeyRange getTrailingRange(RowKeySchema rowKeySchema, int clippedPkPos, KeyRange range, KeyRange clippedResult, ImmutableBytesWritable ptr) {
+        // We are interested in the clipped part's Seperator. Since we combined first part, we need to
+        // remove its separator from the trailing parts' start
+        int clippedSepLength= rowKeySchema.getField(clippedPkPos).getDataType().isFixedWidth() ? 0 : 1;
         byte[] lowerRange = KeyRange.UNBOUND;
         boolean lowerInclusive = false;
         // Lower range of trailing part of RVC must be true, so we can form a new range to intersect going forward
@@ -370,7 +373,7 @@ public class WhereOptimizer {
                 && range.getLowerRange().length > clippedResult.getLowerRange().length
                 && Bytes.startsWith(range.getLowerRange(), clippedResult.getLowerRange())) {
             lowerRange = range.getLowerRange();
-            int offset = clippedResult.getLowerRange().length + separatorLength;
+            int offset = clippedResult.getLowerRange().length + clippedSepLength;
             ptr.set(lowerRange, offset, lowerRange.length - offset);
             lowerRange = ptr.copyBytes();
             lowerInclusive = range.isLowerInclusive();
@@ -381,7 +384,7 @@ public class WhereOptimizer {
                 && range.getUpperRange().length > clippedResult.getUpperRange().length
                 && Bytes.startsWith(range.getUpperRange(), clippedResult.getUpperRange())) {
             upperRange = range.getUpperRange();
-            int offset = clippedResult.getUpperRange().length + separatorLength;
+            int offset = clippedResult.getUpperRange().length + clippedSepLength;
             ptr.set(upperRange, offset, upperRange.length - offset);
             upperRange = ptr.copyBytes();
             upperInclusive = range.isUpperInclusive();
@@ -1307,7 +1310,7 @@ public class WhereOptimizer {
                 // code doesn't work correctly for WhereOptimizerTest.testMultiSlotTrailingIntersect()
                 if (result.isSingleKey() && !(range.isSingleKey() && otherRange.isSingleKey())) {
                     int trailingPkPos = pkPos + Math.min(minSpan, otherMinSpan);
-                    KeyRange trailingRange = getTrailingRange(rowKeySchema, trailingPkPos, minSpan > otherMinSpan ? range : otherRange, result, ptr);
+                    KeyRange trailingRange = getTrailingRange(rowKeySchema, pkPos, minSpan > otherMinSpan ? range : otherRange, result, ptr);
                     trailingRanges[trailingPkPos] = trailingRanges[trailingPkPos].intersect(trailingRange);
                 } else {
                     // Add back clipped part of range