oracle 11g PL/SQL Programming学习六

----------------------------------------------------------------------------
-----------------PL/SQL学习笔记系列 By Cryking-----------------
------------------------转载请注明出处,谢谢!------------------------ 

 

第8章 大对象(Large Objects)
大对象数据类型是很有用的数据结构,它可以用来存储文本、图片、音乐、视频.
11g对LOB类型进行了改造,使它变更快、更安全了.
通过DBMS_LOB.GET_STORAGE_LIMIT可以得到当前数据库允许的LOB类型的最大长度.
21:36:04 SYS@orcl> declare
21:36:43   2  v clob:='a';
21:36:48   3  begin
21:36:50   4  dbms_output.put_line( DBMS_LOB.GET_STORAGE_LIMIT(v)/1024/1024/1024||'G');
21:37:27   5  end;
21:37:32   6  /
16263.99999621324241161346435546875G

PL/SQL 过程已成功完成。


存储字符串的大对象使用CLOB,存储二进制的大对象使用BLOB,以上2个对象都存储在数据库内部,存储在数据库外部的
大对象类型使用BFILE.BFILE实际存储的是一个指向外部物理文件的指针.


CLOB和NCLOB大对象类型
CLOB和NCLOB可作为表的字段或嵌套表的列.CLOB类型用来存储文本文件.
它们的最大长度在8TB到128TB之间.(受DB_BLOCK_SIZE参数影响,此参数为1KB时,CLOB/NCLOB最大为8TB;此参数为32时,CLOB/NCLOB最大为128TB)
CLOB列通常与表的其他行分开存储.只有描述符或定位符存储在表列的对应位置.(也就是通过定位符来找到实际存储的CLOB对象的内容的).
定位符不仅指向CLOB存储的内容,并且提供SGA私有工作区的引用.
当你给一个CLOB对象赋值数字的时候,数字首先转换为字符类型,然后由字符类型转为CLOB类型.
声明CLOB变量:
  var1 CLOB; -- Declare a null reference to a CLOB.
var1 CLOB := empty_clob(); -- Declare an empty CLOB.
var2 CLOB := 'some_string';
CLOB不同如其他的标量数据类型,它不止NULL或NOT NULL状态.它还有以下状态:
 NULL--包含NULL值
 EMPTY--包含LOB定位符,指向空的实例.此时使用DBMS_LOB.GETLENGTH,返回为0.
 populated--包含LOB定位符,并指向内容,此时使用DBMS_LOB.GETLENGTH,返回为正数.
 
大对象类型的使用
DBMS_LOB包提供了读写大对象的工具.首先需要你定义一个虚拟目录(DIRECTORY).
如:CREATE DIRECTORY generic AS 'C:\tmp';
建立虚拟目录后,你需要把目录的读写权限给指定用户
GRANT READ,WRITE ON DIRECTORY generic TO plsql;
接下来读取文件,并写数据到表的CLOB列.
--使用NDS(本地动态SQL)完成大对象的读写
CREATE OR REPLACE PROCEDURE LOAD_CLOB_FROM_FILE(SRC_FILE_NAME     IN VARCHAR2,
                                                TABLE_NAME        IN VARCHAR2,
                                                COLUMN_NAME       IN VARCHAR2,
                                                PRIMARY_KEY_NAME  IN VARCHAR2,
                                                PRIMARY_KEY_VALUE IN VARCHAR2) IS
  -- 为DBMS_LOB.LOADCLOBFROMFILE定义的变量.
  DES_CLOB   CLOB;
  SRC_CLOB   BFILE := BFILENAME('GENERIC', SRC_FILE_NAME);
  DES_OFFSET NUMBER := 1;
  SRC_OFFSET NUMBER := 1;
  CTX_LANG   NUMBER := DBMS_LOB.DEFAULT_LANG_CTX;
  WARNING    NUMBER;
  --定义读取内容的大小
  SRC_CLOB_SIZE NUMBER;
  -- 为NDS定义的变量
  STMT VARCHAR2(2000);
BEGIN
  --判断文件是否存在及是否打开
  IF DBMS_LOB.FILEEXISTS(SRC_CLOB) = 1 AND
     NOT DBMS_LOB.ISOPEN(SRC_CLOB) = 1 THEN
    SRC_CLOB_SIZE := DBMS_LOB.GETLENGTH(SRC_CLOB);
    DBMS_LOB.OPEN(SRC_CLOB, DBMS_LOB.LOB_READONLY);--打开外部文件,读取内容到SRC_CLOB中
  END IF;
  --定义动态SQL,将CLOB列更新为EMPTY,并返回CLOB列到绑定变量locator中
  STMT := 'UPDATE ' || TABLE_NAME || ' ' || 'SET ' || COLUMN_NAME ||
          ' = empty_clob() ' || 'WHERE ' || PRIMARY_KEY_NAME || ' = ' || '''' ||
          PRIMARY_KEY_VALUE || ''' ' || 'RETURNING ' || COLUMN_NAME ||
          ' INTO :locator';
  --执行动态SQL
  EXECUTE IMMEDIATE STMT
    USING OUT DES_CLOB;
  --读写文件到CLOB列,关闭源文件并提交.
  DBMS_LOB.LOADCLOBFROMFILE(DEST_LOB     => DES_CLOB,
                            SRC_BFILE    => SRC_CLOB,
                            AMOUNT       => DBMS_LOB.GETLENGTH(SRC_CLOB),
                            DEST_OFFSET  => DES_OFFSET,
                            SRC_OFFSET   => SRC_OFFSET,
                            BFILE_CSID   => DBMS_LOB.DEFAULT_CSID,
                            LANG_CONTEXT => CTX_LANG,
                            WARNING      => WARNING);
  DBMS_LOB.CLOSE(SRC_CLOB);
  IF SRC_CLOB_SIZE = DBMS_LOB.GETLENGTH(DES_CLOB) THEN
    $IF $$DEBUG = 1 $THEN DBMS_OUTPUT.PUT_LINE('Success!');--条件编译
    $END COMMIT;
  ELSE
    $IF $$DEBUG = 1 $THEN DBMS_OUTPUT.PUT_LINE('Failure.');--条件编译
    $END RAISE DBMS_LOB.OPERATION_FAILED;
  END IF;
END LOAD_CLOB_FROM_FILE;
/


BLOB类型
基本同CLOB,只注意BLOB内存储的是二进制内容.
使用DBMS_LOB.LOADBLOBFROMFILE读文件到BLOB对象变量.


安全文件
安全文件是特殊的大对象.它们使用特定的存储参数声明,让你可以加密、压缩、删除它们.
11G让你使用BLOB、CLOB和NCLOB列存储安全文件.它们工作在传输数据加密和使用oracle钱包的加密中.
传输数据加密(TDE)可以选择使用以下加密算法:
3DES168,AES128,AES192(default),AES256
--查询当前数据库是否使用加密文件
SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME LIKE 'db_securefile';


--使用oracle钱包管理器配置oracle钱包来建立加密密码
C:> %ORACLE_HOME%\bin\launch.exe "oracle的标准路径\bin" owm.cl
如果使用菜单的话,选择 开始|程序|Oracle-Oracle Home|集成管理工具|Waller Manager.在这里你可以建立加密密码.
加密的KEY默认保存在目录%USERPROFILE%\ORACLE\WALLETS(windows下).
创建Wallet密码后,再为你的安全文件创建一个指定表空间:
CREATE TABLESPACE securefiles
DATAFILE '<canonical_path>\sec_file.dbf' SIZE 5M
EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT AUTO;
--给表增加安全文件列
ALTER TABLE item ADD (sec_file CLOB) LOB(sec_file)
STORE AS SECUREFILE sec_file (TABLESPACE securefile);
--对该列按指定方式加密
ALTER TABLE item MODIFY LOB(sec_file) (ENCRYPT USING '3DES168');
任何内部LOB存储都支持安全文件加密.应当注意的是你应当将安全文件放在单独的表空间.




BFILE类型(二进制文件)
BFILE与BLOB、CLOB等的工作方式不同.最大的不同就是BFILE的值是只读的LOB类型,并且存储在数据库外.
BFILE的最大物理大小受操作系统限制.


创建和使用虚拟目录
虚拟目录就像同义词,它们指向操作系统的物理路径.虚拟目录名以及路径名存储在数据库的视图dba_directories里.
数据库用户有SELECT_CATALOG_ROLE角色的能查询这个视图.缺省SYSTEM用户能查看DBA_DIRECTORIES视图.
SYSTEM用户能使用CREATE ANY DIRECTORY给其他用户赋予创建虚拟目录的权限.(你应当禁止DBA用户拥有创建目录的权限)
所有虚拟目录实际上都被SYS所拥有.
CREATE DIRECTORY images AS '/var/www/html/images';(LINUX或UNIX下)
--给用户赋予读取目录的权限
GRANT READ ON DIRECTORY images TO hr;
--查询目录及路径
SELECT * FROM dba_directories WHERE directory_name = 'IMAGES';
--更新BFILE列
UPDATE item
set item_photo = BFILENAME('IMAGES','Raiders3.png')
WHERE item_id = 1055;
--查看BFLIE列指定值所指的文件大小
DECLARE
  FILE_LOCATOR BFILE;
BEGIN
  SELECT ITEM_PHOTO INTO FILE_LOCATOR FROM ITEM WHERE ITEM_ID = 1055;
  IF DBMS_LOB.FILEEXISTS(FILE_LOCATOR) = 1 THEN --判断文件是否存在
    DBMS_OUTPUT.PUT_LINE('File is: [' || DBMS_LOB.GETLENGTH(FILE_LOCATOR) || ']');
  ELSE
    DBMS_OUTPUT.PUT_LINE('No file found.');
  END IF;
END;
/


--获取指定BFLIE列里指定值的文件名
CREATE OR REPLACE FUNCTION GET_BFILENAME(TABLE_NAME        VARCHAR2,
                                         COLUMN_NAME       VARCHAR2,
                                         PRIMARY_KEY_NAME  VARCHAR2,
                                         PRIMARY_KEY_VALUE VARCHAR2)
  RETURN VARCHAR2 IS
  -- Define a locator.
  LOCATOR BFILE;
  -- Define alias and filename.
  DIR_ALIAS VARCHAR2(255);
  DIRECTORY VARCHAR2(255);
  FILE_NAME VARCHAR2(255);
  -- Define local variable for Native Dynamic SQL.
  STMT      VARCHAR2(2000);
  DELIMITER VARCHAR2(1) := '/';
  -- Define a local exception for size violation.
  DIRECTORY_NUM EXCEPTION;
  PRAGMA EXCEPTION_INIT(DIRECTORY_NUM, -22285);
BEGIN
  -- Wrap the statement in an anonymous block to create and OUT mode variable.
  STMT := 'BEGIN ' || 'SELECT ' || COLUMN_NAME || ' ' || 'INTO :locator ' ||
          'FROM ' || TABLE_NAME || ' ' || 'WHERE ' || PRIMARY_KEY_NAME ||
          ' = ' || '''' || PRIMARY_KEY_VALUE || ''';' || 'END;';
  -- Return a scalar query result from a dynamic SQL statement.
  EXECUTE IMMEDIATE STMT
    USING OUT LOCATOR;
  -- Check for available locator.
  IF LOCATOR IS NOT NULL THEN
    DBMS_LOB.FILEGETNAME(LOCATOR, DIR_ALIAS, FILE_NAME);
  END IF;
  -- Return filename.
  RETURN DELIMITER || LOWER(DIR_ALIAS) || DELIMITER || FILE_NAME;
EXCEPTION
  WHEN DIRECTORY_NUM THEN
    RETURN NULL;
END GET_BFILENAME;


--调用
SELECT GET_BFILENAME('ITEM', 'ITEM_PHOTO', 'ITEM_ID', '1055') AS DIRECTORY
  FROM DUAL;
  
DIRECTORY
---------------------
/images/Raiders3.png


--根据虚拟目录名获得实际物理路径
CREATE OR REPLACE FUNCTION GET_DIRECTORY_PATH(VIRTUAL_DIRECTORY IN VARCHAR2)
  RETURN VARCHAR2 IS
  -- Define return variable.
  DIRECTORY_PATH VARCHAR2(256) := 'C:\';
  -- Define dynamic cursor.
  CURSOR GET_DIRECTORY(VIRTUAL_DIRECTORY VARCHAR2) IS
    SELECT DIRECTORY_PATH
      FROM SYS.DBA_DIRECTORIES
     WHERE DIRECTORY_NAME = VIRTUAL_DIRECTORY;
  -- Define a local exception for name violation.
  DIRECTORY_NAME EXCEPTION;
  PRAGMA EXCEPTION_INIT(DIRECTORY_NAME, -22284);
BEGIN
  OPEN GET_DIRECTORY(VIRTUAL_DIRECTORY);
  FETCH GET_DIRECTORY
    INTO DIRECTORY_PATH;
  CLOSE GET_DIRECTORY;
  -- Return filename.
  RETURN DIRECTORY_PATH;
EXCEPTION
  WHEN DIRECTORY_NAME THEN
    RETURN NULL;
END GET_DIRECTORY_PATH;



DBMS_LOB包
包常量:
包内有4种指定类型:2种是记录类型,另外2种是关联数组类型.( 一个是CLOB,一个是BLOB)
记录结构:
  TYPE blob_deduplicate_region IS RECORD (
    lob_offset          INTEGER,
    len                 INTEGER,
    primary_lob         BLOB,
    primary_lob_offset  NUMBER,
    mime_type           VARCHAR2(80));


  TYPE clob_deduplicate_region IS RECORD (
    lob_offset          INTEGER,
    len                 INTEGER,
    primary_lob         CLOB,
    primary_lob_offset  NUMBER,
    mime_type           VARCHAR2(80));
    
关联数组:
  TYPE blob_deduplicate_region_tab IS TABLE OF blob_deduplicate_region
       INDEX BY PLS_INTEGER;
  TYPE clob_deduplicate_region_tab IS TABLE OF clob_deduplicate_region
       INDEX BY PLS_INTEGER;


包定义了8个异常:
  invalid_argval EXCEPTION;
    PRAGMA EXCEPTION_INIT(invalid_argval, -21560);
    invalid_argval_num NUMBER := 21560;
  access_error EXCEPTION;
    PRAGMA EXCEPTION_INIT(access_error, -22925);
    eccess_error_num NUMBER := 22925;  
  noexist_directory EXCEPTION;
    PRAGMA EXCEPTION_INIT(noexist_directory, -22285);
    noexist_directory_num NUMBER := 22285;
  nopriv_directory EXCEPTION;
    PRAGMA EXCEPTION_INIT(nopriv_directory, -22286);
    nopriv_directory_num NUMBER := 22286;
  invalid_directory EXCEPTION;
    PRAGMA EXCEPTION_INIT(invalid_directory, -22287);
    invalid_directory_num NUMBER := 22287;
  operation_failed EXCEPTION;
    PRAGMA EXCEPTION_INIT(operation_failed, -22288);
    operation_failed_num NUMBER := 22288;
  unopened_file EXCEPTION;
    PRAGMA EXCEPTION_INIT(unopened_file, -22289);
    unopened_file_num NUMBER := 22289;
  open_toomany EXCEPTION;
    PRAGMA EXCEPTION_INIT(open_toomany, -22290);
    open_toomany_num NUMBER := 22290;
具体请看DBMS_LOB包定义.


--dbms_lob.issecurefile的使用示例
DECLARE
  audit_blob BLOB;
  CURSOR c IS
    SELECT NVL(item_blob, empty_blob) FROM item WHERE item_id = 1021;
BEGIN
  OPEN c;
  FETCH c
    INTO audit_blob;
  IF dbms_lob.issecurefile(audit_blob) THEN
    dbms_output.put_line('A secure file.');
  ELSE
    dbms_output.put_line('Not a secure file.');
  END IF;
  CLOSE c;
END;
 
--DBMS_LOB.COMPARE的使用示例
SELECT CASE
         WHEN DBMS_LOB.COMPARE(i1.item_blob, i2.item_blob) = 0 THEN
          'True'
         ELSE
          'False'
       END AS compared
  FROM em i1
 CROSS JOIN item i2--CROSS JOIN就是笛卡尔积
 WHERE i1.item_id = 1021
   AND i2.item_id = 1022;


--DBMS_LOB.GETCHUNKSIZE的使用示例,返回的是一个可用的块大小,一般和参数db_block_size一致
00:09:50 SCOTT@orcl> SELECT DBMS_LOB.GETCHUNKSIZE('aaa')
00:28:54   2    FROM dual;


DBMS_LOB.GETCHUNKSIZE('AAA')
----------------------------
                        8132


已选择 1 行。
00:30:01 SYS@orcl> show parameter db_block_size


NAME                                 TYPE        VALUE
------------------------------------ ----------- -------
db_block_size                        integer     8192



第九章 包(Packages)
包就是把函数和存储组合到一个库.在库里,你可以共享使用变量、类型、组件(就是函数和存储)等.
包包含变量声明、类型声明/定义、函数、存储等.你可以在其他PL/SQL块里使用包定义的变量和类型.
给所有用户执行指定包的权限,如: grant execute on dbms_lob to public;
在包体定义的函数、存储不能访问定义在其之后的包变量.
如:
19:58:24 SYS@orcl> DECLARE
20:38:43   2    PROCEDURE a IS
20:38:43   3    BEGIN
20:38:43   4      dbms_output.put_line(ab);
20:38:43   5    END;
20:38:43   6    ab integer := 2;
20:38:43   7  BEGIN
20:38:43   8    a();
20:38:43   9  END;
20:38:45  10  /
  ab integer := 2;
  *
第 6 行出现错误:
ORA-06550: 第 6 行, 第 3 列:
PLS-00103: 出现符号 "AB"在需要下列之一时:
begin function pragma
procedure
ORA-06550: 第 9 行, 第 4 列:
PLS-00103: 出现符号 "end-of-file"在需要下列之一时:
end not pragma
final instantiable order overriding static member constructor map


20:38:46 SYS@orcl> DECLARE
20:39:28   2    ab integer := 2;
20:39:28   3    PROCEDURE a IS
20:39:28   4    BEGIN
20:39:28   5      dbms_output.put_line(ab);
20:39:28   6    END;
20:39:28   7  BEGIN
20:39:28   8    a();
20:39:28   9  END;
20:39:28  10  /


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00
20:39:29 SYS@orcl> SET SERVEROUTPUT ON
20:39:41 SYS@orcl> /
2


PL/SQL 过程已成功完成。


如果是过程/函数调用过程/函数则可使用向前引用.
向前引用:
20:41:24 SYS@orcl> DECLARE
20:41:31   2    PROCEDURE b(caller VARCHAR2); --向前引用.
20:41:31   3    PROCEDURE a(caller VARCHAR2) IS
20:41:31   4      procedure_name VARCHAR2(1) := 'A';
20:41:31   5    BEGIN
20:41:31   6      dbms_output.put_line('Procedure "A" called by [' || caller || ']');
20:41:31   7      b(procedure_name);
20:41:31   8    END;
20:41:31   9    PROCEDURE b(caller VARCHAR2) IS
20:41:31  10      procedure_name VARCHAR2(1) := 'B';
20:41:31  11    BEGIN
20:41:31  12      dbms_output.put_line('Procedure "B" called by [' || caller || ']');
20:41:31  13    END;
20:41:31  14  BEGIN
20:41:31  15    a('Main');
20:41:31  16  END;
20:41:32  17  /
Procedure "A" called by [Main]
Procedure "B" called by [A]


PL/SQL 过程已成功完成。


在其他的PL/SQL块中调用包的存储或函数等,使用方法包名.存储名(或函数名、变量名)
注意:包的变量类型可以包共享游标.而共享游标是互斥的,也就是任何时候只有一个进程来运行它.


重载(Overloading)
重载就是指你可以创建同一个名称而有不同参数(数据类型不同或数量不同)的存储或函数.
但是PL/SQL不允许只简单改变变量的名称的重载形式,如:
--创建的时候不会报错
20:59:48 SCOTT@orcl> CREATE OR REPLACE PACKAGE not_overloading IS
20:59:50   2    FUNCTION adding(a NUMBER, b NUMBER) RETURN NUMBER;
20:59:50   3    FUNCTION adding(one NUMBER, two NUMBER) RETURN BINARY_INTEGER;
20:59:50   4  END not_overloading;
20:59:51   5  /


程序包已创建。


--使用的时候报错
20:59:52 SCOTT@orcl> select not_overloading.adding(1,2) from dual;
select not_overloading.adding(1,2) from dual
       *
第 1 行出现错误:
ORA-06553: PLS-307: 有太多的 'ADDING' 声明与此次调用相匹配


--重载示例
21:05:49 SCOTT@orcl> CREATE OR REPLACE PACKAGE overloading IS
21:06:16   2  FUNCTION adding (a NUMBER, b NUMBER) RETURN NUMBER;
21:06:18   3  FUNCTION adding (a VARCHAR2, b VARCHAR2) RETURN VARCHAR2;
21:06:20   4  END;
21:06:31   5  /


程序包已创建。


已用时间:  00: 00: 00.00
21:06:33 SCOTT@orcl> CREATE OR REPLACE PACKAGE BODY overloading IS
21:06:46   2  FUNCTION adding (a VARCHAR2, b VARCHAR2) RETURN VARCHAR2
21:06:51   3  IS
21:06:55   4  begin RETURN a||','||b; end;
21:07:25   5  FUNCTION adding (a NUMBER, b NUMBER) RETURN NUMBER
21:07:32   6  IS
21:07:34   7  begin RETURN a+b; end;
21:07:45   8  end;
21:07:48   9  /


程序包体已创建。


已用时间:  00: 00: 00.06
--包内函数查看
21:16:29 SCOTT@orcl> desc overloading
FUNCTION ADDING RETURNS NUMBER
参数名称                       类型                    输入/输出默认值?
------------------------------ ----------------------- ------ --------
 A                              NUMBER                  IN
 B                              NUMBER                  IN
FUNCTION ADDING RETURNS VARCHAR2
参数名称                       类型                    输入/输出默认值?
------------------------------ ----------------------- ------ --------
 A                              VARCHAR2                IN
 B                              VARCHAR2                IN
 
21:07:49 SCOTT@orcl> select overloading.adding(1,2) from dual;


OVERLOADING.ADDING(1,2)
-----------------------
                      3


已选择 1 行。
21:10:53 SCOTT@orcl> select overloading.adding('1','2') a from dual;


A
-----
1,2


已选择 1 行。



包头的原型
CREATE [OR REPLACE] PACKAGE package_name [AUTHID {DEFINER | CURRENT_USER}] IS
  [PRAGMA SERIALLY_REUSABLE;]
  [variable_name [CONSTANT] scalar_datatype [:= value];]
  [collection_name [CONSTANT] collection_datatype [:= constructor];]
  [object_name [CONSTANT] object_datatype [:= constructor];]
  [TYPE record_structure IS RECORD
  ( field_name1 datatype
  [,field_name2 datatype
  [,field_name(n+1) datatype]]);]
  [CURSOR cursor_name
  [(parameter_name1 datatype
  [,parameter_name2 datatype
  [,parameter_name(n+1) datatype]])] IS select_statement;]
  [TYPE ref_cursor IS REF CURSOR [RETURN { catalog_row | record_structure }];]
  [user_exception_name EXCEPTION;
  [PRAGMA EXCEPTION_INIT(user_exception_name,-20001);]]
