You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ya...@apache.org on 2020/07/17 04:42:38 UTC

[phoenix] branch master updated: PHOENIX-5924 RVC Offset does not handle variable length fields exclusive scan boundary correctly

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

yanxinyi 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 28eb698  PHOENIX-5924 RVC Offset does not handle variable length fields exclusive scan boundary correctly
28eb698 is described below

commit 28eb6980a668dc3d98d387692aedf7bec863b6c7
Author: Daniel Wong <da...@salesforce.com>
AuthorDate: Thu Jul 16 18:21:37 2020 -0700

    PHOENIX-5924 RVC Offset does not handle variable length fields exclusive scan boundary correctly
    
    Signed-off-by: Xinyi Yan <xy...@salesforce.com>
---
 .../end2end/RowValueConstructorOffsetIT.java       | 39 ++++++++++++++++++++++
 .../apache/phoenix/compile/RVCOffsetCompiler.java  | 27 +++++++++++++--
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorOffsetIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorOffsetIT.java
index b91997b..38d4557 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorOffsetIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorOffsetIT.java
@@ -30,6 +30,8 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 
 import org.apache.phoenix.compile.QueryPlan;
@@ -1011,4 +1013,41 @@ public class RowValueConstructorOffsetIT extends ParallelStatsDisabledIT {
         }
     }
 
+    @Test
+    public void rvcOffsetTrailingVariableLengthKeyTest() throws Exception {
+        String TEST_DDL = "CREATE TABLE IF NOT EXISTS TEST_SCHEMA (\n"
+                + " ORGANIZATION_ID VARCHAR(15), \n" + " TEST_ID VARCHAR(15), \n"
+                + " CREATED_DATE DATE, \n" + " LAST_UPDATE DATE\n"
+                + " CONSTRAINT TEST_SCHEMA_PK PRIMARY KEY (ORGANIZATION_ID, TEST_ID) \n" + ")";
+
+        try (Statement statement = conn.createStatement()) {
+            statement.execute(TEST_DDL);
+        }
+        //setup
+        List<String> upserts = new ArrayList<>();
+        upserts.add("UPSERT INTO TEST_SCHEMA(ORGANIZATION_ID,TEST_ID) VALUES ('1','1')");
+        upserts.add("UPSERT INTO TEST_SCHEMA(ORGANIZATION_ID,TEST_ID) VALUES ('1','10')");
+        upserts.add("UPSERT INTO TEST_SCHEMA(ORGANIZATION_ID,TEST_ID) VALUES ('2','2')");
+
+        for(String sql : upserts) {
+            try (Statement statement = conn.createStatement())
+
+            { statement.execute(sql); }
+        }
+
+        conn.commit();
+
+        String query = "SELECT * FROM TEST_SCHEMA OFFSET (ORGANIZATION_ID,TEST_ID) = ('1','1')";
+
+        try (Statement statement = conn.createStatement() ; ResultSet rs2 = statement.executeQuery(query) ) {
+            assertTrue(rs2.next());
+            assertEquals("1",rs2.getString(1));
+            assertEquals("10",rs2.getString(2));
+            assertTrue(rs2.next());
+            assertEquals("2",rs2.getString(1));
+            assertEquals("2",rs2.getString(2));
+            assertFalse(rs2.next());
+        }
+    }
+
 }
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/RVCOffsetCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/RVCOffsetCompiler.java
index cc1cbe6..e665e3d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/RVCOffsetCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/RVCOffsetCompiler.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.compile;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.phoenix.expression.AndExpression;
 import org.apache.phoenix.expression.CoerceExpression;
@@ -37,12 +38,13 @@ import org.apache.phoenix.query.KeyRange;
 import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.RowKeySchema;
 import org.apache.phoenix.schema.RowValueConstructorOffsetInternalErrorException;
 import org.apache.phoenix.schema.RowValueConstructorOffsetNotAllowedInQueryException;
 import org.apache.phoenix.schema.RowValueConstructorOffsetNotCoercibleException;
 import org.apache.phoenix.schema.TypeMismatchException;
-import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.IndexUtil;
+import org.apache.phoenix.util.ScanUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -251,11 +253,32 @@ public class RVCOffsetCompiler {
                     "RVC Offset must be a point lookup.");
         }
 
+
+        RowKeySchema.RowKeySchemaBuilder builder = new RowKeySchema.RowKeySchemaBuilder(columns.size());
+
+        for(PColumn column : columns) {
+            builder.addField(column, column.isNullable(), column.getSortOrder());
+        }
+
+        RowKeySchema rowKeySchema = builder.build();
+
+        //we make a ScanRange with 1 keyslots that cover the entire PK to reuse the code
+        KeyRange pointKeyRange = scanRanges.getScanRange();
+        KeyRange keyRange = KeyRange.getKeyRange(pointKeyRange.getLowerRange(), false, KeyRange.UNBOUND, true);
+        List<KeyRange> myRangeList = Lists.newArrayList(keyRange);
+        List<List<KeyRange>> slots = new ArrayList<>();
+        slots.add(myRangeList);
+        int[] slotSpan = new int[1];
+
+        //subtract 1 see ScanUtil.SINGLE_COLUMN_SLOT_SPAN is 0
+        slotSpan[0] = columns.size() - 1;
+        byte[] key = ScanUtil.getMinKey(rowKeySchema,slots,slotSpan);
+
         // Note the use of ByteUtil.nextKey() to generate exclusive offset
         CompiledOffset
                 compiledOffset =
                 new CompiledOffset(Optional.<Integer>absent(),
-                        Optional.of(ByteUtil.nextKey(scanRanges.getScanRange().getLowerRange())));
+                        Optional.of(key));
 
         return compiledOffset;
     }