Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@023-dev
Copy link

@023-dev 023-dev commented Jan 19, 2026

Problem

Flyway was generating invalid SQL when parsing Snowflake migrations containing nested IF statements within BEGIN...END blocks. The parser prematurely terminated at the first END IF, causing it to miss the semicolon and the final END of the block.

Related

Fixes #4179

Issue Reproduction

DECLARE
  var_one BOOLEAN;
  var_two BOOLEAN;
BEGIN
  SELECT sysdate() > '1900-01-01' INTO var_one;
  IF (var_one) THEN
    SELECT sysdate() < '1900-01-01' INTO var_two;
    IF (var_two) THEN
      SELECT 'Edge case 1' as truth;
    ELSE
      SELECT '...or edge case 2' as truth;
    END IF;  -- Parser stopped here (missing semicolon)
    SELECT 'Finish the work';
  END IF;
END;  -- This was not included
SELECT 'Do the normal thing';

What Flyway Was Executing (INVALID)

-- Statement 1 (missing semicolon and END)
DECLARE ... END IF

-- Statement 2
END

-- Statement 3
SELECT 'Do the normal thing'

Snowflake Error:

SQL compilation error: syntax error line 19 at position 10 unexpected '<eof>'.

Solution

Updated SnowflakeParser.readBetweenRecursive() to properly distinguish between:

  1. Control structure endings: END IF, END FOR, END CASE (continue reading)
  2. Block ending: END (stop reading)

Changes/Modified

  • flyway-database/flyway-database-snowflake/src/main/java/org/flywaydb/database/snowflake/SnowflakeParser.java

Modified Method: readBetweenRecursive()

  1. Priority-based checking: Check for END IF/FOR/CASE BEFORE checking for block END
  2. Lookahead logic: When encountering END, peek ahead to see if it's followed by IF/FOR/CASE
  3. Proper semicolon handling: Include semicolons after all control structure endings
  4. Clean loop control: Refactored to use state flags instead of multiple break/continue statements

Implementation Details

The fix uses a boolean flag blockEnded to control loop termination and delegates logic to helper methods:

  • handleEndKeyword(): Checks if END is followed by IF/FOR/CASE keywords
  • handleGeneralContent(): Processes regular content and nested BEGIN blocks

This approach eliminates nested conditionals and multiple break/continue statements while maintaining the same parsing logic.

After Fix (Valid)

-- Statement 1 (complete and valid)
DECLARE
  var_one BOOLEAN;
  var_two BOOLEAN;
BEGIN
  SELECT sysdate() > '1900-01-01' INTO var_one;
  IF (var_one) THEN
    SELECT sysdate() < '1900-01-01' INTO var_two;
    IF (var_two) THEN
      SELECT 'Edge case 1' as truth;
    ELSE
      SELECT '...or edge case 2' as truth;
    END IF;  -- Properly included with semicolon
    SELECT 'Finish the work';
  END IF;  -- Properly included with semicolon
END  -- Block properly terminated

-- Statement 2
SELECT 'Do the normal thing'

Testing

Test Cases

  1. Nested IF statements (original issue scenario)
  2. Sequential IF statements (issue comment scenario)
  3. Simple IF statement (baseline)

Test Results

All tests pass:

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
  • Nested IF with 2 levels correctly parsed (2 statements)
  • Sequential IF statements correctly parsed (1 statement with 3 END IFs)
  • Simple IF statement correctly parsed (1 statement)

Test Output Example (Nested IF)

Parsing Result
Total statements: 2

--- Statement 1 ---
DECLARE
  var_one BOOLEAN;
  var_two BOOLEAN;
BEGIN
  SELECT sysdate() > '1900-01-01' INTO var_one;
  IF (var_one) THEN
    SELECT sysdate() < '1900-01-01' INTO var_two;
    SELECT 'Due to var_one, we need to handle edge cases before we continue';
    IF (var_two) THEN
      SELECT 'Edge case 1' as truth;
    ELSE
      SELECT '...or edge case 2' as truth;
    END IF;
    SELECT 'Finish the work';
  END IF;
END

--- Statement 2 ---
SELECT 'Do the normal thing'

@CLAassistant
Copy link

CLAassistant commented Jan 19, 2026

CLA assistant check
All committers have signed the CLA.

@023-dev
Copy link
Author

023-dev commented Jan 20, 2026

@piers-williams @trainman can you please review this?

@trainman
Copy link

I'm not a maintainer, so IDK if my review would mean anything.

@023-dev
Copy link
Author

023-dev commented Jan 22, 2026

@trainman
Got it, thanks for clarifying.
In that case, I’ll wait for a maintainer’s review, but feel free to leave any comments if something stands out.

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.

Flyway generates invalid SQL when running multi-statement snowflake migrations with nested if statements.

3 participants