Skip to content

planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772)#68858

Open
ti-chi-bot wants to merge 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-68772-to-release-8.5
Open

planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772)#68858
ti-chi-bot wants to merge 1 commit into
pingcap:release-8.5from
ti-chi-bot:cherry-pick-68772-to-release-8.5

Conversation

@ti-chi-bot
Copy link
Copy Markdown
Member

@ti-chi-bot ti-chi-bot commented Jun 2, 2026

This is an automated cherry-pick of #68772

What problem does this PR solve?

Issue Number: ref #65712 close #68773

Problem Summary:

For queries like SELECT * FROM t WHERE (a = 1 OR b > 5) ORDER BY c LIMIT 5, where indexes idx_ac(a, c) and idx_bc(b, c) are available:

  • The a = 1 partial path on idx_ac can satisfy ORDER BY c (single value on the leading column a).
  • The b > 5 partial path on idx_bc cannot satisfy ORDER BY c (range scan on the leading column b).

Previously, if not all partial paths of an IndexMerge could satisfy the ORDER BY, the plan would fall back to a global TopN without any pushdown, scanning all matching rows before sorting.

This is Solution 2 described in the issue.

What changed and how does it work?

create table t(a int, b int, c int, d int, index idx_ac(a,c), index idx_bc(b,c));
explain select * from t where a = 1 or b > 5 order by c limit 3;
-- Before (global TopN, no pushdown):
+----------------------------------+---------+-----------+-----------------------------+------------------------------------------------+
| id                               | estRows | task      | access object               | operator info                                  |
+----------------------------------+---------+-----------+-----------------------------+------------------------------------------------+
| TopN_9                           | 3.00    | root      |                             | test.t.c, offset:0, count:3                    |
| └─IndexMerge_21                  | 3.00    | root      |                             | type: union                                    |
|   ├─IndexRangeScan_17(Build)     | 10.00   | cop[tikv] | table:t, index:idx_ac(a, c) | range:[1,1], keep order:false, stats:pseudo    |
|   ├─IndexRangeScan_18(Build)     | 3333.33 | cop[tikv] | table:t, index:idx_bc(b, c) | range:(5,+inf], keep order:false, stats:pseudo |
|   └─TopN_20(Probe)               | 3.00    | cop[tikv] |                             | test.t.c, offset:0, count:3                    |
|     └─TableRowIDScan_19          | 3340.00 | cop[tikv] | table:t                     | keep order:false, stats:pseudo                 |
+----------------------------------+---------+-----------+-----------------------------+------------------------------------------------+

-- After (Limit to ordered paths, TopN to others):
+-------------------------------+---------+-----------+-----------------------------+------------------------------------------------+
| id                            | estRows | task      | access object               | operator info                                  |
+-------------------------------+---------+-----------+-----------------------------+------------------------------------------------+
| TopN_9                        | 3.00    | root      |                             | test.t.c, offset:0, count:3                    |
| └─IndexMerge_25               | 3.00    | root      |                             | type: union                                    |
|   ├─Limit_22(Build)           | 3.00    | cop[tikv] |                             | offset:0, count:3                              |
|   │ └─IndexRangeScan_19       | 10.00   | cop[tikv] | table:t, index:idx_ac(a, c) | range:[1,1], keep order:false, stats:pseudo    |
|   ├─TopN_23(Build)            | 3.00    | cop[tikv] |                             | test.t.c, offset:0, count:3                    |
|   │ └─IndexRangeScan_20       | 3333.33 | cop[tikv] | table:t, index:idx_bc(b, c) | range:(5,+inf], keep order:false, stats:pseudo |
|   └─TopN_24(Probe)            | 3.00    | cop[tikv] |                             | test.t.c, offset:0, count:3                    |
|     └─TableRowIDScan_21       | 3340.00 | cop[tikv] | table:t                     | keep order:false, stats:pseudo                 |
+-------------------------------+---------+-----------+-----------------------------+------------------------------------------------+
  1. A new field SortItemsHints is added to PhysicalProperty. When TopN sits directly above a DataSource, the ORDER BY columns are passed as advisory sort items through the property.
  2. DataSource uses these advisory sort items when selecting alternatives for OR-type IndexMerge, preferring partial paths that can satisfy the sort order.
  3. When not all partial paths satisfy the advisory sort order, Limit is pushed to the matching ones while TopN is pushed to the rest.

Key changes:

  • PhysicalProperty: new SortItemsHints field for advisory sort preferences (pkg/planner/property/physical_property.go)
  • getPhysTopN: sets SortItemsHints when the child is a DataSource (pkg/planner/core/operator/physicalop/physical_topn.go)
  • candidatePath: new matchWithAdvisorySortItems flag (true when matching used SortItemsHints) and partialPathMatchResults field storing each partial path's matchProperty result, replacing the simpler boolean satisfaction slice (pkg/planner/core/find_best_task.go)
  • CopTask: new IdxMergeMatchWithAdvisorySortItems flag and IdxMergePartPlansMatchResults field storing each partial path's matchProperty result (pkg/planner/core/operator/physicalop/task_base.go)
  • matchPropForIndexMergeAlternatives / isMatchPropForIndexMerge: collect per-path matchProperty results inline during matching rather than recomputing afterwards (pkg/planner/core/find_best_task.go)
  • convertToIndexMergeScan: passes each partial path's own match result (and the effective prop — hints-based or original) when building partial scans (pkg/planner/core/find_best_task.go)
  • attach2Task4PhysicalTopN: new handleAdvisorySortItemsForIndexMerge that pushes Limit to satisfying partial paths and TopN to others. Only applies when some (but not all) paths satisfy, since the existing Limit pushdown handles the all-satisfying case. (pkg/planner/core/task.go)

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.

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

Summary by CodeRabbit

Release Notes

  • New Features

    • Optimized execution plans for queries combining index merge with ORDER BY LIMIT, enabling the optimizer to push limit operations into individual merge paths for improved performance.
  • Tests

    • Added and updated test cases to validate optimized index merge and limit pushdown behavior.

Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
@ti-chi-bot ti-chi-bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR. labels Jun 2, 2026
@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

This cherry pick PR is for a release branch and has not yet been approved by triage owners.
Adding the do-not-merge/cherry-pick-not-approved label.

To merge this cherry pick:

  1. It must be LGTMed and approved by the reviewers firstly.
  2. For pull requests to TiDB-x branches, it must have no failed tests.
  3. AFTER it has lgtm and approved labels, please wait for the cherry-pick merging approval from triage owners.
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.

@ti-chi-bot
Copy link
Copy Markdown
Member Author

@time-and-fate This PR has conflicts, I have hold it.
Please resolve them or ask others to resolve them, then comment /unhold to remove the hold label.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

@ti-chi-bot: ## If you want to know how to resolve it, please read the guide in TiDB Dev Guide.

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 ti-community-infra/tichi repository.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

[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 0xpoe 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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements support for pushing Limit and TopN operators into individual partial paths of IndexMerge plans. The work extends the physical property system with advisory sort items and partial-order metadata, introduces PhysicalTopN operator implementation, refactors IndexMerge candidate matching to compute per-partial match results, and updates task attachment logic to apply per-partial-path sort behavior. Test data and integration tests validate the new plan shapes and correctness.

Changes

Push Limit/TopN into IndexMerge Partial Paths with Advisory Sort

Layer / File(s) Summary
Physical property extensions and task-base infrastructure
pkg/planner/property/physical_property.go, pkg/planner/core/operator/physicalop/task_base.go
PhysicalProperty adds IndexJoinProp, NoCopPushDown, PartialOrderInfo, AdvisorySortItems fields and new structs PartialOrderInfo, PartialOrderMatchResult, IndexJoinRuntimeProp. Core task types RootTask, MppTask, CopTask are introduced to implement base.Task with plan storage, warnings, partition metadata, index-merge partial-plan support, and root-task conversion.
Physical TopN operator
pkg/planner/core/operator/physicalop/physical_topn.go
New PhysicalTopN type with support for order-by items, offset/count, and prefix-index metadata (PrefixCol, PrefixLen). Implements Init, Clone, ExplainInfo, ToPB, cost computation, and getPhysTopN which generates multi-task candidates including advisory-sort items when TopN is directly above DataSource, partial-order optimization for Selection/Projection→DataSource chains, and vector-index TopK for MPP.
Index merge candidate matching
pkg/planner/core/find_best_task.go
candidatePath extends with matchWithAdvisorySortItems and partialPathMatchResults. matchPropForIndexMergeAlternatives refactored to support advisory-sort mode and return per-partial match results. convergeIndexMergeCandidate and getIndexMergeCandidate updated to populate candidate with new metadata.
CopTask integration and conversion
pkg/planner/core/find_best_task.go
convertToIndexMergeScan builds PhysPlanPartInfo, computes advisoryProp when advisory matching enabled, iterates partial paths selecting effective property per partial, calls updated physicalop.ConvertToPartialIndexScan with per-partial results, populates CopTask with IdxMergePartPlansMatchResults and IdxMergeMatchWithAdvisorySortItems.
TopN task attachment and helpers
pkg/planner/core/task.go
PhysicalTopN.Attach2Task updated to use physicalop.CopTask and handle IndexMerge advisory-sort partial-path cases via handleAdvisorySortItemsForIndexMerge. Adds handlePartialOrderTopN for prefix-order metadata and optional PhysicalLimit pushdown, estimateMaxXForPartialOrder stub, and attach2Task4PhysicalProjection/attach2Task4PhysicalExpand helpers.
Test expectations and integration coverage
pkg/executor/testdata/*.json, pkg/planner/cardinality/testdata/*.json, pkg/planner/core/casetest/*/testdata/*.json, tests/integrationtest/r/*, tests/integrationtest/t/*
Updated expected plans in multiple test data files reflecting new operator IDs/shapes. Introduces analyze_suite_xut.json fixture. Adds comprehensive IndexMerge integration tests for ORDER BY LIMIT scenarios (DESC ordering, transaction correctness, PREPARE/EXECUTE), TestIssue58361 validating IndexMerge ordering satisfaction, and TestIndexMergeSortItemsHints verifying LIMIT/OFFSET pushdown to ordered vs unordered partial paths.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • pingcap/tidb#65822: This PR addresses the need to build IndexMerge for nested OR/IN cases and push down per-partial limits by extending IndexMerge candidate matching and CopTask/TopN pushdown logic to honor per-partial match results and advisory sort information.

Possibly related PRs

  • pingcap/tidb#67771: Related IndexMerge partial-path ordering work that changes how partial-path "keep order" is handled via property matching and propagation of grouped-range metadata.
  • pingcap/tidb#66746: Related planner refactoring of IndexMerge ordering handling around ORDER BY + LIMIT/TopN in pkg/planner/core/find_best_task.go.

Suggested labels

cherry-pick-approved, ok-to-test

Suggested reviewers

  • AilinKid
  • qw4990
  • hawkingrei

Poem

🐰 A rabbit hops through IndexMerge lanes,
With Limit and TopN riding partial chains,
Advisory sort items light the way,
Each path gets ordered—hip-hip-hooray!
The plans push down so cleanly now,
All partial paths know when and how!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% 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
Title check ✅ Passed The PR title clearly summarizes the main change: supporting pushing Limit and TopN to individual partial paths of IndexMerge, which aligns with the core functionality added across multiple files.
Description check ✅ Passed The PR description includes Issue Number reference (ref #65712 close #68773), Problem Summary explaining the optimization goal, What Changed section with code examples and detailed explanation, and a completed Check List with integration tests marked.
Linked Issues check ✅ Passed The code changes fully implement the requirements from linked issue #68773 (Solution 2 of #65712): adding SortItemsHints to PhysicalProperty, advisory sort matching in DataSource/IndexMerge selection, and selective Limit/TopN pushdown to partial paths.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the advisory sort pushdown feature for IndexMerge: core planner logic in physical_topn.go, find_best_task.go, task.go and task_base.go; property extensions in physical_property.go; test data and integration tests validating the new behavior.

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

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

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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.

@tiprow
Copy link
Copy Markdown

tiprow Bot commented Jun 2, 2026

@ti-chi-bot: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
fast_test_tiprow_for_release a2757a5 link true /test fast_test_tiprow_for_release

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.

@ti-chi-bot
Copy link
Copy Markdown

ti-chi-bot Bot commented Jun 2, 2026

@ti-chi-bot: 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/mysql-test a2757a5 link true /test mysql-test
idc-jenkins-ci-tidb/check_dev a2757a5 link true /test check-dev
idc-jenkins-ci-tidb/check_dev_2 a2757a5 link true /test check-dev2
idc-jenkins-ci-tidb/unit-test a2757a5 link true /test unit-test
idc-jenkins-ci-tidb/build a2757a5 link true /test build

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
tests/integrationtest/r/planner/core/plan_cost_ver2.result (1)

8-32: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

This expected-cost fixture still contains an unresolved cherry-pick conflict.

The conflict markers in this block leave two different plan/cost snapshots in the same .result file, so the planner test cannot validate a single expected answer. Resolve the hunk and keep only the intended regenerated output.

🤖 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 `@tests/integrationtest/r/planner/core/plan_cost_ver2.result` around lines 8 -
32, The file contains unresolved git conflict markers (<<<<<<<, =======,
>>>>>>>) mixing two planner output variants (e.g., nodes TableReader_16 vs
TableReader_19, TopN_15 vs TopN_18, Selection_14 vs Selection_17,
TableFullScan_13 vs TableFullScan_16, TopN_8 differences); remove the conflict
markers and the unwanted duplicate block and leave only the correct regenerated
expected output for the test (i.e., a single contiguous plan snapshot consistent
with current generator), ensuring no leftover markers remain so the test can
validate a single expected answer.
tests/integrationtest/r/executor/issues.result (1)

934-970: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Clean up the committed merge conflicts in these regression results.

Both EXPLAIN ANALYZE sections still include Git conflict markers, which makes the checked-in expectation unusable and guarantees result drift in the integration suite. Resolve each hunk to one final output before regenerating or validating the file.

Also applies to: 1006-1044

🤖 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 `@tests/integrationtest/r/executor/issues.result` around lines 934 - 970, The
file contains unresolved Git conflict markers (<<<<<<<, =======, >>>>>>>) in the
EXPLAIN ANALYZE blocks (e.g., around Limit_10/Limit_12,
TableReader_17/TableReader_22, TableFullScan_15/TableFullScan_20 and the
following Limit_11/Limit_12/Limit_13 groups); remove the conflict markers and
choose the correct, single expected output for each hunk so the regression
result is deterministic, then save the cleaned EXPLAIN ANALYZE output (apply the
same cleanup to the later hunks noted in the comment, e.g., the section that
includes Limit_11–Limit_13 and TableFullScan_17–TableFullScan_23) and
regenerate/commit the file.
tests/integrationtest/r/planner/core/indexmerge_path.result (1)

1215-1398: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Unresolved Git merge conflict markers present

This test result file contains unresolved Git merge conflict markers (<<<<<<<, =======, >>>>>>>). The file must be manually resolved before merging:

  • HEAD version (lines 1216-1223): Shows estRows column in explain output
  • Incoming version (lines 1225-1398): Different format without estRows plus extensive new test cases

The presence of these markers will cause:

  1. Test parsing failures
  2. Invalid golden file comparisons
  3. Build/CI failures

Action required: Manually resolve the conflict by choosing the correct output format and regenerating the expected results if needed.

🤖 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 `@tests/integrationtest/r/planner/core/indexmerge_path.result` around lines
1215 - 1398, The test result file contains unresolved git conflict markers
(<<<<<<<, =======, >>>>>>>) around the explain output (notice the HEAD block
with an extra "estRows" column vs the incoming block without it and the large
new test cases including IndexMerge outputs and TopN/Limit cases); remove the
conflict markers, decide which version to keep (merge fields as needed — e.g.,
keep the incoming expanded tests and drop the stray "estRows" header or
reconcile headers across outputs), ensure the explain outputs (IndexMerge,
IndexRangeScan, TableRowIDScan, TopN, Limit) are consistent, then regenerate the
expected golden output (indexmerge_path.result) so CI uses the resolved file.
🧹 Nitpick comments (1)
pkg/planner/core/task.go (1)

1192-1195: ⚖️ Poor tradeoff

estimateMaxXForPartialOrder returns constant 0, affecting row estimation.

The TODO is noted, but returning 0 means estimatedRows = partialOrderedLimit + 0, which may underestimate the actual rows processed. This affects cost calculations for the partial order optimization path.

Consider adding a tracking issue for implementing this estimation, as it could impact query plan selection quality for partial order scenarios.

🤖 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/task.go` around lines 1192 - 1195, The function
estimateMaxXForPartialOrder currently returns a constant 0 which underestimates
rows used in partial-order planning; update estimateMaxXForPartialOrder in
pkg/planner/core/task.go to compute and return a reasonable upper-bound (e.g.,
derive from TopN/bucket statistics and relevant session variables) so
estimatedRows = partialOrderedLimit + estimateMaxXForPartialOrder() is accurate,
and add a TODO comment plus create a tracking issue reference (issue ID or URL)
in the comment to ensure full implementation and future improvements are
tracked; ensure you reference the function name estimateMaxXForPartialOrder when
committing the change.
🤖 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.

Inline comments:
In `@pkg/executor/testdata/prepare_suite_out.json`:
- Around line 1211-1219: The JSON fixture contains leftover git conflict markers
(<<<<<<<, =======, >>>>>>>) that break parsing; remove the conflict block and
choose the correct plan lines consistently (e.g., keep either the variant with
"TableReader_14/TopN_13/TableFullScan_12" or the variant with
"TableReader_17/TopN_16/TableFullScan_15") for the entries around the shown diff
and the similar block at lines 1233-1241 so the file becomes valid JSON with no
conflict markers.

In `@pkg/planner/cardinality/testdata/cardinality_suite_out.json`:
- Around line 1179-1185: The expectation is missing the unordered partial-path
TopN that should be pushed to the ib(b) branch; update the test fixture output
so the IndexMerge plan shows a TopN on the ib(b) side (i.e., the
IndexRangeScan(Build) for index:ib(b) should be wrapped with TopN(Probe) or
equivalent unordered TopN), while keeping the Limit(Build) on the ic(c)
branch—adjust the lines describing "IndexRangeScan(Build) table:t, index:ib(b)
..." to reflect the new TopN pushdown behavior.

In `@pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json`:
- Around line 543-627: Resolve the Git conflict markers in
analyze_suite_out.json by removing the raw merge markers (<<<<<<<, =======,
>>>>>>>) and restore only the intended TestIssue62438 expectations instead of
the spliced test cases; specifically pick and keep the correct Plan block for
TestIssue62438 (the block that contains Projection_7 / Projection_21 /
IndexLookUp_20 or the updated Projection_32 / Projection_31 / IndexLookUp_30
according to the intended cherry-pick) and delete the unrelated
TestReproHashJoinIssue and subsequent test case fragments that were merged in
erroneously so the JSON is valid and only contains the expected TestIssue62438
entries.

In `@pkg/planner/core/casetest/testdata/integration_suite_out.json`:
- Around line 70-78: Remove the Git conflict markers and keep only the resolved
expected plan JSON for each conflicted block: remove the lines starting with
<<<<<<<, =======, and >>>>>>> and retain the final plan variant (e.g., the block
containing "└─TableReader_17", "└─TopN_16", "└─TableFullScan_15") so the JSON is
valid; apply the same fix to the second conflict region (the one around lines
showing "TableReader_15"/"TopN_14"/"TableFullScan_13") so both fixtures become
deterministic and parseable by the casetest loader.

In `@pkg/planner/core/find_best_task.go`:
- Around line 686-701: Resolve the leftover cherry-pick conflict by removing the
git conflict markers and keeping the updated IndexMerge fields introduced in the
new commit: retain partialOrderMatchResult (property.PartialOrderMatchResult),
matchWithAdvisorySortItems (bool), partialPathMatchResults
([]property.PhysicalPropMatchResult), isFullRange (bool), and eqOrInCount (int),
and ensure indexJoinCols remains present once; then update any helper
calls/imports that reference the old field names or the advisory-sort/task-base
wiring so usages of partialOrderMatchResult, matchWithAdvisorySortItems, and
partialPathMatchResults compile correctly (adjust imports for property package
if needed) and remove any duplicated declarations from the old implementation.

In `@pkg/planner/core/task.go`:
- Around line 1101-1104: Resolve the unresolved merge markers by removing the
conflict delimiters and merging the incoming helper functions into the file
alongside the existing method: keep the PhysicalExpand.Attach2Task method
signature and body from HEAD but incorporate the new helper functions
(handlePartialOrderTopN, estimateMaxXForPartialOrder,
handleAdvisorySortItemsForIndexMerge, attach2Task4PhysicalProjection,
attach2Task4PhysicalExpand) into the same file; ensure Attach2Task delegates to
or integrates with attach2Task4PhysicalExpand where appropriate so the new
advisory sort items and partial-order TopN logic are used, and verify there are
no duplicate symbols or leftover <<<<<<< / ======= / >>>>>>> markers.
- Around line 1054-1075: Remove the literal merge conflict markers and keep the
correct, consistent variant (use the incoming/updated form that references
physicalop.CopTask and the standalone function canPushDownToTiKV(p, copTask)
with exported fields like RootTaskConds, IdxMergePartPlans,
IdxMergePartPlansMatchResults, IndexPlanFinished, IdxMergeIsIntersection,
IdxMergeMatchWithAdvisorySortItems); ensure the surrounding block (the
IndexMerge advisory-sort handling and the call to
handleAdvisorySortItemsForIndexMerge(p, copTask)) is preserved, update imports
to include physicalop if needed, and delete the HEAD variant and the conflict
markers so the file compiles.

In `@pkg/planner/property/physical_property.go`:
- Around line 290-380: The file contains unresolved git conflict markers
(<<<<<<<, =======, >>>>>>>) that break compilation; remove these markers and
reconcile the two conflicting blocks so types and methods are defined once and
consistently — ensure PhysicalProperty struct fields (IndexJoinProp,
NoCopPushDown, PartialOrderInfo, AdvisorySortItems), the PartialOrderInfo type
and its AllSameOrder method, PartialOrderMatchResult, IndexJoinRuntimeProp and
its CloneEssentialFields method are present and correctly implemented (preserve
intended comments and field names), and apply the same cleanup for the other
reported ranges (around lines 487-575 and 596-603) so there are no leftover
conflict markers.

In `@tests/integrationtest/r/executor/index_lookup_pushdown_partition.result`:
- Around line 26-40: The .result file contains unresolved git conflict markers
with two variants of the expected plan (e.g., IndexLookUp_16 vs IndexLookUp_19,
LocalIndexLookUp_18 vs LocalIndexLookUp_21, TopN_15 vs TopN_18,
IndexRangeScan_13 vs IndexRangeScan_16); decide which regenerated plan is
correct for the test, remove the <<<<<<</=======/>>>>>>> scaffolding, keep only
the chosen hunk content (and repeat this for the other conflicted region at
lines 219-285), and ensure the file contains a single deterministic expected
plan.

In `@tests/integrationtest/r/executor/index_lookup_pushdown.result`:
- Around line 366-382: The test result file contains Git conflict markers
(<<<<<<<, =======, >>>>>>>) causing a conflicted artifact; open the failing
expected output block and remove the conflict markers, keeping only one
canonical plan tree (choose either the IndexLookUp_17/... block or the
IndexLookUp_20/... block) so the .result contains a single valid plan (ensure
you remove the marker lines and any duplicated plan copy left by the merge).

In `@tests/integrationtest/r/index_merge.result`:
- Around line 867-972: The file contains unresolved Git conflict markers
(<<<<<<< HEAD, =======, >>>>>>>) around the new test section; remove those
markers and accept the incoming change block (the entire "IndexMerge with IN
conditions and ORDER BY LIMIT..." section including table t_im_in creation,
inserts, analyze, the explain outputs referencing
IndexMerge_35/IndexRangeScan_30/31/TableRowIDScan_32, UnionScan_21, and the
PREPARE/EXECUTE example) so the result file contains only the incoming test
content (no conflict lines) and retains examples like the prepare stmt and
outputs as-is.

In `@tests/integrationtest/t/planner/core/indexmerge_path.test`:
- Around line 520-599: Resolve the unresolved git conflict markers by removing
the conflict delimiters (<<<<<<< HEAD, =======, >>>>>>> 2310c3d99f3) and keeping
the incoming test blocks under TestIssue58361 and TestIndexMergeSortItemsHints
(i.e., accept the incoming content for those tests), then update the
corresponding .result expectations to match the added tests and run the test
suite to verify parsing/execution succeed; locate the test sections by the
unique test headings "TestIssue58361" and "TestIndexMergeSortItemsHints" to
apply the fix.

---

Outside diff comments:
In `@tests/integrationtest/r/executor/issues.result`:
- Around line 934-970: The file contains unresolved Git conflict markers
(<<<<<<<, =======, >>>>>>>) in the EXPLAIN ANALYZE blocks (e.g., around
Limit_10/Limit_12, TableReader_17/TableReader_22,
TableFullScan_15/TableFullScan_20 and the following Limit_11/Limit_12/Limit_13
groups); remove the conflict markers and choose the correct, single expected
output for each hunk so the regression result is deterministic, then save the
cleaned EXPLAIN ANALYZE output (apply the same cleanup to the later hunks noted
in the comment, e.g., the section that includes Limit_11–Limit_13 and
TableFullScan_17–TableFullScan_23) and regenerate/commit the file.

In `@tests/integrationtest/r/planner/core/indexmerge_path.result`:
- Around line 1215-1398: The test result file contains unresolved git conflict
markers (<<<<<<<, =======, >>>>>>>) around the explain output (notice the HEAD
block with an extra "estRows" column vs the incoming block without it and the
large new test cases including IndexMerge outputs and TopN/Limit cases); remove
the conflict markers, decide which version to keep (merge fields as needed —
e.g., keep the incoming expanded tests and drop the stray "estRows" header or
reconcile headers across outputs), ensure the explain outputs (IndexMerge,
IndexRangeScan, TableRowIDScan, TopN, Limit) are consistent, then regenerate the
expected golden output (indexmerge_path.result) so CI uses the resolved file.

In `@tests/integrationtest/r/planner/core/plan_cost_ver2.result`:
- Around line 8-32: The file contains unresolved git conflict markers (<<<<<<<,
=======, >>>>>>>) mixing two planner output variants (e.g., nodes TableReader_16
vs TableReader_19, TopN_15 vs TopN_18, Selection_14 vs Selection_17,
TableFullScan_13 vs TableFullScan_16, TopN_8 differences); remove the conflict
markers and the unwanted duplicate block and leave only the correct regenerated
expected output for the test (i.e., a single contiguous plan snapshot consistent
with current generator), ensuring no leftover markers remain so the test can
validate a single expected answer.

---

Nitpick comments:
In `@pkg/planner/core/task.go`:
- Around line 1192-1195: The function estimateMaxXForPartialOrder currently
returns a constant 0 which underestimates rows used in partial-order planning;
update estimateMaxXForPartialOrder in pkg/planner/core/task.go to compute and
return a reasonable upper-bound (e.g., derive from TopN/bucket statistics and
relevant session variables) so estimatedRows = partialOrderedLimit +
estimateMaxXForPartialOrder() is accurate, and add a TODO comment plus create a
tracking issue reference (issue ID or URL) in the comment to ensure full
implementation and future improvements are tracked; ensure you reference the
function name estimateMaxXForPartialOrder when committing the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 60348d0e-30c2-43f3-9de6-e40abbd33cdc

📥 Commits

Reviewing files that changed from the base of the PR and between b7e0663 and a2757a5.

📒 Files selected for processing (18)
  • pkg/executor/testdata/prepare_suite_out.json
  • pkg/planner/cardinality/testdata/cardinality_suite_out.json
  • pkg/planner/core/casetest/cbotest/testdata/analyze_suite_out.json
  • pkg/planner/core/casetest/cbotest/testdata/analyze_suite_xut.json
  • pkg/planner/core/casetest/testdata/integration_suite_out.json
  • pkg/planner/core/casetest/testdata/integration_suite_xut.json
  • pkg/planner/core/find_best_task.go
  • pkg/planner/core/operator/physicalop/physical_topn.go
  • pkg/planner/core/operator/physicalop/task_base.go
  • pkg/planner/core/task.go
  • pkg/planner/property/physical_property.go
  • tests/integrationtest/r/executor/index_lookup_pushdown.result
  • tests/integrationtest/r/executor/index_lookup_pushdown_partition.result
  • tests/integrationtest/r/executor/issues.result
  • tests/integrationtest/r/index_merge.result
  • tests/integrationtest/r/planner/core/indexmerge_path.result
  • tests/integrationtest/r/planner/core/plan_cost_ver2.result
  • tests/integrationtest/t/planner/core/indexmerge_path.test

Comment on lines +1211 to +1219
<<<<<<< HEAD
"└─TableReader_14 1.00 root data:TopN_13",
" └─TopN_13 1.00 cop[tikv] test.t.b, offset:0, count:1",
" └─TableFullScan_12 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
=======
"└─TableReader_17 1.00 root data:TopN_16",
" └─TopN_16 1.00 cop[tikv] test.t.b, offset:0, count:1",
" └─TableFullScan_15 10000.00 cop[tikv] table:t keep order:false, stats:pseudo"
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve the leftover cherry-pick conflict markers.

These <<<<<<< / ======= / >>>>>>> markers make the fixture invalid JSON, so the prepare-suite testdata cannot even be parsed. Pick the intended plan variant and remove the conflict artifact before merge.

Also applies to: 1233-1241

🧰 Tools
🪛 Biome (2.4.16)

[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: unexpected character <

(parse)


[error] 1211-1211: expected , but instead found HEAD

(parse)


[error] 1212-1212: expected , but instead found "└─TableReader_14 1.00 root data:TopN_13"

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1215-1215: unexpected character =

(parse)


[error] 1216-1216: expected , but instead found "└─TableReader_17 1.00 root data:TopN_16"

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: unexpected character >

(parse)


[error] 1219-1219: expected , but instead found 2310

(parse)


[error] 1219-1219: expected , but instead found c3d99f3

(parse)


[error] 1219-1219: unexpected character (

(parse)


[error] 1219-1219: expected , but instead found planner

(parse)


[error] 1219-1219: expected , but instead found :

(parse)


[error] 1219-1219: unexpected character (

(parse)


[error] 1219-1219: unexpected character #

(parse)


[error] 1219-1219: expected , but instead found 68772

(parse)


[error] 1219-1219: unexpected character )

(parse)


[error] 1219-1219: unexpected character )

(parse)

🤖 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/executor/testdata/prepare_suite_out.json` around lines 1211 - 1219, The
JSON fixture contains leftover git conflict markers (<<<<<<<, =======, >>>>>>>)
that break parsing; remove the conflict block and choose the correct plan lines
consistently (e.g., keep either the variant with
"TableReader_14/TopN_13/TableFullScan_12" or the variant with
"TableReader_17/TopN_16/TableFullScan_15") for the entries around the shown diff
and the similar block at lines 1233-1241 so the file becomes valid JSON with no
conflict markers.

Comment on lines 1179 to 1185
"TopN 1.00 root test.t.c, offset:0, count:1",
"└─IndexMerge 1.00 root type: union",
" ├─IndexRangeScan(Build) 510.00 cop[tikv] table:t, index:ib(b) range:[0,50], keep order:false, stats:pseudo",
" ├─IndexRangeScan(Build) 510.00 cop[tikv] table:t, index:ic(c) range:[0,50], keep order:false, stats:pseudo",
" ├─Limit(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan 510.00 cop[tikv] table:t, index:ic(c) range:[0,50], keep order:true, stats:pseudo",
" └─TopN(Probe) 1.00 cop[tikv] test.t.c, offset:0, count:1",
" └─TableRowIDScan 1017.40 cop[tikv] table:t keep order:false, stats:pseudo"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

This expectation still misses the unordered partial-path TopN.

For the mixed-match IndexMerge case, the new behavior is supposed to push Limit to the ordered ic(c) branch and TopN to the unordered ib(b) branch. Here the ib(b) side is still a bare IndexRangeScan(Build), so this fixture does not actually lock in the selective pushdown behavior the PR is adding.

🤖 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/cardinality/testdata/cardinality_suite_out.json` around lines
1179 - 1185, The expectation is missing the unordered partial-path TopN that
should be pushed to the ib(b) branch; update the test fixture output so the
IndexMerge plan shows a TopN on the ib(b) side (i.e., the IndexRangeScan(Build)
for index:ib(b) should be wrapped with TopN(Probe) or equivalent unordered
TopN), while keeping the Limit(Build) on the ic(c) branch—adjust the lines
describing "IndexRangeScan(Build) table:t, index:ib(b) ..." to reflect the new
TopN pushdown behavior.

Comment on lines +543 to +627
<<<<<<< HEAD
"Projection_7 5001.00 9913298.19 ((((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms",
"└─Projection_25 5001.00 9906310.79 ((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms, test.objects.metastore_uuid, test.objects.securable_id",
" └─IndexLookUp_24 5001.00 9902317.99 (((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00 root limit embedded(offset:0, count:5001)",
" ├─Limit_23(Build) 5001.00 1253699.35 ((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00) cop[tikv] offset:0, count:5001",
" │ └─IndexRangeScan_21 5001.00 1253699.35 (scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects, index:idx_metastore_securable_seq(metastore_uuid, securable_id, seq) range:(\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 17299834,\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 +inf], keep order:true",
" └─TableRowIDScan_22(Probe) 5001.00 1688011.54 (scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects keep order:false"
=======
"Projection_32 5001.00 9909305.39 (((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms",
"└─Projection_31 5001.00 9906310.79 ((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms, test.objects.metastore_uuid, test.objects.securable_id",
" └─IndexLookUp_30 5001.00 9902317.99 (((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00 root limit embedded(offset:0, count:5001)",
" ├─Limit_29(Build) 5001.00 1253699.35 ((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00) cop[tikv] offset:0, count:5001",
" │ └─IndexRangeScan_27 5001.00 1253699.35 (scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects, index:idx_metastore_securable_seq(metastore_uuid, securable_id, seq) range:(\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 17299834,\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 +inf], keep order:true",
" └─TableRowIDScan_28(Probe) 5001.00 1688011.54 (scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects keep order:false"
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
]
},
{
"SQL": "explain format = 'cost_trace' \nSELECT\n /*+ limit_to_cop(), QB_NAME(`listObjectsWithPrefix_FilterByCreated_Since_Securable`) */\n path,\n updated_ms,\n size,\n etag,\n seq,\n last_seen_ms\nFROM\n objects FORCE INDEX(idx_metastore_securable_seq)\nWHERE\n metastore_uuid = 0x3CBCC26CA7E740A48DD164D74757DEE2\n AND securable_id = 2238365063123291\n AND (\n seq > 17299834\n AND TRUE\n )\nORDER BY\n seq\nLIMIT\n 5001;",
"Plan": [
<<<<<<< HEAD
"Projection_7 5001.00 9913298.19 ((((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms",
"└─Projection_21 5001.00 9906310.79 ((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms, test.objects.metastore_uuid, test.objects.securable_id",
" └─IndexLookUp_20 5001.00 9902317.99 (((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00 root limit embedded(offset:0, count:5001)",
" ├─Limit_19(Build) 5001.00 1253699.35 ((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00) cop[tikv] offset:0, count:5001",
" │ └─IndexRangeScan_17 5001.00 1253699.35 (scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects, index:idx_metastore_securable_seq(metastore_uuid, securable_id, seq) range:(\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 17299834,\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 +inf], keep order:true",
" └─TableRowIDScan_18(Probe) 5001.00 1688011.54 (scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects keep order:false"
=======
"Projection_32 5001.00 9909305.39 (((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms",
"└─Projection_31 5001.00 9906310.79 ((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms, test.objects.metastore_uuid, test.objects.securable_id",
" └─IndexLookUp_30 5001.00 9902317.99 (((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00 root limit embedded(offset:0, count:5001)",
" ├─Limit_29(Build) 5001.00 1253699.35 ((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00) cop[tikv] offset:0, count:5001",
" │ └─IndexRangeScan_27 5001.00 1253699.35 (scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects, index:idx_metastore_securable_seq(metastore_uuid, securable_id, seq) range:(\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 17299834,\"<\\xbc\\xc2l\\xa7\\xe7@\\xa4\\x8d\\xd1d\\xd7GW\\xde\\xe2\" 2238365063123291 +inf], keep order:true",
" └─TableRowIDScan_28(Probe) 5001.00 1688011.54 (scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00 cop[tikv] table:objects keep order:false"
]
}
]
},
{
"Name": "TestReproHashJoinIssue",
"Cases": [
{
"SQL": "explain format = 'brief' SELECT COUNT(*) FROM t_small s STRAIGHT_JOIN t_big b ON b.id1 = s.id4 WHERE s.id1 = '10001' AND s.id2 = 0 AND s.id3 = 123456789 AND b.id2 = 10001 AND b.id3 = 0 AND b.id4 = 20991231;",
"Ratio": 0,
"Plan": [
"HashAgg 1.00 root funcs:count(1)->Column#16",
"└─IndexHashJoin 100000.00 root inner join, inner:IndexReader, outer key:repro_hash_join_issue.t_small.id4, inner key:repro_hash_join_issue.t_big.id1, equal cond:eq(repro_hash_join_issue.t_small.id4, repro_hash_join_issue.t_big.id1)",
" ├─TableReader(Build) 1000.00 root data:Selection",
" │ └─Selection 1000.00 cop[tikv] eq(repro_hash_join_issue.t_small.id1, \"10001\"), eq(repro_hash_join_issue.t_small.id2, 0), eq(repro_hash_join_issue.t_small.id3, 123456789)",
" │ └─TableFullScan 1000.00 cop[tikv] table:s keep order:false",
" └─IndexReader(Probe) 100000.00 root index:IndexRangeScan",
" └─IndexRangeScan 100000.00 cop[tikv] table:b, index:idx_id1_id2_id3_id4_id5(id1, id2, id3, id4, id5) range: decided by [eq(repro_hash_join_issue.t_big.id1, repro_hash_join_issue.t_small.id4) eq(repro_hash_join_issue.t_big.id2, 10001) eq(repro_hash_join_issue.t_big.id3, 0) eq(repro_hash_join_issue.t_big.id4, 20991231)], keep order:false"
]
},
{
"SQL": "explain format = 'brief' SELECT COUNT(*) FROM t_small s STRAIGHT_JOIN t_big b ON b.id1 = s.id4 WHERE s.id1 = '10001' AND s.id2 = 0 AND s.id3 = 123456789 AND b.id2 = 10001 AND b.id3 = 0 AND b.id4 = 20991231;",
"Ratio": 0.5,
"Plan": [
"HashAgg 1.00 root funcs:count(1)->Column#16",
"└─HashJoin 100000.00 root inner join, equal:[eq(repro_hash_join_issue.t_small.id4, repro_hash_join_issue.t_big.id1)]",
" ├─TableReader(Build) 1000.00 root data:Selection",
" │ └─Selection 1000.00 cop[tikv] eq(repro_hash_join_issue.t_small.id1, \"10001\"), eq(repro_hash_join_issue.t_small.id2, 0), eq(repro_hash_join_issue.t_small.id3, 123456789)",
" │ └─TableFullScan 1000.00 cop[tikv] table:s keep order:false",
" └─IndexReader(Probe) 1000.00 root index:Selection",
" └─Selection 1000.00 cop[tikv] eq(repro_hash_join_issue.t_big.id2, 10001), eq(repro_hash_join_issue.t_big.id3, 0), eq(repro_hash_join_issue.t_big.id4, 20991231)",
" └─IndexFullScan 1000.00 cop[tikv] table:b, index:idx_id1_id2_id3_id4_id5(id1, id2, id3, id4, id5) keep order:false"
]
}
]
},
{
"Name": "TestIndexJoinPreferIndexCoversMoreJoinKeyCols",
"Cases": [
{
"SQL": "explain format ='brief' SELECT \n mp.col1,\n mp.col2,\n mp.col3,\n mp.col4,\n mp.col5,\n mp.col6\nFROM\n mp\n LEFT JOIN ab ON ab.col1 = mp.col2\n AND ab.col2 = mp.col6\nWHERE\n mp.col5 = 'PKR'\n AND mp.col3 = 1\n AND mp.col6 IN ('1685', '2239')\n AND mp.col4 >= 1764788400\n AND mp.col4 <= 1767466799\n AND ab.col3 IN ('cj9dkqw7', 'del_cj9dkqw7')\nORDER BY\n mp.col4 DESC\nLIMIT\n 100;",
"Plan": [
"TopN 84.77 root test.mp.col4:desc, offset:0, count:100",
"└─IndexHashJoin 84.77 root inner join, inner:IndexLookUp, outer key:test.ab.col1, test.ab.col2, inner key:test.mp.col2, test.mp.col6, equal cond:eq(test.ab.col1, test.mp.col2), eq(test.ab.col2, test.mp.col6)",
" ├─Batch_Point_Get(Build) 4.00 root table:ab, index:idx_1(col3, col2) keep order:false, desc:false",
" └─IndexLookUp(Probe) 84.77 root ",
" ├─Selection(Build) 382.27 cop[tikv] in(test.mp.col6, \"1685\", \"2239\")",
" │ └─IndexRangeScan 382.27 cop[tikv] table:mp, index:idx_1(col2, col6, col7) range: decided by [eq(test.mp.col2, test.ab.col1) eq(test.mp.col6, test.ab.col2)], keep order:false",
" └─Selection(Probe) 84.77 cop[tikv] eq(test.mp.col3, 1), eq(test.mp.col5, \"PKR\"), ge(test.mp.col4, 1764788400), le(test.mp.col4, 1767466799)",
" └─TableRowIDScan 382.27 cop[tikv] table:mp keep order:false"
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Clean up the unresolved conflict block before this fixture can be used.

This hunk still contains raw merge markers, so analyze_suite_out.json is unparsable. It also appears to splice unrelated test cases into TestIssue62438, which would broaden this cherry-pick beyond the stated scope if the wrong side is kept. Resolve the conflict and keep only the intended TestIssue62438 expectations here.

🧰 Tools
🪛 Biome (2.4.16)

[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: unexpected character <

(parse)


[error] 543-543: expected , but instead found HEAD

(parse)


[error] 544-544: expected , but instead found "Projection_7 5001.00 9913298.19 ((((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms"

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 550-550: unexpected character =

(parse)


[error] 551-551: expected , but instead found "Projection_32 5001.00 9909305.39 (((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms"

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: unexpected character >

(parse)


[error] 557-557: expected , but instead found 2310

(parse)


[error] 557-557: expected , but instead found c3d99f3

(parse)


[error] 557-557: unexpected character (

(parse)


[error] 557-557: expected , but instead found planner

(parse)


[error] 557-557: expected , but instead found :

(parse)


[error] 557-557: unexpected character (

(parse)


[error] 557-557: unexpected character #

(parse)


[error] 557-557: expected , but instead found 68772

(parse)


[error] 557-557: unexpected character )

(parse)


[error] 557-557: unexpected character )

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: unexpected character <

(parse)


[error] 563-563: expected , but instead found HEAD

(parse)


[error] 564-564: expected , but instead found "Projection_7 5001.00 9913298.19 ((((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms"

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 570-570: unexpected character =

(parse)


[error] 571-571: expected , but instead found "Projection_32 5001.00 9909305.39 (((((((net(5001*rowsize(54.67)*tidb_kv_net_factor(3.96))) + (((scan(5001*logrowsize(71.47926389640116)*tikv_scan_factor(40.7)))*1.00)))/15.00) + (((((net(5001*rowsize(273.515)*tidb_kv_net_factor(3.96))) + ((scan(5001*logrowsize(313.69926389640113)*tikv_scan_factor(40.7)))*1.00))/15.00) + ((double-read-cpu(5001*tidb_cpu_factor(49.9))) + (doubleRead(tasks(8.0016)*tidb_request_factor(6e+06)))))/5.00))*1.00)*1.00) + ((cpu(5001*filters(0.08)*tidb_cpu_factor(49.9)))/5.00)) + ((cpu(5001*filters(0.060000000000000005)*tidb_cpu_factor(49.9)))/5.00) root test.objects.path, test.objects.updated_ms, test.objects.size, test.objects.etag, test.objects.seq, test.objects.last_seen_ms"

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: unexpected character >

(parse)


[error] 627-627: expected , but instead found 2310

(parse)


[error] 627-627: expected , but instead found c3d99f3

(parse)


[error] 627-627: unexpected character (

(parse)


[error] 627-627: expected , but instead found planner

(parse)


[error] 627-627: expected , but instead found :

(parse)


[error] 627-627: unexpected character (

(parse)


[error] 627-627: unexpected character #

(parse)


[error] 627-627: expected , but instead found 68772

(parse)


[error] 627-627: unexpected character )

(parse)


[error] 627-627: unexpected character )

(parse)

🪛 OpenGrep (1.22.0)

[ERROR] 548-548: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 548-548: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 555-555: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 555-555: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 561-561: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 568-568: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 568-568: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 575-575: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 575-575: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)

🤖 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/casetest/cbotest/testdata/analyze_suite_out.json` around
lines 543 - 627, Resolve the Git conflict markers in analyze_suite_out.json by
removing the raw merge markers (<<<<<<<, =======, >>>>>>>) and restore only the
intended TestIssue62438 expectations instead of the spliced test cases;
specifically pick and keep the correct Plan block for TestIssue62438 (the block
that contains Projection_7 / Projection_21 / IndexLookUp_20 or the updated
Projection_32 / Projection_31 / IndexLookUp_30 according to the intended
cherry-pick) and delete the unrelated TestReproHashJoinIssue and subsequent test
case fragments that were merged in erroneously so the JSON is valid and only
contains the expected TestIssue62438 entries.

Comment on lines +70 to +78
<<<<<<< HEAD
"└─TableReader_15 1.00 54.34 root data:TopN_14",
" └─TopN_14 1.00 688.32 cop[tikv] test.t3.a, offset:0, count:1",
" └─TableFullScan_13 3.00 681.92 cop[tikv] table:t3 keep order:false"
=======
"└─TableReader_17 1.00 54.34 root data:TopN_16",
" └─TopN_16 1.00 688.32 cop[tikv] test.t3.a, offset:0, count:1",
" └─TableFullScan_15 3.00 681.92 cop[tikv] table:t3 keep order:false"
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve the leftover merge conflict markers.

These <<<<<<< / ======= / >>>>>>> markers make the fixture invalid JSON, so the casetest loader will fail before the updated plan expectations are exercised. Keep only the final expected plan block for each case.

As per coding guidelines, "Testdata: Keep test changes minimal and deterministic; avoid broad golden/testdata churn unless required; follow test naming and shard_count guidance".

Also applies to: 85-93

🧰 Tools
🪛 Biome (2.4.16)

[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: unexpected character <

(parse)


[error] 70-70: expected , but instead found HEAD

(parse)


[error] 71-71: expected , but instead found "└─TableReader_15 1.00 54.34 root data:TopN_14"

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 74-74: unexpected character =

(parse)


[error] 75-75: expected , but instead found "└─TableReader_17 1.00 54.34 root data:TopN_16"

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: unexpected character >

(parse)


[error] 78-78: expected , but instead found 2310

(parse)


[error] 78-78: expected , but instead found c3d99f3

(parse)


[error] 78-78: unexpected character (

(parse)


[error] 78-78: expected , but instead found planner

(parse)


[error] 78-78: expected , but instead found :

(parse)


[error] 78-78: unexpected character (

(parse)


[error] 78-78: unexpected character #

(parse)


[error] 78-78: expected , but instead found 68772

(parse)


[error] 78-78: unexpected character )

(parse)


[error] 78-78: unexpected character )

(parse)

🤖 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/casetest/testdata/integration_suite_out.json` around lines
70 - 78, Remove the Git conflict markers and keep only the resolved expected
plan JSON for each conflicted block: remove the lines starting with <<<<<<<,
=======, and >>>>>>> and retain the final plan variant (e.g., the block
containing "└─TableReader_17", "└─TopN_16", "└─TableFullScan_15") so the JSON is
valid; apply the same fix to the second conflict region (the one around lines
showing "TableReader_15"/"TopN_14"/"TableFullScan_13") so both fixtures become
deterministic and parseable by the casetest loader.

Comment on lines +686 to +701
<<<<<<< HEAD
indexJoinCols int // how many index columns are used in access conditions in this IndexJoin.
=======
// partialOrderMatch records the partial order match result for TopN optimization.
// When the matched is true, it means this path can provide partial order using prefix index.
partialOrderMatchResult property.PartialOrderMatchResult // Result of matching partial order property
// matchWithAdvisorySortItems indicates the property matching used SortItemsHints
// (i.e. noSortItem && len(prop.SortItemsHints) > 0). Only relevant for IndexMerge.
matchWithAdvisorySortItems bool
// partialPathMatchResults stores each partial path's matchProperty result.
// Length equals len(path.PartialIndexPaths). Only set for IndexMerge paths.
partialPathMatchResults []property.PhysicalPropMatchResult
indexJoinCols int // how many index columns are used in access conditions in this IndexJoin.
isFullRange bool // cached result of whether this path covers the full scan range.
eqOrInCount int // cached result of equalPredicateCount().
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Finish resolving the cherry-pick in this file.

The remaining conflict blocks interleave the old IndexMerge implementation with the new advisory-sort/task-base wiring, so this file will not build as-is and the selected branch still needs its helper/import/field-name updates reconciled.

Also applies to: 1139-1195, 1231-1236, 1323-1332, 1374-1385, 1391-1412, 2014-2024, 2050-2054, 2087-2096

🤖 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/find_best_task.go` around lines 686 - 701, Resolve the
leftover cherry-pick conflict by removing the git conflict markers and keeping
the updated IndexMerge fields introduced in the new commit: retain
partialOrderMatchResult (property.PartialOrderMatchResult),
matchWithAdvisorySortItems (bool), partialPathMatchResults
([]property.PhysicalPropMatchResult), isFullRange (bool), and eqOrInCount (int),
and ensure indexJoinCols remains present once; then update any helper
calls/imports that reference the old field names or the advisory-sort/task-base
wiring so usages of partialOrderMatchResult, matchWithAdvisorySortItems, and
partialPathMatchResults compile correctly (adjust imports for property package
if needed) and remove any duplicated declarations from the old implementation.

Comment on lines +290 to +380
<<<<<<< HEAD
=======

IndexJoinProp *IndexJoinRuntimeProp

// NoCopPushDown indicates if planner must not push this agg down to coprocessor.
// It is true when the agg is in the outer child tree of apply.
NoCopPushDown bool

// PartialOrderInfo is used for TopN's partial order optimization.
// When this field is not nil, it indicates that prefix index can be used
// to provide partial order for TopN.
// For example:
// query: order by a, b limit 10
// partialOrderInfo: sortItems: [a, b]
// The partialOrderInfo property will pass through to the datasource and try to matchPartialOrderProperty such as:
// index: (a, b(10) )
PartialOrderInfo *PartialOrderInfo

// AdvisorySortItems contains sort items that are preferred but not required.
// When SortItems is empty and AdvisorySortItems is not, DataSource can try to
// generate paths that satisfy these sort items, enabling Limit pushdown to
// partial paths of IndexMerge.
// Currently only set when TopN is directly above a DataSource.
AdvisorySortItems []SortItem
}

// PartialOrderInfo records information needed for partial order optimization.
// When PhysicalProperty.PartialOrderInfo is not nil, it indicates that
// prefix index can be used to provide partial order.
type PartialOrderInfo struct {
// SortItems are the ORDER BY columns from TopN
SortItems []*SortItem
}

// AllSameOrder checks if all the items have same order.
func (p *PartialOrderInfo) AllSameOrder() (isSame bool, desc bool) {
if len(p.SortItems) == 0 {
return true, false
}
for i := 1; i < len(p.SortItems); i++ {
if p.SortItems[i].Desc != p.SortItems[i-1].Desc {
return
}
}
return true, p.SortItems[0].Desc
}

// PartialOrderMatchResult records the result of matching partial order property with an access path.
// It is stored in candidatePath to allow each path to have its own match result.
type PartialOrderMatchResult struct {
// Matched indicates whether this path can provide partial order
Matched bool
// PrefixCol is the last and only one prefix column ID of index, only used for executor part
// For example:
// Query ORDER BY a,b,c
// Index: a, b, c(10)
// PrefixCol: c, the col c
// PrefixLen: 10, the col length of c in index
PrefixCol *expression.Column

// PrefixLen is the prefix length in bytes for prefix index, only used for executor part
PrefixLen int
}

// IndexJoinRuntimeProp is the inner runtime property for index join.
type IndexJoinRuntimeProp struct {
// for complete the last col range access, cuz its runtime constant.
OtherConditions []expression.Expression
// for filling the range msg info
OuterJoinKeys []*expression.Column
// for inner ds/index to detect the range, cuz its runtime constant.
InnerJoinKeys []*expression.Column
// AvgInnerRowCnt is computed from join.EqualCondCount / outerChild.RowCount.
// since ds only can build empty range before seeing runtime data, the so inner
// ds can get an accurate countAfterAccess. Once index join prop pushed to the
// deeper side like through join, the deeper DS's countAfterAccess should be
// thought twice.
AvgInnerRowCnt float64
// since tableRangeScan and indexRangeScan can't be told which one is better at
// copTask phase because of the latter attached operators into cop and the single
// and double reader cost consideration. Therefore, we introduce another bool to
// indicate prefer tableRangeScan or indexRangeScan each at a time.
TableRangeScan bool
}

// CloneEssentialFields clone the essential fields for IndexJoinRuntimeProp.
func (ijr *IndexJoinRuntimeProp) CloneEssentialFields() *IndexJoinRuntimeProp {
one := *ijr
return &one
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve the leftover merge conflicts before merging.

This file still contains <<<<<<< / ======= / >>>>>>> blocks, so PhysicalProperty and its hash/clone paths cannot compile in the current state.

Also applies to: 487-575, 596-603

🤖 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/property/physical_property.go` around lines 290 - 380, The file
contains unresolved git conflict markers (<<<<<<<, =======, >>>>>>>) that break
compilation; remove these markers and reconcile the two conflicting blocks so
types and methods are defined once and consistently — ensure PhysicalProperty
struct fields (IndexJoinProp, NoCopPushDown, PartialOrderInfo,
AdvisorySortItems), the PartialOrderInfo type and its AllSameOrder method,
PartialOrderMatchResult, IndexJoinRuntimeProp and its CloneEssentialFields
method are present and correctly implemented (preserve intended comments and
field names), and apply the same cleanup for the other reported ranges (around
lines 487-575 and 596-603) so there are no leftover conflict markers.

Comment on lines +26 to +40
<<<<<<< HEAD
└─IndexLookUp_16 3.00 root partition:all
├─LocalIndexLookUp_18(Build) 3.00 cop[tikv] index handle offsets:[1]
│ ├─TopN_15(Build) 3.00 cop[tikv] executor__index_lookup_pushdown_partition.tp1.a, offset:0, count:3
│ │ └─IndexRangeScan_13 3323.33 cop[tikv] table:tp1, index:b(b) range:[-inf,10), keep order:false, stats:pseudo
│ └─TableRowIDScan_17(Probe) 3.00 cop[tikv] table:tp1 keep order:false, stats:pseudo
└─TableRowIDScan_14(Probe) 0.00 cop[tikv] table:tp1 keep order:false, stats:pseudo
=======
└─IndexLookUp_19 3.00 root partition:all
├─LocalIndexLookUp_21(Build) 3.00 cop[tikv] index handle offsets:[1]
│ ├─TopN_18(Build) 3.00 cop[tikv] executor__index_lookup_pushdown_partition.tp1.a, offset:0, count:3
│ │ └─IndexRangeScan_16 3323.33 cop[tikv] table:tp1, index:b(b) range:[-inf,10), keep order:false, stats:pseudo
│ └─TableRowIDScan_20(Probe) 3.00 cop[tikv] table:tp1 keep order:false, stats:pseudo
└─TableRowIDScan_17(Probe) 0.00 cop[tikv] table:tp1 keep order:false, stats:pseudo
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Resolve both conflicted expected-plan hunks before merging.

These conflict markers leave two incompatible result variants in the same .result file, so the integration test cannot verify a deterministic output. Pick the intended regenerated plan for each hunk and remove the conflict scaffolding entirely.

Also applies to: 219-285

🤖 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 `@tests/integrationtest/r/executor/index_lookup_pushdown_partition.result`
around lines 26 - 40, The .result file contains unresolved git conflict markers
with two variants of the expected plan (e.g., IndexLookUp_16 vs IndexLookUp_19,
LocalIndexLookUp_18 vs LocalIndexLookUp_21, TopN_15 vs TopN_18,
IndexRangeScan_13 vs IndexRangeScan_16); decide which regenerated plan is
correct for the test, remove the <<<<<<</=======/>>>>>>> scaffolding, keep only
the chosen hunk content (and repeat this for the other conflicted region at
lines 219-285), and ensure the file contains a single deterministic expected
plan.

Comment on lines +366 to +382
<<<<<<< HEAD
└─IndexLookUp_17 4.00 root
├─LocalIndexLookUp_19(Build) 4.00 cop[tikv] index handle offsets:[]
│ ├─TopN_16(Build) 4.00 cop[tikv] executor__index_lookup_pushdown.t2.a:desc, executor__index_lookup_pushdown.t2.b:desc, offset:0, count:4
│ │ └─Selection_15 6656.67 cop[tikv] ne(executor__index_lookup_pushdown.t2.b, 3)
│ │ └─IndexFullScan_13 10000.00 cop[tikv] table:t2, index:i(c) keep order:false, stats:pseudo
│ └─TableRowIDScan_18(Probe) 4.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableRowIDScan_14(Probe) 0.00 cop[tikv] table:t2 keep order:false, stats:pseudo
=======
└─IndexLookUp_20 4.00 root
├─LocalIndexLookUp_22(Build) 4.00 cop[tikv] index handle offsets:[]
│ ├─TopN_19(Build) 4.00 cop[tikv] executor__index_lookup_pushdown.t2.a:desc, executor__index_lookup_pushdown.t2.b:desc, offset:0, count:4
│ │ └─Selection_18 6656.67 cop[tikv] ne(executor__index_lookup_pushdown.t2.b, 3)
│ │ └─IndexFullScan_16 10000.00 cop[tikv] table:t2, index:i(c) keep order:false, stats:pseudo
│ └─TableRowIDScan_21(Probe) 4.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableRowIDScan_17(Probe) 0.00 cop[tikv] table:t2 keep order:false, stats:pseudo
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove the unresolved conflict block from this expected result.

The <<<<<<< / ======= / >>>>>>> lines are still in the checked-in .result file, so the integration test now asserts against a conflicted artifact instead of a single canonical plan. Resolve the hunk and keep only one expected plan tree.

🤖 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 `@tests/integrationtest/r/executor/index_lookup_pushdown.result` around lines
366 - 382, The test result file contains Git conflict markers (<<<<<<<, =======,
>>>>>>>) causing a conflicted artifact; open the failing expected output block
and remove the conflict markers, keeping only one canonical plan tree (choose
either the IndexLookUp_17/... block or the IndexLookUp_20/... block) so the
.result contains a single valid plan (ensure you remove the marker lines and any
duplicated plan copy left by the merge).

Comment on lines +867 to +972
<<<<<<< HEAD
=======
///// IndexMerge with IN conditions and ORDER BY LIMIT (merge sort for partial paths)
drop table if exists t_im_in;
create table t_im_in (
id int not null,
a int default null,
b int default null,
c int default null,
padding varchar(100) default null,
primary key (id) clustered,
key idx_a_c (a, c),
key idx_b_c (b, c)
);
insert into t_im_in values
(1, 1, 1, 10, 'row1'), (2, 1, 2, 20, 'row2'), (3, 2, 1, 30, 'row3'),
(4, 2, 2, 40, 'row4'), (5, 1, 3, 50, 'row5'), (6, 3, 1, 60, 'row6'),
(7, 3, 2, 70, 'row7'), (8, 1, 1, 5, 'row8'), (9, 2, 3, 15, 'row9'),
(10, 3, 3, 25, 'row10');
analyze table t_im_in;
# Case 1: a=1 keeps order directly, b IN (1,2) needs merge sort
explain select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c limit 5;
id estRows task access object operator info
IndexMerge_35 5.00 root type: union, limit embedded(offset:0, count:5)
├─Limit_33(Build) 2.44 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_30 2.44 cop[tikv] table:t_im_in, index:idx_a_c(a, c) range:[1,1], keep order:true
├─Limit_34(Build) 4.27 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_31 4.27 cop[tikv] table:t_im_in, index:idx_b_c(b, c) range:[1,1], [2,2], keep order:true
└─TableRowIDScan_32(Probe) 5.00 cop[tikv] table:t_im_in keep order:false
select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c limit 5;
id a b c padding
8 1 1 5 row8
1 1 1 10 row1
2 1 2 20 row2
3 2 1 30 row3
4 2 2 40 row4
# Case 2: Both partial paths need merge sort
explain select /*+ use_index_merge(t_im_in) */ * from t_im_in where a in (1, 2) or b in (1, 2) order by c limit 5;
id estRows task access object operator info
IndexMerge_35 5.00 root type: union, limit embedded(offset:0, count:5)
├─Limit_33(Build) 3.85 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_30 3.85 cop[tikv] table:t_im_in, index:idx_a_c(a, c) range:[1,1], [2,2], keep order:true
├─Limit_34(Build) 3.85 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_31 3.85 cop[tikv] table:t_im_in, index:idx_b_c(b, c) range:[1,1], [2,2], keep order:true
└─TableRowIDScan_32(Probe) 5.00 cop[tikv] table:t_im_in keep order:false
select /*+ use_index_merge(t_im_in) */ * from t_im_in where a in (1, 2) or b in (1, 2) order by c limit 5;
id a b c padding
8 1 1 5 row8
1 1 1 10 row1
9 2 3 15 row9
2 1 2 20 row2
3 2 1 30 row3
# Case 3: DESC ordering with IN condition
explain select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c desc limit 5;
id estRows task access object operator info
IndexMerge_35 5.00 root type: union, limit embedded(offset:0, count:5)
├─Limit_33(Build) 2.44 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_30 2.44 cop[tikv] table:t_im_in, index:idx_a_c(a, c) range:[1,1], keep order:true, desc
├─Limit_34(Build) 4.27 cop[tikv] offset:0, count:5
│ └─IndexRangeScan_31 4.27 cop[tikv] table:t_im_in, index:idx_b_c(b, c) range:[1,1], [2,2], keep order:true, desc
└─TableRowIDScan_32(Probe) 5.00 cop[tikv] table:t_im_in keep order:false
select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c desc limit 5;
id a b c padding
7 3 2 70 row7
6 3 1 60 row6
5 1 3 50 row5
4 2 2 40 row4
3 2 1 30 row3
# Case 4: UnionScan - verify correctness with uncommitted data
begin;
insert into t_im_in values (11, 1, 1, 1, 'uncommitted');
explain select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c limit 5;
id estRows task access object operator info
Limit_15 5.00 root offset:0, count:5
└─UnionScan_21 5.00 root or(eq(index_merge.t_im_in.a, 1), in(index_merge.t_im_in.b, 1, 2))
└─IndexMerge_25 5.00 root type: union
├─IndexRangeScan_22(Build) 2.44 cop[tikv] table:t_im_in, index:idx_a_c(a, c) range:[1,1], keep order:true
├─IndexRangeScan_23(Build) 4.27 cop[tikv] table:t_im_in, index:idx_b_c(b, c) range:[1,1], [2,2], keep order:true
└─TableRowIDScan_24(Probe) 5.00 cop[tikv] table:t_im_in keep order:false
select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = 1 or b in (1, 2) order by c limit 5;
id a b c padding
11 1 1 1 uncommitted
8 1 1 5 row8
1 1 1 10 row1
2 1 2 20 row2
3 2 1 30 row3
rollback;
# Case 5: PREPARE/EXECUTE with different parameter values
prepare stmt from 'select /*+ use_index_merge(t_im_in) */ * from t_im_in where a = ? or b in (1, 2) order by c limit 5';
set @a = 1;
execute stmt using @a;
id a b c padding
8 1 1 5 row8
1 1 1 10 row1
2 1 2 20 row2
3 2 1 30 row3
4 2 2 40 row4
set @a = 3;
execute stmt using @a;
id a b c padding
8 1 1 5 row8
1 1 1 10 row1
2 1 2 20 row2
10 3 3 25 row10
3 2 1 30 row3
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Unresolved Git merge conflict markers present

This test result file contains unresolved merge conflict markers. The conflict shows:

  • HEAD version (line 867): Empty (no conflicting content)
  • Incoming version (lines 869-972): New test section for "IndexMerge with IN conditions and ORDER BY LIMIT (merge sort for partial paths)" with table creation, data insertion, and multiple test cases

The presence of these markers will cause:

  1. Test file parsing errors
  2. Integration test failures
  3. CI/build breakage

Action required: Resolve the conflict manually. Since HEAD has no content, this likely means accepting the incoming changes and removing the conflict markers.

🤖 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 `@tests/integrationtest/r/index_merge.result` around lines 867 - 972, The file
contains unresolved Git conflict markers (<<<<<<< HEAD, =======, >>>>>>>) around
the new test section; remove those markers and accept the incoming change block
(the entire "IndexMerge with IN conditions and ORDER BY LIMIT..." section
including table t_im_in creation, inserts, analyze, the explain outputs
referencing IndexMerge_35/IndexRangeScan_30/31/TableRowIDScan_32, UnionScan_21,
and the PREPARE/EXECUTE example) so the result file contains only the incoming
test content (no conflict lines) and retains examples like the prepare stmt and
outputs as-is.

Comment on lines +520 to +599
<<<<<<< HEAD
=======

# TestIssue58361

# Test non-MV index OR IndexMerge can collect usable filters (only support eq now) from the top level AND filters
drop table if exists t;
create table t (a int, b int, c int, d int,
index iab(a,b),
index iac(a,c),
index iad(a,d));
explain format='plan_tree' select /*+ use_index_merge(t) */ * from t where a = 1 and (b = 2 or c = 3 or d = 4);

drop table if exists t;
create table t(a int, b int, c int, d int,
index iab(b,a),
index iac(c,a,d),
index iad(a,d));
explain format='plan_tree' select /*+ use_index_merge(t) */ * from t where a = 1 and (b = 2 or (c = 3 and d = 4) or d = 5);

# Test MV index OR IndexMerge can satisfy Sort property when there are multiple indexes to choose from
drop table if exists t;
create table t (a int, b int, c int, j1 json, j2 json,
key mvi1((cast(j1 as unsigned array)), a),
key mvi2((cast(j1 as unsigned array)), b),
key mvi3((cast(j2 as unsigned array)), a),
key mvi4((cast(j2 as unsigned array)), b) );
explain format='plan_tree' select * from t where 1 member of (j1) or 2 member of (j2) order by a;
explain format='plan_tree' select * from t where 1 member of (j1) or 2 member of (j2) order by b;
explain format='plan_tree' select * from t where json_overlaps(j1, '[1,3,5]') or 2 member of (j2) order by a desc limit 10;
explain format='plan_tree' select * from t where 1 member of (j1) or json_contains(j2, '[5]') order by b limit 10000;

INSERT INTO t VALUES (2, 2, 2, '[1,2,3]', '[4,5,6]');
INSERT INTO t VALUES (5, 1, 5, '[]', '[2]');
INSERT INTO t VALUES (10, 10, 10, '[1,2,3]', '[4,5,6]');
INSERT INTO t VALUES (1, 2, 3, '[1,2,3]', '[4,5,6]');
INSERT INTO t VALUES (4, 5, 6, '[7,8,5]', '[10,11,2]');
INSERT INTO t VALUES (7, 8, 9, '[13,14,15]', '[16,17,18]');
INSERT INTO t VALUES (10, 11, 12, '[19,20,21]', '[22,23,24]');
INSERT INTO t VALUES (13, 14, 15, '[25,1,27]', '[2,29,30]');
INSERT INTO t VALUES (16, 17, 18, '[31,32,33]', '[34,35,36]');
INSERT INTO t VALUES (19, 20, 21, '[37,38,39]', '[40,2,42]');
INSERT INTO t VALUES (22, 23, 24, '[5,44,45]', '[46,47,48]');
INSERT INTO t VALUES (25, 26, 27, '[49,50,3]', '[52,53,54]');
INSERT INTO t VALUES (28, 29, 30, '[5,56,57]', '[58,2,60]');
INSERT INTO t VALUES (31, 32, 33, '[61,3,63]', '[64,65,66]');
INSERT INTO t VALUES (34, 35, 36, '[67,68,69]', '[70,71,72]');
INSERT INTO t VALUES (37, 38, 39, '[73,74,2]', '[76,2,2]');

select /*+ use_index_merge(t) */ * from t where json_overlaps(j1, '[1,3,5]') or 2 member of (j2) order by a limit 2;
select /*+ use_index_merge(t) */ * from t where 1 member of (j1) or 2 member of (j2) order by b desc;

drop table if exists t;
create table t (a int, b int, c int, d int, e int, j1 json, j2 json,
key mvi1((cast(j1 as unsigned array)), a, e),
key idx1(a, b, e),
key mvi2(b, (cast(j2 as unsigned array)), e),
key idx2(d, e, c) );

explain format='plan_tree' select /*+ use_index_merge(t) */ * from t where
a = 5 and
(1 member of (j1) or b = 3 or b = 4 and json_overlaps(j2, '[3,4,5]') or d = 10)
order by e;

explain format='plan_tree' select /*+ use_index_merge(t) */ * from t where
a = 5 and
(1 member of (j1) or b = 3 or b = 4 and json_overlaps(j2, '[3,4,5]') or d = 10)
order by e desc limit 10;

# TestIndexMergeSortItemsHints
# When one partial path can keep order (a=1 on idx_ac) and another cannot (b>5 on idx_bc),
# Limit should be pushed to the ordered partial path and TopN to the unordered one.
drop table if exists t;
create table t(a int, b int, c int, index idx_ac(a, c), index idx_bc(b, c));
insert into t values(1, 1, 100), (1, 2, 50), (1, 3, 150), (6, 6, 10), (7, 7, 20), (8, 8, 30), (9, 9, 5);
explain format='plan_tree' select /*+ use_index_merge(t, idx_ac, idx_bc) */ * from t where a = 1 or b > 5 order by c limit 3;
select /*+ use_index_merge(t, idx_ac, idx_bc) */ * from t where a = 1 or b > 5 order by c limit 3;
explain format='plan_tree' select /*+ use_index_merge(t, idx_ac, idx_bc) */ * from t where a = 1 or b > 5 order by c limit 3 offset 1;
select /*+ use_index_merge(t, idx_ac, idx_bc) */ * from t where a = 1 or b > 5 order by c limit 3 offset 1;
>>>>>>> 2310c3d99f3 (planner: support pushing Limit and TopN to individual partial paths of IndexMerge (#68772))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Unresolved Git merge conflict markers present

This test input file contains unresolved merge conflict markers. The conflict shows:

  • HEAD version (line 520): Empty (no conflicting content)
  • Incoming version (lines 522-599): New test sections:
    • TestIssue58361: Tests for non-MV index OR IndexMerge filter collection and MV index OR IndexMerge sort satisfaction
    • TestIndexMergeSortItemsHints: Tests for Limit/TopN pushdown to ordered/unordered partial paths

The presence of these markers will cause:

  1. Test file parsing errors
  2. Integration test execution failures
  3. CI pipeline breakage

Action required: Resolve the conflict manually. Since HEAD is empty, this likely means accepting the incoming test cases and removing the conflict markers. Ensure consistency with the corresponding .result file resolution.

🤖 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 `@tests/integrationtest/t/planner/core/indexmerge_path.test` around lines 520 -
599, Resolve the unresolved git conflict markers by removing the conflict
delimiters (<<<<<<< HEAD, =======, >>>>>>> 2310c3d99f3) and keeping the incoming
test blocks under TestIssue58361 and TestIndexMergeSortItemsHints (i.e., accept
the incoming content for those tests), then update the corresponding .result
expectations to match the added tests and run the test suite to verify
parsing/execution succeed; locate the test sections by the unique test headings
"TestIssue58361" and "TestIndexMergeSortItemsHints" to apply the fix.

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

Labels

do-not-merge/cherry-pick-not-approved do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. type/cherry-pick-for-release-8.5 This PR is cherry-picked to release-8.5 from a source PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants