Skip to content

[SPARK-57500][SQL] Fix wrong results and SQL injection in MySQL JDBC pushdown of string values containing backslashes - #56558

Open
jiwen624 wants to merge 6 commits into
apache:masterfrom
jiwen624:SPARK-mysql-backslash-literal-pushdown
Open

jiwen624 wants to merge 6 commits into
apache:masterfrom
jiwen624:SPARK-mysql-backslash-literal-pushdown

Conversation

@jiwen624

@jiwen624 jiwen624 commented Jun 17, 2026 •

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Extends the SPARK-57332 fix for MySQL backslash escaping from LIKE to all pushed-down string values, and makes it independent of sql_mode. With this fix MySQLDialect pushes strings that contain \ as hex literals (_utf8mb4 X'...'), which MySQL reads the same in every sql_mode. Escaping inside a quoted literal can't do that, because \ is an escape character only when NO_BACKSLASH_ESCAPES is off, and Spark does not know the mode when it compiles the filter.

STARTS_WITH/ENDS_WITH/CONTAINS are now built from the raw pattern value, with ! as MySQL's LIKE escape character, so the MySQL override of escapeStringLiteralForLikePattern is no longer needed. Patterns that are not string literals are no longer pushed down.

Not changed here (as follow-ups instead):

  • DDL and metadata SQL, such as MySQL table comments: COMMENT accepts only a quoted literal, so it has no sql_mode-independent form.
  • V2ExpressionSQLBuilder.visitStartsWith/visitEndsWith/visitContains still strip the quotes from the rendered pattern, which affects non-JDBC DSv2 sources.

Why are the changes needed?

MySQL reads \ in a pushed literal as an escape:

  • Wrong results: df.filter($"path" === "C:\\temp") pushes 'C:\temp', which MySQL reads as C:<TAB>emp, so the row is silently not returned.
  • SQL injection: df.filter($"c" === "x\\' OR 1=1) #") closes the literal early and runs OR 1=1, returning every row. An application that passes untrusted input into such a filter lets that input run SQL in the pushed WHERE clause.

Also, on all dialects, startswith(a, b) with a column pattern was pushed as a LIKE 'b%' and returned no rows.

Does this PR introduce any user-facing change?

Yes. These filters now return correct results, and string values can no longer inject SQL. Known limitation: on MySQL/MariaDB with a non-default connection collation, a comparison with no column operand against a value containing \ can fail with Illegal mix of collations. Comparisons against columns are unaffected.

How was this patch tested?

New tests in JDBCSuite, JDBCV2Suite and MySQLIntegrationSuite (both sql_modes, MySQL and MariaDB drivers); all fail without the fix. Also verified manually on TiDB v8.5.1 and MariaDB 12.2.2.

Was this patch authored or co-authored using generative AI tooling?

Yes.

@jiwen624
jiwen624 force-pushed the SPARK-mysql-backslash-literal-pushdown branch 4 times, most recently from 35839ad to 83fecd4 Compare September 19, 2026 00:21
@jiwen624 jiwen624 changed the title [SPARK-57500][SQL] Escape backslash in MySQL JDBC pushdown for string literals in comparison/IN predicates [SPARK-57500][SQL] Fix wrong results and SQL injection in MySQL JDBC pushdown of string values containing backslashes Oct 23, 2026
@jiwen624
jiwen624 force-pushed the SPARK-mysql-backslash-literal-pushdown branch 2 times, most recently from 677c6f3 to 96dcebf Compare October 24, 2026 06:22
@jiwen624
jiwen624 force-pushed the SPARK-mysql-backslash-literal-pushdown branch from 92e1c42 to ddc790b Compare October 24, 2026 23:04
@jiwen624
jiwen624 marked this pull request as ready for review October 25, 2026 05:54
@jiwen624

Copy link
Copy Markdown
Contributor Author

Hi @cloud-fan since you fixed the LIKE side of this in SPARK-57332, could you take a look? This extends the same fix to =/IN (where a \ silently drops rows, or lets a value inject SQL) using hex literals, so it holds regardless of sql_mode.

This branch has not been deployed

No deployments
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