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
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睿思达DBA_WGX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值