背景:
国产化改造过程中,原业务大量使用plsql的场景下,遇到“包计划运行时失效”的问题,某些情况下,可以通过简单的改写绕过这类报错。
案例:
1、创建测试数据,两张表结构相同
create table table_a (name varchar2(20));
create table table_temp (name varchar2(20));
2、创建包,包中包含两个存储过程
CREATE OR REPLACE PACKAGE PKG_TEST
IS
PROCEDURE P_SEL();--查询数据
PROCEDURE P_DATA_EX();--数据交换
END PKG_TEST;
CREATE OR REPLACE PACKAGE BODY PKG_TEST
IS
PROCEDURE P_SEL()
IS
BEGIN
SELECT * FROM TABLE_A;
END;
PROCEDURE P_DATA_EX()
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_TEMP';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_A RENAME TO TABLE_B';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_TEMP RENAME TO TABLE_A';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_B RENAME TO TABLE_TEMP';
END;
END;
3、通过匿名块模拟业务顺序调用包内存储过程
BEGIN
PKG_TEST.P_SEL();
PKG_TEST.P_DATA_EX();
PKG_TEST.P_SEL();
END;
执行失败(语句1)
-7188: 包计划运行时失效
在数据库底层机制中,RENAME 操作会直接修改对象在系统目录表(如 SYSOBJECTS)中的唯一标识符(ID)。由于包内对象之间通过依赖关系表(如 SYSDEPENDENCIES)相互绑定,一旦目标对象的 ID 发生变更,原有的依赖链路即被破坏,导致整个包进入失效状态。
这种失效状态会进一步波及匿名块的执行。因为匿名块的执行计划是在运行前预先编译生成的,当块内按顺序调用的存储过程因上述 RENAME 操作而失去有效性时,匿名块原先缓存的执行计划便随之失效,从而无法继续正常执行。
绕过方法
1、创建存储过程,处理数据交换,不在包内执行
create or REPLACE PROCEDURE pro_data_ex()
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_TEMP';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_A RENAME TO TABLE_B';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_TEMP RENAME TO TABLE_A';
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_B RENAME TO TABLE_TEMP';
end;
2、创建查询表的同义词
CREATE OR REPLACE PACKAGE PKG_TEST
IS
PROCEDURE P_SEL();
END PKG_TEST;
CREATE OR REPLACE PACKAGE BODY PKG_TEST
IS
PROCEDURE P_SEL()
IS
BEGIN
--SELECT * FROM TABLE_A;
SELECT * FROM SYN_TABLE_A;--create synonym syn_table_a for table_a
END;
END;
3、通过匿名块模拟业务顺序调用包内存储过程
BEGIN
PKG_TEST.P_SEL();
pro_data_ex();
PKG_TEST.P_SEL();
END
空结果集
执行成功, 执行耗时62毫秒. 执行号:3926
影响了0条记录
注:参数PL_SQL_STRIP=4 需要开启
文章
阅读量
获赞
