oracle存儲過程的定義者權限與調用者權限
當某個用戶定義的存儲過程由另一個用戶調用時,需要指定存儲過程的Definer(定義者權限 )與Invoker(調用者權限)。
一、存儲過程的定義者權限
存儲過程默認爲該權限,也可以在定義存儲過程的is|as之前添加authid definer參數,格式如下:
create [or replace] procedure 名稱
[(參數1 in | out | in out 類型,
參數2 in | out | in out 類型, ...)]
authid definer
is|as
--變量聲明區間
begin
--業務邏輯區間
exception
--異常處理
end;
/
說明:如果一個存儲過程的執行權限爲定義者權限,則當另一個用戶調用該存儲過程時,和存儲過程的所有者調用該存儲過程是一樣的(就相當於是存儲過程的所有者調用了該存儲過程)。
測試效果:
1、在scott用戶下創建一張表t1,並輸入數據
create table t1(
id number(6) primary key,
name varchar2(20),
age number(2),
phone varchar2(20)
);
SQL> select * from t1;
ID NAME AGE PHONE
---------- -------------------- ---------- --------------------
101 JACK 25 13603735588
102 JERRY 21 13503736645
103 TOM 32 13037350422
104 ROSE 28 13903732266
105 MARK 19 15903736633
106 JIMMI 20 15037355066
6 rows selected.
2、在scott用戶下創建一個存儲過程,使用默認的definer權限,查看某個用戶的姓名和電話
SQL>
create or replace procedure sp_get_t1
(v_id number,
v_name out varchar2,
v_phone out varchar2)
authid definer
is
begin
select name,phone into v_name,v_phone
from t1
where id=v_id;
exception
when no_data_found then
dbms_output.put_line('沒有該用戶信息!');
end;
15 /
Procedure created.
3、查看該存儲過程的信息
該存儲過程的執行權限爲DEFINER(定義者權限)。
SQL> select object_name,procedure_name,authid from user_procedures where object_name='SP_GET_T1';
OBJECT_NAME PROCEDURE_NAME AUTHID
------------------------------ -------------------- ------------
SP_GET_T1 DEFINER
4、調用該存儲過程
SQL>
declare
v_id t1.id%type;
v_name t1.name%type;
v_phone t1.phone%type;
begin
v_id:=&t1_id;
sp_get_t1(v_id,v_name,v_phone);
dbms_output.put_line(
v_id||'用戶的姓名:'||v_name||
',電話:'||v_phone);
end;
12 /
Enter value for t1_id: 103
old 6: v_id:=&t1_id;
new 6: v_id:=103;
103用戶的姓名:TOM,電話:13037350422
PL/SQL procedure successfully completed.
5、創建一個用戶JACK,在該用戶下創建表t1,並輸入數據
(1)創建用戶JACK並授權
SQL> show user;
USER is "SYS"
SQL>
create user JACK identified by JACK;
User created.
Elapsed: 00:00:00.09
Elapsed: 00:00:00.03
SQL> grant resource,connect to JACK;
Grant succeeded.
(2)以JACK用戶身份登錄,創建表t1並輸入數據
SQL> show user;
USER is "JACK"
SQL>
create table t1(
id number(6) primary key,
name varchar2(20),
age number(2),
phone varchar2(20)
6 );
Table created.
SQL> select * from t1;
ID NAME AGE PHONE
---------- -------------------- ---------- --------------------
101 張飛 25 100801
102 趙雲 21 200258
103 關羽 32 400125
6、以scott用戶身份登錄,把存儲過程sp_get_t1的執行權限授予用戶JACK
SQL> show user;
USER is "SCOTT"
SQL> grant execute on sp_get_t1 to JACK;
Grant succeeded.
7、以用戶JACK身份登錄,調用存儲過程sp_get_t1並查看結果
SQL> show user;
USER is "JACK"
SQL>
declare
v_id t1.id%type;
v_name t1.name%type;
v_phone t1.phone%type;
begin
v_id:=&t1_id;
sp_get_t1(v_id,v_name,v_phone);
dbms_output.put_line(
v_id||'用戶的姓名:'||v_name||
',電話:'||v_phone);
end;
11 12 /
Enter value for t1_id: 103
old 6: v_id:=&t1_id;
new 6: v_id:=103;
103用戶的姓名:TOM,電話:13037350422
PL/SQL procedure successfully completed.
此時發現,用戶JACK調用存儲過程sp_get_t1的輸出結果和存儲過程的定義者scott調用該存儲過程的結果是完全相同的。
二、存儲過程的調用者權限
可以在定義存儲過程的is|as之前添加authid current_user參數,格式如下:
create [or replace] procedure 名稱
[(參數1 in | out | in out 類型,
參數2 in | out | in out 類型, ...)]
authid current_user
is|as
--變量聲明區間
begin
--業務邏輯區間
exception
--異常處理
end;
/
說明:如果一個存儲過程的執行權限爲調用者權限,則當另一個用戶調用該存儲過程時,就相當於該用戶自己創建了一個完全相同的存儲過程。
測試效果:
1、在scott用戶下創建一個存儲過程,使用current_user權限,查看某個用戶的姓名和電話
SQL> show user;
USER is "SCOTT"
SQL>
create or replace procedure sp_get_t1_02
(v_id number,
v_name out varchar2,
v_phone out varchar2)
authid current_user
is
begin
select name,phone into v_name,v_phone
from t1
where id=v_id;
exception
when no_data_found then
dbms_output.put_line('沒有該用戶信息!');
end;
15 /
Procedure created.
2、查看該存儲過程的信息
該存儲過程的執行權限爲CURRENT_USER(調用者權限)。
SQL> select object_name,procedure_name,authid from user_procedures
where object_name='SP_GET_T1_02';
OBJECT_NAME PROCEDURE_NAME AUTHID
------------------------------ -------------------- ------------
SP_GET_T1_02 CURRENT_USER
3、scott用戶調用該存儲過程
SQL> show user;
USER is "SCOTT"
SQL>
declare
v_id t1.id%type;
v_name t1.name%type;
v_phone t1.phone%type;
begin
v_id:=&t1_id;
sp_get_t1_02(v_id,v_name,v_phone);
dbms_output.put_line(
v_id||'用戶的姓名:'||v_name||
',電話:'||v_phone);
end;
12 /
Enter value for t1_id: 103
old 6: v_id:=&t1_id;
new 6: v_id:=103;
103用戶的姓名:TOM,電話:13037350422
PL/SQL procedure successfully completed.
4、以scott用戶身份登錄,把存儲過程sp_get_t1_02的執行權限授予用戶JACK
SQL> show user;
USER is "SCOTT"
SQL> SQL> grant execute on sp_get_t1_02 to JACK;
Grant succeeded.
5、以用戶JACK身份登錄,調用存儲過程sp_get_t1_02並查看結果
SQL> show user;
USER is "JACK"
SQL>
declare
v_id t1.id%type;
v_name t1.name%type;
v_phone t1.phone%type;
begin
v_id:=&t1_id;
scott.sp_get_t1_02(v_id,v_name,v_phone);
dbms_output.put_line(
v_id||'用戶的姓名:'||v_name||
',電話:'||v_phone);
end;
12 /
Enter value for t1_id: 103
old 6: v_id:=&t1_id;
new 6: v_id:=103;
103用戶的姓名:關羽,電話:400125
PL/SQL procedure successfully completed.
此時發現,用戶JACK調用存儲過程sp_get_t1_02,就像自己編寫了一個存儲過程,調用的是自己的t1表。
四、查看存儲過程信息
1、查看當前用戶所定義的所有存儲過程的名稱
SQL> select object_name,procedure_name,object_type,deterministic,authid from user_procedures;
OBJECT_NAME PROCEDURE_NAME OBJECT_TYPE DET AUTHID
------------------------------ -------------------- ------------------- --- ------------
SP_EMP_INSERT PROCEDURE NO DEFINER
SP_SET_EMP_SAL PROCEDURE NO DEFINER
SP_DISP PROCEDURE NO DEFINER
SP_CIRCLE_AREA PROCEDURE NO DEFINER
SP_UPDATE_EMP_SAL PROCEDURE NO DEFINER
SP_GET_EMP PROCEDURE NO DEFINER
SP_UPDATE_EMP_SAL_01 PROCEDURE NO DEFINER
SP_INSERT_T01_FORALL PROCEDURE NO DEFINER
SP_SCORE_GRADE PROCEDURE NO DEFINER
SP_DELETE_T1_FORALL PROCEDURE NO DEFINER
SP_INSERT_T01_FORALL02 PROCEDURE NO DEFINER
SP_UPDATE_T1_FORALL PROCEDURE NO DEFINER
SP_INSERT_T01 PROCEDURE NO DEFINER
SP_UPDATE_EMP_BULK PROCEDURE NO DEFINER
SP_UPDATE_T01_FORALL PROCEDURE NO DEFINER
SP_EMP_ENAME_DEPT PROCEDURE NO DEFINER
SP_EMP_DEPTNO11 PROCEDURE NO DEFINER
SP_EMP_DEPTNO PROCEDURE NO DEFINER
SP_FETCH_EMP PROCEDURE NO DEFINER
PS_ADD PROCEDURE NO DEFINER
SP_ADD PROCEDURE NO DEFINER
SET_SAL PROCEDURE NO DEFINER
GET_EMP PROCEDURE NO DEFINER
TEST_CREATE PROCEDURE NO DEFINER
UPDATE_SAL PROCEDURE NO DEFINER
ADD_SAL PROCEDURE NO DEFINER
26 rows selected.
2、查看存儲過程的參數信息
SQL> desc get_emp;
PROCEDURE get_emp
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
P_EMPNO NUMBER IN
V_ENAME VARCHAR2 OUT
V_SAL NUMBER OUT
3、查看某個存儲過程的代碼
SQL> select text from user_source where name='SP_UPDATE_EMP_SAL';
TEXT
--------------------------------------------------------------------------------
procedure sp_update_emp_sal
as
type t_table_emp is table of emp%rowtype
index by binary_integer;
v_table_emp t_table_emp;
begin
update emp set sal=sal*1.1 where deptno=10;
select * bulk collect into v_table_emp from emp where deptno=10;
for i in v_table_emp.first..v_table_emp.last loop
dbms_output.put_line('僱員編號:'||v_table_emp(i).empno||
', 姓名:'||v_table_emp(i).ename||
', 工資:'||v_table_emp(i).sal);
end loop;
end;
14 rows selected.
五、存儲過程應用舉例
1、無參數存儲過程
把emp表10部分所有人的工資增加10%,並且顯示員工編號、姓名及工資信息。
SQL>
create or replace procedure sp_update_emp_sal
as
type t_table_emp is table of emp%rowtype
index by binary_integer;
v_table_emp t_table_emp;
begin
update emp set sal=sal*1.1 where deptno=10;
select * bulk collect into v_table_emp from emp where deptno=10;
for i in v_table_emp.first..v_table_emp.last loop
dbms_output.put_line('僱員編號:'||v_table_emp(i).empno||
', 姓名:'||v_table_emp(i).ename||
', 工資:'||v_table_emp(i).sal);
end loop;
end;
/
Procedure created.
運行存儲過程,結果如下:
SQL> call sp_update_emp_sal();
僱員編號:7934, 姓名:MILLER, 工資:1574.21
僱員編號:7782, 姓名:CLARK, 工資:2965.71
僱員編號:7839, 姓名:KING, 工資:6051.21
Call completed.
注意:無參數存儲過程調用時要加一對空括號。
2、帶輸入參數的存儲過程
對上例的存儲過程進行修改,通過指定一個輸入參數,用戶在調用時指定某個部門,則把該部門員工的工資增加10%,並顯示該部門員工的工號、姓名和工資。代碼如下:
SQL>
create or replace procedure sp_update_emp_sal_01
(v_deptno number)
as
type t_table_emp is table of emp%rowtype
index by binary_integer;
v_table_emp t_table_emp;
begin
update emp set sal=sal*1.1 where deptno=v_deptno;
select * bulk collect into v_table_emp from emp where deptno=v_deptno;
for i in v_table_emp.first..v_table_emp.last loop
dbms_output.put_line('僱員編號:'||v_table_emp(i).empno||
', 姓名:'||v_table_emp(i).ename||
', 工資:'||v_table_emp(i).sal);
end loop;
end;
/
Procedure created.
調用時指定20部門作爲參數,查詢結果如下:
SQL> call sp_update_emp_sal_01(20);
僱員編號:7788, 姓名:SCOTT, 工資:2423.63
僱員編號:7876, 姓名:ADAMS, 工資:1334.63
僱員編號:7566, 姓名:JONES, 工資:3603.38
僱員編號:7902, 姓名:FORD, 工資:3633.63
僱員編號:7369, 姓名:SMITH, 工資:971.63
Call completed.
3、指定輸出參數
輸入一個圓的半徑,求圓的面積,代碼如下:
SQL>
create or replace procedure sp_circle_area
(v_radius in number,area out number)
as
begin
area:=3.1415926*power(v_radius,2);
end;
7 /
Procedure created.
在代碼塊中調用該該存儲過程,結果如下:
SQL>
declare
v_area number(15,8);
begin
sp_circle_area(4,v_area);
dbms_output.put_line('圓的面積爲:'||v_area);
end;
7 /
圓的面積爲:50.2654816
PL/SQL procedure successfully completed.
4、綜合練習
爲emp插入一條新記錄:
(1)創建一個序列seq_emp,從9001開始編號
SQL> create sequence seq_emp start with 9001;
Sequence created.
(2)創建一個存儲過程sp_emp_insert
create or replace procedure sp_emp_insert
(v_ename varchar2,
v_job varchar2 default 'SALESMAN',
v_mgr number default 7698,
v_hiredate date default sysdate,
v_sal number default 2000,
v_comm number default 0,
v_deptno number default 40)
as
begin
insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
values(seq_emp.nextval,
v_ename,
v_job,
v_mgr,
v_hiredate,
v_sal,
v_comm,
v_deptno);
end;
/
執行存儲過程:
SQL> call sp_emp_insert('Jerry');
Call completed.
Elapsed: 00:00:00.02
SQL> call sp_emp_insert('John',v_sal=>1800);
Call completed.
Elapsed: 00:00:00.00
SQL> call sp_emp_insert('Merry',v_hiredate=>sysdate-10,v_sal=>2100);
Call completed.
Elapsed: 00:00:00.01
SQL> select * from emp where empno>9000;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ------
9001 Jerry SALESMAN 7698 2020-02-17 01:01:22 2000 0 40
9002 John SALESMAN 7698 2020-02-17 01:02:39 1800 0 40
9003 Merry SALESMAN 7698 2020-02-07 01:03:40 2100 0 40