暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

对于DBMS_METADATA API的正确使用方式

Oracle蓝莲花 2021-04-15
2587

--------------------------------------------------------------------------------------------------------------

- --TroubleShooting :对于DBMS_METADATA API的正确使用方式

- --Description :DBMS_METADATA常用功能介绍、如何重建数据库失效对象、附赠部分问题处理脚本

- --Author :600团队

- --Remark :The article was produced by 600 teams

- --TimeStamp :2018-07-22 12:30

--------------------------------------------------------------------------------------------------------------

1.基于Oracle官方对DBMS_METADATA做如下分解介绍:


The DBMS_METADATA package provides a way for you to retrieve metadata from the database dictionary as XML or 

creation DDL and to submit the XML to re-create the object.


DBMS_METADATA包为我们提供了一种方法,可以从数据库字典中检索作为XML或创建DDL的元数据,并提交XML以重新创建对象


DBMS_METADATA概念及其功能介绍:

用于DDL检索的API和用于DDL和关联的API

•起源于9i版本,到了Oracle 10g得到增强,随着版本迭代更新12c功能更加强大

•支撑Oracle 10g 11g datapump

•默认情况下返回XML

•过滤器(排除某些对象或过滤器过滤对象类型)

•转换(例如,返回SQL DDL转换(例如,返回SQL DDL)

•解析项(以返回有关解析项的信息)

--------------------------------------------------------------------------------------------------------------

2.代码演示:

--获取表的元数据

SELECT DBMS_METADATA.GET_DDL('TABLE', U.TABLE_NAME)

  FROM USER_ALL_TABLES U

 WHERE U.NESTED = 'NO'

   AND (U.IOT_TYPE IS NULL OR U.IOT_TYPE = 'IOT');

   

注:如果该表是一个索引组织的表,那么IOT_TYPE就是IOT、IOT_OVERFLOW或IOT_MAPPING。如果该表不是索引组织的表,

    则IOT_TYPE为NULL

NESTED指示该表是否是嵌套表(YES)或否(NO)

--GET_DEPENDENT_DDL GET_DEPENDENT_DDL获取约束信息

SELECT DBMS_METADATA.GET_DEPENDENT_DDL('OBJECT_GRANT', 'EMPLOYEES', 'HR')

  FROM DUAL;

  

Answer: GRANT SELECT ON "HR"."EMPLOYEES" TO "SCOTT" WITH GRANT OPTION

GRANT REFERENCES ON "HR"."EMPLOYEES" TO "OE"

GRANT SELECT ON "HR"."EMPLOYEES" TO "OE"


--获取某个用户系统权限

SELECT DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', '&OWNER') FROM DUAL;


Answer:  GRANT MANAGE SCHEDULER TO "SCOTT"

GRANT ON COMMIT REFRESH TO "SCOTT"

         GRANT GLOBAL QUERY REWRITE TO "SCOTT"

         GRANT QUERY REWRITE TO "SCOTT"

         GRANT CREATE MATERIALIZED VIEW TO "SCOTT"

         GRANT CREATE ANY PROCEDURE TO "SCOTT"

         GRANT CREATE ANY INDEX TO "SCOTT"

         GRANT DELETE ANY TABLE TO "SCOTT"

         GRANT SELECT ANY TABLE TO "SCOTT"

         GRANT UNLIMITED TABLESPACE TO "SCOTT"

         GRANT ALTER SYSTEM TO "SCOTT"

 

--该函数比较两个对象的元数据,并返回一组ALTER语句,以便像object2那样创建对象1

SELECT DBMS_METADATA_DIFF.COMPARE_ALTER(OBJECT_TYPE => '&OBJECT_TYPE',

                                        NAME1       => '&NAME1',

                                        NAME2       => '&NAME2',

                                        SCHEMA1     => '&OWNER1',

                                        SCHEMA2     => '&OWNER2')

  FROM DUAL;

  

Answer:ALTER TABLE "SCOTT"."T_600_COMPARE1" DROP ("COL_ENAME")

  ALTER TABLE "SCOTT"."T_600_COMPARE1" DROP ("COL_DEPTNO")

       ALTER TABLE "SCOTT"."T_600_COMPARE1" RENAME TO "T_600_COMPARE2"

  

--获取约束和权限:

BEGIN

  DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.session_transform,

                                    'SQLTERMINATOR', true);

  DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.session_transform,

                                    'SEGMENT_ATTRIBUTES', false);

