Oracle 构建顺序和 PL/SQL 包依赖项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2187520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 19:56:18  来源:igfitidea点击:

Oracle build order and PL/SQL package dependencies

oracleplsqldependencies

提问by FrustratedWithFormsDesigner

I'm trying to build up a list of PL/SQL package dependencies so that I can help set up an automated build script for my packages to run on the test server. Is there a way to start with a single package (a "root" package identified by name, ideally) and then find all of the dependencies, and the order they must be compiled in? Dependencies are already fully resolved in my personal schema (so at least I have somewhere to start - but where do I go next?).

我正在尝试构建一个 PL/SQL 包依赖项列表,以便我可以帮助为我的包设置一个自动构建脚本,以便在测试服务器上运行。有没有办法从单个包(理想情况下是由名称标识的“根”包)然后找到所有依赖项,以及它们必须被编译的顺序?依赖关系已经在我的个人模式中完全解决了(所以至少我有地方可以开始 - 但我下一步要去哪里?)。

(Oracle 10.2)

(甲骨文 10.2)

EDIT:

编辑:

The build tool that is being used will use the build order and will retreive those files in order from source control, and then pass them to Oracle to compile (the actual build tool itself is written in Python or Java or both - I don't have access to the source). Basically, the build tool needs as input a list of files to compile in the order they must be compiled in, and acces to those files in source control. If it has that, everything will work quite nicely.

正在使用的构建工具将使用构建顺序并从源代码管理中按顺序检索这些文件,然后将它们传递给 Oracle 进行编译(实际的构建工具本身是用 Python 或 Java 或两者编写的 - 我不可以访问源)。基本上,构建工具需要将要编译的文件列表作为输入,按照它们必须被编译的顺序,并在源代码控制中访问这些文件。如果有的话,一切都会很好地工作。

EDIT:

编辑:

Thanks for the neat scripts. Unfortunately, the build process is mostly out of my hands. The process is based around a build tool which was built by the vendor of the product we are integrating with, which is why the only inputs I can give to the build process are a list of files in the order they need to be built in. If there is a compiler error, the build tool fails, we have to manually submit a request for a new build. So a list of files in the order they should be compiled is important.

感谢您提供整洁的脚本。不幸的是,构建过程大部分都在我的掌控之中。该过程基于由我们正在集成的产品的供应商构建的构建工具,这就是为什么我可以为构建过程提供的唯一输入是按照需要构建的顺序排列的文件列表。如果出现编译器错误,构建工具失败,我们必须手动提交一个新的构建请求。因此,按照应编译的顺序列出文件列表很重要。

EDIT:

编辑:

Found this: http://www.oracle.com/technology/oramag/code/tips2004/091304.htmlGives me the dependencies of any object. Now I just need to get the ordering right... If I get something working I'll post it here.

发现这个:http: //www.oracle.com/technology/oramag/code/tips2004/091304.html给我任何对象的依赖关系。现在我只需要正确排序...如果我得到了一些工作,我会在这里发布。

EDIT:(with code!)

编辑:(用代码!)

I know that in general, this sort of thing is not necessary for Oracle, but for anyone who's still interested...

我知道一般来说,这种事情对于 Oracle 来说不是必需的,但对于任何仍然感兴趣的人来说......

I have cobbled together a little script that seems to be able to get a build order such that all packages will be built in the correct order with no dependency-related errors (with respect to pacakges) the first time around:

我拼凑了一个小脚本,它似乎能够获得一个构建顺序,这样所有包都将以正确的顺序构建,第一次没有与依赖相关的错误(关于 pacakges):

declare

    type t_dep_list is table of varchar2(40) index by binary_integer;
    dep_list t_dep_list;
    i number := 1;
    cursor c_getObjDepsByNameAndType is
    --based on a query found here: http://www.oracle.com/technology/oramag/code/tips2004/091304.html
        select lvl, u.object_id, u.object_type, LPAD(' ', lvl) || object_name obj
        FROM (SELECT level lvl, object_id
               FROM SYS.public_dependency s
               START WITH s.object_id = (select object_id
                                         from user_objects
                                         where object_name = UPPER(:OBJECT_NAME)
                                               and object_type = UPPER(:OBJECT_TYPE))
               CONNECT BY s.object_id = PRIOR referenced_object_id
               GROUP BY level, object_id) tree, user_objects u
        WHERE tree.object_id = u.object_id
              and u.object_type like 'PACKAGE%' --only look at packages, not interested in other types of objects
        ORDER BY lvl desc;

    function fn_checkInList(in_name in varchar2) return boolean is
    begin
        for j in 1 .. dep_list.count loop
            if dep_list(j) = in_name then
                return true;
            end if;
        end loop;
        return false;
    end;



    procedure sp_getDeps(in_objID in user_objects.object_id%type, in_name in varchar2) is
        cursor c_getObjDepsByID(in_objID in user_objects.object_id%type) is
        --based on a query found here: http://www.oracle.com/technology/oramag/code/tips2004/091304.html
            select lvl, u.object_id, u.object_type, LPAD(' ', lvl) || object_name obj
            FROM (SELECT level lvl, object_id
                   FROM SYS.public_dependency s
                   START WITH s.object_id = (select uo.object_id
                                             from user_objects uo
                                             where uo.object_name =
                                                   (select object_name from user_objects uo where uo.object_id = in_objID)
                                                   and uo.object_type = 'PACKAGE BODY')
                   CONNECT BY s.object_id = PRIOR referenced_object_id
                   GROUP BY level, object_id) tree, user_objects u
            WHERE tree.object_id = u.object_id
                  and u.object_id <> in_objID --exclude self (requested Object ID) from list.
            ORDER BY lvl desc;
    begin
        --loop through the dependencies
        for r in c_getObjDepsByID(in_objID) loop
            if fn_checkInList(trim(r.obj)) = false and (r.object_type = 'PACKAGE' or r.object_type = 'PACKAGE BODY') and
               trim(r.obj) <> trim(in_name) then
                dbms_output.put_line('checking deps of: ' || r.obj || ' ' || r.object_id || ' level: ' || r.lvl);
                --now for each dependency, check the sub-dependency
                sp_getDeps(r.object_id, trim(r.obj));
                --add the object to the dependency list.
                dep_list(i) := trim(r.obj);
                i := i + 1;
            end if;
        end loop;
    exception
        when NO_DATA_FOUND then
            dbms_output.put_line('no more data for: ' || in_objID);
    end;

begin

    for r in c_getObjDepsByNameAndType loop
        dbms_output.put_line('top-level checking deps of: ' || r.obj || ' ' || r.object_id || ' level: ' || r.lvl);
        sp_getDeps(r.object_id, trim(r.obj));
    end loop;

    dbms_output.put_line('dep count: ' || dep_list.count);
    for j in 1 .. dep_list.count loop
        dbms_output.put_line('obj: ' || j || ' ' || dep_list(j));
    end loop;
end;

I know it's not the prettiest code (globals all over the place, etc... ugh), and I'll probably repost it if I can get a chance this afternoon to clean it up, but right now, it produces a build order that seems to run the first time with no problems.

我知道这不是最漂亮的代码(到处都是全局代码,等等......呃),如果我今天下午有机会清理它,我可能会重新发布它,但现在,它产生了一个构建订单这似乎第一次运行没有问题。

:OBJECT_NAMEshould be the root object that you want to trace all dependencies and build order of. For me, this is a main package with a single method that is the entry point to the rest of the system.

:OBJECT_NAME应该是要跟踪所有依赖项和构建顺序的根对象。对我来说,这是一个带有单一方法的主包,它是系统其余部分的入口点。

:OBJECT_TYPEI have mostly restricted to PACKAGE BODY, but it shouldn't be too much work to include other types, such as triggers.

:OBJECT_TYPE我主要限于PACKAGE BODY,但包含其他类型(例如触发器)应该不会有太多工作。

One last thing, the object specified by :OBJECT_NAMEwill not appear in the output, but it should be the last item, so you'll have to add that to your build list manually.

最后一件事,由 指定的对象:OBJECT_NAME不会出现在输出中,但它应该是最后一项,因此您必须手动将其添加到构建列表中。

UPDATE:I just discovered user_dependenciesand all_dependencies, this code could probably be made much simpler now.

更新:我刚刚发现user_dependencies并且all_dependencies,这个代码现在可能会变得更简单。

采纳答案by FrustratedWithFormsDesigner

Actual solution: The script above seems to give the correct build order. Could probably be rewritten "nicer", but I'll leave that as an exercise to the reader. ;)

实际解决方案:上面的脚本似乎给出了正确的构建顺序。可能可以重写为“更好”,但我会将其作为练习留给读者。;)

After some discussion, the build tool will perform n(4, actually) builds in a row before reporting errors. This would also help resolve dependency compile errors if the build order is wrong, but I'd rather just get the build order right the first time around.

经过一些讨论,构建工具会在报告错误之前连续执行n(实际上是 4)次构建。如果构建顺序错误,这也将有助于解决依赖项编译错误,但我宁愿第一次就获得正确的构建顺序。

回答by APC

If you're really dealing with just PL/SQL packages you do not need to sweat the build order. Just build all the package specifications first. Then you can deploy all the package bodies and they will compile, because their dependencies are the package specs.

如果您真的只处理 PL/SQL 包,则无需担心构建顺序。只需先构建所有封装规范。然后你可以部署所有的包体,它们将被编译,因为它们的依赖是包规范。

If you happen to have some package specs which do depend on other specs - if you have packages which declare, say, constants, subtypes or ref cursors which are used in the signatures of packaged procedures - then you need to build those package specs first. But there should be few enough of them that you can arrange them in the build script by hand.

如果你碰巧有一些依赖于其他规范的包规范——如果你有声明常量、子类型或引用游标的包,它们在打包过程的签名中使用——那么你需要首先构建这些包规范。但是它们应该很少,您可以手动将它们安排在构建脚本中。

edit

编辑

