PL/SQL专家指南4——调用者权限和定义者权限 下篇

-------------------------------------------------------------调用者权限和定义者权限学习---------------------------------------------------

转自群友shehasgone:

--调用者权限的存储过程  print_table

create or replace procedure print_table(p_query in varchar2)
authid current_user
is
    l_theCursor integer default dbms_sql.open_cursor;
    l_columnValue varchar2(4000);
    l_status integer;
    l_descTb1 dbms_sql.desc_tab;
    l_colCnt number;
begin
   dbms_sql.parse(l_theCursor,p_query,dbms_sql.native);
   dbms_sql.describe_columns(l_theCursor,l_colCnt,l_descTb1);

     for i in 1..l_colCnt loop
        dbms_sql.define_column(l_theCursor,i,l_columnValue,4000);
     end loop;

     l_status:=dbms_sql.execute(l_theCursor);
     while(dbms_sql.fetch_rows(l_theCursor)>0) loop
     for i in 1..l_colCnt loop
         dbms_sql.column_value(l_theCursor,i,l_columnValue);
         dbms_output.put_line(rpad(l_descTb1(i).col_name,30)
                                   ||':'||
                                   l_columnValue);
      end loop;
      dbms_output.put_line('--------------------------');
    end loop;
 exception
   when others then
          dbms_sql.close_cursor(l_theCursor);
          raise;
 end;

 ---把这个存储过程的执行权限授予 public
SQL> grant execute on print_table to public;
 
Grant succeeded

--调用者权限的存储过程  desc_table
create or replace procedure desc_table(p_tname in varchar2)
authid current_user
as
begin
   dbms_output.put_line('Datatypes for Table '||p_tname);
   dbms_output.new_line;
   
   dbms_output.put_line(rpad('Column Name',31)||
                              rpad('Datatype',20) ||
                              rpad('Length',11) ||
                              'Nullable');
   dbms_output.put_line(rpad('-',30,'-')||''||
                                 rpad('-',19,'-')||''||
                                 rpad('-',10,'-')||''||
                                 '-----------');
    for x in 
      ( select column_name,
               data_type,
               substr(decode(data_type,
               'NUMBER',decode(data_precision,NULL,NULL,'('||data_precision||','||data_scale||')'),
                data_length),1,11) data_length,
                decode(nullable,'Y','null','not null') nullable
                from user_tab_columns
                where table_name = upper(trim(p_tname)) 
                order by column_id)
       loop
        dbms_output.put_line(rpad(x.column_name,31)||
                             rpad(x.data_type,20)||
                             rpad(x.data_length,11)||
                             x.nullable);
       end loop;
       
       dbms_output.put_line(chr(10)||chr(10)||'Indexes on '||p_tname);
       
       
       for z in 
        ( select a.index_name,a.uniqueness from user_indexes a 
           where a.table_name = upper(trim(p_tname))
           and index_type='NORMAL')
       loop
         dbms_output.put(rpad(z.index_name,31)||
                             z.uniqueness);
                             
           for y in 
            ( select decode(column_position,1,'(',',')||column_name column_name
                from user_ind_columns b
                where b.index_name = z.index_name
                order by column_position)
                
                loop
                dbms_output.put(y.column_name);
                end loop;
                dbms_output.put_line(')'||chr(10));
           end loop;
           
end;              
 ---把这个存储过程的执行权限授予 public
SQL> grant execute on desc_table to public;

--定义一个调用者权限函数
--先建立一个测试表

create table t ( x varchar2(255));

--建立调用者权限函数
create or replace function Invoker_rights_function return varchar2
authid current_user
as
     l_data varchar2(4000);
begin
   dbms_output.put_line('I am an IR PROC owned by A');
   select 'current_user='||sys_context('userenv','currnet_user')||
    'current_schema='||sys_context('userenv','current_schema')||
    'active roles='||cnt||
    'data from T='||t.x
    into l_data
        from (select count(*) cnt from session_roles), t;
        return l_data;

  end;

--把这个调用者权限函数授权到public
SQL> grant execute on she.invoker_rights_function to public;
 
Grant succeeded

--定义一个定义者权限函数
create or replace function Definer_rights_function return varchar2
as
     l_data varchar2(4000);