END;

/

SELECT DBMS_METADATA.GET_DDL('TABLE', TABLE_NAME)

  FROM USER_TABLES

 WHERE TABLE_NAME IN ('DEPT', 'EMP');

/

BEGIN

  DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,

                                    'CONSTRAINTS_AS_ALTER',

                                    TRUE);

  DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,

                                    'REF_CONSTRAINTS',

                                    FALSE);

END;

/

SELECT DBMS_METADATA.GET_DDL('TABLE', TABLE_NAME)

  FROM USER_TABLES

 WHERE TABLE_NAME IN ('DEPT', 'EMP');

/

SELECT DBMS_METADATA.GET_DEPENDENT_DDL('REF_CONSTRAINT', TABLE_NAME)

  FROM USER_TABLES T

 WHERE TABLE_NAME IN ('EMP', 'DEPT')

   AND EXISTS (SELECT 1

          FROM USER_CONSTRAINTS

         WHERE TABLE_NAME = T.TABLE_NAME

           AND CONSTRAINT_TYPE = 'R');

  

注:SQLTERMINATOR为true是为了在每个命令的末尾获得分号

SEGMENT_ATTRIBUTES为false是为了缩短生成的ddl脚本时间

用ALTER语句通过将CONSTRAINTS_AS_ALTER参数设置为true来分别创建约束

通过将REF_CONSTRAINTS设置为false,在生成DDL期间跳过引用约束


--------------------------------------------------------------------------------------------------------------

3.了解DBMS_METADATA的data types,然后我们来做一个综合案例:

--返回所有DDL的函数的代码片段分解介绍,以下为代码片段1:

3.1代码片段1:

create or replace function func_get_ddl_for_table(p_schema_name in varchar2,

 p_sqlterminator in boolean default false)

--该sys.ku$_ddls为系统定义类型返回值

return sys.ku$_ddls 

is

v_outputddls sys.ku$_ddls := sys.ku$_ddls(); <----通过变量接收系统定义的类型

v_parsed_items parsed_items_t;

begin

v_handle := dbms_metadata.open(‘TABLE’);<----打开一个上下文句柄

--设置筛选器,只获取指定模式的对象

dbms_metadata.set_filter(v_handle,cv_schema, p_schema_name);

注:DBMS_METADATA API基于对象和表类型,要么在类型中定义,要么在SYS系统类型中定义

常用的两个系统定义类型为 KU$_PARSED ITEM 和KU$_DDL,它们以数组的形式呈现,例如如下代码

CREATE TYPE

sys.ku$_parsed_item

AS OBJECT (

item VARCHAR2(30),

value VARCHAR2(4000),

object_row NUMBER )

/

CREATE TYPE

sys.ku$_ddl

AS OBJECT (

ddlText CLOB,

parsedItem

sys.ku$_parsed_items ) 

--------------------------------------------------------------------------------------------------------------

4.综合实例演示:

CREATE OR REPLACE FUNCTION FUNC_TABLEDDL(P_INPUT_VALUES SYS_REFCURSOR)

