oracle存儲過程的定義者權限與調用者權限

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章