【问题标题】:Running DDL within Oracle Procedure - ORA-06508 - How to recompile on runtime?在 Oracle 过程中运行 DDL - ORA-06508 - 如何在运行时重新编译?
【发布时间】:2012-11-24 04:44:48
【问题描述】:

我有一个 oracle 程序,它调用了一些其他程序。

程序1
程序2
程序3
..

现在发生的事情是PROCEDURE2 正在对后续过程 3 及以后的过程中使用的一些依赖表执行 DDL (EXECUTE IMMEDIATE 'DDL PROCESS')。这运行良好,直到它到达 PROCEDURE3 并抛出 ORA-06508 - Program / Unit being called not found

我们不能修改它不使用 DDL,我们必须使用它们。我曾尝试在 DDL 语句后重新编译,但它在 PROCEDURE1PROCEDURE2 中都不起作用(ALTER PROCEDURE PROCEDURE3 RECOMPILE)。

我怀疑PROCEDURE1 本身会变得无效,并且在运行时编译它会导致无限循环。我试过了,不行。

所以我需要使用一些技巧,在对依赖对象执行 DDL 后,使这些过程在运行时再次有效。

提前感谢参与回答的人。

【问题讨论】:

  • 你应该尝试从匿名块调用过程。
  • @user1881540:你在做什么 ddl 改变,比如创建一个表?并在程序 3 中使用该表。请发布代码。

标签: oracle plsql procedure ddl


【解决方案1】:

如果我没记错的话,Oracle 9 在依赖和失效方面比 Oracle >=10 更严格。

我在 Oracle 9 中遇到过一些过程和/或包在它们所依赖的表上执行 DDL 的案例。 我得出的结论是,最实用的解决方案是让它们 依赖于这些表。 IE。而不是做静态SQL

select COL1 into my_var from MY_CHANGING_TABLE ...;

将其作为动态 SQL 执行

execute immediate 'select COL1 from MY_CHANGING_TABLE ...' into my_var;

【讨论】:

    【解决方案2】:

    在这种情况下,与许多其他情况一样,创建一个包而不是一堆独立的程序会更好。包打破依赖链。这是一个例子:

        SQL> create table tb_t(
         2    col1 number
         3  )
         4  ;
    
        Table created
    
    1. 独立程序

      SQL> create or replace procedure Proc1
        2  is
        3  begin
        4    execute immediate 'alter table tb_t add (col2 number)';
        5  end;
        6  /
      

      程序已创建

      SQL> create or replace procedure Proc2
       2  is
       3    l_var number;
       4  begin
       5    select count(*)
       6      into l_var
       7      from tb_t;
       8    dbms_output.put_line(to_char(l_var));
       9  end;
       10  /
      
       Procedure created
      
       SQL> begin
        2    proc1;
        3    proc2;
        4  end;
        5  /
      

    我们得到了

         ORA-06508: PL/SQL: could not find program unit being called
    
    1. SQL> create or replace package test_pkg
        2  is
        3    procedure proc1;
        4    procedure proc2;
        5  end;
        6  /
      
      Package created
      
      SQL> create or replace package body test_pkg
        2  is
        3    procedure proc1
        4    is
        5    begin
        6      execute immediate 'alter table tb_t add (col3 number)';
        7    end;
        8  
        9    procedure proc2
       10    is
       11     l_var number;
       12    begin
       13      select count(*)
       14        into l_var
       15        from tb_t;
       16      dbms_output.put_line(to_char(l_var));
       17    end;
       18  
       19  end;
       20  /
      
       Package body created
      
      
       SQL> begin
         2    test_pkg.proc1;
         3    test_pkg.proc2;
         4  end;
         5  /
      
         0
      
         PL/SQL procedure successfully completed
      

    【讨论】:

    • 不想创建包怎么办?
    • 你能找到另一种方法吗?
    • @user1881540 What if I do not want to create a package。为什么不?如果你真的不想创建一个包,你可以使用execute immediate 语句(execute immediate begin proc1; end;(对于 pl/sql 块中的每个过程)),它也会破坏依赖关系跟踪。 Take a look at this。但是最好使用一个包。
    【解决方案3】:
    alter procedure PX3 compile; -- not "recompile"
    

    这按预期工作:

    set serveroutput ON
    
    create table X as select 42 A from DUAL;
    
    create procedure PX3
    as
      a int;
    begin
      select max(A) into a from X;
      dbms_output.put_line(a);
    end;
    /
    
    create procedure PX2
    as
    begin
      execute immediate 'alter table X add (B int)';
      execute immediate 'alter procedure PX3 compile';
      PX3;
    end;
    /
    
    create procedure PX1
    as
    begin
      PX2;
    end;
    /
    
    begin
      PX1;
    end;
    /
    
    drop procedure PX1;
    drop procedure PX2;
    drop procedure PX3;
    drop table X;
    

    【讨论】:

    • 这不起作用。我已经尝试过使用编译语句
    • 好吧,我提供的代码在放入文件 testcase.sql 并在连接到 Oracle 9 服务器时在 SQL*Plus 中执行时有效。它适用于您的系统吗?如果可行,您在代码中做了哪些不同的事情?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 2014-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多