Skip to content

feat(sql): support multiline @set inline variable values (#7478) - #11147

Merged
t8y2 merged 2 commits into
t8y2:mainfrom
lxk955:feat/7478-multiline-sql-variables
Oct 8, 2026
Merged

t8y2 merged 2 commits into
t8y2:mainfrom
lxk955:feat/7478-multiline-sql-variables

Conversation

@lxk955

@lxk955 lxk955 commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Resolves #7478.

Currently, inline SQL variables declared via @set stop parsing at the first newline if the value is not enclosed within parentheses (...) or PostgreSQL array brackets [...]. As a result, multiline SQL fragments such as multiline FROM / WHERE clauses (@set cond =\n from users\n where id = 42;) only capture the line containing = or fail to recognize the variable altogether.

Changes

  • Updated readValueEnd in apps/desktop/src/lib/sql/sqlVariables.ts to allow @set variable values to span multiple lines until the terminating ;.
  • Handled line comments (--) and block comments (/* ... */) within multiline values so comments (and any semicolons within comments) do not prematurely terminate the value.
  • Added lookahead check for @set keyword (isNextDeclaration) so unsemicoloned declarations preceding another @set declaration still terminate cleanly at newline.
  • Added comprehensive unit tests covering multiline values starting after = or on new lines, inline comments, semicolons inside comments, and sequential multiline declarations.

Verification

  • pnpm exec vitest run apps/desktop/src/lib/__tests__/sql/sqlVariables.spec.ts (28/28 passed)
  • pnpm exec vitest run apps/desktop/src/lib/__tests__/sql/sqlVariableSyntax.spec.ts apps/desktop/src/composables/__tests__/useSqlExecution.spec.ts (89/89 passed)
  • pnpm lint (0 errors)
  • NODE_OPTIONS="--max-old-space-size=8192" pnpm typecheck (passed)

@github-actions github-actions Bot added area/desktop Desktop application or Tauri shell enhancement New feature or request labels Oct 6, 2026

@t8y2 t8y2 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢提交!多行 @set 值确实是 #7478 需要的能力,isNextDeclaration 的实现(跳过空白和注释后匹配 @set)本身写得很扎实,带 ; 的多行场景也验证正确。

但目前有一个必须先解决的回归:readValueEnd 去掉了「换行即终止值」的旧规则后,唯一剩下的终止条件是 ;、EOF、以及下一行是 @set。这意味着所有不带分号的既有写法都会被破坏,例如:

@set user_id = 42
select * from users where id = @user_id

旧版本会展开成完整查询;此 PR 下整个 select 被吞进变量值,随后 stripDeclaration 把它整段删除,最终 SQL 为空串(我在本地用 PR head 的文件实测确认,useSqlExecution.ts 中空 SQL 会静默取消执行,用户看不到任何报错)。带中间分号的变体会静默丢掉第一条语句;选中语句执行(declarationSql 路径)则产出重复且损坏的 SQL;值后行注释同理。这违反了仓库「Feature 不得破坏旧行为」的约定,且失败是静默的。

这个问题的难点在于:@set cond = from users\nwhere id = 42;(你新增测试期望的跨行续值)与 @set a = 42\nselect @a(旧行为应在新行终止)在词法上无法区分,需要一个产品层面的取舍,例如:多行值必须以 ; 结尾、只有从 = 下一行开始的值才允许多行、或其他明确的续行规则——任何选择都会与当前某个测试期望冲突,所以建议先在 Issue/PR 里讨论定下终止语义再改。DBeaver 的 @set 是严格单行的,没有可参考的先例。

另外两点小建议:补充 CRLF 用例(代码看起来已处理 \r 但无测试覆盖);补充「不带分号的声明后跟普通语句」的用例——这正是本次回归路径。期待调整后的版本。

@lxk955

lxk955 commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

非常感谢 @t8y2 的详尽评审和指引!

针对上述回归与语义取舍,本次采用了**选项 2(只有从 = 下一行开始的值才允许多行)**进行修复:

1. 语义规则与取舍说明

  • 多行值判定:在解析 @set name = 时,若 = 后仅包含水平空白(空格/制表符)并紧跟换行符(\n 或 \r\n),则标记为多行值,值从下一行起始处开始读取,直至遇到分号 ;、下一个 @set 声明(isNextDeclaration)或 EOF 为止。
  • 单行旧行为严格保全:若在 = 同一行上存在值(如 @set user_id = 42),则保持单行语义,在换行符(\n / \r\n)或行内注释(-- / /*)处严格终止(括号 (...)、PostgreSQL 数组 [...]、引号与美元引号内跨行不受影响)。
  • 冲突测试调整:将原先在同一行起始的跨行测试用例 @set cond = from users\nwhere id = 42; 更新为新语义断言(在换行处终止,不会吞并后续行);需要多行值的场景均统一采用 @set cond =\n from users\n where id = 42;。

2. 具体改动

  • sqlVariables.ts:
    • 更新 skipInlineWhitespace 仅跳过水平空白字符(空格与制表符),确保 \r 作为行边界被正确识别。
    • readDeclaration 依据 = 后是否紧跟换行确定 isMultiline 标记并跃过换行。
    • readValueEnd 支持 isMultiline 参数:在单行模式且顶级深度时,行尾换行(LF / CRLF)和注释立即终止值读取;多行模式下才允许跨行并容纳行内/块注释。
  • 测试覆盖:
    • 补充「不带分号的声明后跟普通语句」回归测试(涵盖基础查询、带行注释、中间带分号的多语句、选中语句执行 declarationSql 上下文展开)。
    • 补充 CRLF 换行测试(覆盖单行无分号、单行有分号、多行续值、连续声明)。
    • 在 useSqlExecution.spec.ts 补充测试,验证不带分号的旧写法在执行器中不再产出空 SQL 或静默取消。

3. 验证结果

  • vitest:
    • sqlVariables.spec.ts (36/36 passed)
    • sqlVariableSyntax.spec.ts (18/18 passed)
    • useSqlExecution.spec.ts (73/73 passed)
  • oxlint: 0 errors / 0 warnings(改动文件)
  • vue-tsc: 通过(NODE_OPTIONS="--max-old-space-size=8192" pnpm typecheck)

@t8y2 t8y2 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢跟进,"只有从 = 下一行开始的值才允许多行"这个取舍很清晰,新 head(346b90f)已逐点复核:

  1. 无分号回归已修复:基础查询、中间分号多语句、值后行注释、declarationSql 选中执行四条路径均不再吞语句,并有单测与 useSqlExecution 端到端测试锁定;本地用新 head 的解析器实测这些场景及 CRLF 变体,行为全部符合预期。
  2. 终止语义已在 readDeclaration 注释中明确文档化:多行值止于 ;、下一个 @set 或 EOF;同行起值保持单行语义,引号、美元引号、括号与 PG 数组跨行不受影响,@set 出现在字符串/注释内不误判。
  3. CRLF 用例与"无分号声明后跟普通语句"用例均已补充,CI 全绿。

两点非阻塞备注,可后续跟进:多行值漏写终止 ; 且无后续 @set 时会吞到 EOF,最终 SQL 可能为空并静默取消(新语法的固有失败模式,建议后续加提示);单行值在括号内遇行注释时新版保留完整值(旧版会截断产生残缺 SQL),属修复性变化。LGTM。

@t8y2
t8y2 merged commit 934d731 into t8y2:main Oct 8, 2026
26 checks passed
@t8y2

t8y2 commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Thanks for the contribution! Merged in 934d731, will be released in the next version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/desktop Desktop application or Tauri shell enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] @set user_id = 42; 内联变量展开功能,变量值支持换行

2 participants