--pipe管道接收

 RETURN T_600_TABLEDDL_TYPE

  PIPELINED IS

  --设定自治事务

  PRAGMA AUTONOMOUS_TRANSACTION;

  --定义变量

  --创建T_600_TABLEDDL对象类型表的字段信息用于变量接收,例如table_name通过V_TABLE_NAME接收

  V_TABLE_NAME VARCHAR2(30);

  --创建T_600_TABLEDDL对象类型表的字段信息用于变量接收,例如orig_schema通过V_orig_schema接收

  V_ORIG_SCHEMA VARCHAR2(30);

  --创建T_600_TABLEDDL对象类型表的字段信息用于变量接收,例如comp_schema通过V_comp_schema接收

  V_COMP_SCHEMA VARCHAR2(30);

  -- 设置T_600_TABLEDDL对象类型表输出记录

  OUT_REC T_600_TABLEDDL := T_600_TABLEDDL(NULL, NULL, NULL, NULL, NULL);

  --获取元数据信息句柄为了跟踪不同的对象DDL,在function中我们来具体引用

  HOPENORIG0  NUMBER;

  HOPENORIG   NUMBER;

  HOPENCOMP   NUMBER;

  HMODIFYORIG NUMBER;

  HTRANSDDL   NUMBER;

  DMSF        PLS_INTEGER; --dbms_metadata.session_transform接收变量


  ***********************************

  *clob持有DDL

  *Orig_ddl0将保存要比较的对象的基线DDL

  *Orig_ddl1还将保存要比较的对象的基线DDL但是在被比较之前也会经过校正

  *针对Comp_ddl2 Comp_ddl2将包含要与基线进行比较的DDL

  *************************************/

  ORIG_DDL0 CLOB;

  ORIG_DDL1 CLOB;

  COMP_DDL2 CLOB;

  RET       NUMBER;

BEGIN

  --去掉DDL中不涉及的属性。如果你关心表空间、存储或段信息只注释掉这几行

  DMSF := DBMS_METADATA.SESSION_TRANSFORM;

  DBMS_METADATA.SET_TRANSFORM_PARAM(DMSF, 'TABLESPACE', FALSE);

  DBMS_METADATA.SET_TRANSFORM_PARAM(DMSF, 'STORAGE', FALSE);

  DBMS_METADATA.SET_TRANSFORM_PARAM(DMSF, 'SEGMENT_ATTRIBUTES', FALSE);

  -- 通过游标循环遍历结果集

  LOOP

    --传入参数通过游标变量接收

    FETCH P_INPUT_VALUES

      INTO V_TABLE_NAME, V_ORIG_SCHEMA, V_COMP_SCHEMA;

    EXIT WHEN P_INPUT_VALUES%NOTFOUND; 

    --获取原始对象类型标的DDL定义元数据

    HOPENORIG0 := DBMS_METADATA.OPEN('TABLE');

    DBMS_METADATA.SET_FILTER(HOPENORIG0, 'NAME', 'T_600_TABLEDDL_TYPE');

    DBMS_METADATA.SET_FILTER(HOPENORIG0, 'SCHEMA', 'SCOTT');

    * 对将进行转换的原始表DDL重新设置句柄,我们为原始对象DDL设置了两个句柄,因为我们希望能够。

    操作一个集进行比较,但将原始DDL打印输出 */

    HOPENORIG := DBMS_METADATA.OPEN('TABLE');

    DBMS_METADATA.SET_FILTER(HOPENORIG, 'NAME', 'T_600_TABLEDDL_TYPE');

    DBMS_METADATA.SET_FILTER(HOPENORIG, 'SCHEMA', 'SCOTT'); 

    -- 设置表的句柄,以便与原始表进行比较

    HOPENCOMP := DBMS_METADATA.OPEN('TABLE');

    DBMS_METADATA.SET_FILTER(HOPENCOMP, 'NAME', 'T_600_TABLEDDL_TYPE');

    DBMS_METADATA.SET_FILTER(HOPENCOMP, 'SCHEMA', 'SCOTT'); 

    --修改“orig_schema”的转换,使其具有comp_schema权限

    HMODIFYORIG := DBMS_METADATA.ADD_TRANSFORM(HOPENORIG, 'MODIFY');

    DBMS_METADATA.SET_REMAP_PARAM(HMODIFYORIG,

                                  'REMAP_SCHEMA',

                                  'SCOTT',

                                  'SCOTT');

    -- 创建DDL,但不比较XML

    HTRANSDDL := DBMS_METADATA.ADD_TRANSFORM(HOPENORIG0, 'DDL');


    HTRANSDDL := DBMS_METADATA.ADD_TRANSFORM(HOPENORIG, 'DDL');

    HTRANSDDL := DBMS_METADATA.ADD_TRANSFORM(HOPENCOMP, 'DDL');

    -- 获取DDD并将其存储到CLOB PL/SQL变量中

    ORIG_DDL0 := DBMS_METADATA.FETCH_CLOB(HOPENORIG0);

    ORIG_DDL1 := DBMS_METADATA.FETCH_CLOB(HOPENORIG);

    --把基线对象存储于Comp_schema中

    BEGIN

      COMP_DDL2 := DBMS_METADATA.FETCH_CLOB(HOPENCOMP);

    EXCEPTION

      WHEN OTHERS THEN

        COMP_DDL2 := 'DOES NOT EXIST';

    END; 

    -- 比较两个DDL语句和输出行

    RET := DBMS_LOB.COMPARE(ORIG_DDL1, COMP_DDL2);

    IF RET != 0 THEN

      OUT_REC.TABLE_NAME  := 'T_600_TABLEDDL_TYPE';

      OUT_REC.ORIG_SCHEMA := 'SCOTT';

      OUT_REC.ORIG_DDL    := ORIG_DDL0;

      OUT_REC.COMP_SCHEMA := 'SCOTT';

      OUT_REC.COMP_DDL    := COMP_DDL2;

      PIPE ROW(OUT_REC);

    END IF;

    -- 关闭游标并释放句柄

    DBMS_METADATA.CLOSE(HOPENORIG0);

    DBMS_METADATA.CLOSE(HOPENORIG);

    DBMS_METADATA.CLOSE(HOPENCOMP);

  END LOOP;

  RETURN;

