You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reviewing the documentation and source code, it appears there is none.
Are there any known workarounds?
Any plans to implement this kind of support?
Something like:
SET TERM ^^ ;
CREATE OR ALTER PROCEDURE STP_ONE...
ASBEGIN
END
^^
CREATE PROCEDURE STP_TWO...
ASBEGIN
END
^^
Or, even better
CREATE OR ALTER PROCEDURE STP_ONE...
ASBEGIN
END;
CREATE PROCEDURE STP_TWO...
ASBEGIN
END;
I've never been a fan of SET TERM. And most SQL databases get by just fine without it.
Any parser could easily track BEGIN/END pairs and distinguish between semicolons inside the block and the ones that terminate the CREATE PROCEDURE command.
Tracks BEGIN/END pairs only for commands with <module-body>, as per the docs;
Do not execute SET TERM.
defparse_firebird_script(script: str) ->list[str]:
""" Parse a Firebird SQL script into statements, handling SET TERM and BEGIN/END blocks only for module body commands (procedures, triggers, functions, packages, execute blocks). """importre# Pattern for all module body commands# https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref50/firebird-50-language-reference.html#fblangref50-psql-elements-body-syntaxmodule_body_pattern=re.compile(
r""" \b( (?:CREATE|ALTER|RECREATE|CREATE\s+OR\s+ALTER)\s+ (?:TRIGGER|PROCEDURE|FUNCTION|PACKAGE(?:\s+BODY)?)| EXECUTE\s+BLOCK )\b """,
re.IGNORECASE|re.VERBOSE,
)
defremove_comments(line: str) ->str:
"""Remove comments from a line for logic processing."""# Remove -- commentsline=re.sub(r"--.*", "", line)
# Remove /* */ commentsline=re.sub(r"/\*.*?\*/", "", line)
returnlinestatements= []
current_lines= []
terminator=";"block_depth=0in_module_body=Falselines=script.replace("\r\n", "\n").replace("\r", "\n").split("\n")
forlineinlines:
logic_line=remove_comments(line)
# Handle SET TERMifmatch:=re.match(r"\s*SET\s+TERM\s+(\S+)", logic_line, re.IGNORECASE):
terminator=match.group(1)
continue# Don't include SET TERM in outputcurrent_lines.append(line)
# This starts a module body command?ifnotin_module_body:
current_text="\n".join(current_lines)
ifmodule_body_pattern.search(remove_comments(current_text)):
in_module_body=True# Track BEGIN/END depth only in module bodiesifin_module_body:
block_depth+=len(re.findall(r"\bBEGIN\b", logic_line, re.IGNORECASE))
block_depth-=len(re.findall(r"\bEND\b", logic_line, re.IGNORECASE))
# Check for statement endends_with_terminator=logic_line.strip().endswith(terminator)
is_complete= (notin_module_body) or (block_depth<=0)
ifends_with_terminatorandis_complete:
statement="\n".join(current_lines).rstrip()
ifstatement.endswith(terminator):
statement=statement[: -len(terminator)]
ifstatement.strip():
statements.append(statement.strip())
# Reset for next statementcurrent_lines= []
block_depth=0in_module_body=False# Add any remaining statementifcurrent_linesandany(line.strip() forlineincurrent_lines):
statements.append("\n".join(current_lines).strip())
return [stmtforstmtinstatementsifstmt.strip()]
Activity
fdcastel commentedon Jun 26, 2025
An initial attempt:
fdcastel commentedon Jun 26, 2025
BTW: The above function is intended to handle both scenarios.
SET TERMis completely optional (but still works for backward compatibility). It also works with semicolon-only scripts.asfernandes commentedon Jun 27, 2025
ALTER DATABASE BEGIN BACKUPboom
fdcastel commentedon Jun 27, 2025
v2:
BEGIN/ENDpairs only for commands with<module-body>, as per the docs;SET TERM.