Skip to content

Conversation

@yakirgb
Copy link
Contributor

@yakirgb yakirgb commented Feb 9, 2026

Summary

Fixes #1625 — four related bugs found by code inspection of the trigger handling logic.

Bug 1: Double-transformation in trigger length validation

  • ValidateGhostTriggerLengthBelowMaxLength called GetGhostTriggerName on an already-transformed name, adding the suffix twice and falsely rejecting valid trigger names.
  • Fix: validate length as-is since the caller already transforms the name.

Bug 2: Atomic cut-over silently ignores trigger creation errors

  • CreateTriggersOnGhost error was logged but not returned during atomic cut-over, causing silent trigger loss.
  • Fix: add return to match the two-step cut-over behavior.

Bug 3: validateGhostTriggersDontExist checks wrong table scope

  • Validation filtered by event_object_table, missing conflicts on other tables in the same schema.
  • Fix: remove the table filter since MySQL trigger names are unique per schema.

Bug 4: SQL injection in GetTriggers()

  • Used fmt.Sprintf string interpolation instead of parameterized query.
  • Fix: switch to ? placeholders, matching the safe pattern in inspect.go.

Test plan

  • Updated unit tests in go/base/context_test.go — tests now simulate the real call pattern (transform first, then validate) with boundary tests at 64/65 chars
  • Added localtests/trigger-long-name-validation — verifies 60-char trigger names are not falsely rejected (Bug 1)
  • Added localtests/trigger-ghost-name-conflict — verifies ghost name conflicts on other tables are detected (Bug 3)
  • go build ./... — clean
  • go test ./go/base/ ./go/mysql/ ./go/sql/ — all pass

Thank you, Yakir Gibraltar

ValidateGhostTriggerLengthBelowMaxLength was calling GetGhostTriggerName
on an already-transformed name, adding the suffix twice. This caused valid
trigger names (ghost name <= 64 chars) to be falsely rejected.

The caller in inspect.go:627 already transforms the name via
GetGhostTriggerName before passing it, so the validation function
should check the length as-is.

Unit tests updated to reflect the correct call pattern: transform first
with GetGhostTriggerName, then validate the result. Added boundary tests
for exactly 64 and 65 char names.
During atomic cut-over, if CreateTriggersOnGhost failed, the error was
logged but not returned. The migration continued and completed without
triggers, silently losing them.

The two-step cut-over (line 793) already correctly returns the error.
This aligns the atomic cut-over to do the same.
validateGhostTriggersDontExist was filtering by event_object_table,
only checking if the ghost trigger name existed on the original table.
MySQL trigger names are unique per schema, so a trigger with the same
name on any other table would block CREATE TRIGGER but pass validation.

Remove the event_object_table filter to check trigger_name + trigger_schema
only, matching MySQL's uniqueness constraint.
GetTriggers used fmt.Sprintf with string interpolation for database and
table names, causing SQL syntax errors with special characters and
potential SQL injection. Switched to parameterized query with ? placeholders,
matching the safe pattern already used in inspect.go:553-559.
Add two integration tests:
- trigger-long-name-validation: verifies 60-char trigger names
  (64-char ghost name) are not falsely rejected by double-transform
- trigger-ghost-name-conflict: verifies validation detects ghost
  trigger name conflicts on other tables in the same schema
@meiji163
Copy link
Contributor

meiji163 commented Feb 9, 2026

Thanks for the PR @yakirgb ! Can you gofmt the code so the CI passes?

@yakirgb
Copy link
Contributor Author

yakirgb commented Feb 10, 2026

Thanks @meiji163! Just pushed a gofmt fix (commit 0599625). Should be good now.

@meiji163 meiji163 merged commit c6f95cc into github:master Feb 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trigger handling bugs: double-transform, silent errors, wrong scope, SQL injection

3 participants