[ 
https://issues.apache.org/jira/browse/PHOENIX-7032?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17772085#comment-17772085
 ] 

ASF GitHub Bot commented on PHOENIX-7032:
-----------------------------------------

ranganathg commented on code in PR #1701:
URL: https://github.com/apache/phoenix/pull/1701#discussion_r1346828959


##########
phoenix-core/src/main/java/org/apache/phoenix/compile/CreateIndexCompiler.java:
##########
@@ -45,11 +59,92 @@ public CreateIndexCompiler(PhoenixStatement statement, 
Operation operation) {
         this.operation = operation;
     }
 
+
+    private static class IndexWhereParseNodeVisitor extends 
StatelessTraverseAllParseNodeVisitor {
+        private boolean  hasSubquery = false;
+
+        @Override
+        public Void visit(SubqueryParseNode node) throws SQLException {
+            hasSubquery = true;
+            return null;
+        }
+    }
+    private String getValue(PDataType type) {
+        if (type instanceof PNumericType || type instanceof PTimestamp ||
+                type instanceof PUnsignedTime) {
+            return "0";
+        } else if (type instanceof PChar || type instanceof PVarchar) {
+            return "'a'";
+        } else if (type instanceof PDate || type instanceof PTime) {
+            return (new Date(System.currentTimeMillis())).toString();
+        } else {
+            return "0x00";
+        }
+    }
+    private void verifyIndexWhere(ParseNode indexWhere, StatementContext 
context,
+            TableName dataTableName) throws SQLException {
+        if (indexWhere == null) {
+            return;
+        }
+        PhoenixConnection connection = context.getConnection();
+        IndexWhereParseNodeVisitor indexWhereParseNodeVisitor = new 
IndexWhereParseNodeVisitor();
+        indexWhere.accept(indexWhereParseNodeVisitor);
+        if (indexWhereParseNodeVisitor.hasSubquery) {
+            throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_INDEX_WHERE_WITH_SUBQUERY).
+                    build().buildException();
+        }
+        ExpressionCompiler expressionCompiler = new 
ExpressionCompiler(context);
+        Expression indexWhereExpression = 
indexWhere.accept(expressionCompiler);
+        PTable dataTable = PhoenixRuntime.getTable(connection, 
dataTableName.toString());
+
+        boolean autoCommit = connection.getAutoCommit();
+        connection.setAutoCommit(false);
+        StringBuilder stringBuilder = new StringBuilder("UPSERT INTO ");
+        stringBuilder.append(dataTableName);
+        stringBuilder.append(" Values(");
+        int i = dataTable.getBucketNum() != null ? 1 : 0;
+        for (; i < dataTable.getColumns().size() - 1; i++) {
+            PDataType dataType = dataTable.getColumns().get(i).getDataType();
+            stringBuilder.append(getValue(dataType) + ",");
+        }
+        PDataType dataType = dataTable.getColumns().get(i).getDataType();
+        stringBuilder.append(getValue(dataType)+ ")");
+        PreparedStatement ps = 
context.getConnection().prepareStatement(stringBuilder.toString());
+        ps.execute();
+        Iterator<Pair<byte[],List<Cell>>> dataTableNameAndMutationIterator =
+                PhoenixRuntime.getUncommittedDataIterator(connection);
+        Pair<byte[], List<Cell>> dataTableNameAndMutation = null;
+        while (dataTableNameAndMutationIterator.hasNext()) {
+            dataTableNameAndMutation = dataTableNameAndMutationIterator.next();
+            if (!java.util.Arrays.equals(dataTableNameAndMutation.getFirst(),
+                    dataTableName.toString().getBytes())) {
+                dataTableNameAndMutation = null;
+            }
+        }
+        if (dataTableNameAndMutation == null) {
+            ps.close();
+            connection.setAutoCommit(autoCommit);
+            throw new RuntimeException("Unexpected result from " +
+                    "PhoenixRuntime#getUncommittedDataIterator for " + 
dataTableName);
+        }
+        ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+        ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+        MultiKeyValueTuple tuple = new 
MultiKeyValueTuple(dataTableNameAndMutation.getSecond());
+        if (!indexWhereExpression.evaluate(tuple, ptr)) {
+            ps.close();
+            connection.setAutoCommit(autoCommit);
+            throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_EVALUATE_INDEX_WHERE).
+                    build().buildException();
+        }
+        ps.close();
+        connection.setAutoCommit(autoCommit);

Review Comment:
   would it be good put this code in a try/finally block?





> Partial Global Secondary Indexes
> --------------------------------
>
>                 Key: PHOENIX-7032
>                 URL: https://issues.apache.org/jira/browse/PHOENIX-7032
>             Project: Phoenix
>          Issue Type: New Feature
>            Reporter: Kadir Ozdemir
>            Assignee: Kadir Ozdemir
>            Priority: Major
>
> The secondary indexes supported in Phoenix have been full indexes such that 
> for every data table row there is an index row. Generating an index row for 
> every data table row is not always required. For example, some use cases do 
> not require index rows for the data table rows in which indexed column values 
> are null. Such indexes are called sparse indexes. Partial indexes generalize 
> the concept of sparse indexing and allow users to specify the subset of the 
> data table rows for which index rows will be maintained. This subset is 
> specified using a WHERE clause added to the CREATE INDEX DDL statement.
> Partial secondary indexes were first proposed by Michael Stonebraker 
> [here|https://dsf.berkeley.edu/papers/ERL-M89-17.pdf]. Since then several SQL 
> databases (e.g., 
> [Postgres|https://www.postgresql.org/docs/current/indexes-partial.html] and 
> [SQLite|https://www.sqlite.org/partialindex.html])  and NoSQL databases 
> (e.g., [MongoDB|https://www.mongodb.com/docs/manual/core/index-partial/]) 
> have supported some form of partial indexes. It is challenging to allow 
> arbitrary WHERE clauses in DDL statements. For example, Postgres does not 
> allow subqueries in these where clauses and SQLite supports much more 
> restrictive where clauses. 
> Supporting arbitrary where clauses creates challenges for query optimizers in 
> deciding the usability of a partial index for a given query. If the set of 
> data table rows that satisfy the query is a subset of the data table rows 
> that the partial index points back, then the query can use the index. Thus, 
> the query optimizer has to decide if the WHERE clause of the query implies 
> the WHERE clause of the index. 
> Michael Stonebraker [here|https://dsf.berkeley.edu/papers/ERL-M89-17.pdf] 
> suggests that an index WHERE clause is a conjunct of simple terms, i.e: 
> i-clause-1 and i-clause-2 and ... and i-clause-m where each clause is of the 
> form <column> <operator> <constant>. Hence, the qualification can be 
> evaluated for each tuple in the indicated relation without consulting 
> additional tuples. 
> Phoenix partial indexes will initially support a more general set of index 
> WHERE clauses that can be evaluated on a single row with the following 
> exceptions
>  * Subqueries are not allowed.
>  * Like expressions are allowed with very limited support such that an index 
> WHERE clause with like expressions can imply/contain a query if the query has 
> the same like expressions that the index WHERE clause has.
>  * Comparison between columns are allowed without supporting transitivity, 
> for example, a > b and b > c does not imply a > c.
> Partial indexes will be supported initially for global secondary indexes, 
> i.e.,  covered global indexes and uncovered global indexes. The local 
> secondary indexes will be supported in future.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to