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_r363573547
 
 

 ##########
 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
+            // Construct a mini where clause
+            ParseNode miniWhere = equalParseNode;
+
+            Set<HintNode.Hint> originalHints = statement.getHint().getHints();
+            WhereCompiler.WhereExpressionCompiler whereCompiler = new 
WhereCompiler.WhereExpressionCompiler(context);
+
+            Expression whereExpression = miniWhere.accept(whereCompiler);
+
+            Expression expression = 
WhereOptimizer.pushKeyExpressionsToScan(context, originalHints, whereExpression,
+                    null, Optional.<byte[]>absent());
+            if (expression == null) {
+                LOGGER.error("Unexpected error while compiling RVC Offset, got 
null expression.");
+                throw new RowValueConstructorOffsetNotCoercibleException("RVC 
Offset unexpected failure.");
+            }
+
+            // Now that columns etc have been resolved lets check to make sure 
they match the pk order
+            // Today the RowValueConstuctor Equality gets Rewritten into AND 
of EQ Ops.
+            if (!(whereExpression instanceof AndExpression)) {
+                LOGGER.warn("Unexpected error while compiling RVC Offset, 
expected AndExpression got " + whereExpression.getClass().getName());
+                throw new RowValueConstructorOffsetNotCoercibleException("RVC 
Offset must specify the tables PKs.");
+            }
+
+            List<RowKeyColumnExpression> rowKeyColumnExpressionList = 
buildListOfRowKeyColumnExpressions(whereExpression.getChildren(),isIndex);
+            if(rowKeyColumnExpressionList.size() != numUserColumns) {
+                LOGGER.warn("Unexpected error while compiling RVC Offset, 
expected " + numUserColumns + " found " + rowKeyColumnExpressionList.size());
+                throw new RowValueConstructorOffsetNotCoercibleException("RVC 
Offset must specify the table's PKs.");
+            }
+
+            for (int i = 0; i < numUserColumns; i++) {
+                PColumn column = columns.get(i + userColumnIndex);
+                //
 
 Review comment:
   Missing comment

----------------------------------------------------------------
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