END FUNC_TABLEDDL;


SELECT *

  FROM TABLE(FUNC_TABLEDDL(CURSOR (SELECT TABLE_NAME, OWNER, 'SCOTT'

                              FROM DBA_TABLES

                             WHERE OWNER = 'SCOTT')));


注:为了代码演示方便,我们用对象类型表代替函数中的变量,保证编译通过,实际使用过程可以将TABLE_NAME直接替换

     或者当传入参数利用ref cursor直接代入即可。

--------------------------------------------------------------------------------------------------------------

5.对于dbms_metadata API简单封装代码,方便查询元数据内容

CREATE OR REPLACE PACKAGE PKG_GET_INFO IS

  *************************************************************

  * Cpmtemt:Use This Package For Get Database Object Information

  * AUTHOR :600团队

  * TimeStamp :2016-04-22 15:27:00

  *************************************************************/

  --------------------------------------------------------------

  --Get Procedure Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_PROCEDURE_INFO;

  --------------------------------------------------------------

  --Get Function Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_FUNCTION_INFO;

  --------------------------------------------------------------

  --Get Trigger Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_TRIGGER_INFO;

  --------------------------------------------------------------

  --Get View Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_VIEW_INFO;

  --------------------------------------------------------------

  --Get Sequence Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_SEQUENCE_INFO;

  --------------------------------------------------------------

  --Get Table Script

  --------------------------------------------------------------

  PROCEDURE PROC_GET_TABLE_INFO;

END PKG_GET_INFO;

/

