fix(sql): keep Oracle anonymous blocks with local routines whole
This commit is contained in:
1 parent
929c72407d
commit
ffe1e3a2ee
3 files changed
+70
-3
No files matched your search
@@ -2535,11 +2535,30 @@ impl OraclePlSqlBlock {
|
||||
|
||||
for (index, token) in self.tokens.iter().enumerate() {
|
||||
if token.is_semicolon() {
|
||||
if matches!(scopes.last(), Some(OraclePlSqlScope::RoutineHeader)) {
|
||||
scopes.pop();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if token.is_word("BEGIN") {
|
||||
scopes.push(OraclePlSqlScope::Block);
|
||||
if token.is_word("DECLARE") {
|
||||
if !matches!(scopes.last(), Some(OraclePlSqlScope::Declaration)) {
|
||||
scopes.push(OraclePlSqlScope::Declaration);
|
||||
}
|
||||
} else if token.is_any_word(&["PROCEDURE", "FUNCTION"])
|
||||
&& matches!(scopes.last(), Some(OraclePlSqlScope::Declaration | OraclePlSqlScope::Routine))
|
||||
{
|
||||
scopes.push(OraclePlSqlScope::RoutineHeader);
|
||||
} else if token.is_any_word(&["IS", "AS"]) && matches!(scopes.last(), Some(OraclePlSqlScope::RoutineHeader))
|
||||
{
|
||||
*scopes.last_mut().unwrap() = OraclePlSqlScope::Routine;
|
||||
} else if token.is_word("BEGIN") {
|
||||
// A local routine's BEGIN belongs to that routine, not to the outer block.
|
||||
if matches!(scopes.last(), Some(OraclePlSqlScope::Declaration | OraclePlSqlScope::Routine)) {
|
||||
*scopes.last_mut().unwrap() = OraclePlSqlScope::Block;
|
||||
} else {
|
||||
scopes.push(OraclePlSqlScope::Block);
|
||||
}
|
||||
saw_begin = true;
|
||||
complete = false;
|
||||
} else if token.is_word("CASE") {
|
||||
@@ -2631,6 +2650,12 @@ enum OraclePlSqlCreateObjectKind {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum OraclePlSqlScope {
|
||||
Object,
|
||||
/// DECLARE section awaiting its own BEGIN.
|
||||
Declaration,
|
||||
/// Local PROCEDURE/FUNCTION header, before IS/AS (a `;` here is a forward declaration).
|
||||
RoutineHeader,
|
||||
/// Local PROCEDURE/FUNCTION after IS/AS, awaiting its own BEGIN.
|
||||
Routine,
|
||||
Block,
|
||||
Case,
|
||||
}
|
||||
@@ -3833,6 +3858,25 @@ SELECT 2 FROM DUMMY;";
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_split_keeps_anonymous_block_with_local_routines_together() {
|
||||
let cases = [
|
||||
"DECLARE\nPROCEDURE local_proc IS\nBEGIN\n NULL;\nEND;\n\nBEGIN\nlocal_proc;\nEND;",
|
||||
"DECLARE\n v NUMBER;\n PROCEDURE p1 IS BEGIN NULL; END;\n FUNCTION f1 RETURN NUMBER IS BEGIN RETURN 1; END f1;\nBEGIN\n p1;\n v := f1;\nEND;",
|
||||
"DECLARE\n PROCEDURE fwd(x NUMBER);\n PROCEDURE fwd(x NUMBER) IS BEGIN NULL; END;\nBEGIN\n fwd(1);\nEND;",
|
||||
"DECLARE\n PROCEDURE outer_p IS\n PROCEDURE inner_p IS BEGIN NULL; END;\n BEGIN\n inner_p;\n END;\nBEGIN\n outer_p;\nEND;",
|
||||
];
|
||||
for sql in cases {
|
||||
assert_eq!(split_sql_statements_for_database(sql, DatabaseType::Oracle), vec![sql.to_string()], "{sql}");
|
||||
}
|
||||
let block = cases[0];
|
||||
let sql = format!("{block}\nSELECT 1 FROM dual;");
|
||||
assert_eq!(
|
||||
split_sql_statements_for_database(&sql, DatabaseType::Oracle),
|
||||
vec![block.to_string(), "SELECT 1 FROM dual".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_like_split_keeps_anonymous_plsql_block_together() {
|
||||
let sql = "\
|
||||
|
||||
Reference in new issue
Block a user