It looks like they wil be doing incremental AND "clean-sweep" builds, so the build order will matter most for when they clean out the environment and rebuild it.

看起来他们将进行增量和“清理”构建,因此构建顺序对于他们清理环境并重建环境时最重要。

That doesn't alter anything.

那不会改变任何事情。

Here is an extended example. I have a schema with three packages....

这是一个扩展示例。我有一个包含三个包的架构....

SQL> select object_name, object_type, status
  2  from user_objects
  3  order by 1, 2
  4  /

OBJECT_NAME     OBJECT_TYPE     STATUS
--------------- --------------- -------
PKG1            PACKAGE         VALID
PKG1            PACKAGE BODY    VALID
PKG2            PACKAGE         VALID
PKG2            PACKAGE BODY    VALID
PKG3            PACKAGE         VALID
PKG3            PACKAGE BODY    VALID

6 rows selected.

SQL>

The interesting thing is that a procedure in PKG1 calls a procedure from PKG2, a procedure in PKG2 calls a procedure from PKG3 and a procedure in PKG3 calls a procedure from PKG1.

有趣的是,PKG1 中的过程调用PKG2 中的过程,PKG2 中的过程调用PKG3 中的过程,PKG3 中的过程调用PKG1 中的过程。

Q.How does that circular dependency work?
A.It's not a circular dependency....

:这种循环依赖是如何工作的?
A.这不是循环依赖....

SQL> select name, type, referenced_name, referenced_type
  2  from user_dependencies
  3  where referenced_owner = user
  4  /

NAME            TYPE            REFERENCED_NAME REFERENCED_TYPE
--------------- --------------- --------------- ---------------
PKG1            PACKAGE BODY    PKG1            PACKAGE
PKG1            PACKAGE BODY    PKG2            PACKAGE
PKG2            PACKAGE BODY    PKG2            PACKAGE
PKG2            PACKAGE BODY    PKG3            PACKAGE
PKG3            PACKAGE BODY    PKG3            PACKAGE
PKG3            PACKAGE BODY    PKG1            PACKAGE

6 rows selected.

SQL> 

All the dependent objects are the package bodies, all the referenced objects are the packaged specs. Consequently, if I trash'n'rebuild the schema it really doesn't matter what order I use. First we trash ...

所有依赖的对象都是包体,所有引用的对象都是打包的规范。因此,如果我对架构进行垃圾处理和重建,那么我使用的顺序实际上并不重要。首先我们垃圾...

SQL> drop package pkg1
  2  /

Package dropped.

SQL> drop package pkg2
  2  /

Package dropped.

SQL> drop package pkg3
  2  /

Package dropped.

SQL>

Then we rebuild ...

然后我们重建...

SQL> create or replace package pkg3 is
  2      procedure p5;
  3      procedure p6;
  4  end pkg3;
  5  /

Package created.

SQL> create or replace package pkg2 is
  2      procedure p3;
  3      procedure p4;
  4  end pkg2;
  5  /

