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-------------------------------------
--------------------------------全文完---------------------------------------
相关文章
|
22天前
|
SQL 存储 Oracle
Oracle的PL/SQL定义变量和常量:数据的稳定与灵动
【4月更文挑战第19天】在Oracle PL/SQL中,变量和常量扮演着数据存储的关键角色。变量是可变的“魔术盒”,用于存储程序运行时的动态数据,通过`DECLARE`定义,可在循环和条件判断中体现其灵活性。常量则是不可变的“固定牌”,一旦设定值便保持不变,用`CONSTANT`声明,提供程序稳定性和易维护性。通过 `%TYPE`、`NOT NULL`等特性,可以更高效地管理和控制变量与常量,提升代码质量。善用两者,能优化PL/SQL程序的结构和性能。
|
2月前
|
SQL Perl
PL/SQL经典练习
PL/SQL经典练习
14 0
|
11天前
|
SQL 关系型数据库 数据库
SQL 42501: Postgresql查询中的权限不足错误
SQL 42501: Postgresql查询中的权限不足错误
|
22天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL游标属性:数据的“导航仪”与“仪表盘”
【4月更文挑战第19天】Oracle PL/SQL游标属性如同车辆的导航仪和仪表盘,提供丰富信息和控制。 `%FOUND`和`%NOTFOUND`指示数据读取状态,`%ROWCOUNT`记录处理行数,`%ISOPEN`显示游标状态。还有`%BULK_ROWCOUNT`和`%BULK_EXCEPTIONS`增强处理灵活性。通过实例展示了如何在数据处理中利用这些属性监控和控制流程,提高效率和准确性。掌握游标属性是提升数据处理能力的关键。
|
22天前
|
SQL Oracle 安全
Oracle的PL/SQL循环语句:数据的“旋转木马”与“无限之旅”
【4月更文挑战第19天】Oracle PL/SQL中的循环语句(LOOP、EXIT WHEN、FOR、WHILE)是处理数据的关键工具,用于批量操作、报表生成和复杂业务逻辑。LOOP提供无限循环,可通过EXIT WHEN设定退出条件;FOR循环适用于固定次数迭代,WHILE循环基于条件判断执行。有效使用循环能提高效率,但需注意避免无限循环和优化大数据处理性能。掌握循环语句,将使数据处理更加高效和便捷。
|
22天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL条件控制:数据的“红绿灯”与“分岔路”
【4月更文挑战第19天】在Oracle PL/SQL中,IF语句与CASE语句扮演着数据流程控制的关键角色。IF语句如红绿灯,依据条件决定程序执行路径;ELSE和ELSIF提供多分支逻辑。CASE语句则是分岔路,按表达式值选择执行路径。这些条件控制语句在数据验证、错误处理和业务逻辑中不可或缺,通过巧妙运用能实现高效程序逻辑,保障数据正确流转,支持企业业务发展。理解并熟练掌握这些语句的使用是成为合格数据管理员的重要一环。
|
22天前
|
SQL Oracle 关系型数据库
Oracle的PL/SQL表达式:数据的魔法公式
【4月更文挑战第19天】探索Oracle PL/SQL表达式,体验数据的魔法公式。表达式结合常量、变量、运算符和函数,用于数据运算与转换。算术运算符处理数值计算,比较运算符执行数据比较,内置函数如TO_CHAR、ROUND和SUBSTR提供多样化操作。条件表达式如CASE和NULLIF实现灵活逻辑判断。广泛应用于SQL查询和PL/SQL程序,助你驾驭数据,揭示其背后的规律与秘密,成为数据魔法师。
|
1天前
|
SQL 存储 数据库连接
LabVIEW与SQL Server 2919 Express通讯
LabVIEW与SQL Server 2919 Express通讯
|
2天前
|
SQL Windows
安装SQL Server 2005时出现对性能监视器计数器注册表值执行系统配置检查失败的解决办法...
安装SQL Server 2005时出现对性能监视器计数器注册表值执行系统配置检查失败的解决办法...
12 4