CREATE OR REPLACE PACKAGE BODY PKG_GET_INFO IS

  -----------------------------------------------

  --Global Contant

  C_PROCEDURE CONSTANT VARCHAR2(20) := 'PROCEDURE';

  C_FUNCTION  CONSTANT VARCHAR2(20) := 'FUNCTION';

  C_TRIGGER   CONSTANT VARCHAR2(20) := 'TRIGGER';

  C_VIEW      CONSTANT VARCHAR2(20) := 'VIEW';

  C_SEQUENCE  CONSTANT VARCHAR2(20) :='SEQUENCE';

  C_USER      CONSTANT VARCHAR2(20) := 'SCOTT';

  C_TABLE CONSTANT VARCHAR2(20) :='TABLE';

  -----------------------------------------------

  -----------------------------------------------

  --Get Procedure Script

  -----------------------------------------------

  PROCEDURE PROC_GET_PROCEDURE_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_PROCEDURE  SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[INVEST]'

         AND OBJECT_TYPE = Q'[PROCEDURE]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_PROCEDURE;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_PROCEDURE,

                                   NAME        => V_PROCEDURE,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB);

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_PROCEDURE_INFO;


  -----------------------------------------------

  --Get Function Script

  -----------------------------------------------

  PROCEDURE PROC_GET_FUNCTION_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_FUNCTION   SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[INVEST]'

         AND OBJECT_TYPE = Q'[FUNCTION]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_FUNCTION;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_FUNCTION,

                                   NAME        => V_FUNCTION,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB);

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_FUNCTION_INFO;

  -----------------------------------------------

  --Get Trigger Script

  -----------------------------------------------

  PROCEDURE PROC_GET_TRIGGER_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_TRIGGER   SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[INVEST]'

         AND OBJECT_TYPE = Q'[TRIGGER]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_TRIGGER;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_TRIGGER,

                                   NAME        => V_TRIGGER,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB);

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_TRIGGER_INFO;

  -----------------------------------------------

  --Get View Script

  -----------------------------------------------

 PROCEDURE PROC_GET_VIEW_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_VIEW   SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[INVEST]'

         AND OBJECT_TYPE = Q'[VIEW]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_VIEW;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_VIEW,

                                   NAME        => V_VIEW,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB||';');

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_VIEW_INFO;

  -----------------------------------------------

  --Get View Script

  -----------------------------------------------

  PROCEDURE PROC_GET_SEQUENCE_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_SEQUENCE   SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[INVEST]'

         AND OBJECT_TYPE = Q'[SEQUENCE]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_SEQUENCE;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_SEQUENCE,

                                   NAME        => V_SEQUENCE,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB||';');

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_SEQUENCE_INFO;

  -----------------------------------------------

  --Get Table Script

  -----------------------------------------------

  PROCEDURE PROC_GET_TABLE_INFO IS

    V_BEGIN_TIME NUMBER;

    V_END_TIME   NUMBER;

    V_RESULT     NUMBER;

    L_ERR_NUMS   PLS_INTEGER;

    V_TABLE   SYS.DBA_OBJECTS.OBJECT_NAME%TYPE;

    V_CLOB       CLOB;

    CURSOR CUR_PROCEDURE IS

      SELECT OBJECT_NAME

        FROM DBA_OBJECTS

       WHERE OWNER = Q'[SCOTT]'

         AND OBJECT_TYPE = Q'[TABLE]';

  BEGIN

    DBMS_OUTPUT.ENABLE(BUFFER_SIZE => NULL);

    SELECT DBMS_UTILITY.GET_TIME INTO V_BEGIN_TIME FROM DUAL;

    OPEN CUR_PROCEDURE;

    LOOP

      FETCH CUR_PROCEDURE

        INTO V_TABLE;

      SELECT DBMS_METADATA.GET_DDL(OBJECT_TYPE => C_TABLE,

                                   NAME        => V_TABLE,

                                   SCHEMA      => C_USER)

        INTO V_CLOB

        FROM DUAL;

      DBMS_OUTPUT.PUT_LINE(V_CLOB||';');

      EXIT WHEN CUR_PROCEDURE%NOTFOUND;

    END LOOP;

    SELECT DBMS_UTILITY.GET_TIME INTO V_END_TIME FROM DUAL;

    SELECT TO_CHAR(V_END_TIME - V_BEGIN_TIME) 100

      INTO V_RESULT

      FROM DUAL;

  EXCEPTION

    WHEN OTHERS THEN

      L_ERR_NUMS := SQLCODE;

      DBMS_OUTPUT.PUT_LINE(L_ERR_NUMS || '-------' || SQLERRM);

  END PROC_GET_TABLE_INFO;