Package created.

SQL> create or replace package pkg1 is
  2      procedure p1;
  3      procedure p2;
  4  end pkg1;
  5  /

Package created.

SQL> create or replace package body pkg2 is
  2      procedure p3 is
  3      begin
  4          pkg3.p5;
  5      end p3;
  6      procedure p4 is
  7      begin
  8          dbms_output.put_line('PKG2.P4');
  9      end p4;
 10  end pkg2;
 11  /

Package body created.

SQL> create or replace package body pkg3 is
  2      procedure p5 is
  3      begin
  4          dbms_output.put_line('PKG3.P5');
  5      end p5;
  6      procedure p6 is
  7      begin
  8          pkg1.p1;
  9      end p6;
 10  end pkg3;
 11  /

Package body created.

SQL> create or replace package body pkg1 is
  2      procedure p1 is
  3      begin
  4          dbms_output.put_line('PKG1.P1');
  5      end p1;
  6      procedure p2 is
  7      begin
  8          pkg2.p4;
  9      end p2;
 10  end pkg1;
 11  /

Package body created.

SQL>

The order of the individual objects is irrelevant. Just build the package specs before the package bodies. Although even that does not really matter...

各个对象的顺序无关紧要。只需在包体之前构建包规范。虽然这也没什么关系……

SQL> create or replace package pkg4 is
  2      procedure p7;
  3  end pkg4;
  4  /

Package created.

SQL> create or replace package body pkg4 is
  2      procedure p7 is
  3      begin
  4          dbms_output.put_line('PKG4.P7::'||constants_pkg.whatever);
  5      end p7;
  6  end pkg4;
  7  /

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY PKG4:

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9      PL/SQL: Statement ignored
4/43     PLS-00201: identifier 'CONSTANTS_PKG.WHATEVER' must be declared
SQL>

PKG4is INVALID because we have not built CONSTANTS_PKGyet.

PKG4是无效的,因为我们还没有构建CONSTANTS_PKG

SQL> create or replace package constants_pkg is
  2      whatever constant varchar2(20) := 'WHATEVER';
  3  end constants_pkg;
  4  /

Package created.

SQL> select object_name, object_type, status
  2  from user_objects
  3  where status != 'VALID'
  4  order by 1, 2
  5  /

OBJECT_NAME     OBJECT_TYPE     STATUS
--------------- --------------- -------
PKG4            PACKAGE BODY    INVALID

SQL> 
SQL> set serveroutput on size unlimited
SQL> exec pkg4.p7
PKG4.P7::WHATEVER

PL/SQL procedure successfully completed.

SQL> select object_name, object_type, status
  2  from user_objects
  3  where status != 'VALID'
  4  order by 1, 2
  5  /

no rows selected

SQL>

Anything built using CREATE OR REPLACEis always created, it is just marked as INVALID if there are errors. As soon as we execute it, directly or indirectly, the database compiles it for us. So, order does not matter. Really it doesn't.

任何使用构建的东西CREATE OR REPLACE总是会被创建,如果有错误,它只会被标记为 INVALID。一旦我们直接或间接执行它,数据库就会为我们编译它。所以,顺序并不重要。真的没有。

If the idea of finishing a build with invalid objects concerns you - and I have some sympathy with that, we are told not to live with broken windows - you can use the utlrpscript or in 11g the UTL_RECOMP package; either approach requires a SYSDBA account.

如果使用无效对象完成构建的想法让您感到担忧 - 我对此表示同情,我们被告知不要忍受破碎的窗口 - 您可以使用utlrp脚本或在 11g 中使用 UTL_RECOMP 包;这两种方法都需要一个 SYSDBA 帐户。

edit 2

编辑 2

The process is based around a build tool which was built by the vendor of the product we are integrating with, which is why the only inputs I can give to the build process are a list of files in the order they need to be built in. If there is a compiler error, the build tool fails, we have to manually submit a request for a new build.

该过程基于由我们正在集成的产品的供应商构建的构建工具,这就是为什么我可以为构建过程提供的唯一输入是按照需要构建的顺序排列的文件列表。如果出现编译器错误,构建工具失败,我们必须手动提交一个新的构建请求。

This is a political problem not a technical one. Which isn't to say that political problems can't be resolved with a technical fix, just that the technical fix is not the best tool for the job. Good luck.

