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 <daniel.w...@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;