You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by st...@apache.org on 2023/08/01 12:59:58 UTC

[phoenix] branch master updated: PHOENIX-5833 Fix Incorrect results with RVCs and AND operator

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

stoty pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/master by this push:
     new 3e26042666 PHOENIX-5833 Fix Incorrect results with RVCs and AND operator
3e26042666 is described below

commit 3e26042666f48bb7e51b4294183b7022320fdd66
Author: Daniel Wong <da...@salesforce.com>
AuthorDate: Tue Apr 21 16:58:13 2020 -0700

    PHOENIX-5833 Fix Incorrect results with RVCs and AND operator
---
 .../phoenix/end2end/RowValueConstructorIT.java     | 41 ++++++++++++++++++++++
 .../org/apache/phoenix/compile/WhereOptimizer.java |  4 +++
 .../apache/phoenix/compile/WhereOptimizerTest.java | 34 +++++++++++++++---
 3 files changed, 75 insertions(+), 4 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 dee1792c90..270b81bb76 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
@@ -36,6 +36,7 @@ import static org.apache.phoenix.util.TestUtil.ROW7;
 import static org.apache.phoenix.util.TestUtil.ROW8;
 import static org.apache.phoenix.util.TestUtil.ROW9;
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -47,6 +48,7 @@ import java.sql.DriverManager;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.sql.Timestamp;
 import java.util.List;
 import java.util.Properties;
@@ -54,6 +56,7 @@ import java.util.Properties;
 import org.apache.phoenix.compile.ExplainPlan;
 import org.apache.phoenix.compile.ExplainPlanAttributes;
 import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
+import org.apache.phoenix.jdbc.PhoenixStatement;
 import org.apache.phoenix.util.DateUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.PropertiesUtil;
@@ -1734,6 +1737,44 @@ public class RowValueConstructorIT extends ParallelStatsDisabledIT {
         }
     }
 
+    @Test
+    public void testRVCConjunction() throws Exception {
+        try (Connection conn = DriverManager.getConnection(getUrl())){
+
+            String tableName = generateUniqueName();
+            String ddl = String.format("create table %s(a varchar(10) not null, b varchar(10) not null, c varchar(10) not null constraint pk primary key(a, b, c))",tableName);
+            String upsert = String.format("upsert into %s values(?, ?, ?)", tableName);
+
+            try( Statement statement = conn.createStatement()){
+                statement.execute(ddl);
+            }
+
+            try( PreparedStatement statement = conn.prepareStatement(upsert)){
+                statement.setString(1,"abc");
+                statement.setString(2,"def");
+                statement.setString(3,"RRSQ_IMKKL");
+                statement.executeUpdate();
+                statement.setString(3,"RRS_ZYTDT");
+                statement.executeUpdate();
+            }
+            conn.commit();
+
+            String conjunctionSelect = String.format("select A, B, C from %s where (A, B, C) > ('abc', 'def', 'RRSQ_IMKKL') AND C like 'RRS\\\\_%%'",tableName);
+            try(Statement statement = conn.createStatement(); ResultSet rs = statement.executeQuery(conjunctionSelect)) {
+                assertTrue(rs.next());
+                assertEquals("abc",rs.getString(1));
+                assertEquals("def",rs.getString(2));
+                assertEquals("RRS_ZYTDT",rs.getString(3));
+                PhoenixStatement phoenixStatement = statement.unwrap(PhoenixStatement.class);
+
+                byte[] lowerBound = phoenixStatement.getQueryPlan().getScans().get(0).get(0).getStartRow();
+                byte[] expected = new byte[] {'a','b','c',0,'d','e','f',0,'R','R','S','_'};
+                assertArrayEquals(expected,lowerBound);
+                assertFalse(rs.next());
+            }
+        }
+    }
+
     private StringBuilder generateQueryToTest(int numItemsInClause, String fullViewName) {
         StringBuilder querySb =
                 new StringBuilder("SELECT OBJECT_ID,OBJECT_DATA2,OBJECT_DATA FROM " + fullViewName);
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 21011c24b4..b7a3d0aa2d 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
@@ -1458,6 +1458,7 @@ public class WhereOptimizer {
                     return KeyRange.EMPTY_RANGE;
                 }
                 // If we're not dealing with single keys, then we can use our normal intersection
+                //   however, if we truncate a span then we need to change exclusive to inclusive
                 if (otherRange.intersect(KeyRange.getKeyRange(trailingBytes)) == KeyRange.EMPTY_RANGE) {
                     // Exit early since the upper range is the same as the lower range
                     if (result.isSingleKey()) {
@@ -1465,6 +1466,9 @@ public class WhereOptimizer {
                     }
                     ptr.set(result.getLowerRange(), 0, lowerOffset - separatorLength);
                     lowerRange = ptr.copyBytes();
+                    if(pkPos < otherPKPos && !lowerInclusive) {
+                        lowerInclusive = true;
+                    }
                 }
             }
             boolean upperInclusive = result.isUpperInclusive();
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 e46386afac..cdf14ccd9c 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
@@ -2663,7 +2663,7 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
             assertEquals(
                     Arrays.asList(
                         Arrays.asList(
-                                KeyRange.getKeyRange(PChar.INSTANCE.toBytes("A"), false, PChar.INSTANCE.toBytes("D"), true)
+                                KeyRange.getKeyRange(PChar.INSTANCE.toBytes("A"), true, PChar.INSTANCE.toBytes("D"), true)
                                 ),
                         Arrays.asList(
                                 KeyRange.getKeyRange(PChar.INSTANCE.toBytes("EE"), true, KeyRange.UNBOUND, false)
@@ -2671,7 +2671,7 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
                             ),
                      rowKeyRanges
                     );
-            assertArrayEquals(PChar.INSTANCE.toBytes("BEE"), scan.getStartRow());
+            assertArrayEquals(PChar.INSTANCE.toBytes("AEE"), scan.getStartRow());
             assertArrayEquals(PChar.INSTANCE.toBytes("E"), scan.getStopRow());
         }
     }