这是一个问题而不是技术问题。这并不是说问题不能通过技术修复来解决,只是技术修复不是这项工作的最佳工具。祝你好运。

回答by Vinodh Ramasubramanian

Look at the following script from http://www.oracle-base.com/articles/misc/RecompilingInvalidSchemaObjects.php

http://www.oracle-base.com/articles/misc/RecompilingInvalidSchemaObjects.php查看以下脚本

SET SERVEROUTPUT ON SIZE 1000000
BEGIN
  FOR cur_rec IN (SELECT owner,
                         object_name,
                         object_type,
                         DECODE(object_type, 'PACKAGE', 1,
                                             'PACKAGE BODY', 2, 2) AS recompile_order
                  FROM   dba_objects
                  WHERE  object_type IN ('PACKAGE', 'PACKAGE BODY')
                  AND    status != 'VALID'
                  ORDER BY 4)
  LOOP
    BEGIN
      IF cur_rec.object_type = 'PACKAGE' THEN
        EXECUTE IMMEDIATE 'ALTER ' || cur_rec.object_type || 
            ' "' || cur_rec.owner || '"."' || cur_rec.object_name || '" COMPILE';
      ElSE
        EXECUTE IMMEDIATE 'ALTER PACKAGE "' || cur_rec.owner || 
            '"."' || cur_rec.object_name || '" COMPILE BODY';
      END IF;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.put_line(cur_rec.object_type || ' : ' || cur_rec.owner || 
                             ' : ' || cur_rec.object_name);
    END;
  END LOOP;
END;
/

回答by APC

One little thing to watch out for when walking the dependency tree. Dependencies for uncompiled programs don't show...

走依赖树时要注意的一件小事。未编译程序的依赖项不显示...

SQL> drop package constants_pkg
  2  /

Package dropped.

SQL> create or replace package body pkg4 is
  2      procedure p7 is
  3      begin
  4          dbms_output.put_line('PKG4.P7::'||zzz_constants_pkg.whatever);
  5      end p7;
  6  end pkg4;
  7  /

Warning: Package Body created with compilation errors.

SQL> show errors
Errors for PACKAGE BODY PKG4:

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/9      PL/SQL: Statement ignored
4/43     PLS-00201: identifier 'ZZZ_CONSTANTS_PKG.WHATEVER' must be
         declared

SQL>

So, the body for PKG4is INVALID because ZZZ_CONSTANTS_PKGdoesn't exist.

因此,主体 forPKG4是无效的,因为ZZZ_CONSTANTS_PKG不存在。

SQL> create or replace package zzz_constants_pkg is
  2      whatever constant varchar2(20) := 'WHATEVER';
  3  end zzz_constants_pkg;
  4  /

Package created.

SQL>

But the body for PKG4is still INVALID so the following query does not return its dependency on ZZZ_CONSTANTS_PKG....

但主体 forPKG4仍然无效,因此以下查询不会返回其对ZZZ_CONSTANTS_PKG....

SQL> select name, type, referenced_name, referenced_type
  2  from user_dependencies
  3  where referenced_owner = user
  4  /

NAME            TYPE            REFERENCED_NAME   REFERENCED_TYPE
--------------- --------------- ----------------- ---------------
PKG1            PACKAGE BODY    PKG1              PACKAGE
PKG1            PACKAGE BODY    PKG2              PACKAGE
PKG2            PACKAGE BODY    PKG2              PACKAGE
PKG2            PACKAGE BODY    PKG3              PACKAGE
PKG3            PACKAGE BODY    PKG3              PACKAGE
PKG3            PACKAGE BODY    PKG1              PACKAGE
PKG4            PACKAGE BODY    PKG4              PACKAGE

7 rows selected.

SQL>

Now let's compile PKG4and re-query the dependencies ....

现在让我们编译PKG4并重新查询依赖项....

SQL> alter package pkg4 compile body;

Package body altered.

SQL> select name, type, referenced_name, referenced_type
  2  from user_dependencies
  3  where referenced_owner = user
  4  /

