為了便于建立性能良好的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