[
https://issues.apache.org/jira/browse/PHOENIX-7032?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17772087#comment-17772087
]
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 to 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)