NAME            TYPE            REFERENCED_NAME   REFERENCED_TYPE
--------------- --------------- ----------------- ---------------
PKG1            PACKAGE BODY    PKG1              PACKAGE
PKG1            PACKAGE BODY    PKG2              PACKAGE
PKG2            PACKAGE BODY    PKG2              PACKAGE
PKG2            PACKAGE BODY    PKG3              PACKAGE
PKG3            PACKAGE BODY    PKG3              PACKAGE
PKG3            PACKAGE BODY    PKG1              PACKAGE
PKG4            PACKAGE BODY    PKG4              PACKAGE
PKG4            PACKAGE BODY    ZZZ_CONSTANTS_PKG PACKAGE

8 rows selected.

SQL> 

回答by Pranav Shah

Try this instead for 11.1 and up. Run the script in any order. At the end issue the following command: (Change the command parameters to suit your needs)

在 11.1 及更高版本中试试这个。以任意顺序运行脚本。最后发出以下命令:(更改命令参数以满足您的需要)

-- Compile invalid objects
EXEC DBMS_UTILITY.compile_schema(USER, FALSE);

More details on DBMS_UTILITY.compile_scema

有关DBMS_UTILITY.compile_scema 的更多详细信息

回答by dpbradley

You don't need a build order - just build the packages with "CREATE OR REPLACE..." on a file-by-file basis and then compile them in a two-level nested loop - each pass in the inner loop compiles everything that is still invalid and the outer loop is used to check the count of remaining invalid objects and set some sort of threshold for maximum executions of the inner loop. In practice, I've never seen the number of passes needed be higher than three.

您不需要构建顺序 - 只需在逐个文件的基础上使用“CREATE OR REPLACE...”构建包,然后在两级嵌套循环中编译它们 - 内循环中的每次传递都会编译所有内容这仍然无效,外循环用于检查剩余无效对象的计数,并为内循环的最大执行次数设置某种阈值。在实践中,我从未见过需要的传球次数超过 3 次。

If you have multiple schemas involved in the dependencies, look into running Oracles utlrp.sql script, which works across schemas and sets up some infrastructure to manage the process - this needs a privileged account however.

如果依赖项中涉及多个模式,请查看运行 Oracles utlrp.sql 脚本,该脚本跨模式工作并设置一些基础结构来管理该过程 - 但是这需要一个特权帐户。

Also, if you extend your source control to include views, be sure that the scripts use "CREATE OR REPLACE FORCE VIEW... " to create views which have unmet dependencies at the time of their creation.

此外,如果您扩展源代码管理以包含视图,请确保脚本使用“CREATE OR REPLACE FORCE VIEW...”来创建在创建时具有未满足依赖项的视图。

Example script that I use:

我使用的示例脚本:

set serveroutput on
declare
 cursor invalidObjCur is 
  select object_name, object_type
    from user_objects
    where status <> 'VALID'
    ;
 compileStmt varchar2(4000); 
 passCount pls_integer := 0;
 maxPasses pls_integer := 5;
 lastInvalidCount pls_integer := 32000; 
 objectCount pls_integer;
 continue boolean := TRUE;

begin
 dbms_output.enable(1000000);
 while (continue) loop
   passCount := passCount + 1;
   dbms_output.put_line('Pass '||passCount);
   objectCount := 0;
   for curRow in InvalidObjCur loop
    if curRow.object_type = 'PACKAGE BODY' then
        compileStmt := 'alter PACKAGE '||curRow.object_name||' compile body';
    else
        compileStmt := 'alter '||curRow.object_type||' '||
        chr(34)||curRow.object_name||chr(34)||' compile';
    end if;
    begin
      execute immediate compileStmt;
    exception when others then
      null;
    end;
   objectCount := objectCount + 1;
   end loop;
   dbms_output.put_line('Recompilations attempted: '||objectCount);
   continue := (passCount < maxPasses) and (objectCount < lastInvalidCount);
   lastInvalidCount := objectCount;
 end loop;
dbms_output.put_line('***** Remaining Invalid ********');
for curRow in InvalidObjCur loop
 dbms_output.put_line(curRow.object_type||' '||curRow.object_name);
end loop; 
dbms_output.put_line('********************************');
end;    
/

回答by PenFold

Add the following command to the top of your script:

将以下命令添加到脚本的顶部:

SET VERIFY OFF

设置验证关闭

this will allow your scripts to run without validation and therefore can be run in any order.

这将使您的脚本无需验证即可运行,因此可以按任何顺序运行。

You can later query DBA_ERRORS to get all errors and warnings in your packages, views and types.

您可以稍后查询 DBA_ERRORS 以获取包、视图和类型中的所有错误和警告。