#4273·flyway

Snowflake 解析器: 创建任务中嵌套的 BEGIN...EXCEPTION...END; 子块仍会截断语句 (出现了意料之外的 '<EOF>')

作者: yingxuansampg创建于 2026年8月18日更新于 2026年8月18日

环境

  • 测试的 Flyway 版本: 12.11.0、13.2.0 (两者都能完全重现问题)
  • 数据库: Snowflake
  • 驱动: 与各 Flyway 版本一起提供的 Snowflake JDBC 驱动
  • 迁移类型: 可重复迁移 (R__*.sql)

概要

当一个 Snowflake 脚本的 CREATE TASK ... AS BEGIN ... END; 体包含一个嵌套的普通 BEGIN...EXCEPTION...END; 子块 (用于处理异常),Flyway 的 SQL 语句解析器会在到达外层块的最后一个关键字 END; 之前截断语句,并丢弃同一迁移文件中跟着它的任何语句。截断后的 SQL 会发送到 Snowflake,导致 SQL 编译错误: 语法错误 ... 遇到 '<EOF>' 非法字符。 这与 #4179 / #4194 中修复的情况相关但不同: #4194 修复了嵌套的 IF/FOR/CASE 子块。该修复似乎不适用于嵌套的普通 BEGIN...END (异常处理) 子块 — 这在 12.11.0 和 13.2.0 中都能重现,而后者是在 12.0.0 中发布的 #4194 修复之后。

最小重现

CREATE OR REPLACE TASK my_schema.my_task
WAREHOUSE = 'MY_WH'
SCHEDULE = '5 MINUTE'
AS
BEGIN
    LET flag BOOLEAN := FALSE;
    BEGIN
        SELECT TRUE INTO :flag
        FROM my_schema.some_control_table
        WHERE some_condition = TRUE
        LIMIT 1;
    EXCEPTION
        WHEN OTHER THEN
            LET flag := FALSE;
    END;

    IF (:flag) THEN
        CALL SYSTEM$SET_RETURN_VALUE('a');
    ELSE
        IF ((SELECT COUNT(*) FROM my_schema.some_table) = 0) THEN
            CALL SYSTEM$SET_RETURN_VALUE('a');
        ELSE
            CALL SYSTEM$SET_RETURN_VALUE('b');
        END IF;
    END IF;
END;

SELECT SYSTEM$TASK_DEPENDENTS_ENABLE('my_schema.my_task');

预期行为

Flyway 会将完整的 CREATE OR REPLACE TASK ... 语句 (通过其最后的 END;) 发送给 Snowflake,然后是第二个语句的尾部 SELECT SYSTEM$TASK_DEPENDENTS_ENABLE(...)。

实际行为

Flyway 会在最后一个 END; 之前截断语句,并完全丢弃尾部的 SELECT SYSTEM$TASK_DEPENDENTS_ENABLE(...) 语句。Snowflake 收到一个不完整的脚本,并抛出以下错误: SQL State : 42000 Error Code : 1003 Message : SQL compilation error: syntax error line 34 at position 10 unexpected ''。 在 Flyway 错误输出中捕获的语句证实了截断点 — 它立即在第二个 END IF (缺少分号) 之后结束,外层块的关键字 END; 和随后的 SELECT 语句都不在实际发送给 Snowflake 的内容中。

可疑原因

与 #4179 中描述的机制相一致,但构造不同: 解析器的深度计数器似乎正确地跟踪嵌套的 IF/END IF 对,但在通过嵌套的普通 BEGIN...EXCEPTION...END; 子块后丢失了深度,导致它在外层块之前关闭一个 END;。

工作绕过(已确认有效)

将 …