Skip to content

feat(move-tables): fix target table creation to use target DB + abort if exists (#8207)#1710

Merged
zacharysierakowski merged 2 commits into
feature-move-tablesfrom
womoruyi/move-tables-1.3-target-table-crud
Jun 12, 2026
Merged

feat(move-tables): fix target table creation to use target DB + abort if exists (#8207)#1710
zacharysierakowski merged 2 commits into
feature-move-tablesfrom
womoruyi/move-tables-1.3-target-table-crud

Conversation

@womoruyi

Copy link
Copy Markdown

Behavior change for move-tables mode: fixes createTargetTableFromStatement to execute on the target cluster (not the source), and adds an explicit "abort if exists" pre-check before creating the target table. Standard --alter migrations are unaffected.

What approach did you choose and why?

The prototype's createTargetTableFromStatement (applier.go:600) used apl.db.Begin() to open a transaction — but apl.db is the source (applier) connection. In move-tables mode, the target table must be created on apl.moveTablesTargetDB (the target cluster). This PR fixes the DB handle selection: createTargetTableFromStatement now checks IsMoveTablesMode() and uses moveTablesTargetDB when true.

For the "abort if exists" behavior, the design doc says "Don't use IF NOT EXISTS for the target table. An existing table is an error condition, not a no-op" (move_table_mode.md §1.3). Rather than relying on MySQL's implicit ERROR 1050, CreateTargetTable now pre-checks information_schema.tables on the target and returns a descriptive gh-ost error message telling the operator what to do. This matches the existing ValidateOrDropExistingTables pattern used for ghost tables (applier.go:483).

Scope (#8207 only):

  1. go/logic/applier.go:608-612createTargetTableFromStatement now selects moveTablesTargetDB in move-tables mode instead of always using apl.db.
  2. go/logic/applier.go:643-673CreateTargetTable adds an explicit information_schema pre-check on the target cluster before attempting CREATE TABLE.
  3. go/logic/applier_test.go — Two new integration tests: TestCreateTargetTable_HappyPath (schema equivalence via SHOW CREATE TABLE, both-side assertion) and TestCreateTargetTable_AbortsIfExists (pre-creates target, asserts descriptive error).

Explicitly NOT in this PR (belongs to adjacent issues):

  • DML event routing to target DB (ApplyDMLEventQueries move-tables branch at applier.go:2067) — #8175
  • Copy query builders (moveTablesCopySelectFirstQueryBuilder etc.) — #8175 / #8163
  • Heartbeat/changelog skips — #8206
  • Cutover orchestration (moveTablesCutOver) — #8209
  • Throttler initialization — #8212
  • Duplicate moveTablesTargetDB initialization block at applier.go:163-179 — pre-existing prototype duplication, not introduced or fixed here

Which feature flags are involved in this change?

  • None. Move-tables mode is gated by the existing IsMoveTablesMode() predicate (#8167).

Which environments does this change target?

  • N/A — gh-ost is an operator tool, not a service. Built and shipped via script/build.

Risk assessment

  • Low risk. The fix only affects code paths gated by IsMoveTablesMode(). Standard --alter migrations never reach CreateTargetTable (it returns an error if called outside move-tables mode). The createTargetTableFromStatement change adds a conditional DB handle selection but preserves the original apl.db path for non-move-tables callers.

How did/will you validate this change?

  • Testsgo test -run 'TestApplier/TestCreateTargetTable' -v ./go/logic/... — both PASS.
  • Othergo build ./... clean. gofmt -l ./go/ clean. go vet ./go/logic/... clean.
  • Other — Boundary check: only go/logic/applier.go and go/logic/applier_test.go modified.

Known pre-existing test failures (not introduced by this PR)

  • TestEventsStreamer — intermittent testcontainers startup flake (same root cause as #8206 / #8209 PRs).

Are there related full stack changes?

  • No — this is a bug fix inside the gh-ost Go binary.

If something goes wrong, what are the mitigation and rollback strategies?

  • Rollback — Revert the merge commit on feature-move-tables. The change is contained to go/logic/applier.go.
  • Operator workaround — Move-tables is opt-in via --move-tables. Operators on standard --alter are unaffected.

Reviewers: The key change is the DB handle fix at applier.go:608-612 — verify that moveTablesTargetDB is the correct connection for target table creation. The "abort if exists" pre-check at applier.go:655-665 is a design choice (explicit error vs implicit MySQL 1050); if you prefer the implicit approach, the pre-check block is self-contained and removable. DML routing (#8175) and cutover (#8209) are not in this PR by design.

womoruyi and others added 2 commits June 12, 2026 20:26
… if exists (#8207)

AC #1: createTargetTableFromStatement now uses moveTablesTargetDB instead of
apl.db in move-tables mode, so the table is created on the target cluster
(not the source). The SHOW CREATE TABLE DDL from the inspector already
contains the correct table name; the connection handles the database.

AC #2: CreateTargetTable pre-checks information_schema on the target for
an existing table and returns a descriptive gh-ost error before attempting
CREATE TABLE. The design doc says 'An existing table is an error condition,
not a no-op' (move_table_mode.md §1.3).

Tests: TestCreateTargetTable_HappyPath (schema equivalence via SHOW CREATE
TABLE on target, both-side assertion per TI #3), TestCreateTargetTable_AbortsIfExists
(precondition asserted per TQ #4, error message checked).

Ref: database-infrastructure#8207
@womoruyi womoruyi requested a review from meiji163 as a code owner June 12, 2026 20:44
Copilot AI review requested due to automatic review settings June 12, 2026 20:44
@womoruyi womoruyi added the feature-move-tables PRs that are associated with the new move-tables feature label Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR changes move-tables mode behavior so that target table creation runs against the target cluster connection (not the source/applier connection), and adds an explicit pre-check that aborts early if the target table already exists. Standard --alter migrations remain unaffected because CreateTargetTable is gated behind IsMoveTablesMode().

Changes:

  • Update createTargetTableFromStatement to use moveTablesTargetDB in move-tables mode instead of always using apl.db.
  • Add an information_schema.tables existence pre-check in CreateTargetTable with a descriptive operator-facing error message.
  • Add integration tests covering successful target table creation and the “abort if exists” behavior.
Show a summary per file
File Description
go/logic/applier.go Selects the correct DB handle in move-tables mode and adds an explicit “abort if exists” pre-check before creating the target table.
go/logic/applier_test.go Adds integration tests for move-tables target table creation and abort-on-exists behavior.

Copilot's findings

Tip

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

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment thread go/logic/applier.go
Comment on lines +608 to +612
db := apl.db
if apl.migrationContext.IsMoveTablesMode() {
db = apl.moveTablesTargetDB
}

Comment thread go/logic/applier.go
Comment on lines +661 to +668
// Explicit pre-check: abort before any data is copied if the target table
// already exists. The CREATE TABLE would also fail (MySQL ERROR 1050), but
// this gives operators a clear gh-ost error message explaining what to do.
var count int
err := apl.moveTablesTargetDB.QueryRow(
"SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=? AND table_name=?",
targetDatabase, targetTableName,
).Scan(&count)
Comment thread go/logic/applier_test.go
Comment on lines +875 to +878
err = applier.CreateTargetTable(sourceCreateDDL)
suite.Require().Error(err, "CreateTargetTable must return an error when target table already exists")
suite.Require().Contains(err.Error(), "already exists", "error message must mention 'already exists'")
suite.Require().Contains(err.Error(), testMysqlTableName, "error message must name the table")
@zacharysierakowski zacharysierakowski merged commit bb029da into feature-move-tables Jun 12, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature-move-tables PRs that are associated with the new move-tables feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants