Skip to content

planner: simplify contradictory inequality predicates | tidb-test=pr/2765#69324

Open
zimulala wants to merge 4 commits into
pingcap:masterfrom
zimulala:codex/69058-predicate-simplification-v2
Open

planner: simplify contradictory inequality predicates | tidb-test=pr/2765#69324
zimulala wants to merge 4 commits into
pingcap:masterfrom
zimulala:codex/69058-predicate-simplification-v2

Conversation

@zimulala

@zimulala zimulala commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #69058

Problem Summary:

For impossible predicates that only contain contradictory inequality bounds on
the same column, such as a > 0 AND a < 0, predicate simplification did not
reduce the plan to TableDual. Equality contradictions, such as
a > 0 AND a = 0, were already simplified.

What changed and how does it work?

This PR extends predicate simplification to detect contradictions between
same-column numeric lower and upper bounds, including exclusive and inclusive
bound combinations:

  • a > x AND a < y
  • a > x AND a <= y
  • a >= x AND a < y
  • a >= x AND a <= y when the lower bound is greater than the upper bound

The new simplification is intentionally narrow:

  • only same-column predicates are considered
  • only constant numeric bounds are considered
  • NULL, string, time, non-constant, and plan-cache-sensitive expressions are not
    simplified by this path

When a contradiction is detected, the predicate list is replaced with a constant
false predicate, allowing the planner to produce TableDual.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

Focused test:

go test --tags=intest ./pkg/planner/core/casetest/rule -run TestPredicateSimplification -count=1
go test --tags=intest ./pkg/planner/core/casetest/partition -run TestListColumnsPartitionPruner -count=1
go test --tags=intest ./pkg/planner/core/casetest/index -run TestRangeIntersection -count=1
go test --tags=intest ./pkg/executor/test/plancache -run TestPreparedPlanCacheSessionInteractions -count=1

Additional compile-only signal:

go test ./pkg/planner/core/rule -run '^$' -count=1

Integration tests:

cd tests/integrationtest
./run-tests.sh -t agg_predicate_pushdown
./run-tests.sh -t executor/partition/partition_boundaries -s ./integrationtest_tidb-server

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

None

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-triage-completed do-not-merge/needs-tests-checked release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. sig/planner SIG: Planner labels Jun 18, 2026
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Inequality-only contradiction detection is added to the predicate simplification rule. New helpers scan predicate pairs for contradictory lower/upper bound comparisons on the same column with constant numeric values; contradictions replace the predicate set with a constant-false expression, producing TableDual instead of a full scan. Four test cases validate the new behavior, and cascading test plan updates reflect improved optimization across partition boundary, index range, and aggregation predicate pushdown scenarios.

Changes

Inequality bounds contradiction in predicate simplification

Layer / File(s) Summary
Contradiction detection and unsatisfiability helpers
pkg/planner/core/rule/rule_predicate_simplification.go
detectInequalityBoundsContradiction is called from applyPredicateSimplificationHelper and iterates predicate pairs; inequalityBoundsContradiction and its supporting helpers classify bound types, verify numeric constants, and compare values via binary collation to determine if a lower/upper bound pair is impossible. unsatisfiable is extended to call inequalityBoundsContradiction for OR-branch pruning.
Test fixtures for contradiction cases
pkg/planner/core/casetest/rule/testdata/predicate_simplification_in.json, predicate_simplification_out.json, predicate_simplification_xut.json
Input JSON adds four SQL queries covering a > 0 AND a < 0, a > 0 AND a <= 0, a >= 0 AND a < 0, and a >= 0 AND a <= 0; output and XUT fixtures record expected plans — TableDual rows:0 for the three contradictory cases and TableReader/Selection with ge+le for the satisfiable inclusive case.
Cascading test plan updates
tests/integrationtest/r/executor/partition/partition_boundaries.result, pkg/planner/core/casetest/partition/testdata/partition_pruner_out.json, partition_pruner_xut.json, pkg/planner/core/casetest/index/testdata/index_range_out.json, index_range_xut.json, tests/integrationtest/r/agg_predicate_pushdown.result
Partition boundary tests now expect TableDual rows:0 for impossible BETWEEN conditions and impossible AND/NOT combinations instead of TableReader with Selection; predicate order and structure are simplified in partition pruner tests; index range and aggregation predicate pushdown tests reflect minor operator changes (HashAgg to StreamAgg) as side effects of improved predicate simplification.
Test assertion and build configuration updates
pkg/executor/test/plancache/plan_cache_test.go, br/pkg/task/BUILD.bazel, br/pkg/task/operator/BUILD.bazel
Plan cache test assertion updated to check for TableDual operator presence using requireExplainContainsOperator instead of fixed row count; Bazel test configuration for task_test increases shard count from 47 to 49; dependency order in operator_test is adjusted.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • qw4990
  • Reminiscent
  • AilinKid
  • windtalker

Poem

🐇 A bunny hopped through WHERE clauses one day,
Found a > 0 AND a < 0 blocking the way!
"Impossible!" cried the planner with glee,
TableDual appears — no full scan, you see!
The contradictions folded, the query runs free. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR fully addresses issue #69058 by implementing detection and simplification of inequality-only contradictions (e.g., a > 0 AND a < 0) to produce TableDual with zero rows.
Out of Scope Changes check ✅ Passed All changes are directly related to detecting and simplifying contradictory inequality predicates and updating corresponding test expectations; no unrelated modifications present.
Description check ✅ Passed The PR description comprehensively covers the problem, solution, and testing approach with clear examples and dedicated test commands.
Title check ✅ Passed The title accurately describes the main change: adding logic to simplify contradictory inequality predicates in the query planner.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ti-chi-bot ti-chi-bot Bot added release-note-none Denotes a PR that doesn't merit a release note. and removed do-not-merge/needs-triage-completed release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/needs-tests-checked labels Jun 18, 2026
@zimulala zimulala force-pushed the codex/69058-predicate-simplification-v2 branch from 2acb254 to 856638e Compare June 18, 2026 09:59
@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jun 18, 2026
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.83051% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.8501%. Comparing base (f869cc3) to head (e785a60).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #69324        +/-   ##
================================================
- Coverage   76.3192%   74.8501%   -1.4691%     
================================================
  Files          2041       2034         -7     
  Lines        561552     571169      +9617     
================================================
- Hits         428572     427521      -1051     
- Misses       132076     143475     +11399     
+ Partials        904        173       -731     
Flag Coverage Δ
integration 41.1141% <89.8305%> (+1.4713%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 60.4610% <ø> (ø)
parser ∅ <ø> (∅)
br 48.9470% <ø> (-13.8696%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@zimulala zimulala force-pushed the codex/69058-predicate-simplification-v2 branch from 856638e to e8d6627 Compare June 18, 2026 10:18

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
pkg/planner/core/rule/rule_predicate_simplification.go (1)

411-414: 💤 Low value

Consider adding a brief comment explaining the comparison threshold difference.

The cmp > 0 vs cmp >= 0 distinction handles the subtle difference between inclusive and strict bounds:

  • a >= x AND a <= y allows x == y (point match)
  • All other combinations (>/<, >=/< , >/<=) require a non-empty open interval

A short inline comment would help future readers understand this nuance without re-deriving the logic.

📝 Suggested clarifying comment
 	if lowerType == greaterThanOrEqualPredicate && upperType == lessThanOrEqualPredicate {
+		// >= and <= can both be satisfied at a single point when lower == upper
 		return cmp > 0
 	}
+	// At least one strict bound requires lower < upper for any value to exist in the range
 	return cmp >= 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/planner/core/rule/rule_predicate_simplification.go` around lines 411 -
414, Add an inline comment before the return statement in the conditional block
that checks if lowerType equals greaterThanOrEqualPredicate and upperType equals
lessThanOrEqualPredicate to explain why cmp > 0 is used instead of cmp >= 0. The
comment should clarify that when both bounds are inclusive (>=  and <=), a point
match where the lower bound equals the upper bound is allowed, requiring strict
comparison, whereas other bound combinations with at least one strict inequality
require non-strict comparison cmp >= 0 to ensure a valid non-empty interval
exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/planner/core/rule/rule_predicate_simplification.go`:
- Around line 411-414: Add an inline comment before the return statement in the
conditional block that checks if lowerType equals greaterThanOrEqualPredicate
and upperType equals lessThanOrEqualPredicate to explain why cmp > 0 is used
instead of cmp >= 0. The comment should clarify that when both bounds are
inclusive (>=  and <=), a point match where the lower bound equals the upper
bound is allowed, requiring strict comparison, whereas other bound combinations
with at least one strict inequality require non-strict comparison cmp >= 0 to
ensure a valid non-empty interval exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d9c9fcb4-7769-4d3a-b8b4-d1e7c8e251ce

📥 Commits

Reviewing files that changed from the base of the PR and between 856638e and cb63542.

📒 Files selected for processing (13)
  • br/pkg/task/BUILD.bazel
  • br/pkg/task/operator/BUILD.bazel
  • pkg/executor/test/plancache/plan_cache_test.go
  • pkg/planner/core/casetest/index/testdata/index_range_out.json
  • pkg/planner/core/casetest/index/testdata/index_range_xut.json
  • pkg/planner/core/casetest/partition/testdata/partition_pruner_out.json
  • pkg/planner/core/casetest/partition/testdata/partition_pruner_xut.json
  • pkg/planner/core/casetest/rule/testdata/predicate_simplification_in.json
  • pkg/planner/core/casetest/rule/testdata/predicate_simplification_out.json
  • pkg/planner/core/casetest/rule/testdata/predicate_simplification_xut.json
  • pkg/planner/core/rule/rule_predicate_simplification.go
  • tests/integrationtest/r/agg_predicate_pushdown.result
  • tests/integrationtest/r/executor/partition/partition_boundaries.result
✅ Files skipped from review due to trivial changes (6)
  • br/pkg/task/operator/BUILD.bazel
  • pkg/planner/core/casetest/rule/testdata/predicate_simplification_out.json
  • pkg/planner/core/casetest/partition/testdata/partition_pruner_xut.json
  • tests/integrationtest/r/agg_predicate_pushdown.result
  • pkg/planner/core/casetest/partition/testdata/partition_pruner_out.json
  • tests/integrationtest/r/executor/partition/partition_boundaries.result
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/planner/core/casetest/index/testdata/index_range_xut.json
  • pkg/planner/core/casetest/index/testdata/index_range_out.json
  • pkg/planner/core/casetest/rule/testdata/predicate_simplification_xut.json

@zimulala zimulala changed the title planner: simplify contradictory inequality predicates planner: simplify contradictory inequality predicates | tidb-test=pr/2765 Jun 18, 2026
@zimulala

Copy link
Copy Markdown
Contributor Author

/retest

@ti-chi-bot

ti-chi-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ailinkid for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot

ti-chi-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

@zimulala: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
idc-jenkins-ci-tidb/unit-test e785a60 link true /test unit-test
idc-jenkins-ci-tidb/mysql-test e785a60 link true /test mysql-test
pull-unit-test-next-gen e785a60 link true /test pull-unit-test-next-gen

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Impossible WHERE with inequality-only contradictions not optimized

1 participant