begin
   dbms_output.put_line('I am an IR PROC owned by A');
   select 'current_user='||sys_context('userenv','currnet_user')||
    'current_schema='||sys_context('userenv','current_schema')||
    'active roles='||cnt||
    'data from T='||t.x
    into l_data
        from (select count(*) cnt from session_roles), t;
        return l_data;

  end;

--把这个调用者权限函数授权到public
SQL> grant execute on she.Definer_rights_function to public;
 
Grant succeeded

--如果是视图则以定义者权限存储
 create view V
  as

  select invoker_rights_function from dual;

--把视图的查询权限授予public
SQL> GRANT SELECT ON V TO PUBLIC;
 
Grant succeeded
 
当切换用户执行时如果如下:
SELECT * FROM SHE.V
结果
current_user=current_schema=SHEactive roles=0data from T=SHE'table
这说明,查的不是当前用户,而是she用户下的。
此时当前用户下无T表也不会报错。 

--对于查询
SELECT SHE.INVOKER_RIGHTS_FUNCTION FROM DUAL;
结果:
current_user=current_schema=SCOTTactive roles=2data from T=SCOTT'table
这个是当前用户下的信息。
此时当前用户下无T表也会报错。 
--最后说明, 视图是以定义者权限进行编译存储的。

--健壮的程序
--建立测试表。
create table t (pk number);
create table y ( c number,d number);
-建立测试存储过程
create or replace procedure P
authid current_user
as
 no_such_table exception;
 pragma exception_init(no_such_table,-942);

 insufficient_privs exception;
 pragma exception_init(insufficient_privs,-1031);

 invalid_column_name exception;
 pragma exception_init(invalid_column_name,-904);

 inconsistent_datatypes exception;
  pragma exception_init(inconsistent_datatypes,-932);

  begin
   for x in (select pk from t ) loop
   update y set c=c+0.5 where d=x.pk;
   end loop;
 commit;
   exception
    when no_such_table then
      dbms_output.put_line('Error Caught:'||sqlerrm);

       when insufficient_privs then
      dbms_output.put_line('Error Caught:'||sqlerrm);

       when invalid_column_name then
      dbms_output.put_line('Error Caught:'||sqlerrm);

       when inconsistent_datatypes then
      dbms_output.put_line('Error Caught:'||sqlerrm);
  rollback;
 end;
---
--换其它用户执行
SQL> conn scott/tiger;
已连接。
SQL> set serveroutput on;
SQL> exec she.p;
Error Caught:ORA-00904: "PK": 无效的标识符

PL/SQL 过程已成功完成。

SQL> exec she.p;

PL/SQL 过程已成功完成。

SQL> exec she.p;
Error Caught:ORA-00904: "D": 无效的标识符

PL/SQL 过程已成功完成。

SQL> exec she.p;
Error Caught:ORA-00932: 不一致的数据类型: 要求 NUMBER 得到的却是 DATE

PL/SQL 过程已成功完成。

SQL> exec she.p;
BEGIN she.p; END;

*
ERROR 位于第 1 行:
ORA-00932: 不一致的数据类型: 要求 NUMBER 得到的却是 DATE
ORA-06512: 在"SHE.P", line 17
ORA-06512: 在line 1

SQL> exec she.p;
Error Caught:ORA-00932: 不一致的数据类型: 要求 NUMBER 得到的却是 DATE

PL/SQL 过程已成功完成。

SQL>

--注:如何获取关联的ora错误编号。 
当我把
 no_such_table exception;
 pragma exception_init(no_such_table,-942);
中的-943后,重新编译这个存储过程
执行时。
SQL> exec she.p;
BEGIN she.p; END;

*
ERROR 位于第 1 行:
ORA-00942: 表或视图不存在
ORA-06512: 在"SHE.P", line 17
ORA-06512: 在line 1
这里是会报错的,真正的错误是ORA-00942
这时就已经提示我们,这个异常编号是和-942关联的
此时,把-943 再换成-942编译后,达到捕捉异常后,过程能运行的目的。 

--select * 的副作用 
 建立测试表及数据。
create table t (msg varchar2(25),c1 int,c2 int);
insert into t values('c1=1,c2=2',1,2);
commit;
--建立调用者权限存储过程
create or replace procedure p
authid current_user
as
begin
  for x in (select * from t) loop
      dbms_output.put_line('msg='||x.msg);
      dbms_output.put_line('c1='||x.c1);
      dbms_output.put_line('c2='||x.c2);
  end loop;
