Skip to content

chore(mysql): apply existing _quote_ident to all SQL paths (#442 follow-up) #511

@yodakanohoshi

Description

@yodakanohoshi

Summary

MySQLDestination already has a _quote_ident helper that correctly handles schema-qualified table names (db.table`db`.`table`), but it's only used in the swap path. The non-swap replace / insert / upsert paths still use raw f-string interpolation, so schema-qualified table names break in those modes.

Background

#442 / PR #498 closed the equivalent gap on the Postgres side (psycopg2.sql.Identifier with (schema, relation) parts). The MySQL audit was listed in #442's "Proposed Approach" but explicitly out of scope — this issue captures it as a follow-up.

The good news: unlike Postgres, the MySQL fix needs no new helpers. _quote_ident already exists in drt/destinations/mysql.py and does the right thing:

@staticmethod
def _quote_ident(table: str) -> str:
    if "." in table:
        return "`" + "`.`".join(table.split(".")) + "`"
    return f"`{table}`"

The work is purely mechanical: replace the remaining raw-backtick f-strings with _quote_ident().

Call sites that still use raw f-strings

Method Line Current Needs
_load_replace L190 f"TRUNCATE TABLE \{table}`"` f"TRUNCATE TABLE {self._quote_ident(table)}"
_build_insert_sql L353 f"INSERT INTO \{table}` ..."` _quote_ident(table)
_build_upsert_sql L368 f"INSERT INTO \{table}` ..."` _quote_ident(table)
_build_upsert_sql L372 f"INSERT IGNORE INTO \{table}` ..."` _quote_ident(table)
get_row_count L144-149 inline split+backtick logic reuse _quote_ident

(_load_replace_swap and finalize_sync already use _quote_ident — leave them.)

Reference PR

PR #498 for the equivalent Postgres work is a near-perfect template — see especially the test patterns in tests/unit/test_postgres_destination.py::TestQualifiedIdentifiers and the test_*_uses_schema_qualified_identifier cases. The MySQL test file (tests/unit/test_mysql_destination.py) follows the same mock_connect pattern, so the diff should look very similar.

Acceptance Criteria

  • All four _load_replace / _build_insert_sql / _build_upsert_sql call sites use _quote_ident
  • get_row_count reuses _quote_ident instead of duplicating the split logic
  • Unit tests cover schema-qualified table names (e.g. mydb.scores) for replace, upsert, and get_row_count paths — mirroring the cases added in PR fix: quote qualified Postgres table identifiers #498
  • No new type: ignore; ruff check and mypy drt pass

Out of Scope

  • Adding support for arbitrary quoted identifiers (embedded ., `, etc.) — not worth supporting until requested.
  • ClickHouse audit — tracked separately.

Good First Issue

This is well-scoped for first-time contributors:

Metadata

Metadata

Assignees

No one assigned

    Labels

    choreBuild process, CI, or tooling changesdestinationDestination connectors (REST API, Slack, HubSpot…)good first issueGood for newcomers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions