天天看點

PL/SQL11——DBMS_DDL包的使用

 為了便于建立性能良好的PL/SQL程式,Oracle提供了大量的系統包供使用。Oracle提供的這些包擴充并增強了資料庫的一些功能,以及突

破了PL/SQL的一些限制。本文講述了Oracle提供的包DBMS_DDL,以及其使用方法。

一、    使用DBMS_DDL包可以對包,包體,存儲過程,函數,觸發器等等進行編譯,以及為資料庫對象提供一些統計資訊。

    下面列出幾個常用的過程

    1.ALTER_COMPILE   --編譯對象

        PROCEDURE DBMS_DDL.ALTER_COMPILE

           (type IN VARCHAR2     --PROCEDURE, FUNCTION, PACKAGE, PACKAGE BODY or TRIGGER.

           ,schema IN VARCHAR2

           ,name IN VARCHAR2);

        與之相等的操作:ALTER PROCEDURE | FUNCTION | PACKAGE [<schema>.] <name> COMPILE [BODY]

        --下面建立一個過程來對資料庫中特定使用者的無效對象進行重新編譯

            CREATE OR REPLACE PROCEDURE recompile

               (status_in IN VARCHAR2 := 'INVALID',

                name_in IN VARCHAR2 := '%',

                type_in IN VARCHAR2 := '%',

                schema_in IN VARCHAR2 := USER)

            IS

               v_objtype VARCHAR2(100);

               err_status NUMERIC;

               CURSOR obj_cur IS  

                  SELECT owner, object_name, object_type

                    FROM ALL_OBJECTS

                   WHERE status LIKE UPPER (status_in)

                     AND object_name LIKE UPPER (name_in)

                     AND object_type LIKE UPPER (type_in)

                     AND owner LIKE UPPER (schema_in)

                   ORDER BY

                     DECODE (object_type,

                        'PACKAGE', 1,

                        'FUNCTION', 2,

                        'PROCEDURE', 3,

                        'PACKAGE BODY', 4);

            BEGIN

               FOR rec IN obj_cur

               LOOP

                  IF rec.object_type = 'PACKAGE'

                  THEN

                     v_objtype := 'PACKAGE SPECIFICATION';

                  ELSE

                     v_objtype := rec.object_type;

                  END IF; 

                  DBMS_DDL.ALTER_COMPILE (v_objtype, rec.owner, rec.object_name);

                  DBMS_OUTPUT.PUT_LINE

                     ('Compiled ' || v_objtype || ' of ' ||

                      rec.owner || '.' || rec.object_name); 

               END LOOP;

            EXCEPTION

               WHEN OTHERS THEN

               BEGIN

                    err_status := SQLCODE;

                    DBMS_OUTPUT.PUT_LINE(' Recompilation failed : ' || SQLERRM(err_status));

                    IF ( obj_cur%ISOPEN) THEN

                       CLOSE obj_cur;

                    END IF;

               END;

            END;

            scott@ORCL> exec recompile(schema_in=>'SCOTT');

            Compiled FUNCTION of SCOTT.F_NEGATIVE

            Compiled PROCEDURE of SCOTT.COMPUTE

            Compiled TRIGGER of SCOTT.E_D

            PL/SQL procedure successfully completed.

    2.ANALYZE_OBJECT   --收集表,索引,簇等的統計資訊

        PROCEDURE DBMS_DDL.ANALYZE_OBJECT

           (type IN VARCHAR2           --TABLE, CLUSTER or INDEX

           ,name IN VARCHAR2

           ,method IN VARCHAR2         --ESTIMATE, COMPUTE or DELETE

           ,estimate_rows IN NUMBER DEFAULT NULL

           ,estimate_percent IN NUMBER DEFAULT NULL

           ,method_opt IN VARCHAR2 DEFAULT NULL) --[FOR TABLE

][ FOR ALL [INDEXED] COLUMNS] [SIZE n][ FOR ALL INDEXES ]

           ,partname   IN VARCHAR2 DEFAULT NULL);  

        與之相等的操作:ANALYZE TABLE|CLUSTER|INDEX [<schema>.]<name> [<method>] STATISTICS [SAMPLE <n> [ROWS|PERCENT]]

scott@ORCL> exec dbms_ddl.analyze_object('TABLE','SCOTT','EMP','ESTIMATE');

            PL/SQL procedure successfully completed.      

    3.DBMS_DDL.WRAP --使用wrap函數可以加密子程式

        該函數使用了3個重載函數,即可以使用3種不同的方式來對子程式進行動态加密

            DBMS_DDL.WRAP(          --方式一

               ddl      VARCHAR2)   --接收VARCHAR2類型的輸入

              RETURN VARCHAR2;

            DBMS_DDL.WRAP(          --方式二

               ddl      DBMS_SQL.VARCHAR2S,     --允許大的DDL語句的輸入,dbms_sql.varchar2s限制為每行256位元組

               lb       PLS_INTEGER,

               ub       PLS_INTEGER)

              RETURN DBMS_SQL.VARCHAR2S;       

            DBMS_DDL.WRAP(         --方式三

               ddl      DBMS_SQL.VARCHAR2A,     --允許大的DDL語句的輸入,dbms_sql.varchar2a為每行32767位元組

              RETURN DBMS_SQL.VARCHAR2A;               

            ddl:入參ddl要求文法為”create or replace…”的字元串,用以建立包、包體、類型、類型體、函數和過程的程式單元的DDL語句

                。如果入參ddl所定義的程式單元不能被加密,或存在文法錯誤,則将抛出“MALFORMED_WRAP_INPUT”異常。

            lb:為加密集合的最低元素

            ub:為加密集合的最高元素

            傳回值:為加密後的代碼。可以将它寫入一個檔案中,或者存儲在表中。

        --使用簡單方式實作加密,使用方式一

            SET SERVEROUTPUT ON SIZE UNLIMITED

            DECLARE

              l_source  VARCHAR2(32767);

              l_wrap    VARCHAR2(32767);

              l_source := 'CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS' ||

                          'BEGIN ' ||

                          'RETURN TO_CHAR(SYSDATE, ''DD-MON-YYYY''); ' ||

                          'END get_date_string;';

              l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source);

              DBMS_OUTPUT.put_line(l_wrap);

            CREATE OR REPLACE FUNCTION get_date_string wrapped

            a000000

            1f

            abcd

            8

            6e 96

            Mm0XeMkyhwPRoFPms2i+maxm+XAwg0xff8upynSmEPJ4IfeVjSbm6TkMCRi9trW1AmVTMIZs

            v4ABZD6CoiUcaSYfjdvzRqCeavAGromyS4qOtqqHxyw/0TtfJ0S2rO1lBTPgb1vb7rX16x0m

            LRwU

            對于使用DBMS_DDL.WRAP輸出的密文,可以将其複制到文本檔案或表中,然後将其部署到需要的地方,從一定程度上保證了代碼

        的安全性。對于方式一而言,VARCHAR2(32767位元組)長度限制了能夠使用的PL/SQL代碼長度,是以使用WRAP的兩外兩個重載函數可以解

        決長度缺陷問題。

    4.使用重載過程CREATE_WRAPPED加密子程式 

        Oracle 除了提供個重載函數WRAP實作加密之外,同時也提供了個重載過程來實作對子程式加密,有關參數描述請參考前面。

            DBMS_DDL.CREATE_WRAPPED (

               ddl     VARCHAR2);

            DBMS_DDL.CREATE_WRAPPED(

               ddl     DBMS_SQL.VARCHAR2A,

               lb      PLS_INTEGER,

               ub      PLS_INTEGER);

               ddl     DBMS_SQL.VARCHAR2S,

        與函數wrap不同,過程create_wrapped不但加密源代碼,而且還會在資料庫中執行加密後的密文。

        --下面使用CREATE_WRAPPED來加密子程式

              l_source  DBMS_SQL.VARCHAR2A;

              l_wrap    DBMS_SQL.VARCHAR2A;

              l_source(1) := 'CREATE OR REPLACE FUNCTION get_date_string RETURN VARCHAR2 AS

';

              l_source(2) := 'BEGIN ';

              l_source(3) := 'RETURN TO_CHAR(SYSDATE, ''DD-MON-YYYY''); ';

              l_source(4) := 'END get_date_string;';

              SYS.DBMS_DDL.CREATE_WRAPPED(ddl => l_source,

                                          lb  => 1,

                                          ub  => l_source.count);

            END;           

            scott@ORCL> SET PAGESIZE 100

            scott@ORCL> SELECT text     --檢視加密後的密文

              2  FROM   user_source

              3  WHERE  name = 'GET_DATE_STRING'

              4  AND    type = 'FUNCTION';

            TEXT

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

            FUNCTION get_date_string wrapped

            6f 96

            i5ktuqFIjCuYLEse2bjmcBG7ZWgwg0xff8upynSmEPJ4IfeVjSbm6TkMCRi9trW1AmVTMB5D

            uU2KKgFAWoMdxYFR8VesyCs4U8zk9ML7b7Q+G/lGiyLbcaOIMZ4bNhIBYc2VVsvjaqr86Fu8

            VByi           

            scott@ORCL> select  --使用get_ddl獲得加密後的密文

              2  dbms_metadata.get_ddl('FUNCTION','GET_DATE_STRING')

              3  from dual;

            DBMS_METADATA.GET_DDL('FUNCTION','GET_DATE_STRING')

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

              CREATE OR REPLACE FUNCTION "SCOTT"."GET_DATE_STRING"

wrapped

            VByi       

    5.DBMS_DDL.IS_TRIGGER_FIRE_ONCE 用于判斷特定的觸發器是否被觸發過               

        DBMS_DDL.IS_TRIGGER_FIRE_ONCE(

            trig_owner  IN VARCHAR2,

            trig_name   IN VARCHAR2)

            RETURN BOOLEAN;

        BEGIN

          IF dbms_ddl.is_trigger_fire_once('SCOTT', 'tr_tb_a') THEN

            dbms_output.put_line('TRUE');

          ELSE

            dbms_output.put_line('FALSE');

          END IF;

        END;

        TRUE