🐛 fix(oracle): 修复过程CASE分割导致执行截断

This commit is contained in:
Syngnat
2026-06-25 13:52:20 +08:00
parent 16a8a763f4
commit f6556f25d5
7 changed files with 277 additions and 0 deletions

View File

@@ -175,6 +175,63 @@ describe('sqlStatementSelection', () => {
});
});
it('keeps Oracle CREATE PROCEDURE cursor CASE expressions as one executable statement', () => {
const sql = [
'CREATE OR REPLACE PROCEDURE proc_accept_to_add(',
' p_acceptno IN t_accept_h.acceptno%TYPE',
') IS',
' CURSOR cur_store_same(p_ind s_sys_ini.inipara%TYPE) IS',
' SELECT si.compid, si.batid, si.wareid',
' FROM t_store_i si',
' ORDER BY CASE',
" WHEN p_ind = '1' THEN",
" to_char(si.invalidate - to_date('19700101', 'yyyymmdd'))",
" WHEN p_ind = '2' THEN",
" lpad(to_char(floor(si.wareqty)), 10, '0')",
' ELSE',
' to_char(si.batid)',
' END,si.batid;',
'BEGIN',
' NULL;',
'END;',
'/',
'SELECT 1 FROM dual;',
].join('\n');
const ranges = findSqlStatementRanges(sql).map((range) => range.text);
expect(ranges).toEqual([
[
'CREATE OR REPLACE PROCEDURE proc_accept_to_add(',
' p_acceptno IN t_accept_h.acceptno%TYPE',
') IS',
' CURSOR cur_store_same(p_ind s_sys_ini.inipara%TYPE) IS',
' SELECT si.compid, si.batid, si.wareid',
' FROM t_store_i si',
' ORDER BY CASE',
" WHEN p_ind = '1' THEN",
" to_char(si.invalidate - to_date('19700101', 'yyyymmdd'))",
" WHEN p_ind = '2' THEN",
" lpad(to_char(floor(si.wareqty)), 10, '0')",
' ELSE',
' to_char(si.batid)',
' END,si.batid;',
'BEGIN',
' NULL;',
'END;',
].join('\n'),
'SELECT 1 FROM dual',
]);
expect(resolveExecutableSql(sql, sql.indexOf('ORDER BY CASE'))).toEqual({
sql: ranges[0],
source: 'statement',
});
expect(resolveExecutableSql(sql, sql.indexOf('NULL'))).toEqual({
sql: ranges[0],
source: 'statement',
});
});
it('skips SQL*Plus slash delimiter comments after named Oracle procedure endings', () => {
const sql = [
'-- 修改函数/存储过程H2.cproc_tzhssr_order2sale_A1',

View File

@@ -205,6 +205,8 @@ export const findSqlStatementRanges = (sql: string): SqlStatementRange[] => {
let dollarTag: string | null = null;
let plsqlDepth = 0;
let plsqlDeclareBeginSkips = 0;
let plsqlCaseDepth = 0;
let skipNextPlsqlCaseEndToken = false;
let justClosedPLSQLBlock = false;
const push = (end: number) => {
@@ -309,6 +311,16 @@ export const findSqlStatementRanges = (sql: string): SqlStatementRange[] => {
tokenEnd++;
}
const token = text.slice(index, tokenEnd).toLowerCase();
if (token === 'case' && plsqlDepth > 0) {
if (skipNextPlsqlCaseEndToken) {
skipNextPlsqlCaseEndToken = false;
} else {
plsqlCaseDepth++;
justClosedPLSQLBlock = false;
}
} else if (token !== 'case') {
skipNextPlsqlCaseEndToken = false;
}
if (token === 'begin' && plsqlDeclareBeginSkips > 0) {
plsqlDeclareBeginSkips--;
justClosedPLSQLBlock = false;
@@ -325,11 +337,20 @@ export const findSqlStatementRanges = (sql: string): SqlStatementRange[] => {
plsqlDeclareBeginSkips++;
}
justClosedPLSQLBlock = false;
} else if (token === 'end' && plsqlDepth > 0 && plsqlCaseDepth > 0) {
plsqlCaseDepth--;
if (nextSqlSignificantToken(text, tokenEnd) === 'case') {
skipNextPlsqlCaseEndToken = true;
}
justClosedPLSQLBlock = false;
} else if (token === 'end' && plsqlDepth > 0 && !isPlsqlControlEnd(text, tokenEnd)) {
plsqlDepth--;
if (plsqlDeclareBeginSkips > plsqlDepth) {
plsqlDeclareBeginSkips = plsqlDepth;
}
if (plsqlCaseDepth > plsqlDepth) {
plsqlCaseDepth = plsqlDepth;
}
justClosedPLSQLBlock = plsqlDepth === 0;
}
index = tokenEnd - 1;