Skip to content

*: honor task collation across DXF encoding and expression paths - #69734

Open
joechenrh wants to merge 34 commits into
pingcap:masterfrom
joechenrh:dxf-collation-followup
Open

*: honor task collation across DXF encoding and expression paths#69734
joechenrh wants to merge 34 commits into
pingcap:masterfrom
joechenrh:dxf-collation-followup

Conversation

@joechenrh

@joechenrh joechenrh commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #69563

Problem Summary:

DXF executes tasks in the SYSTEM keyspace. If its new-collation setting differs from the submitting user keyspace, collation-sensitive encoding and expression paths can use the worker setting and produce incompatible data.

What changed and how does it work?

  • Capture the submitting keyspace's new-collation mode in DXF task metadata, then use that snapshot when reconstructing worker-side objects. Legacy task metadata still falls back to the process setting for compatibility.
  • Keep the runtime state on the objects that own the affected semantics:
    • Table and Index own the encoder used for comparable table and index keys, restored-data decisions, partition routing, and partial-index evaluation.
    • Since BuildContext take charges of the expression evaluation, it also owns the mode used to construct collation-sensitive scalar expressions for DDL reorganization and IMPORT generated-column or assignment evaluation.
  • Let lower-level consumers derive the mode from those owners instead of threading independent booleans through parallel WithCollate APIs. This keeps one task snapshot consistent across key encoding and expression evaluation.
  • Roll back collation-aware Encoder propagation from row/value encoding. New collation changes comparable string sort keys, while row values, old-row values, and generic HashCode serialization use non-comparable encoding and produce identical bytes in either mode. Their original APIs therefore do not need this state.
  • Preserve legacy binary matching for IMPORT ENUM/SET casts without modifying shared schema metadata.

Expression scope: this PR covers scalar expression evaluation used by DXF. Vectorized builtin implementations and the historical INSTR evaluation remain unchanged.

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.

The local NextGen cluster used new_collations_enabled_on_first_bootstrap = false in the user keyspace and true in the SYSTEM keyspace. Every case ran ADMIN CHECK TABLE, checked index/table results where applicable, performed INSERT/UPDATE/DELETE, and ran ADMIN CHECK TABLE again.

ADD INDEX

Case Schema DDL PR result
Clustered VARCHAR handle PRIMARY KEY(id) CLUSTERED, id/fk VARCHAR ALTER TABLE t ADD INDEX idx_fk(fk) Passed
Composite VARCHAR/INT handle PRIMARY KEY(id1,id2) CLUSTERED, fk INT ALTER TABLE t ADD INDEX idx_fk(fk) Passed
Generated string functions LOWER(raw), UPPER(raw), CONCAT(id,':',raw), SUBSTR(raw,1,2) generated columns Add one index for each generated column Passed
Functional indexes id/raw VARCHAR, clustered VARCHAR PK Add indexes on LOWER, UPPER, CONCAT, and SUBSTR Passed
LIST COLUMNS partition id VARCHAR COLLATE utf8mb4_general_ci, PARTITION BY LIST COLUMNS(id) ALTER TABLE t ADD INDEX idx_fk(fk) Passed
KEY partition id VARCHAR COLLATE utf8mb4_general_ci, PARTITION BY KEY(id) PARTITIONS 4 ALTER TABLE t ADD INDEX idx_fk(fk) Passed
RANGE COLUMNS partition id VARCHAR COLLATE utf8mb4_general_ci, PARTITION BY RANGE COLUMNS(id) ALTER TABLE t ADD INDEX idx_fk(fk) Passed
Partial index raw VARCHAR COLLATE utf8mb4_general_ci ALTER TABLE t ADD INDEX idx_partial(fk) WHERE raw='A' Passed
Collation-sensitive generated expressions Generated columns using =, IN, LIKE, IF, CASE, STRCMP, LOCATE, and GREATEST Add indexes for all generated columns Passed; latest upstream fails ADMIN CHECK TABLE
ENUM/SET indexes ENUM('A','a','B'), SET('A','a','B') with utf8mb4_general_ci Add indexes on ENUM and SET columns Passed

IMPORT INTO

The table omits storage URLs; each operation is IMPORT INTO ... FROM <CSV>.

Case Schema IMPORT SQL or assignment PR result
Clustered VARCHAR handle, VARCHAR index PRIMARY KEY(id) CLUSTERED, KEY(fk) IMPORT INTO t(@1,id,fk) Passed
Clustered VARCHAR handle, INT index PRIMARY KEY(id) CLUSTERED, fk INT, KEY(fk) IMPORT INTO t(fk,id,@3) Passed
Composite VARCHAR/INT handle PRIMARY KEY(id1,id2) CLUSTERED, KEY(fk) IMPORT INTO t(id2,fk,id1) Passed
Composite INT handle, VARCHAR index PRIMARY KEY(id1,id2) CLUSTERED, fk VARCHAR, KEY(fk) IMPORT INTO t(id1,id2,fk) Passed
Composite CHAR handle PRIMARY KEY(id1,id2) CLUSTERED, id1/id2 CHAR, KEY(fk) IMPORT INTO t(fk,id1,id2) Passed
Prefix index Clustered VARCHAR PK, KEY(fk(2)) IMPORT INTO t(@1,id,fk) Passed
Extra payload Clustered VARCHAR PK, VARCHAR index, defaulted payload IMPORT INTO t(@1,id,fk) Passed
Generated string functions Stored generated LOWER, UPPER, CONCAT, and SUBSTR, all indexed IMPORT INTO t(@1,id,raw) Passed
Assignment string functions Assigned/indexed LOWER, UPPER, CONCAT, and SUBSTR results IMPORT INTO t(@1,@2,@3) SET ... Passed
INT-handle control Clustered INT PK, VARCHAR index IMPORT INTO t(id,fk,payload) Passed
LIST COLUMNS partition VARCHAR clustered PK, PARTITION BY LIST COLUMNS(id) IMPORT INTO t(id,fk) Passed; physical partitions match a local-DML control table
RANGE COLUMNS partition VARCHAR clustered PK, PARTITION BY RANGE COLUMNS(id) IMPORT INTO t(id,fk) Passed; physical partitions match a local-DML control table
KEY partition VARCHAR clustered PK, PARTITION BY KEY(id) PARTITIONS 4 IMPORT INTO t(id,fk) Passed; all four physical partitions match a local-DML control table
Partial index KEY idx_partial(fk) WHERE raw='A' IMPORT INTO t(@id,@raw) SET fk=CONCAT('v',@id) Passed
Generated comparisons Stored/indexed =, IN, LIKE, IF, CASE, STRCMP, LOCATE, GREATEST IMPORT INTO t(id,raw) Passed; imported values match local-DML control values
Assignment comparisons Assigned/indexed =, IN, LIKE, IF, CASE, STRCMP, LOCATE, GREATEST IMPORT INTO t(@id,@raw) SET ... Passed; values match legacy binary expectations
ENUM/SET conversion ENUM('A','a','B'), SET('A','a','B'), both indexed IMPORT INTO t(id,e,s) Passed; names and numeric values match local DML
Additional scalar expressions Assigned/indexed <=>, !=, <, >=, ILIKE, REGEXP, FIELD, LEAST, WEIGHT_STRING IMPORT INTO t(@id,@raw) SET ... Passed; values match legacy binary expectations

Latest upstream and this PR were tested with the same cluster and input files:

Validation Latest upstream This PR
LIST partition mismatches 2 0
RANGE COLUMNS partition mismatches 2 0
KEY partition mismatches 3 0
Generated-expression row mismatches 2 0
ENUM/SET row mismatches 1 0
Assignment-expression row mismatches 0 0
Advanced assignment-expression row mismatches 0 0
Unfinished IMPORT jobs 0 0

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

Please refer to Release Notes Language Style Guide to write a quality release note.

Fix an issue that DXF ADD INDEX or IMPORT INTO might use the worker keyspace's new-collation setting instead of the submitted task's setting in collation-sensitive paths.

Summary by CodeRabbit

  • Bug Fixes

    • Improved consistency for legacy and new collation behavior across string comparisons, pattern matching, casting, indexing, partitioning, imports, and table reorganization.
    • Preserved each table’s configured collation when evaluating partial indexes and routing partitioned data.
    • Prevented incompatible expression pushdown when collation settings differ.
    • Improved handling of ENUM and SET values under legacy collation settings.
  • Tests

    • Added regression coverage for collation-sensitive expressions, indexes, partitions, and data conversion.

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Jul 9, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Jul 9, 2026
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change moves new-collation selection into expression contexts. It updates expression builtins, table indexes, partition encoding, DDL backfilling, importer plans, and Lightning codecs to use context-specific collation settings. Tests cover legacy and new-collation behavior.

Changes

Collation context and expression operations

Layer / File(s) Summary
Expression context collation state
pkg/expression/..., pkg/planner/core/...
Expression contexts expose NewCollationEnabled(). Expression construction and planner checks use this state instead of explicit builder flags.
Context-aware expression operations
pkg/expression/builtin*.go, pkg/expression/util.go
String comparisons, pattern matching, lookup, location, and weight-string operations use configured collators.

Table and task integration

Layer / File(s) Summary
Table indexes and partition encoding
pkg/table/tables/..., pkg/table/column.go
Index conditions, partition expressions, partition keys, pruning, and ENUM/SET casts use table-specific collation settings.
DDL task collation integration
pkg/ddl/...
Coprocessor constructors no longer accept explicit collation flags. Backfill indexes come from physical tables, and pushdown checks collation-mode compatibility.
Importer and Lightning encoding
pkg/executor/importer/..., pkg/lightning/backend/kv/..., pkg/meta/model/reorg.go
Import plans capture keyspace collation state. Lightning contexts use table collation settings. Reorganization metadata documentation reflects captured task settings.

Validation

Layer / File(s) Summary
Collation regression coverage
pkg/expression/.../*_test.go, pkg/ddl/.../*_test.go, pkg/table/.../*_test.go, pkg/lightning/backend/kv/base_test.go
Tests cover expression evaluation, coprocessor conditions, reorganization metadata, partition collation snapshots, table indexes, casts, and Lightning contexts.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Task
  participant ExpressionContext
  participant TableEncoder
  participant IndexOrPartition
  Task->>ExpressionContext: configure target collation mode
  ExpressionContext->>TableEncoder: expose NewCollationEnabled
  TableEncoder->>IndexOrPartition: encode values with configured collator
  IndexOrPartition-->>Task: return encoded index or partition result
Loading

Possibly related PRs

  • pingcap/tidb#69677: Refactors and completes captured-collation handling across the same DDL, importer, expression, and table paths.
  • pingcap/tidb#70145: Validates persisted Plan.UseNewCollate handling for import tasks.

Suggested labels: component/import

Suggested reviewers: d3hunter, windtalker, yangkeao

Poem

I’m a rabbit with collators neat,
Making old and new modes meet.
Indexes hop, partitions spin,
Contexts tell the right mode in.
Tests nibble bugs away—
Then leap through merge day!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address issue [#69563] by applying the target keyspace collation mode across DXF encoding, partitioning, indexes, expressions, and conversions.
Out of Scope Changes check ✅ Passed The code and test changes remain focused on collation handling for DXF ADD INDEX and IMPORT INTO workflows.
Description check ✅ Passed The description includes the issue number, problem summary, implementation details, extensive test coverage, side effects, documentation impact, and release note.
Title check ✅ Passed The title clearly summarizes the main change: preserving task collation across DXF encoding and expression paths.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. sig/planner SIG: Planner labels Jul 9, 2026
@ti-chi-bot ti-chi-bot Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 9, 2026
@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jul 9, 2026
@joechenrh joechenrh changed the title *: extend DXF collation snapshot coverage *: extend DXF collation coverage Jul 10, 2026
@joechenrh joechenrh changed the title *: extend DXF collation coverage *: extend DXF collation handling to support partition table and partial index Jul 10, 2026
@ti-chi-bot ti-chi-bot Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Aug 5, 2026
@joechenrh
joechenrh marked this pull request as ready for review August 6, 2026 01:45
@ti-chi-bot ti-chi-bot Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
pkg/expression/builtin_other.go (1)

28-29: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Run make bazel_prepare after the import-section change.

pkg/expression/builtin_other.go import section was changed, so run make bazel_prepare and include the generated Bazel metadata changes. If the command produces no diff, record that result in the PR.

🤖 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/expression/builtin_other.go` around lines 28 - 29, Run make bazel_prepare
after the import changes in pkg/expression/builtin_other.go, then include any
generated Bazel metadata updates in the change; if it produces no diff, record
that result in the PR.

Source: Coding guidelines

🧹 Nitpick comments (2)
pkg/planner/core/expression_test.go (1)

492-494: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Scope the global collation change to the collation cases.

collate.SetNewCollationEnabledForTest(true) runs in the middle of TestBuildExpression, and the restore is deferred to the end of the function. Every assertion after line 558 therefore runs with the new collation mode enabled and with the default utf8mb4 collation switched by switchDefaultCollation. The remaining assertions look collation-insensitive today, but the coupling is easy to break later.

Move the collation cases into a subtest, or restore the setting immediately after the loop.

♻️ Proposed scoping with a subtest
-	origin := collate.NewCollationEnabled()
-	collate.SetNewCollationEnabledForTest(true)
-	defer collate.SetNewCollationEnabledForTest(origin)
-	collationSensitiveTbl := &model.TableInfo{
+	t.Run("collation sensitive expressions", func(t *testing.T) {
+		origin := collate.NewCollationEnabled()
+		collate.SetNewCollationEnabledForTest(true)
+		defer collate.SetNewCollationEnabledForTest(origin)
+		collationSensitiveTbl := &model.TableInfo{

Close the subtest after the assertion loop, and declare expr locally inside it so the outer expr is not reused.

🤖 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/expression_test.go` around lines 492 - 494, Scope the
collation-enabled global state to only the collation cases in
TestBuildExpression. Move the related setup and assertion loop into a subtest,
declare expr within that subtest, and restore the original setting when the
subtest completes so later assertions run with the prior collation
configuration.
pkg/table/tables/test/partition/partition_test.go (1)

76-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the opposite-mode assertion for the list-columns case.

The test builds the table with useNewCollate=false and asserts that "A" routes to p_default. A regression that always routes to the default partition would also pass this assertion. Build the same metadata with TableFromMetaWithCollate(true, ...) and assert that "A" routes to Definitions[0].ID (p0). This makes the snapshot behavior distinguishable from a fallback.

♻️ Proposed positive control
 	physicalTbl, err := pt.GetPartitionByRow(tk.Session().GetExprCtx().GetEvalCtx(), types.MakeDatums("A"))
 	require.NoError(t, err)
 	require.Equal(t, tblInfo.Partition.Definitions[1].ID, physicalTbl.GetPhysicalID())
+
+	newCollateTbl, err := tables.TableFromMetaWithCollate(true, autoid.NewAllocators(tblInfo.SepAutoInc()), tblInfo)
+	require.NoError(t, err)
+	newCollatePt := newCollateTbl.GetPartitionedTable()
+	require.NotNil(t, newCollatePt)
+	physicalTbl, err = newCollatePt.GetPartitionByRow(tk.Session().GetExprCtx().GetEvalCtx(), types.MakeDatums("A"))
+	require.NoError(t, err)
+	require.Equal(t, tblInfo.Partition.Definitions[0].ID, physicalTbl.GetPhysicalID())
🤖 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/table/tables/test/partition/partition_test.go` around lines 76 - 80,
Extend the list-columns partition test around GetPartitionByRow to also
construct the table metadata with TableFromMetaWithCollate(true, ...). Route the
same datum "A" through that table and assert its physical ID equals
tblInfo.Partition.Definitions[0].ID (p0), while preserving the existing
false-mode assertion for Definitions[1].ID.
🤖 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/expression/builtin_compare.go`:
- Around line 3420-3421: Update the string-comparison path around
CompareStringWithCollationInfo and genCompareString to use the collation mode
captured from context by CheckAndDeriveCollationFromExprs, rather than the
process-global mode used by collate.GetCollator; pass the resolved
collate.Collator or obtain it through collate.GetCollatorWithCollate, preserving
the behavior selected by ctx.NewCollationEnabled.

---

Outside diff comments:
In `@pkg/expression/builtin_other.go`:
- Around line 28-29: Run make bazel_prepare after the import changes in
pkg/expression/builtin_other.go, then include any generated Bazel metadata
updates in the change; if it produces no diff, record that result in the PR.

---

Nitpick comments:
In `@pkg/planner/core/expression_test.go`:
- Around line 492-494: Scope the collation-enabled global state to only the
collation cases in TestBuildExpression. Move the related setup and assertion
loop into a subtest, declare expr within that subtest, and restore the original
setting when the subtest completes so later assertions run with the prior
collation configuration.

In `@pkg/table/tables/test/partition/partition_test.go`:
- Around line 76-80: Extend the list-columns partition test around
GetPartitionByRow to also construct the table metadata with
TableFromMetaWithCollate(true, ...). Route the same datum "A" through that table
and assert its physical ID equals tblInfo.Partition.Definitions[0].ID (p0),
while preserving the existing false-mode assertion for Definitions[1].ID.
🪄 Autofix

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 Plus

Run ID: 2b73578a-1de7-4a41-9c12-dee8e74b079f

📥 Commits

Reviewing files that changed from the base of the PR and between 60996fd and 9ec074a.

📒 Files selected for processing (40)
  • pkg/ddl/backfilling_dist_scheduler.go
  • pkg/ddl/backfilling_operators.go
  • pkg/ddl/backfilling_test.go
  • pkg/ddl/backfilling_txn_executor.go
  • pkg/ddl/copr/BUILD.bazel
  • pkg/ddl/copr/copr_ctx.go
  • pkg/ddl/copr/copr_ctx_test.go
  • pkg/ddl/index.go
  • pkg/ddl/index_cop.go
  • pkg/ddl/reorg.go
  • pkg/executor/importer/BUILD.bazel
  • pkg/executor/importer/import.go
  • pkg/executor/importer/sampler.go
  • pkg/expression/builtin.go
  • pkg/expression/builtin_compare.go
  • pkg/expression/builtin_ilike.go
  • pkg/expression/builtin_ilike_test.go
  • pkg/expression/builtin_other.go
  • pkg/expression/builtin_string.go
  • pkg/expression/exprctx/context.go
  • pkg/expression/expression.go
  • pkg/expression/exprstatic/BUILD.bazel
  • pkg/expression/exprstatic/exprctx.go
  • pkg/expression/sessionexpr/BUILD.bazel
  • pkg/expression/sessionexpr/sessionctx.go
  • pkg/expression/util.go
  • pkg/lightning/backend/kv/base.go
  • pkg/lightning/backend/kv/base_test.go
  • pkg/lightning/backend/kv/context.go
  • pkg/lightning/backend/kv/kv2sql.go
  • pkg/lightning/backend/kv/sql2kv.go
  • pkg/meta/model/reorg.go
  • pkg/planner/core/expression_rewriter.go
  • pkg/planner/core/expression_test.go
  • pkg/table/tables/index.go
  • pkg/table/tables/partition.go
  • pkg/table/tables/tables.go
  • pkg/table/tables/tables_test.go
  • pkg/table/tables/test/partition/BUILD.bazel
  • pkg/table/tables/test/partition/partition_test.go
💤 Files with no reviewable changes (3)
  • pkg/executor/importer/sampler.go
  • pkg/ddl/backfilling_txn_executor.go
  • pkg/lightning/backend/kv/sql2kv.go

Comment on lines +3420 to +3421
return compareStringWithCollator(sctx, lhsArg, rhsArg, lhsRow, rhsRow, collate.GetCollator(collation))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 6 '\b(genCompareString|CompareStringWithCollationInfo)\s*\(' pkg --glob '*.go'
rg -n -C 4 'WithNewCollationEnabled|NewCollationEnabled|collate\.GetCollator\(' \
  pkg/expression pkg/lightning --glob '*.go'

Repository: pingcap/tidb

Length of output: 26197


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate collate symbols =="
rg -n -C 3 'func GetCollatorWithCollate|func NewCollationEnabled|func SetNewCollationEnabledForTest|var NewCollation' pkg/collate pkg/expression* pkg/lightning --glob '*.go' | head -n 220

echo
echo "== genCompareString callers only =="
rg -n -C 8 'genCompareString\s*\(' pkg --glob '*.go'

echo
echo "== CompareStringWithCollationInfo callers only =="
rg -n -C 8 'CompareStringWithCollationInfo\s*\(' pkg --glob '*.go'

echo
echo "== generate function template references =="
rg -n -C 12 'CompareStringWithCollationInfo|genCompareString|CompareString\(ctx|String\(ctx' pkg/expression/generator pkg/expression/*.go --glob '*.go' | head -n 260

echo
echo "== expression.go relevant helpers =="
sed -n '80,130p' pkg/expression/expression.go

Repository: pingcap/tidb

Length of output: 238


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo top-level directories =="
find . -maxdepth 2 -type d | sed 's#^\./##' | sort | head -n 120

echo
echo "== locate collate.go =="
find . -path './.git' -prune -o -name 'collate.go' -print

echo
echo "== candidate collate symbols =="
rg -n -C 3 'func GetCollatorWithCollate|func NewCollationEnabled|func SetNewCollationEnabledForTest|var NewCollation' . --glob '*.go' | head -n 240

echo
echo "== genCompareString callers only =="
rg -n -C 8 '\bgenCompareString\s*\(' . --glob '*.go'

echo
echo "== CompareStringWithCollationInfo callers only =="
rg -n -C 8 '\bCompareStringWithCollationInfo\s*\(' . --glob '*.go'

echo
echo "== generate function template references =="
rg -n -C 12 'CompareStringWithCollationInfo|genCompareString|CompareString\(ctx|String\(ctx' . --glob '*.go' | head -n 320

echo
echo "== expression.go relevant helpers =="
sed -n '80,130p' pkg/expression/expression.go

Repository: pingcap/tidb

Length of output: 40780


Capture the collation mode when making string comparisons reachable from genCompareString.

genCompareString derives the collation through CheckAndDeriveCollationFromExprs(ctx, ...), then CompareStringWithCollationInfo calls collate.GetCollator(collation), which uses the process-global collation mode. Use the captured context collation mode through that generic path, for example by passing collate.GetCollatorWithCollate(...) or the resolved collate.Collator that matches ctx.NewCollationEnabled.

🤖 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/expression/builtin_compare.go` around lines 3420 - 3421, Update the
string-comparison path around CompareStringWithCollationInfo and
genCompareString to use the collation mode captured from context by
CheckAndDeriveCollationFromExprs, rather than the process-global mode used by
collate.GetCollator; pass the resolved collate.Collator or obtain it through
collate.GetCollatorWithCollate, preserving the behavior selected by
ctx.NewCollationEnabled.

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.08213% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.6024%. Comparing base (b6db59b) to head (41bad5e).
⚠️ Report is 119 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #69734        +/-   ##
================================================
- Coverage   76.3227%   74.6024%   -1.7204%     
================================================
  Files          2041       2107        +66     
  Lines        560306     609152     +48846     
================================================
+ Hits         427641     454442     +26801     
- Misses       131764     150772     +19008     
- Partials        901       3938      +3037     
Flag Coverage Δ
integration 45.1984% <69.0821%> (+5.4932%) ⬆️

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/expression/exprstatic/exprctx_test.go (1)

185-185: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve coverage for the explicit collation override.

Line [185] excludes newCollationEnabled from both comparisons. The test can then pass if MakeExprContextStatic drops or changes a WithNewCollationEnabled(...) override. Add a case with an explicit override and assert that obj.NewCollationEnabled() equals staticObj.NewCollationEnabled().

🤖 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/expression/exprstatic/exprctx_test.go` at line 185, Add a test case in
the comparison coverage around MakeExprContextStatic that applies an explicit
WithNewCollationEnabled override, then assert obj.NewCollationEnabled() matches
staticObj.NewCollationEnabled(). Ensure newCollationEnabled is no longer
excluded from the comparison so changes to the override behavior are detected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/expression/exprstatic/exprctx_test.go`:
- Line 185: Add a test case in the comparison coverage around
MakeExprContextStatic that applies an explicit WithNewCollationEnabled override,
then assert obj.NewCollationEnabled() matches staticObj.NewCollationEnabled().
Ensure newCollationEnabled is no longer excluded from the comparison so changes
to the override behavior are detected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97028f32-9fbf-47d3-a96e-9a724e51a855

📥 Commits

Reviewing files that changed from the base of the PR and between 22e4c1b and 76648a3.

📒 Files selected for processing (1)
  • pkg/expression/exprstatic/exprctx_test.go

@joechenrh joechenrh changed the title *: extend DXF collation handling to support partition table and partial index *: honor task collation across DXF encoding and expression paths Aug 6, 2026
@ti-chi-bot

ti-chi-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign gmhdbjd, hawkingrei, xuhuaiyu 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

Comment thread pkg/ddl/copr/copr_ctx.go
tblInfo *model.TableInfo,
idxCols []*model.IndexColumn,
requestSource string,
useNewCollate bool,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After this PR, almost all the code path can obtain useNewCollate from either Table/Index/BuildContext, so we can drop many of the previous added argument.

@ingress-bot

Copy link
Copy Markdown

🔍 Starting code review for this PR...

@ingress-bot ingress-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This review was generated by AI and should be verified by a human reviewer.
Manual follow-up is recommended before merge.

Summary

  • Total findings: 8
  • Inline comments: 5
  • Summary-only findings (no inline anchor): 2
Findings (highest risk first)

⚠️ [Major] (1)

  1. Collator-override guard for LOCATE case-folding is duplicated per eval mode, and the vectorized copy was left unfixed (pkg/expression/builtin_string.go:1669, pkg/expression/builtin_string_vec.go:429, pkg/expression/builtin_string.go:4106, pkg/expression/builtin_string_vec.go:1751)

🟡 [Minor] (6)

  1. ForKeyPruning's new private collation field is only preserved by full-struct copy across a package boundary (pkg/table/tables/partition.go:467, pkg/planner/core/rule/rule_partition_processor.go:281)
  2. Collation-mismatch push-down skip in buildDAGPB has no direct regression test (pkg/ddl/index_cop.go:192, pkg/ddl/backfilling_test.go:130, pkg/ddl/copr/copr_ctx_test.go:134)
  3. Collation-mode-mismatch pushdown skip in buildDAGPB has no code comment explaining the invariant (pkg/ddl/index_cop.go:192)
  4. Struct-copy that preserves ForKeyPruning.useNewCollate has no comment explaining why it isn't a fresh literal (pkg/planner/core/rule/rule_partition_processor.go:281, pkg/table/tables/partition.go:380)
  5. initNeedRestoreData comment no longer explains why laziness is still needed (pkg/table/tables/index.go:62, pkg/table/tables/index.go:85, pkg/table/tables/index.go:192)
  6. CanSkip's documented skip-cases were dropped when it became TableCommon.canSkip (pkg/table/tables/tables.go:1523)

🧹 [Nit] (1)

  1. collatorOverridden guard in LOCATE's manual case-folding has no explanation of the bug it prevents (pkg/expression/builtin_string.go:1669)

Unanchored findings

⚠️ [Major] (1)

  1. Collator-override guard for LOCATE case-folding is duplicated per eval mode, and the vectorized copy was left unfixed
    • Request: Extract the collator-derived CI-folding decision (!b.collatorOverridden && collate.IsCICollation(b.collation), or equivalently a check on b.collator()) into one shared helper called from both evalInt and vecEvalInt for builtinLocate3ArgsUTF8Sig (and apply the same fix to builtinInstrUTF8Sig's scalar/vectorized pair), so the scalar and vectorized paths cannot drift again.

🟡 [Minor] (1)

  1. ForKeyPruning's new private collation field is only preserved by full-struct copy across a package boundary
    • Request: Give tables.ForKeyPruning (or PartitionExpr) an owned way to derive a copy with overridden KeyPartCols, e.g. a WithKeyPartCols method, so callers outside the package don't need to know they must shallow-copy the struct to preserve its private state.

Comment thread pkg/ddl/index_cop.go
partExpr := tbl.(base.PartitionTable).PartitionExpr()
partCols, colLen := partExpr.GetPartColumnsForKeyPartition(columns)
pe := &tables.ForKeyPruning{KeyPartCols: partCols}
pe := *partExpr.ForKeyPruning

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [Minor] Struct-copy that preserves ForKeyPruning.useNewCollate has no comment explaining why it isn't a fresh literal

Impact
getUsedKeyPartitions now copies partExpr.ForKeyPruning by value instead of building a fresh tables.ForKeyPruning{KeyPartCols: partCols} literal, purely to carry over the useNewCollate field that pe.LocateKeyPartition -> datumToHashKey depends on for correct key hashing.
Nothing at the call site records that intent, so a future edit that "simplifies" this back to a literal construction (a very plausible cleanup, since the old code did exactly that) would silently reset useNewCollate to false and route rows to the wrong key partition without any compile-time or obvious runtime signal.

Scope

  • pkg/planner/core/rule/rule_partition_processor.go:281getUsedKeyPartitions
  • pkg/table/tables/partition.go:380ForKeyPruning.datumToHashKey

Evidence
pe := *partExpr.ForKeyPruning; pe.KeyPartCols = partCols replaces the old &tables.ForKeyPruning{KeyPartCols: partCols} literal with no comment; ForKeyPruning.useNewCollate is only set once, at construction in generateKeyPartitionExpr, and is otherwise invisible from this call site.

Change request
Add a short comment at the copy explaining that it must copy the existing struct (not build a fresh literal) to preserve useNewCollate, which key-partition hashing depends on for correctness.

@joechenrh joechenrh Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

41bad5e adds a comment explaining that the full struct copy is intentional and preserves the captured collation mode.

I am not adding a WithKeyPartCols method here because it would expand the table API for one call site. The local copy remains small and preserves all private pruning state.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Resolved — a comment at the struct copy now records that it intentionally preserves the captured collation mode rather than rebuilding a fresh literal. Keeping this a local copy instead of a new table API method is a sensible call for a single call site.

Comment thread pkg/table/tables/index.go Outdated
Comment thread pkg/table/tables/tables.go
Comment thread pkg/expression/builtin_string.go
@joechenrh

Copy link
Copy Markdown
Contributor Author

Summary-only findings in #69734 (review)

  • The scalar/vectorized builtin alignment is intentionally outside this DXF collation refactor. The affected DXF generated-column, assignment, partial-index, and partition-expression paths use scalar per-row evaluation. A complete vectorized alignment spans generated comparison operators, IN, GREATEST/LEAST, STRCMP, and LOCATE, so it should be handled as a separate change.
  • INSTR does not select its current behavior from the task-level NewCollationEnabled state, so this PR leaves both scalar and vectorized INSTR unchanged.
  • I did not add WithKeyPartCols for a single call site. The existing full struct copy preserves all private pruning state, and 41bad5e now documents that requirement.

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

Labels

release-note Denotes a PR that will be considered when it comes time to generate release notes. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nextgen: tasks can use SYSTEM new_collation_enabled when encoding user keyspace KV

2 participants