Skip to content

importinto: fix cancel race before DXF task commit (#69968) - #69991

Merged
ti-chi-bot[bot] merged 3 commits into
pingcap:release-nextgen-202603from
ti-chi-bot:cherry-pick-69968-to-release-nextgen-202603
Jul 23, 2026
Merged

ti-chi-bot[bot] merged 3 commits into
pingcap:release-nextgen-202603from
ti-chi-bot:cherry-pick-69968-to-release-nextgen-202603

Conversation

@ti-chi-bot

@ti-chi-bot ti-chi-bot commented Jul 23, 2026 •

Copy link
Copy Markdown
Member

This is an automated cherry-pick of #69968

What problem does this PR solve?

Issue Number: ref #61702

Problem Summary:

This is a follow-up to #69701.

In nextgen user keyspace mode, the import job and its SYSTEM-keyspace DXF task are committed in separate transactions. If CANCEL IMPORT JOB updates the DXF task before the task transaction commits, but the task becomes visible before WaitTaskDoneByKey performs its first lookup, no cancellation is recorded. The command then waits for the task's natural terminal state and can return successfully even though it did not cancel the import job.

What changed and how does it work?

  • Probe the live DXF task table by task key before issuing the cancel update.
  • If no task is visible, immediately use the dangling-job fallback instead of waiting for a task that may be committed later.
  • If the task exists, issue the normal cancel update and wait for terminal completion. An existing task outside the cancellable-state predicate is therefore not mistaken for a missing task.
  • Add regression coverage for a task committed immediately after the probe misses and for an existing terminal task.
  • Update the import job/DXF task transaction notes to document the new ordering and remaining races.

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.
./tools/check/failpoint-go-test.sh pkg/dxf/importinto -run TestSubmitTaskNextgen -count=1
./tools/check/failpoint-go-test.sh pkg/dxf/framework/storage -run TestTaskState -count=1
make lint

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 a race where CANCEL IMPORT JOB can miss a DXF task being committed in the SYSTEM keyspace and wait for it without cancelling the import job.

Summary by CodeRabbit

  • Bug Fixes
    • Improved IMPORT INTO next-gen job cancellation and wait behavior when the related DXF task is missing, not yet visible, or created later.
    • Added active/history-aware probing to avoid unnecessary waiting and to correctly handle dangling-job detection.
  • Tests
    • Expanded coverage for cross-keyspace cancellation scenarios and for cancellation outcomes when tasks are reverted or appear after the cancel probe.
    • Added a test helper to cancel and wait for IMPORT INTO jobs by job ID.
  • Documentation
    • Refined documentation of IMPORT INTO vs DXF cancellation semantics, including updated timing cases and correctness invariants.

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 Denotes a PR that will be considered when it comes time to generate release notes. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. type/cherry-pick-for-release-nextgen-202603 labels Jul 23, 2026
@ti-chi-bot

Copy link
Copy Markdown
Member Author

@D3Hunter 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

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

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

@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 14a1a6a6-5780-4705-a57f-1befff0216ce

📥 Commits

Reviewing files that changed from the base of the PR and between a99f7a0 and 484530c.

📒 Files selected for processing (1)
  • pkg/dxf/importinto/job_testkit_test.go
💤 Files with no reviewable changes (1)
  • pkg/dxf/importinto/job_testkit_test.go

📝 Walkthrough

Walkthrough

IMPORT INTO cancellation now probes live and historical DXF tasks before cancelling and waiting, or directly cancels dangling jobs when no task is found. Tests cover archived-task and lookup-miss races, while documentation describes the updated semantics.

Changes

IMPORT INTO cancellation flow

Layer / File(s) Summary
Probe-based cancellation flow
pkg/executor/import_into.go, pkg/executor/pkg_test.go, pkg/executor/import_into_test.go
Cancellation probes DXF task history, then either cancels and waits or directly cancels a dangling import job.
DXF race and history test coverage
pkg/dxf/importinto/job_testkit_test.go
Shared setup and subtests cover archived tasks, lookup-miss races, and dangling user-keyspace jobs.
Cancellation semantics documentation
pkg/dxf/importinto/job_doc.go, .agents/skills/tidb-test-guidelines/references/*-case-map.md
Documentation describes history-aware lookup, cancellation interleavings, zero-row updates, invariants, consistency windows, and test coverage.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ImportExecutor
  participant DXFStorage
  participant ImportJobStorage
  Client->>ImportExecutor: Cancel import job
  ImportExecutor->>DXFStorage: Probe live/history task by key
  alt task exists
    ImportExecutor->>DXFStorage: Cancel task
    ImportExecutor->>DXFStorage: Wait for task completion
  else task not found
    ImportExecutor->>ImportJobStorage: Cancel dangling import job
  end
  ImportExecutor-->>Client: Return cancellation result
Loading

Possibly related PRs

  • pingcap/tidb#69701: Adds the dangling IMPORT INTO job cancellation logic that this probe-based flow extends.
  • pingcap/tidb#69787: Covers related dangling-job cancellation implementation and tests.
  • pingcap/tidb#69968: Modifies the same history-probe cancellation flow and race scenarios.

Suggested labels: sig/planner, lgtm

Suggested reviewers: joechenrh, wjhuang2016

Poem

I’m a bunny watching tasks in flight,
Probing history, then choosing right.
Cancel and wait, or clear the stray,
Tests chase races along the way.
Docs hop softly into tune.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 title is concise and accurately summarizes the main change: fixing a cancellation race in importinto before DXF task commit.
Description check ✅ Passed The description matches the template well and includes the issue reference, problem summary, implementation details, tests, documentation, and release note.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@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

🤖 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/dxf/importinto/job_testkit_test.go`:
- Around line 202-304: Remove the unresolved merge-conflict markers surrounding
the three added subtests in the test file, including the empty HEAD section and
the separator/commit marker. Preserve all three subtests unchanged so the file
compiles and retains the incoming test coverage.
🪄 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 Plus

Run ID: c355e5c3-6d95-4214-a802-7dd775737fee

📥 Commits

Reviewing files that changed from the base of the PR and between 6982770 and 4431e39.

📒 Files selected for processing (7)
  • .agents/skills/tidb-test-guidelines/references/dxf-case-map.md
  • .agents/skills/tidb-test-guidelines/references/executor-case-map.md
  • pkg/dxf/importinto/job_doc.go
  • pkg/dxf/importinto/job_testkit_test.go
  • pkg/executor/import_into.go
  • pkg/executor/import_into_test.go
  • pkg/executor/pkg_test.go

Comment thread pkg/dxf/importinto/job_testkit_test.go Outdated
Comment on lines +202 to +304
<<<<<<< HEAD
=======

t.Run("cancel user keyspace job with an archived reverted DXF task", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
require.NoError(t, err)
// This is a synthetic state, not a normal real-world scheduler outcome:
// onReverting calls importScheduler.OnDone to fail or cancel the job before
// RevertedTask marks the DXF task reverted. Bypassing OnDone here isolates
// the check that an existing terminal task is not treated as a missing task.
require.NoError(t, sysKSTaskMgr.RevertTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("already reverted")))
require.NoError(t, sysKSTaskMgr.RevertedTask(ctx, taskID))
task, err := sysKSTaskMgr.GetTaskByID(ctx, taskID)
require.NoError(t, err)
require.NoError(t, sysKSTaskMgr.TransferTasks2History(ctx, []*proto.Task{task}))
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where id = ?", taskID).
Check(testkit.Rows("0"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))

userKSTK.MustExec(fmt.Sprintf("cancel import job %d", jobID))

userKSTK.MustQuery("select status from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("pending"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))
})

t.Run("cancel pending user keyspace job when task is created after lookup miss", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows("0"))

var lateTaskID atomic.Int64
callbackErrCh := make(chan error, 1)
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/executor/afterCancelImportTaskProbeMiss",
func(probeMissJobID int64) {
if probeMissJobID != jobID {
callbackErrCh <- fmt.Errorf("unexpected job ID %d", probeMissJobID)
return
}
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
if err != nil {
callbackErrCh <- err
return
}
lateTaskID.Store(taskID)
},
)

cancelErrCh := make(chan error, 1)
go func() {
_, err := userKSTK.Exec(fmt.Sprintf("cancel import job %d", jobID))
cancelErrCh <- err
}()

select {
case err := <-cancelErrCh:
require.NoError(t, err)
case <-time.After(5 * time.Second):
if taskID := lateTaskID.Load(); taskID != 0 {
require.NoError(t, sysKSTaskMgr.FailTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("unblock timed out cancel")))
<-cancelErrCh
}
require.FailNow(t, "cancel import waited for a task created after the cancel-by-key miss")
}
select {
case err := <-callbackErrCh:
require.NoError(t, err)
default:
}

userKSTK.MustQuery("select status, error_message from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("cancelled cancelled by user"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows(string(proto.TaskStatePending)))
})

t.Run("submit global-sort task uses async prepare mode", func(t *testing.T) {
sysKSTK.MustExec("delete from mysql.tidb_import_jobs")
sysKSTK.MustExec("delete from mysql.tidb_global_task")
config.UpdateGlobal(func(conf *config.Config) {
conf.KeyspaceName = keyspace.System
})
manuallyInitFn(t, sysKSStore, sysKSStore)

jobID, task, err := importinto.SubmitTask(ctx, &importer.Plan{
TableInfo: &model.TableInfo{},
Parameters: &importer.ImportParameters{},
ThreadCnt: 16,
MaxNodeCnt: 8,
CloudStorageURI: "local:///tmp/prepare-mode-sort",
}, "import into t from 's3://bucket/test.csv'")
require.NoError(t, err)
sysKSTK.MustQuery("select count(1) from mysql.tidb_import_jobs where id = ?", jobID).Check(testkit.Rows("1"))
sysKSTK.MustQuery(
"select concurrency, max_node_count, json_extract(extra_params, '$.prepare_mode') "+
"from mysql.tidb_global_task where id = ?",
task.ID,
).Check(testkit.Rows("1 1 1"))
})
>>>>>>> ce53f1c50aa (importinto: fix cancel race before DXF task commit (#69968))

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 | 🔴 Critical | ⚡ Quick win

Unresolved merge-conflict markers left in source — file won't compile.

Lines 202-204 and 304 still contain literal <<<<<<< HEAD / ======= / >>>>>>> ce53f1c50aa (...) markers. This breaks go build/go vet for the package. Since the HEAD side is empty, resolution here is just removing the markers and keeping the incoming content (the three new subtests).

🔧 Proposed fix
-<<<<<<< HEAD
-=======

 	t.Run("cancel user keyspace job with an archived reverted DXF task", func(t *testing.T) {
@@ ... (subtests unchanged) ... @@
-	})
->>>>>>> ce53f1c50aa (importinto: fix cancel race before DXF task commit (`#69968`))
+	})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<<<<<<< HEAD
=======
t.Run("cancel user keyspace job with an archived reverted DXF task", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
require.NoError(t, err)
// This is a synthetic state, not a normal real-world scheduler outcome:
// onReverting calls importScheduler.OnDone to fail or cancel the job before
// RevertedTask marks the DXF task reverted. Bypassing OnDone here isolates
// the check that an existing terminal task is not treated as a missing task.
require.NoError(t, sysKSTaskMgr.RevertTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("already reverted")))
require.NoError(t, sysKSTaskMgr.RevertedTask(ctx, taskID))
task, err := sysKSTaskMgr.GetTaskByID(ctx, taskID)
require.NoError(t, err)
require.NoError(t, sysKSTaskMgr.TransferTasks2History(ctx, []*proto.Task{task}))
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where id = ?", taskID).
Check(testkit.Rows("0"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))
userKSTK.MustExec(fmt.Sprintf("cancel import job %d", jobID))
userKSTK.MustQuery("select status from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("pending"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))
})
t.Run("cancel pending user keyspace job when task is created after lookup miss", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows("0"))
var lateTaskID atomic.Int64
callbackErrCh := make(chan error, 1)
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/executor/afterCancelImportTaskProbeMiss",
func(probeMissJobID int64) {
if probeMissJobID != jobID {
callbackErrCh <- fmt.Errorf("unexpected job ID %d", probeMissJobID)
return
}
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
if err != nil {
callbackErrCh <- err
return
}
lateTaskID.Store(taskID)
},
)
cancelErrCh := make(chan error, 1)
go func() {
_, err := userKSTK.Exec(fmt.Sprintf("cancel import job %d", jobID))
cancelErrCh <- err
}()
select {
case err := <-cancelErrCh:
require.NoError(t, err)
case <-time.After(5 * time.Second):
if taskID := lateTaskID.Load(); taskID != 0 {
require.NoError(t, sysKSTaskMgr.FailTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("unblock timed out cancel")))
<-cancelErrCh
}
require.FailNow(t, "cancel import waited for a task created after the cancel-by-key miss")
}
select {
case err := <-callbackErrCh:
require.NoError(t, err)
default:
}
userKSTK.MustQuery("select status, error_message from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("cancelled cancelled by user"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows(string(proto.TaskStatePending)))
})
t.Run("submit global-sort task uses async prepare mode", func(t *testing.T) {
sysKSTK.MustExec("delete from mysql.tidb_import_jobs")
sysKSTK.MustExec("delete from mysql.tidb_global_task")
config.UpdateGlobal(func(conf *config.Config) {
conf.KeyspaceName = keyspace.System
})
manuallyInitFn(t, sysKSStore, sysKSStore)
jobID, task, err := importinto.SubmitTask(ctx, &importer.Plan{
TableInfo: &model.TableInfo{},
Parameters: &importer.ImportParameters{},
ThreadCnt: 16,
MaxNodeCnt: 8,
CloudStorageURI: "local:///tmp/prepare-mode-sort",
}, "import into t from 's3://bucket/test.csv'")
require.NoError(t, err)
sysKSTK.MustQuery("select count(1) from mysql.tidb_import_jobs where id = ?", jobID).Check(testkit.Rows("1"))
sysKSTK.MustQuery(
"select concurrency, max_node_count, json_extract(extra_params, '$.prepare_mode') "+
"from mysql.tidb_global_task where id = ?",
task.ID,
).Check(testkit.Rows("1 1 1"))
})
>>>>>>> ce53f1c50aa (importinto: fix cancel race before DXF task commit (#69968))
t.Run("cancel user keyspace job with an archived reverted DXF task", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
require.NoError(t, err)
// This is a synthetic state, not a normal real-world scheduler outcome:
// onReverting calls importScheduler.OnDone to fail or cancel the job before
// RevertedTask marks the DXF task reverted. Bypassing OnDone here isolates
// the check that an existing terminal task is not treated as a missing task.
require.NoError(t, sysKSTaskMgr.RevertTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("already reverted")))
require.NoError(t, sysKSTaskMgr.RevertedTask(ctx, taskID))
task, err := sysKSTaskMgr.GetTaskByID(ctx, taskID)
require.NoError(t, err)
require.NoError(t, sysKSTaskMgr.TransferTasks2History(ctx, []*proto.Task{task}))
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where id = ?", taskID).
Check(testkit.Rows("0"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))
userKSTK.MustExec(fmt.Sprintf("cancel import job %d", jobID))
userKSTK.MustQuery("select status from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("pending"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task_history where id = ?", taskID).
Check(testkit.Rows(string(proto.TaskStateReverted)))
})
t.Run("cancel pending user keyspace job when task is created after lookup miss", func(t *testing.T) {
jobID, sysKSTaskMgr := setupUserKeyspaceImportJob(t)
sysKSTK.MustQuery("select count(1) from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows("0"))
var lateTaskID atomic.Int64
callbackErrCh := make(chan error, 1)
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/executor/afterCancelImportTaskProbeMiss",
func(probeMissJobID int64) {
if probeMissJobID != jobID {
callbackErrCh <- fmt.Errorf("unexpected job ID %d", probeMissJobID)
return
}
taskID, err := sysKSTaskMgr.CreateTask(ctx, importinto.TaskKey(jobID), proto.ImportInto, "", 1, "", 0, proto.ExtraParams{}, nil)
if err != nil {
callbackErrCh <- err
return
}
lateTaskID.Store(taskID)
},
)
cancelErrCh := make(chan error, 1)
go func() {
_, err := userKSTK.Exec(fmt.Sprintf("cancel import job %d", jobID))
cancelErrCh <- err
}()
select {
case err := <-cancelErrCh:
require.NoError(t, err)
case <-time.After(5 * time.Second):
if taskID := lateTaskID.Load(); taskID != 0 {
require.NoError(t, sysKSTaskMgr.FailTask(ctx, taskID, proto.TaskStatePending, fmt.Errorf("unblock timed out cancel")))
<-cancelErrCh
}
require.FailNow(t, "cancel import waited for a task created after the cancel-by-key miss")
}
select {
case err := <-callbackErrCh:
require.NoError(t, err)
default:
}
userKSTK.MustQuery("select status, error_message from mysql.tidb_import_jobs where id = ?", jobID).
Check(testkit.Rows("cancelled cancelled by user"))
sysKSTK.MustQuery("select state from mysql.tidb_global_task where task_key = ?", importinto.TaskKey(jobID)).
Check(testkit.Rows(string(proto.TaskStatePending)))
})
t.Run("submit global-sort task uses async prepare mode", func(t *testing.T) {
sysKSTK.MustExec("delete from mysql.tidb_import_jobs")
sysKSTK.MustExec("delete from mysql.tidb_global_task")
config.UpdateGlobal(func(conf *config.Config) {
conf.KeyspaceName = keyspace.System
})
manuallyInitFn(t, sysKSStore, sysKSStore)
jobID, task, err := importinto.SubmitTask(ctx, &importer.Plan{
TableInfo: &model.TableInfo{},
Parameters: &importer.ImportParameters{},
ThreadCnt: 16,
MaxNodeCnt: 8,
CloudStorageURI: "local:///tmp/prepare-mode-sort",
}, "import into t from 's3://bucket/test.csv'")
require.NoError(t, err)
sysKSTK.MustQuery("select count(1) from mysql.tidb_import_jobs where id = ?", jobID).Check(testkit.Rows("1"))
sysKSTK.MustQuery(
"select concurrency, max_node_count, json_extract(extra_params, '$.prepare_mode') "+
"from mysql.tidb_global_task where id = ?",
task.ID,
).Check(testkit.Rows("1 1 1"))
})
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 254-254: Detected a SQL statement built with 'fmt.Sprintf' and passed directly to 'db.Exec'/'db.ExecContext'. Interpolating values into a query string lets an attacker inject arbitrary SQL. Use parameterized queries instead: pass the SQL with placeholders ('?' or '') as the query argument and supply the values as separate arguments, e.g. 'db.Exec("UPDATE t SET x = ? WHERE id = ?", x, id)'.
Context: userKSTK.Exec(fmt.Sprintf("cancel import job %d", jobID))
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').

(sql-injection-exec-sprintf-go)

🪛 OpenGrep (1.25.0)

[ERROR] 255-255: SQL query built via fmt.Sprintf or string concatenation passed to a database method. Use parameterized queries with placeholder arguments.

(coderabbit.sql-injection.go-query-format)

🤖 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/dxf/importinto/job_testkit_test.go` around lines 202 - 304, Remove the
unresolved merge-conflict markers surrounding the three added subtests in the
test file, including the empty HEAD section and the separator/commit marker.
Preserve all three subtests unchanged so the file compiles and retains the
incoming test coverage.

Signed-off-by: D3Hunter <jujj603@gmail.com>
@ti-chi-bot

Copy link
Copy Markdown
Member Author

Cherry-pick conflicts appear resolved; removing the do-not-merge/hold label.

@ti-chi-bot ti-chi-bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 23, 2026
@ti-chi-bot ti-chi-bot Bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jul 23, 2026
@codecov

codecov Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (release-nextgen-202603@6982770). Learn more about missing BASE report.

Additional details and impacted files
@@                     Coverage Diff                     @@
##             release-nextgen-202603     #69991   +/-   ##
===========================================================
  Coverage                          ?   76.1759%           
===========================================================
  Files                             ?       1937           
  Lines                             ?     541181           
  Branches                          ?          0           
===========================================================
  Hits                              ?     412250           
  Misses                            ?     128931           
  Partials                          ?          0           
Flag Coverage Δ
unit 76.1759% <91.6666%> (?)

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

Components Coverage Δ
dumpling 61.5065% <0.0000%> (?)
parser ∅ <0.0000%> (?)
br 48.7288% <0.0000%> (?)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Signed-off-by: D3Hunter <jujj603@gmail.com>
@ti-chi-bot

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: D3Hunter, GMHDBJD

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

The pull request process is described here

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

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

@ti-chi-bot ti-chi-bot Bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jul 23, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-07-23 05:50:29.029764902 +0000 UTC m=+1470415.065859998: ☑️ agreed by D3Hunter.
  • 2026-07-23 06:54:21.701747828 +0000 UTC m=+1474247.737842883: ☑️ agreed by GMHDBJD.

@D3Hunter

Copy link
Copy Markdown
Contributor

/retest

@ti-chi-bot
ti-chi-bot Bot merged commit b3fa6d7 into pingcap:release-nextgen-202603 Jul 23, 2026
18 checks passed
@ti-chi-bot
ti-chi-bot Bot deleted the cherry-pick-69968-to-release-nextgen-202603 branch July 23, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. type/cherry-pick-for-release-nextgen-202603

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants