feat(sql): support quoted braced placeholders - #3666
Conversation
t8y2
left a comment
There was a problem hiding this comment.
Quoted placeholder 插值仍有一个会改变实际参数值的数据库兼容问题。
apps/desktop/src/lib/sql/sqlParameters.ts:838的sqlParameterTextInsideQuote只转义当前引号分隔符,完全忽略已经传入的databaseType。在默认 MySQL 字符串语义下,反斜杠仍是转义字符;例如参数值C:\new被生成成select 'C:\new',服务端会把\n解释为换行,而不是原始反斜杠和字母 n。针对当前 head 的测试探针已复现。请按数据库字符串规则处理反斜杠,或明确限制不具备可靠转义语义的数据库/SQL mode,并覆盖 Windows 路径、\n、\0和NO_BACKSLASH_ESCAPES兼容场景。
Author fix required:这里需要明确不同数据库及 SQL mode 下的转义契约,不能只做通用字符替换。
ce9f197 to
7d72657
Compare
|
Addressed the requested MySQL compatibility fix in The replacement path now uses the active database type. MySQL, Doris, and StarRocks single-quoted values double backslashes under their default string semantics, while an explicit per-database Regression coverage now includes Windows paths, literal I also verified the generated forms against MySQL 8.0.46 under both session modes with |
7d72657 to
1064880
Compare
|
I completed another compatibility pass in The MySQL-family quote-mode contract now applies during both occurrence scanning and substitution:
Regression coverage includes the two newly reproduced failures, default-off behavior, escaped double quotes, all MySQL-family mode combinations, settings normalization, and execution-dialog propagation. Validation completed successfully:
I also executed the generated forms against MySQL 8.0.46 under the default mode, This is ready for re-review. |
t8y2
left a comment
There was a problem hiding this comment.
I'm requesting changes because quoted interpolation is still unsafe for PostgreSQL.
sqlQuoteUsesBackslashEscapes treats every non-MySQL single-quoted region as backslash-escaped, while inserted backslashes are only protected for MySQL-family databases. With PostgreSQL's default standard_conforming_strings=on, an ordinary string ending in a backslash can be scanned incorrectly and produce invalid SQL. The opposite problem occurs for PostgreSQL escape strings: substituting a value containing \n into E'...' can change the parameter bytes by turning it into a newline.
Please make scanning and substitution aware of the PostgreSQL literal form and relevant session semantics, with regression tests for ordinary strings ending in a backslash and E'...' values containing \n. If a reliable contract cannot be provided for a dialect, quoted interpolation should not be offered for that dialect.
Closes #3652
Problem
DBX skipped
${name}and#{name}placeholders inside quoted SQL, while scheduler-style templates commonly quote date and text placeholders before substitution.Root cause
The SQL parameter scanner skipped every quoted region. The initial quoted-interpolation implementation retained the surrounding delimiter but did not apply database string rules consistently.
MySQL, MariaDB, Doris, and StarRocks interpret both single- and double-quoted text as strings by default, consume backslash sequences such as
\nand\0, and change double quotes to identifier delimiters whenANSI_QUOTESis enabled.NO_BACKSLASH_ESCAPESchanges both how quoted boundaries are scanned and how inserted values must be serialized. Applying either SQL mode only during replacement can therefore discover the wrong placeholder range or change the parameter bytes.Changes
${name}and#{name}inside quoted SQL text and identifiers.ANSI_QUOTESandNO_BACKSLASH_ESCAPEScompatibility settings for MySQL, Doris, and StarRocks.NO_BACKSLASH_ESCAPESaffect quote-boundary scanning as well as substitution, including strings ending in a literal backslash.ANSI_QUOTESis enabled.Compatibility contract
ANSI_QUOTESwhen sessions use that SQL mode so double-quoted placeholders are treated as identifiers.NO_BACKSLASH_ESCAPESwhen sessions use that SQL mode so backslashes remain literal during both scanning and substitution.?,:name, and@nameremain ignored inside quoted regions.@setexpansion, and native database variables keep their existing behavior.References
ANSI_QUOTESchanges double quotes to identifiers, and backslash sequences are interpreted unlessNO_BACKSLASH_ESCAPESis enabled: https://dev.mysql.com/doc/refman/8.0/en/string-literals.htmlMySQLDialect#escapeStringapplies MySQL-specific quote and backslash escaping: https://github.com/dbeaver/dbeaver/blob/74ec193c1bb7d1d0dcd31a7a6bd37217e28a75f1/plugins/org.jkiss.dbeaver.ext.mysql/src/org/jkiss/dbeaver/ext/mysql/model/MySQLDialect.java#L271-L284ANSI_QUOTESandNO_BACKSLASH_ESCAPESin their SQL mode helpers.Tests
pnpm vitest run apps/desktop/src/lib/__tests__/sql/sqlParameters.spec.ts apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts packages/app-tests/settingsStore.test.ts— 4 files, 156 tests passedpnpm typecheckpnpm lintpnpm test— 447 files, 3,691 tests passedpnpm buildoxfmt --checkgit diff --checkManual verification
A temporary
mysql:8.0container running MySQL 8.0.46 was used to execute the generated forms under the default session mode,NO_BACKSLASH_ESCAPES,ANSI_QUOTES, and both modes together.C:\newvalues both returnedHEX(...) = 433A5C6E6577.\nvalues both returnedHEX(...) = 5C6E.NO_BACKSLASH_ESCAPES, a preceding string ending in a literal backslash parsed correctly, and single- and double-quotedC:\newvalues returned433A5C6E6577.ANSI_QUOTES, a double-quoted identifier containing a literal backslash executed successfully without doubling the identifier bytes.ANSI_QUOTES,NO_BACKSLASH_ESCAPES, the single-quoted value and double-quoted identifier both preserved their literal backslashes.The temporary container was removed after verification.
Remaining risks
DBX cannot infer different SQL modes for two connections that share the same database type. Users with mixed per-connection modes should keep quoted interpolation disabled or align those session modes. Doris and StarRocks behavior is covered by their upstream SQL mode implementations and the shared regression suite, but this update did not deploy separate Doris or StarRocks servers.