Skip to content

sys_setting's degradation message hands MySQL operators a duplicate-probe statement that does not parse on MySQL (key is reserved) #9434

Description

@os-zhuang

Found while verifying #9381's step 2 (checking the sibling migrations for the same dialect convention). Filed unassigned; not fixed in #9381's PR — different file, different statement, and it needs its own decision about whether these operator-facing statements become dialect-aware too.

What

packages/metadata-protocol/src/migrations/sys-setting-identity-index.ts builds buildSysSettingDuplicateProbeSql() with bare identifiers, and one of the columns it names is key, which is a RESERVED word on MySQL. The statement is never executed by the platform — it is printed into the degradation/conflict log so an operator can list the offending rows themselves.

The audience is exactly the dialect it cannot run on. The unsupported arm is reached specifically on MySQL/MariaDB (no functional key parts, no CREATE INDEX IF NOT EXISTS), and its message ends:

MySQL/MariaDB before 8.0.13 has no functional key parts, so there is no in-dialect fix: run this platform on SQLite/PostgreSQL for the guarantee, and meanwhile watch for duplicates with: SELECT COALESCE(organization_id, '__global__') AS organization_id_key, namespace, key, scope, …

So the one remedy offered to the MySQL operator is a statement their server rejects.

Measured

Live MySQL 8.0.46 (sql_mode = ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION), the exact statement the module prints:

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'key, scope, COALESCE(user_id, '') AS
user_id_key, COUNT(*) AS duplicate_rows FRO' at line 1

Also measured, so the scope is precise:

  • buildOverlayDuplicateProbeSql() in overlay-index.ts — RUNS on the same server (its columns type, name, organization_id, package_id are not reserved). Clean.
  • partial-index-probe.ts — builds no identifier-quoted SQL of its own. Clean.
  • sys-setting-identity-index.ts documents the bare-identifier choice deliberately (the module header says quoting "would not change that verdict" for the INDEX statement, which is true — MySQL refuses that one for other reasons). The header's reasoning does not cover the probe statement, which is a plain SELECT that MySQL could run if key were quoted.

Not a runtime defect

Nothing in the platform executes this statement, so no boot path breaks. What breaks is the operator's copy-paste.

Options (for triage, not decided here)

  1. Quote the identifiers in buildSysSettingDuplicateProbeSql for the connected dialect, the way metadata-protocol's raw-SQL migrations quote identifiers with " on every dialect, but MySQL does not run with ANSI_QUOTES — the #8686 / #8629 / #5839 statements cannot parse there #9381 did for seed-tenancy-backfill.ts and Report the business identifiers already minted twice by the tenancy split — an operator-facing inventory, on installs the #8686 backfill cannot repair #8928 did for migrate/duplicates.ts. Needs the dialect at that seam, which the ensure-function does not currently carry.
  2. Print a MySQL-spelled variant only in the unsupported arm, since that arm is already dialect-specific by construction.
  3. Accept it and say so in the message ("quote key for MySQL").

Backlink: #9381 (the dialect-quoting fix for the seed-tenancy backfill; its PR does not touch this file).

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions