CREATE OR REPLACE PACKAGE BODY public_pkg
IS
PROCEDURE do_only_this
IS
BEGIN
private_pkg.do_this;
private_pkg.do_that;
END;
END;
/
CREATE OR REPLACE PACKAGE BODY
private_pkg
IS
PROCEDURE do_this
IS
BEGIN
DBMS_OUTPUT.put_line ('THIS');
END;
PROCEDURE do_that
IS
BEGIN
DBMS_OUTPUT.put_line ('THAT');
END;
END;
/
现在可以毫无问题的运行这个公共包的过程:
BEGIN
public_pkg.do_only_this;
END;
/
THIS
THAT
但是��果我试图在匿名块中调用私有包的子过程,出现以下错误:(呦吼!耍不了赖了!嗯哼,有意思!)
BEGIN
private_pkg.do_this;
END;
/
ERROR at line 2:
ORA-06550: line 2, column 1:
PLS-00904: insufficient privilege to
access object PRIVATE_PKG
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
程序试图调用私有包的子程序,编译则会报同样的错误:
SQL> CREATE OR REPLACE PROCEDURE
use_private
2 IS
3 BEGIN
4 private_pkg.do_this;
5 END;
6 /
Warning: Procedure created with
compilation errors.
SQL> SHOW ERRORS
Errors for PROCEDURE USE_PRIVATE:
LINE/COL ERROR
———————— ——————————————————————————
4/4 PL/SQL: Statement ignored
4/4 PLS-00904: insufficient
privilege to access object
PRIVATE_PKG
看好了,是“PLS”错误提示,这个问题将在编译期间即被捕捉。使用这个特性不会带来任何的运行时性能影响。
5. 将角色授权给程序单元
12c以前,一个定义者权限的程序单元(以AUTHID DEFINER定义或不指定)总是以单元所有者的权限执行。一个调用者权限程序单元(以AUTHID CURRENT_USER定义)总是以单元调用者的权限执行。
这种设置的一个结果是,如果一个程序需要被所有用户执行,那么该程序将被设置为定义者权限单元。这样一来将拥有定义者所有权限来执行程序单元,从安全角度来看不是很好。
自12c起,你可以将角色授权给PL/SQL包和模式级过程和函数。基于角色权限的程序单元使开发者更细致地分配相应的程序单元给调用者。
你现在可以定义一个调用者权限的程序单元,然后通过授权有限的权限给相应角色来补足调用者权限。
让我们来走查以下例子,展示如何授权角色给程序单元。假设HR模式包含departments和employees表,定义和填充数据如下:
CREATE TABLE departments
(
department_id INTEGER,
department_name VARCHAR2 (100),
staff_freeze CHAR (1)
)
/
BEGIN
INSERT INTO departments
VALUES (10, 'IT', 'Y');
INSERT INTO departments
VALUES (20, 'HR', 'N');
COMMIT;
END;
/
CREATE TABLE employees
(
employee_id INTEGER,
department_id INTEGER,
last_name VARCHAR2 (100)
)
/
BEGIN
DELETE FROM employees;
INSERT INTO employees
VALUES (100, 10, 'Price');
INSERT INTO employees
VALUES (101, 20, 'Sam');
INSERT INTO employees
VALUES (102, 20, 'Joseph');
INSERT INTO employees
VALUES (103, 20, 'Smith');
COMMIT;
END;
/
并且假设SCOTT模式下仅包含employees表,定义和填充数据如下:
CREATE TABLE employees
(
employee_id INTEGER,
department_id INTEGER,
last_name VARCHAR2 (100)
)
/
BEGIN
DELETE FROM employees;
INSERT INTO employees
VALUES (100, 10, 'Price');
INSERT INTO employees
VALUES (104, 20, 'Lakshmi');
INSERT INTO employees
VALUES (105, 20, 'Silva');
INSERT INTO employees
VALUES (106, 20, 'Ling');
COMMIT;
END;
/