Oracle提供的批量操作功能FORALL语句,可以批量的执行动态SQL语句,从而有效的提高执行的效率。
在编写存储过程的时候,碰到一个和FORALL有关的bug,在这里记录一下。
编写的存储过程大致如下:
SQL> CREATE OR REPLACE PROCEDURE P_TEST AS
2 TYPE T_TABLE IS TABLE OF VARCHAR2(30000);
3 V_GRANTS T_TABLE;
4 BEGIN
5 SELECT 'GRANT SELECT ON ' || TABLE_NAME || ' TO SCOTT'
6 BULK COLLECT INTO V_GRANTS
7 FROM USER_TABLES;
8
9 FORALL I IN 1..V_GRANTS.COUNT
10 EXECUTE IMMEDIATE V_GRANTS(I);
11 END;
12 /
警告: 创建的过程带有编译错误。
SQL> SHOW ERR
PROCEDURE P_TEST 出现错误:
LINE/COL ERROR
-------- ----------------------------------------------------------
0/0 PLS-00801: 内部错误 [74301]
而这里如果不使用FORALL语句的话,则不会报错。
SQL> CREATE OR REPLACE PROCEDURE P_TEST AS
2 TYPE T_TABLE IS TABLE OF VARCHAR2(30000);
3 V_GRANTS T_TABLE;
4 BEGIN
5 SELECT 'GRANT SELECT ON ' || TABLE_NAME || ' TO SCOTT'
6 BULK COLLECT INTO V_GRANTS
7 FROM USER_TABLES;
8
9 FOR I IN 1..V_GRANTS.COUNT LOOP
10 EXECUTE IMMEDIATE V_GRANTS(I);
11 END LOOP;
12 END;
13 /
过程已创建。
使用PLS-00801、74301和FORALL在METALINK上进行查询,结果发现果然是Oracle的bug。Oracle不支持在FORALL语句中对多个不同的表同时进行操作。仔细想想也确实有道理。看bug的状态,似乎Oracle并没有打算解决这个bug。那么只能是编程的时候多注意一点了。
这个测试是在9204上进行的。不过这个问题应该是覆盖817以上的所有版本。
METALINK详细描述地址:https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&p_id=3038800