ChinmaySKulkarni commented on a change in pull request #671: PHOENIX-4845 
Support using Row Value Constructors in OFFSET clause fo…
URL: https://github.com/apache/phoenix/pull/671#discussion_r363573432
 
 

 ##########
 File path: 
phoenix-core/src/main/java/org/apache/phoenix/compile/OffsetCompiler.java
 ##########
 @@ -62,23 +82,233 @@ public SortOrder getSortOrder() {
 
     private OffsetCompiler() {}
 
-    public static Integer compile(StatementContext context, 
FilterableStatement statement) throws SQLException {
+    // eager initialization
+    final private static OffsetCompiler OFFSET_COMPILER = getInstance();
+
+    private static OffsetCompiler getInstance() {
+        return new OffsetCompiler();
+    }
+
+    public static OffsetCompiler getOffsetCompiler() {
+        return OFFSET_COMPILER;
+    }
+
+    public CompiledOffset compile(StatementContext context, 
FilterableStatement statement) throws SQLException {
         OffsetNode offsetNode = statement.getOffset();
-        if (offsetNode == null) { return null; }
-        OffsetParseNodeVisitor visitor = new OffsetParseNodeVisitor(context);
-        offsetNode.getOffsetParseNode().accept(visitor);
-        return visitor.getOffset();
+        if (offsetNode == null) { return new 
CompiledOffset(Optional.<Integer>absent(), Optional.<byte[]>absent()); }
+        if (offsetNode.isIntegerOffset()) {
+            OffsetParseNodeVisitor visitor = new 
OffsetParseNodeVisitor(context);
+            offsetNode.getOffsetParseNode().accept(visitor);
+            Integer offset = visitor.getOffset();
+            return new CompiledOffset(Optional.fromNullable(offset), 
Optional.<byte[]>absent());
+        } else {
+            // We have a RVC offset. See PHOENIX-4845
+
+            // This is a EqualParseNode with LHS and RHS 
RowValueConstructorParseNodes
+            // This is enforced as part of the grammar
+            EqualParseNode equalParseNode = 
(EqualParseNode)offsetNode.getOffsetParseNode();
+
+            RowValueConstructorParseNode rvcColumnsParseNode = 
(RowValueConstructorParseNode)equalParseNode.getLHS();
+            RowValueConstructorParseNode rvcConstantParseNode = 
(RowValueConstructorParseNode)equalParseNode.getRHS();
+
+            // disallow use with aggregations
+            if (statement.isAggregate()) { throw new SQLException("RVC Offset 
not allowed in Aggregates"); }
+
+            // Get the tables primary keys
+            if (context.getResolver().getTables().size() != 1) {
+                throw new SQLException("RVC Offset not allowed with zero or 
multiple tables");
+            }
+
+            PTable pTable = context.getCurrentTable().getTable();
+
+            List<PColumn> columns = pTable.getPKColumns();
+
+            int numUserColumns = columns.size(); // columns specified by the 
user
+            int userColumnIndex = 0; // index into the ordered list, columns, 
of where user specified start
+
+            // if we are salted we need to take a subset of the pk
+            Integer buckets = pTable.getBucketNum();
+            if (buckets != null && buckets > 0) { // We are salted
+                numUserColumns--;
+                userColumnIndex++;
+            }
+
+            if (pTable.isMultiTenant() && pTable.getTenantId() != null) {
+                // the tenantId is one of the pks and will be handled 
automatically
+                numUserColumns--;
+                userColumnIndex++;
+            }
+
+            boolean isIndex = false;
+            if (PTableType.INDEX.equals(pTable.getType())) {
+                isIndex = true;
+                // If we are a view index we have to handle the idxId column
+                // Note that viewIndexId comes before tenantId (what about 
salt byte?)
+                if (pTable.getViewIndexId() != null) {
+                    numUserColumns--;
+                    userColumnIndex++;
+                }
+            }
+
+            // Sanity check that they are providing all the user defined keys 
to this table
+            if (numUserColumns != rvcConstantParseNode.getChildren().size()) {
+                throw new RowValueConstructorOffsetNotCoercibleException(
+                        "RVC Offset must exactly cover the tables PK.");
+            }
+
+            // Make sure the order is the same and all the user defined 
columns are mentioned in the column RVC
+            if (numUserColumns != rvcColumnsParseNode.getChildren().size()) {
+                throw new RowValueConstructorOffsetNotCoercibleException("RVC 
Offset must specify the tables PKs.");
+            }
+
+            List<ColumnParseNode> rvcColumnParseNodeList = 
this.buildListOfColumnParseNodes(rvcColumnsParseNode, isIndex);
+
+            if(rvcColumnParseNodeList.size() != numUserColumns) {
+                throw new RowValueConstructorOffsetNotCoercibleException("RVC 
Offset must specify the tables PKs.");
+            }
+
+            // We resolve the mini-where now so we can compare to tables pks 
PColumns and to produce a row offset
 
 Review comment:
   Refactor to its own method. So here, we "convert" the OFFSET syntax to a 
bunch of `PKCol1=x AND PKCol2=y AND PKCol3=z .. ` right?

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to