[FUNCTION function_name
  [( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
  [, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
  [, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype )]
RETURN { sql_data_type | plsql_data_type }
  [ DETERMINISTIC | PARALLEL_ENABLED ]
  [ PIPELINED ]
  [ RESULT_CACHE [ RELIES_ON (table_name) ]];]
  [ PRAGMA RESTRICT_REFERENCES ({ DEFAULT | function_name }
  , option1 [, option2 [, option(n+1) ]]); ]
[PROCEDURE procedure_name
  [( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
  [, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
  [, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype])];]
END package_name;
其中预编译指令SERIALLY_REUSABLE PRAGMA只能用在包的上下文.你必须在包头和包体中同时使用该预编译指令.
在你想共享变量的时候,该预编译指令是很重要的.(因为该预编译指令可以使得包变量在每次调用时都初始化)
CONSTANT表示变量是静态只读的.CONSTANT变量定义后不能被赋值,否则你会获得PLS-00363错误.
如:
00:49:36 SCOTT@orcl> CREATE OR REPLACE PACKAGE PKG_TEST01 AS
00:49:53   2   a CONSTANT NUMBER:=123;
00:50:04   3  END;
00:50:07   4  /


程序包已创建。
00:51:40 SCOTT@orcl> begin
00:51:54   2  pkg_test01.a:=222;
00:51:57   3  dbms_output.put_line(pkg_test01.a);
00:51:59   4  end;
00:52:03   5  /
pkg_test01.a:=222;
           *
第 3 行出现错误:
ORA-06550: 第 3 行, 第 12 列:
PLS-00363: 表达式 'PKG_TEST01.A' 不能用作赋值目标
ORA-06550: 第 3 行, 第 1 列:
PL/SQL: Statement ignored


方案级程序(Schema-Level Programs)
函数、存储、包、对象等都是方案级程序。只有方案级的程序才能被定义为调用者权限或定义者权限。
缺省情况下就是定义者权限,定义者权限是指运行该程序的用户拥有和定义该程序的用户(方案的拥有者--the owner of the schema)一样的权限。
使用AUTHID CURRENT_USER标识程序使用调用者权限.调用者权限是指调用该程序的当前用户的权限.
包里的函数或过程不用定义调用权限,因为它们不是方案级程序。
例:
20:09:31 SCOTT@ORCL> create or replace package body gw_test01 as
20:09:32   2      function f_test_gw(pvar varchar2) RETURN VARCHAR2 AUTHID CURRENT_USER IS
20:09:32   3      begin
20:09:32   4      return pvar || ' Just Test!';
20:09:32   5      end f_test_gw;
20:09:32   6    end;
20:09:34   7    /


警告: 创建的包体带有编译错误。


已用时间:  00: 00: 00.03
20:09:35 SCOTT@orcl> show err
PACKAGE BODY GW_TEST01 出现错误:


LINE/COL ERROR
-------- -----------------------------------------------------------------
2/60     PLS-00157: AUTHID 只允许在方案级程序中使用




在使用结果集缓存(RESULT_CACHE)的时候,不能同时使用AUTHID CURRENT_USER
如:
21:33:49 SCOTT@orcl> create or replace function f_add(a int, b int)
21:55:10   2  return int authid current_user RESULT_CACHE
21:55:10   3  is
21:55:10   4  begin
21:55:10   5    return a + b;
21:55:10   6  end;
21:55:11   7  /


警告: 创建的函数带有编译错误。


已用时间:  00: 00: 00.56
21:55:12 SCOTT@orcl> show err
FUNCTION F_ADD 出现错误:


LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      PL/SQL: Compilation unit analysis terminated
1/10     PLS-00999: 实施限制 (可能是临时) RESULT_CACHE is disallowed on
         subprograms in Invoker-Rights modules


变量
使用SERIALLY_REUSABLE PRAGMA参数指定包为连续可重用的.(使用SERIALLY_REUSABLE,每次调用都会初始化包变量)
使用SERIALLY_REUSABLE后,包变量存储在SGA而不是UGA.
SERIALLY_REUSABLE需要在包头和包体中同时使用.
缺省情况下是非连续可重用的.
连续可重用的会在其他程序单元调用该变量时产生一个副本值,而非连续可重用的会直接重用变量。
包级变量可被其他PL/SQL单元访问,也就是共享的变量.包级变量可跨会话存在。
在SGA中,不常用的包会被逐渐移出SGA.
注:包变量不能使用SQL来访问,只能通过PL/SQL块来访问.
例:
--非SERIALLY_REUSABLE的包
15:42:51 SCOTT@orcl> CREATE OR REPLACE PACKAGE shared_variables IS
15:45:53   2    protected CONSTANT NUMBER := 1;
15:45:53   3    unprotected NUMBER := 1;
15:45:53   4  END shared_variables;
15:45:54   5  /


SP2-0808: 程序包已创建, 但带有编译警告


已用时间:  00: 00: 00.03
15:45:55 SCOTT@orcl> CREATE OR REPLACE PROCEDURE change_unprotected(value NUMBER) IS
15:46:01   2  BEGIN
15:46:01   3    shared_variables.unprotected := shared_variables.unprotected + value;
15:46:01   4    dbms_output.put_line('Unprotected [' || shared_variables.unprotected || ']');
15:46:01   5  END change_unprotected;
15:46:02   6  /


SP2-0804: 过程已创建, 但带有编译警告


已用时间:  00: 00: 00.04
--每执行一次使用存储change_unprotected,都会直接重用包变量unprotected
--所以每次都会递增,直到当前会话结束或者包被重新编译
15:46:03 SCOTT@orcl> EXECUTE change_unprotected(2);
Unprotected [3]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00
15:46:19 SCOTT@orcl> EXECUTE change_unprotected(2);
Unprotected [5]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00
16:28:10 SCOTT@orcl> alter package shared_variables compile SPECIFICATION;


SP2-0809: 程序包已变更, 但带有编译警告


已用时间:  00: 00: 00.04
16:28:19 SCOTT@orcl> EXECUTE change_unprotected(2);
Unprotected [3]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00


--使用SERIALLY_REUSABLE的包
15:46:21 SCOTT@orcl> CREATE OR REPLACE PACKAGE shared_variables IS
15:46:45   2    PRAGMA SERIALLY_REUSABLE;
15:46:45   3    protected CONSTANT NUMBER := 1;
15:46:45   4    unprotected NUMBER := 1;
15:46:45   5  END shared_variables;
15:46:47   6  /


SP2-0808: 程序包已创建, 但带有编译警告


--每次执行change_unprotected存储,包变量都是一样的值,每调用一次存储,都会产生包变量unprotected的一个副本
--直到SGA相应内存被耗完
15:46:48 SCOTT@orcl> EXECUTE change_unprotected(2);
Unprotected [3]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00
15:46:52 SCOTT@orcl> EXECUTE change_unprotected(2);
Unprotected [3]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.01

连续可重用变量和常量的不同在于常量不可修改(即不能被赋值).




类型
通常在包的定义里有两种常见的数据类型。一种静态的,一种是动态的。
动态的数据类型是指:使用%ROWTYPE或%TYPE来定义变量的数据类型、共享型游标
静态的数据类型是指:显示的使用DATE,INTEGER,NUMBER,VARCHAR2来定义变量的数据类型
引用包的记录类型变量或者集合类型变量的PL/SQL块依赖于包的状态,如果包无效了,那么
依赖它的PL/SQL单元也会无效。
22:18:24 SCOTT@orcl> select status from user_objects where object_name='PKG_TEST';


STATUS
-------
INVALID


已选择 1 行。


已用时间:  00: 00: 00.03
22:19:06 SCOTT@orcl> begin
22:19:13   2  dbms_output.put_line(pkg_test.i);
22:19:14   3  end;
22:19:14   4  /
dbms_output.put_line(pkg_test.i);
                     *
第 2 行出现错误:
ORA-06550: 第 2 行, 第 22 列:
PLS-00905: 对象 SCOTT.PKG_TEST 无效
ORA-06550: 第 2 行, 第 1 列:
PL/SQL: Statement ignored


共享游标可以同时被多个程序单元查询.
在11g之前没有游标的读一致性,需要你声明包为连续可重用才能确保游标的读一致性.
--共享游标的使用
22:56:54 SCOTT@orcl> CREATE OR REPLACE PACKAGE shared_cursors IS
22:57:26   2    CURSOR v_cursor IS
22:57:26   3      SELECT EMPLOYEE_ID, LAST_NAME FROM PLCH_EMPLOYEES;
22:57:26   4  END shared_cursors;
22:57:27   5  /


程序包已创建。


已用时间:  00: 00: 00.34
22:58:16 SCOTT@orcl> BEGIN
22:58:34   2    FOR i IN shared_cursors.v_cursor LOOP
22:58:34   3      dbms_output.put_line('[' || i.EMPLOYEE_ID || '][' || i.LAST_NAME || ']');
22:58:34   4    END LOOP;
22:58:34   5  END;
22:58:35   6  /
[1][Emp 1]
[2][Emp 2]
[3][Emp 3]
[4][Emp 4]
[5][Emp 5]


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.09


--共享类型的使用
23:03:27 SCOTT@orcl> CREATE OR REPLACE PACKAGE shared_types IS
23:03:43   2    CURSOR v_cursor IS
23:03:43   3      SELECT EMPLOYEE_ID, LAST_NAME FROM PLCH_EMPLOYEES;
23:03:43   4    TYPE item_type IS RECORD(
23:03:43   5      v_id    PLCH_EMPLOYEES.EMPLOYEE_ID%TYPE,
23:03:43   6      v_title PLCH_EMPLOYEES.LAST_NAME%TYPE);
23:03:43   7  END shared_types;
23:03:44   8  /


程序包已创建。


已用时间:  00: 00: 00.10
23:03:45 SCOTT@orcl> VARIABLE refcur REFCURSOR --定义引用游标类型变量
23:04:30 SCOTT@orcl> DECLARE
23:05:27   2    TYPE package_typed IS REF CURSOR RETURN shared_types.item_type;--引用游标只支持显示游标
23:05:27   3    quick PACKAGE_TYPED;
23:05:27   4  BEGIN
23:05:27   5    OPEN quick FOR
23:05:27   6      SELECT EMPLOYEE_ID, LAST_NAME FROM PLCH_EMPLOYEES;
23:05:27   7     :refcur := quick;
23:05:27   8  END;
23:05:27   9  /


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.09
23:05:28 SCOTT@orcl> SELECT :refcur FROM dual;


:REFCUR
--------------------
CURSOR STATEMENT : 1


CURSOR STATEMENT : 1


EMPLOYEE_ID LAST_NAME
----------- --------------------
          1 Emp 1
          2 Emp 2
          3 Emp 3
          4 Emp 4
          5 Emp 5


已选择5行。
--注意此时不能使用动态语句,否则会获得PLS-00455错误
23:13:57 SCOTT@orcl> DECLARE
23:14:01   2    TYPE package_typed IS REF CURSOR RETURN shared_types.item_type;
23:14:01   3    quick PACKAGE_TYPED;
23:14:01   4  BEGIN
23:14:01   5    OPEN quick FOR
23:14:01   6      'SELECT EMPLOYEE_ID, LAST_NAME FROM PLCH_EMPLOYEES';
23:14:01   7     :refcur := quick;
23:14:01   8  END;
23:14:01   9  /
  OPEN quick FOR
       *
第 5 行出现错误:
ORA-06550: 第 5 行, 第 8 列:
PLS-00455: 游标 'QUICK' 不能在动态 SQL OPEN 语句中使用
ORA-06550: 第 5 行, 第 3 列:
PL/SQL: Statement ignored



包内的函数和存储
在USER_ARGUMENTS、ALL_ARGUMENTS、DBA_ARGUMENTS视图里存放着包内的函数和存储的参数定义.
当在RESTRICT_REFERENCES预编译指令中使用DEFAULT而不是函数名的时候,RESTRICT_REFERENCES将应用到所有函数.
如:PRAGMA RESTRICT_REFERENCES(DEFAULT, WNDS);--约束包内所有函数的行为,确保它们不能写任何数据库状态.


包体
包体包含包规格(包头)声明的实现.
必须严格匹配,包括形参的缺省值都需要和包规格里一样.       
9i之前,你应当在包规格里声明形参,并且不用强制出现在包体里.
所以你从8i迁移到高版本的数据库时,应当注意.
在包体的函数里你不能定义PRAGMA指令,否则会出现PLS-00708错误.
包体原型如下:
CREATE [OR REPLACE] PACKAGE package_name [AUTHID {DEFINER | CURRENT_USER}] IS
[PRAGMA SERIALLY_REUSABLE;]
[variable_name [CONSTANT] scalar_datatype [:= value];]
[collection_name [CONSTANT] collection_datatype [:= constructor];]
[object_name [CONSTANT] object_datatype [:= constructor];]
[TYPE record_structure IS RECORD
( field_name1 datatype
[,field_name2 datatype
[,field_name(n+1) datatype]]);]
[CURSOR cursor_name
[(parameter_name1 datatype
[,parameter_name2 datatype
[,parameter_name(n+1) datatype]])] IS
select_statement;]
[TYPE ref_cursor IS REF CURSOR [RETURN { catalog_row | record_structure }];]
[user_exception_name EXCEPTION;
[PRAGMA EXCEPTION_INIT(user_exception_name,-20001);]]
-- This is a forward referencing stub to a function implemented later.
[FUNCTION function_name
[( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype )]
RETURN { sql_data_type | plsql_data_type }
[ DETERMINISTIC | PARALLEL_ENABLED ]
[ PIPELINED ]
[ RESULT_CACHE [ RELIES_ON (table_name) ]];]
-- This is a forward referencing stub to a procedure implemented later.
[PROCEDURE procedure_name
[( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype])];]
[FUNCTION function_name
[( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype )]
RETURN { sql_data_type | plsql_data_type }
[ DETERMINISTIC | PARALLEL_ENABLED ]
[ PIPELINED ]
[ RESULT_CACHE [ RELIES_ON (table_name) ]] IS
[ PRAGMA AUTONOMOUS_TRANSACTION;] -- Check rules in Chapter 6.
some_declaration_statement; -- Check rules in Chapter 6.
BEGIN
some_execution_statement; -- Check rules in Chapter 6.
[EXCEPTION
WHEN some_exception THEN
some exception_handling_statement;] -- Check rules in Chapter 5.
END [function_name];]
[PROCEDURE procedure_name
[( parameter1 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter2 [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype
[, parameter(n+1) [IN][OUT] [NOCOPY] sql_datatype | plsql_datatype])] IS
[ PRAGMA AUTONOMOUS_TRANSACTION;] -- Check rules in Chapter 6.
some_declaration_statement; -- Check rules in Chapter 6.
BEGIN
some_execution_statement; -- Check rules in Chapter 6.
[EXCEPTION
WHEN some_exception THEN
some exception_handling_statement;] -- Check rules in Chapter 5.
END [procedure_name];]
END [package_name];
/


包体内的全局变量,包外的PL/SQL块不能访问.
如:
23:02:33 SCOTT@orcl> CREATE OR REPLACE PACKAGE package_variables IS
23:07:37   2    -- Declare package components.
23:07:37   3    PROCEDURE set(value VARCHAR2);
23:07:37   4    FUNCTION get RETURN VARCHAR2;
23:07:37   5  END package_variables;
23:07:39   6  /


程序包已创建。


已用时间:  00: 00: 00.57
23:07:40 SCOTT@orcl> CREATE OR REPLACE PACKAGE BODY package_variables IS
23:10:07   2    -- Declare package scope variable.
23:10:07   3    variable VARCHAR2(20) := 'Initial Value';
23:10:07   4    -- Define function
23:10:07   5    FUNCTION get RETURN VARCHAR2 IS
23:10:07   6    BEGIN
23:10:07   7      RETURN variable;
23:10:07   8    END get;
23:10:07   9    -- Define procedure.
23:10:07  10    PROCEDURE set(value VARCHAR2) IS
23:10:07  11    BEGIN
23:10:07  12      variable := value;
23:10:07  13    END set;
23:10:07  14  END package_variables;
23:10:09  15  /


程序包体已创建。


已用时间:  00: 00: 00.04
23:10:10 SCOTT@orcl> VARIABLE outcome VARCHAR2(20)
23:10:50 SCOTT@orcl> CALL package_variables.get() INTO :outcome;


调用完成。


已用时间:  00: 00: 00.01
23:11:08 SCOTT@orcl> SELECT :outcome AS outcome FROM dual;


OUTCOME
--------------------------------
Initial Value


已选择 1 行。


已用时间:  00: 00: 00.00
23:11:18 SCOTT@orcl> EXECUTE package_variables.set('New Value');


PL/SQL 过程已成功完成。


已用时间:  00: 00: 00.00
23:11:36 SCOTT@orcl> CALL package_variables.get() INTO :outcome;


调用完成。


已用时间:  00: 00: 00.00
23:11:46 SCOTT@orcl> SELECT :outcome AS outcome FROM dual;


OUTCOME
--------------------------------
New Value


已选择 1 行。


已用时间:  00: 00: 00.00
--包体的公共变量不可访问
23:11:53 SCOTT@orcl> begin
23:12:40   2  dbms_output.put_line(package_variables.variable);
23:13:09   3  end;
23:13:11   4  /
dbms_output.put_line(package_variables.variable);
                                       *
第 2 行出现错误:
ORA-06550: 第 2 行, 第 40 列:
PLS-00302: 必须声明 'VARIABLE' 组件
ORA-06550: 第 2 行, 第 1 列:
PL/SQL: Statement ignored


已用时间:  00: 00: 00.00



单例模式(Singleton Design Pattern)
单例模式中的一个对象只能创建一个实例.直到原实例对象被废弃,否则你不能新建实例.
这种模式在C++,C#,JAVA等面向对象编程中用的很广泛.
你同样可以使用这种模式确保在任何会话中只能实例化一个包.
 
包体中同样可以声明自己的函数和存储,不过你需要在包体中完成声明(定义)与实现.
只有包头中定义的函数/存储才能被外部PL/SQL块访问.
函数几乎总是声明在存储之前,但在包头中是无顺序的,在局部使用时,为了尽可能的向前引用,函数声明在
存储之前是有意义的.
--单例模式演示 共享包变量variable在会话中只能实例化一个(因为内部有locked函数及unlock存储)
SQL> CREATE OR REPLACE PACKAGE components IS
  2    PROCEDURE set(value VARCHAR2); -- Declare published procedure.
  3    FUNCTION get RETURN VARCHAR2; -- Declare published function.
  4  END components;
  5  /


程序包已创建。


SQL> CREATE OR REPLACE PACKAGE BODY components IS
  2    -- Declare package scoped shared variables.
  3    key      NUMBER := 0;
  4    variable VARCHAR2(20) := 'Initial Value';
  5    -- Define package-only function and procedure.
  6    FUNCTION locked RETURN BOOLEAN IS
  7      key NUMBER := 0;
  8    BEGIN
  9      IF components.key = key THEN
 10        components.key := 1;
 11        RETURN FALSE;
 12      ELSE
 13        RETURN TRUE;
 14      END IF;
 15    END locked;
 16    PROCEDURE unlock IS
 17      key NUMBER := 1;
 18    BEGIN
 19      IF components.key = key THEN
 20        components.key := 0; -- Reset the key.
 21        variable       := 'Initial Value'; -- Reset initial value of shared variable.
 22      END IF;
 23    END unlock;
 24    -- Define published function and procedure.
 25    FUNCTION get RETURN VARCHAR2 IS
 26    BEGIN
 27      RETURN variable;
 28    END get;
 29    PROCEDURE set(value VARCHAR2) IS
 30    BEGIN
 31      IF NOT locked THEN
 32        variable := value;
 33        dbms_output.put_line('The new value until release is [' || get || '].');
 34        unlock;
 35      END IF;
 36    END set;
 37  END components;
 38  /


程序包体已创建。
SQL> VARIABLE current_content VARCHAR2(20)
SQL> CALL components.get() INTO :current_content;


调用完成。


SQL> SELECT :current_content AS contents FROM dual;


CONTENTS
--------------------------------
Initial Value


SQL> SET SERVEROUTPUT ON SIZE 1000000
SQL> EXECUTE components.set('New Value');
The new value until release is [New Value].


PL/SQL 过程已成功完成。


SQL> CALL components.get() INTO :current_content;


调用完成。


SQL> SELECT :current_content AS contents FROM dual;


CONTENTS
--------------------------------
Initial Value
                   
--注意对比
SQL> CREATE OR REPLACE PACKAGE BODY components IS
  2    -- Declare package scoped shared variables.
  3    key      NUMBER := 0;
  4    variable VARCHAR2(20) := 'Initial Value';
  5    -- Define published function and procedure.
  6    FUNCTION get RETURN VARCHAR2 IS
  7    BEGIN
  8      RETURN variable;
  9    END get;
 10    PROCEDURE set(value VARCHAR2) IS
 11    BEGIN
 12        variable := value;
 13        dbms_output.put_line('The new value until release is [' || get || '].');
 14    END set;
 15  END components;
 16  /


程序包体已创建。


SQL> VARIABLE current_content VARCHAR2(20)
SQL> CALL components.get() INTO :current_content;


调用完成。


SQL> SELECT :current_content AS contents FROM dual;


CONTENTS
--------------------------------
Initial Value


SQL> SET SERVEROUTPUT ON SIZE 1000000
SQL> EXECUTE components.set('New Value');
The new value until release is [New Value].


PL/SQL 过程已成功完成。


SQL> CALL components.get() INTO :current_content;


调用完成。


SQL> SELECT :current_content AS contents FROM dual;


CONTENTS
--------------------------------
New Value




授权与同义词
如果你在plsql模式下以定义者权限创建了一个包manage_items,在另一个模式purchasing里想执行这个包.
你需要首先在plsql模式下给purchasing用户赋予包manage_items的执行权限:
GRANT EXECUTE ON manage_items TO purchasing;
此时你在purchasing用户下可以正常使用包manage_item,但是每次使用都需要带上plsql的模式名,如:
DESCRIBE plsql.manage_items
你可以通过同义词来避免每次都写模式名.同义词就是对象的别名。
CREATE SYNONYM manage_items FOR plsql.manage_items;
你可以使用PUBLIC关键字来给其他所有的用户来赋予包manage_item的执行权限:
GRANT EXECUTE ON manage_items TO PUBLIC;


远程调用(Remote Calls)
远程调用就是从一个数据库实例调用另一个数据库实例的对象.
通过DB_LINK实现远程调用,建立DB_LINK需要有CREATE DATABASE LINK权限.
12:51:53 SYS@orcl> GRANT CREATE DATABASE LINK TO CRY;


授权成功。


DB_LINK创建:
--原型
CREATE DATABASE LINK db_link_name
CONNECT TO schema_name IDENTIFIED BY schema_password
USING 'tns_names_alias'


DB_LINK是数据库的静态对象.它存储模式名以及对应的密码,以便可以连接到远程的实例。
当远程实例的密码发生改变时,你需要手动更新DB_LINK的对应密码.
DB_LINK可以连接同一个数据库的不同schema,也可以连接其他数据库的实例.
使用:  SELECT * FROM TAB_NAME@db_link_name;--查询远程数据库的表TAB_NAME
注意:远程实例表中不能有LOB对象,否则会报ORA-22992错误.


数据库目录中包的管理
查找包、验证包是否有效、描述包
管理视图all_objects,dba_objects,user_objects让你可以查找包对象,并且验证包头或包体是否有效.
13:09:34 SCOTT@orcl> col object_name format a18
13:09:53 SCOTT@orcl> SELECT object_name
13:20:18   2        ,object_type
13:20:18   3        ,last_ddl_time
13:20:18   4        ,TIMESTAMP
13:20:18   5        ,status
13:20:18   6    FROM user_objects
13:20:18   7   WHERE object_name IN ('FN_GETNAME', 'PKG_SERIALLY_TEST');


OBJECT_NAME        OBJECT_TYPE         LAST_DDL_TIME  TIMESTAMP           STATUS
------------------ ------------------- -------------- ------------------- -------
FN_GETNAME         FUNCTION            09-1月 -13     2013-01-09:11:42:21 VALID
PKG_SERIALLY_TEST  PACKAGE             08-5月 -13     2013-05-08:15:41:21 VALID
PKG_SERIALLY_TEST  PACKAGE BODY        22-5月 -13     2013-05-22:13:20:05 VALID


已选择3行。




如果包体编译出错,则对应的STATUS字段会变为INVALID.但是包内所使用的函数/存储仍然是VALID的.
因为这些函数、存储是直接依赖于包头的.包体无效,包头的状态仍然是VALID的.
13:20:19 SCOTT@orcl> /


OBJECT_NAME        OBJECT_TYPE         LAST_DDL_TIME  TIMESTAMP           STATUS
------------------ ------------------- -------------- ------------------- -------
PKG_SERIALLY_TEST  PACKAGE BODY        22-5月 -13     2013-05-22:13:20:50 INVALID
PKG_SERIALLY_TEST  PACKAGE             08-5月 -13     2013-05-08:15:41:21 VALID
FN_GETNAME         FUNCTION            09-1月 -13     2013-01-09:11:42:21 VALID


已选择3行。


如果包头无效的话,那么依赖它的包体也会变无效.
13:24:24 SCOTT@orcl> /


OBJECT_NAME        OBJECT_TYPE         LAST_DDL_TIME  TIMESTAMP           STATUS
------------------ ------------------- -------------- ------------------- -------
PKG_SERIALLY_TEST  PACKAGE BODY        22-5月 -13     2013-05-22:13:24:11 INVALID
PKG_SERIALLY_TEST  PACKAGE             22-5月 -13     2013-05-22:13:24:38 INVALID
FN_GETNAME         FUNCTION            09-1月 -13     2013-01-09:11:42:21 VALID


已选择3行。


描述包
13:27:15 SCOTT@orcl> desc PKG_SERIALLY_TEST
FUNCTION INIT_PKG_STATE RETURNS VARCHAR2
参数名称                       类型                    输入/输出默认值?
------------------------------ ----------------------- ------ --------
 N                              NUMBER                  IN
PROCEDURE PRINT_PKG_STATE



你会发现包头内声明的记录、集合等变量类型无法通过desc查看到。你需要通过查询视图all_source,dba_source,user_source其中之一
来查看完整的包头定义。(注意加密的包将会看到乱码)


依赖性检查
根据管理视图all_dependencies,dba_dependencies,user_dependencies来检查对象间的依赖.
SQL> SELECT NAME
  2        ,TYPE
  3        ,referenced_name
  4        ,referenced_type
  5        ,dependency_type
  6    FROM USER_DEPENDENCIES
  7   WHERE NAME = 'DBMS_LOB';
 
NAME       TYPE            REFERENCED_NAME                REFERENCED DEPE
---------- --------------- ------------------------------ ---------- ----
DBMS_LOB   PACKAGE BODY    STANDARD                       PACKAGE    HARD
DBMS_LOB   PACKAGE         STANDARD                       PACKAGE    HARD
DBMS_LOB   PACKAGE BODY    DBMS_LOB                       PACKAGE    HARD



使用时间戳或签名方法使得依赖的对象有效或无效
缺省是使用时间戳方法:
时间戳方法是对比all_objects,dba_objects,user_objects其中之一的视图中的LAST_DDL_TIME字段。
当基础对象比依赖对象有更新的时间戳时,依赖对象将被重编译.
但是当两个数据库实例在不同的时区时,这种对比将是无效的.
签名方法:
这种方法对比模式级别和包级别的函数/存储的定义.改变数据库使用签名方法进行对象生效.
ALTER SYSTEM SET REMOTE_DEPENDENCIES_MODE = SIGNATURE;--需要有执行ALTER SYSTEM命令的权限
它会在编译事件中对比基础对象,如果发现发生改变,它将强制编译依赖包.你可以从视图

all_arguments,dba_arguments,user_arguments中查询对象的签名信息.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值