END PKG_GET_INFO;

/


--------------------------------------------------------------------------------------------------------------

6.如何编译失效对象,这里为各位介绍几种重新编译失效对象的方法:

6.1利用DBMS_DDL.alter_compile方式重新编译失效对象

EXEC DBMS_DDL.alter_compile('PACKAGE', 'MY_SCHEMA', 'MY_PACKAGE');

EXEC DBMS_DDL.alter_compile('PACKAGE BODY', 'MY_SCHEMA', 'MY_PACKAGE');

EXEC DBMS_DDL.alter_compile('PROCEDURE', 'MY_SCHEMA', 'MY_PROCEDURE');

EXEC DBMS_DDL.alter_compile('FUNCTION', 'MY_SCHEMA', 'MY_FUNCTION');

EXEC DBMS_DDL.alter_compile('TRIGGER', 'MY_SCHEMA', 'MY_TRIGGER');

6.2自定义匿名块方式编译:

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;


6.3利用DBMS_UTILITY.compile_schema和UTL_RECOMP.recomp_parallel方式重新编译失效对象

BEGIN

DBMS_UTILITY.compile_schema('SCOTT'); --重新编译用户下所有的程序

END ;

/

BEGIN

SYS.UTL_RECOMP.recomp_parallel(threads =>8 ,schema =>'SCOTT' );--重新编译用户下所有的程序

END ;

6.4利用utlrp.sql重新编译失效对象

$ORACLE_HOME/rdbms/admin/utlrp.sql

注:utlrp。可以调用sql脚本重新编译数据库中的所有对象,就像使用utl_recomp包一样,除了utlrp.sql将查找并重新

编译数据库中的所有无效对象。utlrp的来源作为utl_recomp包的封装。

6.5重建数据库对象脚本:

------------------------------------------------------------------------------------------------

- --TroubleShooting :基于数据字典基表重建各类数据库对象脚本

------------------------------------------------------------------------------------------------

--重建dblink脚本

SELECT 'create '||DECODE(U.NAME,'PUBLIC','public ')||'database link '||CHR(10)

||DECODE(U.NAME,'PUBLIC',Null, U.NAME||'.')|| L.NAME||chr(10)

||'connect to ' || L.USERID || ' identified by '

||L.PASSWORD||' using ''' || L.host || ''''

||chr(10)||';' TEXT

FROM link$ L, user$ U

WHERE L.OWNER# = U.USER#

--重建同义词

SELECT 'create or replace ' || DECODE(O.OWNER#, 1, ' public ') ||

       ' synonym ' || DECODE(O.OWNER#, 1, '', U.NAME || '.') || O.NAME ||

       ' for ' || S.OWNER || '.' || S.NAME || NVL2(S.NODE, '@', '') ||

       S.NODE || ';'

  FROM SYN$ S, OBJ$ O, USER$ U

 WHERE S.OBJ# = O.OBJ#

   AND O.DATAOBJ# IS NULL

   AND S.OWNER = UPPER('&OWNER')

   AND U.USER# = O.OWNER#

--重建视图

SELECT 'CREATE OR REPLACE VIEW ' || O.NAME || '(' ||

       REPLACE(C.COLS, ', ', ', ' || CHR(10)) || ') ' || CHR(10) || 'AS' ||

       CHR(10),

       V.TEXT

  FROM USER$ U,

       OBJ$ O,

       VIEW$ V,

       (SELECT COL.OBJ#, COL.COLS

          FROM (SELECT OBJ#,

                       COL#,

                       SUBSTR(SYS_CONNECT_BY_PATH(NAME, ', '), 2) COLS

                  FROM COL$

                 WHERE COL# > 0

                 START WITH COL# = 1

                CONNECT BY PRIOR OBJ# = OBJ#

                       AND PRIOR COL# = COL# - 1) COL,

               (SELECT OBJ#, COUNT(*) COLCNT

                  FROM COL$

                 WHERE COL# > 0

                 GROUP BY OBJ#) CN

         WHERE COL.OBJ# = CN.OBJ#

           AND COL.COL# = CN.COLCNT) C

 WHERE U.USER# = O.OWNER#

   AND O.OBJ# = C.OBJ#

   AND V.OBJ# = O.OBJ#

   AND U.NAME = UPPER('&NAME');

--重建job行为

SELECT JOB, LOWNER, INTERVAL#, NEXT_DATE, WHAT, SCHEDULER_FLAGS FROM JOB$

--重建索引

SELECT 'CREATE INDEX ' || I.NAME || ' ON ' || T.NAME || '(' || IDX.PATH || ');' INDEX_DDL

  FROM USER$ U,

       OBJ$ T,

       OBJ$ I,

       (SELECT I.PROPERTY,

               I.BO#,

               I.OBJ#,

               C.POS#,

               SUBSTR(SYS_CONNECT_BY_PATH(CN.NAME, ', '), 2) PATH

          FROM IND$ I, ICOL$ C, COL$ CN

         WHERE I.OBJ# = C.OBJ#

           AND I.BO# = C.BO#

           AND I.BO# = CN.OBJ#

           AND C.COL# = CN.INTCOL#

         START WITH C.POS# = 1

        CONNECT BY NOCYCLE PRIOR I.OBJ# = I.OBJ#

               AND PRIOR C.POS# = C.POS#) IDX,

       (SELECT I.BO#, I.OBJ#, COUNT(*) COLCNT

          FROM ICOL$ I

         GROUP BY I.BO#, I.OBJ#) IDXC

 WHERE U.USER# = T.OWNER#

   AND IDX.BO# = T.OBJ#

   AND IDX.OBJ# = I.OBJ#

   AND IDX.BO# = IDXC.BO#

   AND IDX.OBJ# = IDXC.OBJ#

   AND IDX.POS# = IDXC.COLCNT

   AND U.NAME = UPPER('&NAME')

 ORDER BY T.NAME, I.NAME;

--重建触发器

SELECT 'CREATE OR REPLACE TRIGGER ' || TRIGGER_NAME || CHR(10) ||

       DECODE(SUBSTR(TRIGGER_TYPE, 1, 1),

              'A',

              'AFTER ',

              'B',

              'BEFORE ',

              'I',

              'INSTEAD OF ') || TRIGGERING_EVENT || ' ON ' || TABLE_OWNER || '.' ||

       TABLE_NAME || CHR(10) || REF_CLAUSE || CHR(10) ||

       DECODE(INSTR(TRIGGER_TYPE, 'EACH ROW'), 0, NULL, 'FOR EACH ROW'),

       TRIGGER_BODY

  FROM (SELECT TRIGUSR.NAME OWNER,

               TRIGOBJ.NAME TRIGGER_NAME,

               DECODE(T.TYPE#,

                      0,

                      'BEFORE STATEMENT',

                      1,

                      'BEFORE EACH ROW',

                      2,

                      'AFTER STATEMENT',

                      3,

                      'AFTER EACH ROW',

                      4,

                      'INSTEAD OF',

                      'UNDEFINED') TRIGGER_TYPE,

               DECODE(T.INSERT$ * 100 + T.UPDATE$ * 10 + T.DELETE$,

                      100,

                      'INSERT',

                      010,

                      'UPDATE',

                      001,

                      'DELETE',

                      110,

                      'INSERT OR UPDATE',

                      101,

                      'INSERT OR DELETE',

                      011,

                      'UPDATE OR DELETE',

                      111,

                      'INSERT OR UPDATE OR DELETE',

                      'ERROR') TRIGGERING_EVENT,

               TABUSR.NAME TABLE_OWNER,

               TABOBJ.NAME TABLE_NAME,

               'REFERENCING NEW AS ' || T.REFNEWNAME || ' OLD AS ' ||

               T.REFOLDNAME REF_CLAUSE,

               T.WHENCLAUSE,

               DECODE(T.ENABLED, 0, 'DISABLED', 1, 'ENABLED', 'ERROR') STATUS,

               T.DEFINITION,

               T.ACTION# TRIGGER_BODY

          FROM OBJ$     TRIGOBJ,

               OBJ$     TABOBJ,

               TRIGGER$ T,

               USER$    TABUSR,

               USER$    TRIGUSR

         WHERE (TRIGOBJ.OBJ# = T.OBJ# AND TABOBJ.OBJ# = T.BASEOBJECT AND

               TABOBJ.OWNER# = TABUSR.USER# AND

               TRIGOBJ.OWNER# = TRIGUSR.USER# AND

               BITAND(T.PROPERTY, 63) < 8))

 WHERE TABLE_OWNER = UPPER('&OWNER')

 ORDER BY OWNER, TRIGGER_NAME

--重建序列

SELECT 'CREATE SEQUENCE ' || SEQ_NAME || ' MINVALUE ' || MINVAL ||

       ' MAXVALUE ' || MAXVAL || ' START WITH ' || LASTVAL || ' ' || CYC || ' ' || ORD ||

       DECODE(SIGN(CACHE), 1, ' CACHE ' || CACHE, 'NOCACHE') || ';' SEQ_DDL

  FROM (SELECT U.NAME OWNER,

               O.NAME SEQ_NAME,

               S.MINVALUE MINVAL,

               S.MAXVALUE MAXVAL,

               S.INCREMENT$ INC,

               DECODE(S.CYCLE#, 0, 'NOCYCLE', 1, 'CYCLE ') CYC,

               DECODE(S.ORDER$, 0, 'NOORDER', 1, 'ORDER ') ORD,

               S.CACHE,

               S.HIGHWATER LASTVAL

          FROM SEQ$ S, OBJ$ O, USER$ U

         WHERE U.USER# = O.OWNER#

           AND O.OBJ# = S.OBJ#

           AND U.NAME = UPPER('&NAME'))

--重建存储过程

SELECT DECODE(S.LINE, 1, 'CREATE OR REPLACE ') || SOURCE SOURCE

  FROM USER$ U, OBJ$ O, SOURCE$ S

 WHERE U.USER# = O.OWNER#

   AND O.OBJ# = S.OBJ#

   AND U.NAME = '&NAME'

 ORDER BY S.OBJ#, S.LINE;

--------------------------------------------------------------------------------------------------------------

补充说明,例如如下报错信息发生在datapump期间:

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options


ORA-39006: internal error

ORA-39065: unexpected master process exception in DISPATCH

ORA-04045: errors during recompilation/revalidation of SYS.DBMS_METADATA_UTIL

ORA-01775: looping chain of synonyms

ORA-06508: PL/SQL: could not find program unit being called: "SYS.DBMS_METADATA_UTIL"


处理思路:

 

所需的DBMS_METADATA_INT和DBMS_METADATA_INT包处于无效状态,那么首先需要验证无效对象信息:

select owner, object_name, status

     from sys.dba_objects where

     status = 'INVALID'

     and owner in ('SYS','SYSTEM')

     order by 1;


OWNER  OBJECT_NAME         STATUS

------ ------------------- -------


SYS    DBMS_METADATA_INT   INVALID

SYS    DBMS_METADATA_UTIL  INVALID


以SYS用户的身份运行以下脚本以验证包并重新运行DataPump导入作业

SQL> $ORACLE_HOME/rdbms/admin/prvtmeti.plb


SQL> $ORACLE_HOME/rdbms/admin/prvtmetu.plb


SQL> $ORACLE_HOME/rdbms/admin/utlrp.sql

--------------------------------------------------------------------------------------------------------------

<点亮梦想.拒绝平庸>


文章转载自Oracle蓝莲花,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论