From 33d472e790677aeaa02844aa43ea24b54a95318e Mon Sep 17 00:00:00 2001 From: rebelice Date: Tue, 12 May 2026 16:31:46 +0900 Subject: [PATCH] fix(oracle): keep stored unit declarations in split --- oracle/parser/split.go | 21 ++++++++++++++++----- oracle/parser/split_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/oracle/parser/split.go b/oracle/parser/split.go index 00df1414..7495f164 100644 --- a/oracle/parser/split.go +++ b/oracle/parser/split.go @@ -164,6 +164,7 @@ type splitState struct { topLevelTokens int pendingSubprogram bool pendingCaseEnd bool + callSpecStarted bool endPending bool closedOutermost bool @@ -312,6 +313,18 @@ func (s *splitState) observePLSQL(tok Token) { top.compound = true return } + if len(s.frames) == 1 && !top.bodyStarted { + switch top.kind { + case splitPLSQLStoredUnit: + if tok.Str == "LANGUAGE" || tok.Str == "EXTERNAL" { + s.callSpecStarted = true + } + case splitPLSQLTrigger: + if tok.Type == kwCALL { + s.callSpecStarted = true + } + } + } if s.canStartNestedSubprogram(tok) { s.pendingSubprogram = true @@ -340,11 +353,8 @@ func (s *splitState) plsqlCanEndAtSemicolon() bool { if s.endPending { return s.closedOutermost } - if len(s.frames) == 1 { - top := s.frames[0] - if (top.kind == splitPLSQLStoredUnit || top.kind == splitPLSQLTrigger) && !top.bodyStarted { - return true - } + if s.callSpecStarted { + return true } return false } @@ -354,6 +364,7 @@ func (s *splitState) afterPLSQLSemicolon() { s.closedOutermost = false s.pendingSubprogram = false s.pendingCaseEnd = false + s.callSpecStarted = false } func (s *splitState) pushFrame(kind splitPLSQLKind, bodyStarted bool) { diff --git a/oracle/parser/split_test.go b/oracle/parser/split_test.go index e30182db..1c04e74c 100644 --- a/oracle/parser/split_test.go +++ b/oracle/parser/split_test.go @@ -168,6 +168,35 @@ func TestSplitPLSQLBlocks(t *testing.T) { "\nCREATE TABLE t (id NUMBER)", }, }, + { + name: "create function with declarations without slash separator", + sql: "CREATE FUNCTION calc_bonus(p_start_date DATE)\n" + + "RETURN DATE\n" + + "IS\n" + + " v_current_date DATE := p_start_date;\n" + + "BEGIN\n" + + " RETURN v_current_date;\n" + + "END calc_bonus;\n" + + "CREATE TABLE t (id NUMBER);", + want: []string{ + "CREATE FUNCTION calc_bonus(p_start_date DATE)\nRETURN DATE\nIS\n v_current_date DATE := p_start_date;\nBEGIN\n RETURN v_current_date;\nEND calc_bonus;", + "\nCREATE TABLE t (id NUMBER)", + }, + }, + { + name: "create procedure with declarations without slash separator", + sql: "CREATE PROCEDURE update_salary(p_employee_id NUMBER)\n" + + "IS\n" + + " v_delta NUMBER := 1;\n" + + "BEGIN\n" + + " UPDATE employees SET salary = salary + v_delta WHERE id = p_employee_id;\n" + + "END update_salary;\n" + + "CREATE TABLE t (id NUMBER);", + want: []string{ + "CREATE PROCEDURE update_salary(p_employee_id NUMBER)\nIS\n v_delta NUMBER := 1;\nBEGIN\n UPDATE employees SET salary = salary + v_delta WHERE id = p_employee_id;\nEND update_salary;", + "\nCREATE TABLE t (id NUMBER)", + }, + }, { name: "create editionable procedure", sql: "CREATE OR REPLACE EDITIONABLE PROCEDURE p IS\n" +