Skip to content

PHOENIX-7903 Functional index match rule EXPLAIN disclosure - #2523

Merged
apurtell merged 1 commit into
apache:PHOENIX-7876-featurefrom
apurtell:PHOENIX-7903
Jun 12, 2026
Merged

PHOENIX-7903 Functional index match rule EXPLAIN disclosure#2523
apurtell merged 1 commit into
apache:PHOENIX-7876-featurefrom
apurtell:PHOENIX-7903

Conversation

@apurtell

@apurtell apurtell commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Disclose OptimizerReasons for functional indexes.

The chosen functional index's per-scan INDEX line gains the rule matches <expr> where <expr> is the user's original path expression. Candidates discarded because no query expression matched their indexed expression are tagged path expression does not match. QueryOptimizer.recordDecision, labelComparatorRule, and the RULE_ONLY_CANDIDATE path in getApplicablePlansForSingleFlatQuery override the rule label with OptimizerReasons.matches(sourceExpression.toString()) when the winning candidate is a functional index, sourcing sourceExpression from StatementContext.getIndexExpressionSubstitutions() of the winning index. QueryOptimizer.addPlan and tagComparatorRejections switch the rejection tag for functional index candidates to REASON_PATH_EXPRESSION_DOES_NOT_MATCH.

A functional index is detected by an index column with a non-null PColumn.getExpressionStr().

Co-authored-by: Claude Opus 4.8[1m] noreply@anthropic.com

Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances optimizer EXPLAIN disclosure for functional indexes by surfacing which query path expression(s) matched a functional index and by using a more specific rejection reason when a functional index’s expression matches nothing in the query.

Changes:

  • Track and disclose functional-index expression substitutions that actually fired, enabling matches <expr> rule labeling for the chosen functional index.
  • Re-tag certain functional-index rejections as path expression does not match when no query expression matched the functional index expression.
  • Add unit tests covering functional-index rule labeling and rejection reason behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java Adds tests asserting functional-index matches <expr> rule labeling and updated rejection reasons.
phoenix-core-client/src/main/java/org/apache/phoenix/parse/IndexExpressionParseNodeRewriter.java Tracks which functional substitutions actually fired during rewrite to support EXPLAIN disclosure.
phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java Records fired matches into the rewrite context and adjusts rule/rejection labels for functional indexes.
phoenix-core-client/src/main/java/org/apache/phoenix/compile/StatementContext.java Stores per-index “applied expression matches” and marks indexes as functional during rewriting.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@apurtell

Copy link
Copy Markdown
Contributor Author

Test Results

Unit tests — PASS

Test class Tests Failures Errors Skipped
QueryOptimizerTest (modified — +3 new tests) 49 0 0 1
QueryCompilerTest 215 0 0 2
ExplainPlanTest 85 0 0 0
TenantSpecificViewIndexCompileTest 6 0 0 0
QueryPlanTest 4 0 0 0
StatementHintsCompilationTest 4 0 0 0
Total 363 0 0 3

New tests added by the commit (all passing):

  • testFunctionalIndexChosenRuleMatchesExpression — chosen functional index's rule is overridden to matches UPPER(NAME).
  • testFunctionalIndexRejectedPathExpressionDoesNotMatch — functional index that matched no query path expression is rejected with path expression does not match.
  • testFunctionalIndexRejectedDoesNotCoverProjection — functional index whose expression matched but which does not cover the projection keeps the does not cover projection rejection.

Integration tests (*IT) — PASS

Test class Tests Failures Errors Skipped
IndexUsageIT (functional indexes `s2 '_' s3, k1/k2`)
JsonFunctionsIT (JSON path functional indexes) 15 0 0 0
Total 54 0 0 0

Both IT classes exercise the changed optimizer code paths via real plan compilation against a minicluster and assert on indexRule / indexRejected.

@apurtell
apurtell merged commit 3af2420 into apache:PHOENIX-7876-feature Jun 12, 2026
@apurtell
apurtell deleted the PHOENIX-7903 branch June 12, 2026 18:21
apurtell added a commit to apurtell/phoenix that referenced this pull request Jun 17, 2026
)

Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
asf-gitbox-commits pushed a commit that referenced this pull request Jul 24, 2026
Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
apurtell added a commit to apurtell/phoenix that referenced this pull request Aug 4, 2026
)

Co-authored-by: Claude Opus 4.8[1m] <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants