Skip to content

fix(adapters): escape cursor bounds and UDF packages as dialect string literals - #1346

Merged
kvlonge merged 2 commits into
mainfrom
fix/cursor-literal-escaping
Nov 7, 2026
Merged

kvlonge merged 2 commits into
mainfrom
fix/cursor-literal-escaping

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Why

Several adapters interpolated cursor bounds into quotes unescaped (delete+insert filters, eligible-max probes, bound literals, cursor filters), and BigQuery did the same for Python UDF packages. A quote in a value breaks the statement and in principle lets data shape the SQL.

Databricks also quoted every string wrongly: its literals process backslash escapes and concatenate adjacent literals, so 'O''Brien' yields OBrien, and a trailing backslash escaped the closing quote.

Changes

  • BaseAdapter._quote_sql_string is a method, which adapters already override with their dialect's quoting. The base, DuckDB-backed, Postgres, Snowflake, SQL Server, BigQuery and Databricks cursor renderings use it instead of '{value}'. SQLite and ClickHouse already did.
  • BigQuery Python UDF packages are quoted string literals.
  • Databricks quoting backslash-escapes \ and ' for typed STRING scalars (no longer the ANSI doubling renderer), typed objects, loader literals, view-definition lookups and cursor bounds. Identifiers are unchanged: doubled backticks are valid Spark SQL.
  • Tests that pinned Databricks' doubled quotes expect backslash escapes.

Timestamps and integers render as before. A Databricks model whose compiled SQL embeds a typed string with ' or \ gets a new definition hash once, now holding the intended value.

DuckShop: not applicable. Its cursors are timestamps or integers, which cannot carry a quote, and it never emits Databricks or BigQuery SQL.

Verification

  • A new cross-adapter test renders a bound with ', \ and a newline through bound literals, eligible-max date probes and delete+insert filters. It fails on the previous code for DuckDB, MotherDuck, Postgres, SQL Server, Snowflake, Databricks and BigQuery and passes now; ClickHouse, the control, passes on both.
  • A BigQuery UDF package case fails before and passes after.
  • Adapter and executor unit tests and adapter integration tests pass.
  • make check-ci, public-repository scan.

…g literals

Cursor bounds in delete+insert filters, eligible-max probes and bound literals,
and BigQuery Python UDF package names, were interpolated into quotes without
escaping. They now go through each adapter's own string quoting. Databricks
string literals process backslash escapes and concatenate adjacent literals,
so its quoting now backslash-escapes backslashes and quotes instead of doubling
the quote.
@kvlonge
kvlonge enabled auto-merge (squash) November 7, 2026 12:04
@kvlonge
kvlonge merged commit d3fc0e0 into main Nov 7, 2026
55 of 58 checks passed
@kvlonge
kvlonge deleted the fix/cursor-literal-escaping branch November 7, 2026 14:11
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.

1 participant