Describe the bug
sqlparse.parse() and sqlparse.split() split a compound BEGIN ... END; block into multiple statements when the block contains an END FOR; / END IF; / END WHILE; construct, or an inline CASE ... END expression inside a SELECT, and the block is not wrapped in CREATE PROCEDURE/FUNCTION.
The docs state that "semicolons within certain SQL constructs like BEGIN ... END blocks are handled correctly", but this only holds when the splitter has previously seen a CREATE keyword. Anonymous compound blocks — valid in ANSI SQL/PSM, Oracle PL/SQL, Databricks SQL scripting, and other dialects — get incorrectly split.
To Reproduce
Case 1 - END FOR; is treated as terminating the outer block:
import sqlparse
sql = """
BEGIN
SELECT 1;
FOR R DO
SELECT 1;
END FOR;
END;
"""
for i, stmt in enumerate(sqlparse.parse(sql)):
print(f"--- statement {i} ---")
print(str(stmt))
Actual output (2 statements):
--- statement 0 ---
BEGIN
SELECT 1;
FOR R DO
SELECT 1;
END FOR;
--- statement 1 ---
END;
Case 2 - inline CASE ... END inside a SELECT causes a split:
import sqlparse
sql = """
BEGIN
SELECT 1;
IF 1 THEN
SELECT CASE WHEN 1 THEN 2 ELSE 3 END AS COUNT;
ELSE
SELECT 2;
END IF;
END;
"""
for i, stmt in enumerate(sqlparse.parse(sql)):
print(f"--- statement {i} ---")
print(str(stmt))
Actual output (4 statements instead of 1):
--- statement 0 --- BEGIN ... SELECT CASE WHEN 1 THEN 2 ELSE 3 END AS COUNT;
--- statement 1 --- ELSE SELECT 2;
--- statement 2 --- END IF;
--- statement 3 --- END;
For comparison, wrapping the same input in CREATE PROCEDURE p() BEGIN ... END; yields a single statement.
Expected behavior
Each compound block should be returned as a single statement, matching the behavior already in place for CREATE PROCEDURE ... BEGIN ... END;.
Versions
- Python: 3.12.3
- sqlparse: 0.5.5
Describe the bug
sqlparse.parse()andsqlparse.split()split a compoundBEGIN ... END;block into multiple statements when the block contains anEND FOR;/END IF;/END WHILE;construct, or an inlineCASE ... ENDexpression inside aSELECT,and the block is not wrapped inCREATE PROCEDURE/FUNCTION.The docs state that "semicolons within certain SQL constructs like BEGIN ... END blocks are handled correctly", but this only holds when the splitter has previously seen a
CREATEkeyword. Anonymous compound blocks — valid in ANSI SQL/PSM, Oracle PL/SQL, Databricks SQL scripting, and other dialects — get incorrectly split.To Reproduce
Case 1 -
END FOR;is treated as terminating the outer block:Actual output (2 statements):
Case 2 - inline
CASE ... ENDinside aSELECTcauses a split:Actual output (4 statements instead of 1):
For comparison, wrapping the same input in
CREATE PROCEDURE p() BEGIN ... END;yields a single statement.Expected behavior
Each compound block should be returned as a single statement, matching the behavior already in place for
CREATE PROCEDURE ... BEGIN ... END;.Versions