end;
--执行 
exec p;
--结果
msg=c1=1,c2=2
c1=1
c2=2

--把执行权限授予public
SQL> grant execute on p to public;
 
Grant succeeded
--建立测试用户
SQL> create user u1 identified by u1 default tablespace users;

用户已创建

SQL> grant dba,resource,connect to u1;

授权成功。
--切换到u1用户
--建立测试表及数据
create table t (msg varchar2(25),c2 int ,c1 int);
insert into t values('c1=2,c2=1',1,2);
commit;
--调用上面的存储过程 
SQL> set serveroutput on;
SQL> exec she.p;
 
msg=c1=2,c2=1
c1=1
c2=2
 
PL/SQL procedure successfully completed
注意此时的结果 c1=1,c2=2当前用户表中的c1=2,c2=1
分析:它根本不是所要求的--但认真思考后会发现,这确实是按程序实现的。
在编译时,PL/SQL为设置了隐含记录X。记录X只是一个数据结构,具有3个元素:
MSG VARCHAR2,C1 NUMBER,C2 NUMBER。在用户SHE的查询分析阶段,SELECT * 
按次序展开为MSG,C1,C2。然而作为U1,它们被展开为MSG,C2,C1。因为数据类型
完全与隐含的记录X匹配,您不会收到INCONSISTENT DATATYPE 的错误提示(如果
数据类型不匹配,这一错误还是会发生)。数据读取成功,便把记录属性C1列放入
了C2列。这是预期的行为,也是在产品程序中不使用SELECT * 的另一个充分的理由。

---隐藏的伪列
--以she用户建立表和测试数据
create table t (c1 int);
insert into t values(1);
commit;
--建立调用者权限存储过程
create or replace procedure p
authid current_user
as
    c2 number default 5;
begin
   update t set c1=c2;
   commit;
end;  
--在当前用户下执行并查询表T
SQL> exec p;
 
PL/SQL procedure successfully completed
 
SQL> select * from t;
 
                                     C1
---------------------------------------
                                      5
注意这里是5.
--如果表t 有字段c2,同时c2的值为8,那此时看到的值应该是8.

--接着切换到用户u1
--建立测试表及数据
create table t (c1 int ,c2 int);
insert into t values(1,2);
commit;
--执行用户she下的存储过程P并查看结果。
SQL> exec she.p;
 
PL/SQL procedure successfully completed
 
SQL> select * from t;
 
                                     C1                                      C2
--------------------------------------- ---------------------------------------
                                      5                                       2
注意,此时的结果  c1的值为5,但c2的值没有变化。
分析:它的对错在于您如何看待。对于UPDATE SET C1=C2语句,如果在SQL*PLUS提示符状态
运行,结果是C1被设置为2,而不是5.然而,因为编译时PL/SQL重写此查询没有任何对于C2
的引用,所以它对T数据表复本进行操作,与它对其化T数据表复本所做的完全相同--将
C1设置为5。此PL/SQL程序不能“看到”C2列,因为C2不存在于它编译的对象中。
  起先,这似乎有些混乱,因为您不有正常地看到改写后的更新内容,但一旦您了解了它,
它是非常有意义的。

------------------------------2011-10-13-------------------------------------
--------------------------------全文完---------------------------------------

时间: 2024-10-24 11:33:24

PL/SQL专家指南4——调用者权限和定义者权限 下篇的相关文章

PL/SQL专家指南3——调用者权限和定义者权限 上篇

1.介绍定义者(definer)权限和调用者(invoker)权限的概念 定义者权限:定义者权限PL/SQL程序单元是以这个程序单元拥有者的特权来执行它的,也就是说,任何具有这个PL/SQL程序单元执行权的用户都可以访问程序中的对象.所有具有执行权的用户都有相同的访问权限,在定义者权限下,执行的用户操作的schema为定义者,所操作的对象是定义者在编译时指定的对象. 调用者权限:调用者权限是指当前用户(而不是程序的创建者)执行PL/SQL程序体的权限.这意味着不同的用户对于某个对象具有的权限很可

PL/SQL专家指南2——PL/SQL精髓

1.入门级概述 用PL/SQL很久了,很多其他搞IT的人问我PL/SQL是什么,一般我的回答是:1,Oracle的开发语言.2,比SQL复杂了些,多了很多东西(至于什么东西,现在还搞不清楚,还幼稚的以为:PL/SQL=PLus SQL),今天仔细潜心读了些书终于完善了这个定义(不是偷懒复制的,是手抄的): Procedure Language/SQL(PL/SQL) is Oracle Corporation's procedure language extension to SQL, the

PL/SQL专家指南1——高级概念

1.WRAP函数 与 CREATE_WRAPPED过程 详细的介绍先参照博客:http://blog.csdn.net/changyanmanman/article/details/8007757 2.条件编译 http://blog.csdn.net/icbm/article/details/6794610 http://www.dbconf.net/?p=708

SQL Server中授予用户查看对象定义的权限

SQL Server中授予用户查看对象定义的权限   在SQL Server中,有时候需要给一些登录名(用户)授予查看所有或部分对象(存储过程.函数.视图.表)的定义权限存.如果是部分存储过程.函数.视图授予查看定义的权限,那么就像下面脚本所示,比较繁琐:     GRANT VIEW DEFINITION ON  YOUR_PROCEDURE TO   USERNAME;   GRANT VIEW DEFINITION ON  YOUR_FUNCTION TO USERNAME;   GRAN

《Oracle PL/SQL程序设计(第5版)》一一1.5 PL/SQL开发人员的资源

1.5 PL/SQL开发人员的资源 Oracle PL/SQL程序设计(第5版) O'Reilly在1995年出版了本书的第一版.当时,Oracle PL/SQL编程这本书确实造成一个小轰动.它是第一本关于PL/SQL的独立著作(也就是,不是来自于Oracle公司的).从那时开始,PL/SQL程序员的资源─图书.开发环境.工具以及网站─开始蓬勃发展.(当然,迄今为止这本书仍然是这些资源中最重要和最有价值的!) 下面这一节简要地介绍了这许多资源.要充分利用这些资源,许多资源都可以免费获得或者非常低

PL/SQL游标(原创)

游标的相关概念及特性定义映射在结果集中某一行数据的具体位置,类似于C语言中的指针.即通过游标方式定位到结果集中某个特定的行,然后根据业务需求对该行进行相应特定的操作.游标的分类显示游标:即用户自定义游标,专门用于处理select语句返回的多行数据隐式游标:系统自动定义的游标,记录集只有单行数据,用于处理select into 和DML语句游标使用的一般过程:显示游标:声明, 打开, 读取, 关闭隐式游标:直接使用读取,声明.打开.关闭都是系统自动进行的显示游标的过程描述a.声明游标CURSOR

PL/SQL异常处理

     在设计PL/SQL程序时,经常会发生这样或那样的错误,异常处理就是针对错误进行处理的程序段,Oracle 9i中的异常处理分为系统预定义异常处理和自定义异常处理两部分. 系统预定义异常处理     系统预定义异常处理是针对PL/SQL程序编译.执行过程中发生的问题进行处理的程序. 下列代码为正确代码,在[SQLPlus Worksheet]中能够顺利执行.    ―――――――――――――――――――――――――――――――――――――    set serveroutput on  

PL/SQL语言基础(原创)

PL/SQL概述 PL/SQL是过程化的SQL语言,是ORACLE对SQL语言的扩展,在普通SQL语句的基础上增加了编程语言的特点.使得该语言不仅具有过程编程语言的特征,如循环.条件分支等.同时也具有对象编程语言的特征,如重载.继承等.PL/SQL程序语言的组成主要由块组成一个块由三个基本部分组成:声明.执行体.异常处理PL/SQL块有匿名块和命名块命名块会将代码保存到服务器    典型的块结构如下        [ DECLARE                    --声明部分      

Oracle 定义者权限与调用者权限(AUTHID CURRENT_USER)

Oracle定义者权限与调用者权限(AUTHID CURRENT_USER) 参考: http://blog.itpub.net/7607759/viewspace-166557/ http://blog.itpub.net/7607759/viewspace-166558 http://blog.163.com/l_yongfei/blog/static/265673042009420103210297/ 正如大家所知,Oracle从8i开始引入了调用者权限体系结构,之前一直使用定义者权限体系