@@ -2726,11 +2726,37 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
             String query = "SELECT * FROM T WHERE A = 'C' and (A,B,C) > ('C','B','X') and C='C'";
             QueryPlan queryPlan = TestUtil.getOptimizeQueryPlan(conn, query);
             Scan scan = queryPlan.getContext().getScan();
-            assertArrayEquals(ByteUtil.concat(PChar.INSTANCE.toBytes("C"), PChar.INSTANCE.toBytes("C"), PChar.INSTANCE.toBytes("C")), scan.getStartRow());
+            //
+            // Note: The optimal scan boundary for the above query is ['CCC' - *), however, I don't see an easy way to fix this currently so prioritizing.  Opened JIRA PHOENIX-5885
+            assertArrayEquals(ByteUtil.concat(PChar.INSTANCE.toBytes("C"), PChar.INSTANCE.toBytes("B"), PChar.INSTANCE.toBytes("C")), scan.getStartRow());
             assertArrayEquals(PChar.INSTANCE.toBytes("D"), scan.getStopRow());
         }
     }
-    
+
+    @Test
+    public void testEqualityAndGreaterThanRVC2() throws SQLException {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+            conn.createStatement().execute("CREATE TABLE T (\n" +
+                    "    A CHAR(1) NOT NULL,\n" +
+                    "    B CHAR(1) NOT NULL,\n" +
+                    "    C CHAR(1) NOT NULL,\n" +
+                    "    D CHAR(1) NOT NULL,\n" +
+                    "    CONSTRAINT PK PRIMARY KEY (\n" +
+                    "        A,\n" +
+                    "        B,\n" +
+                    "        C,\n" +
+                    "        D\n" +
+                    "    )\n" +
+                    ")");
+            String query = "SELECT * FROM T WHERE A = 'C' and (A,B,C) > ('C','B','A') and C='C'";
+            QueryPlan queryPlan = TestUtil.getOptimizeQueryPlan(conn, query);
+            Scan scan = queryPlan.getContext().getScan();
+            assertArrayEquals(ByteUtil.concat(PChar.INSTANCE.toBytes("C"), PChar.INSTANCE.toBytes("B"), PChar.INSTANCE.toBytes("C")), scan.getStartRow());
+            assertArrayEquals(PChar.INSTANCE.toBytes("D"), scan.getStopRow());
+        }
+    }
+
     @Test
     public void testOrExpressionNonLeadingPKPushToScanBug4602() throws Exception {
         Connection conn = null;