或许你也遇到过同样的问题:
用sql语句建表没问题,但是放到存储过程里执行就报没有权限;
用sql查询或dml操作也是没问题,放到存储过程就报错权限不足,或表不存在.
在官方文档上看到有这么一段话 ,文档地址
http://docs.oracle.com/cd/E11882_01/network.112/e36292/authorization.htm#i1007304
How Roles Work in PL/SQL Blocks
The use of roles in a PL/SQL block depends on whether it is an anonymous block or a named block (stored procedure, function, or trigger), and whether it executes with definer's rights or invoker's rights.
Roles Used in Named Blocks with Definer's Rights
All roles are disabled in any named PL/SQL block (stored procedure, function, or trigger) that executes with definer's rights. Roles are not used for privilege checking and you cannot set roles within a definer's rights procedure.
The SESSION_ROLES view shows all roles that are currently enabled. If a named PL/SQL block that executes with definer's rights queries SESSION_ROLES, then the query does not return any rows.
Roles Used in Named Blocks with Invoker's Rights and Anonymous PL/SQL Blocks
Named PL/SQL blocks that execute with invoker's rights and anonymous PL/SQL blocks are executed based on privileges granted through enabled roles. Current roles are used for privilege checking within an invoker's rights PL/SQL block. You can use dynamic SQL to set a role in the session.
其大意就是说用户角色的权限在命名的pl/sql块里是不可用的,包括存储过程、触发器、函数,但是在匿名的pl/sql块里是没问题的。
什么是角色的权限呢?
可以通过dba_roles查看所有角色:select * from dba_roles;
可以通过user_role_privs及role_sys_privs查看用户有那些角色,及角色具有的权限。 用户在这两个视图中的权限在存储过程、触发器、函数中是不起作用的。
下面演示DDL的实验,用scott用户建一个存储过程来删除表和创建表
-
SQL> set linesize 1000
-
SQL> show user;
-
USER is "SCOTT"
-
SQL> col text format a80
-
SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;
-
-
LINE TEXT
-
---------- --------------------------------------------------------------------------------
-
1 procedure p_emp1
-
2 as
-
3 begin
-
4 execute immediate 'drop table emp1';
-
5 execute immediate 'create table emp1 as select * from emp';
-
6 end;
-
-
6 rows selected.
-
-
SQL> drop table emp1;
-
-
Table dropped.
-
-
SQL> create table emp1 as select * from emp;
-
-
Table created.
-
-
SQL>
-
SQL> exec p_emp1;
-
BEGIN p_emp1; END;
-
-
*
-
ERROR at line 1:
-
ORA-01031: insufficient privileges
-
ORA-06512: at "SCOTT.P_EMP1", line 5
-
ORA-06512: at line 1
发现用sql语句直接运行create table emp1 as select * from emp 是没有问题的,但是在存储过程中提示权限不足。
来查一下scott用户有哪些系统权限
-
SQL> select * from session_roles;
-
-
ROLE
-
------------------------------
-
CONNECT
-
RESOURCE
-
-
SQL> select * from role_sys_privs order by role;
-
-
ROLE PRIVILEGE ADM
-
------------------------------ ---------------------------------------- ---
-
CONNECT CREATE SESSION NO
-
RESOURCE CREATE CLUSTER NO
-
RESOURCE CREATE INDEXTYPE NO
-
RESOURCE CREATE OPERATOR NO
-
RESOURCE CREATE PROCEDURE NO
-
RESOURCE CREATE SEQUENCE NO
-
RESOURCE CREATE TABLE NO
-
RESOURCE CREATE TRIGGER NO
-
RESOURCE CREATE TYPE NO
-
-
9 rows selected.
-
-
SQL> select * from user_sys_privs;
-
-
USERNAME PRIVILEGE ADM
-
------------------------------ ---------------------------------------- ---
-
SCOTT UNLIMITED TABLESPACE NO
scott有CONNECT和RESOURCE两个角色的权限,还有一个UNLIMITED TABLESPACE的系统权限。
接下来,给scott分配create table的权限,在看看效果
-
SQL> conn /as sysdba
-
Connected.
-
SQL> grant create table to scott;
-
-
Grant succeeded.
-
-
SQL> conn scott/scott
-
Connected.
-
SQL> select * from user_sys_privs;
-
-
USERNAME PRIVILEGE ADM
-
------------------------------ ---------------------------------------- ---
-
SCOTT UNLIMITED TABLESPACE NO
-
SCOTT CREATE TABLE NO
-
-
SQL> exec p_emp1;
-
BEGIN p_emp1; END;
-
-
*
-
ERROR at line 1:
-
ORA-00942: table or view does not exist
-
ORA-06512: at "SCOTT.P_EMP1", line 4
-
ORA-06512: at line 1
-
--这里报错是因为刚刚运行存储过程的时候已经drop掉emp1表了,但是create时候报错,所以这是会报表不存在
-
-
SQL> create table emp1 as select * from emp;
-
-
Table created.
-
-
SQL> exec p_emp1;
-
-
PL/SQL procedure successfully completed.
给scott分批create table的权限后,我们可以通过user_sys_privs视图看到scott拥有的权限,这时候存储过程正常了。
*********************************************************************************************************
接下来测试下dml操作,给scott用户dba的角色,然后让scott用户操作test用户下的表
所以在处理存储过程的时候要注意这些权限问题,不要只看用户的角色。
******************************************************************************************************************
我们总是想偷偷懒,每次都要赋权限感觉好麻烦,有没有其他好办法呢?答案是:有。oracle提供了一个authid的属性
-
SQL> conn /as sysdba
-
Connected.
-
SQL> revoke create table from scott;
-
-
Revoke succeeded.
-
-
SQL> conn scott/scott
-
Connected.
-
-
SQL> select * from user_sys_privs;
-
-
USERNAME PRIVILEGE ADM
-
------------------------------ ---------------------------------------- ---
-
SCOTT UNLIMITED TABLESPACE NO
-
-
SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;
-
-
LINE TEXT
-
---------- --------------------------------------------------------------------------------
-
1 procedure p_emp1
-
2 authid CURRENT_USER --注意这里,多了一句
-
3 as
-
4 begin
-
5 execute immediate 'drop table emp1';
-
6 execute immediate 'create table emp1 as select * from emp';
-
7 end;
-
-
7 rows selected.
-
-
SQL> exec p_emp1;
-
-
PL/SQL procedure successfully completed.
添加一个authid CURRENT_USER就可以了,当然这么做也有一点风险,就是如果scott和test用户都有一个emp表,那么当test用户执行的时候,新建的emp1表会在test用户下
-
SQL> select line,text from user_source where type='PROCEDURE' and name='P_EMP1' ORDER BY LINE;
-
-
LINE TEXT
-
---------- --------------------------------------------------------------------------------
-
1 procedure p_emp1
-
2 authid CURRENT_USER
-
3 as
-
4 begin
-
5 execute immediate 'create table emp1 as select * from emp'; --这里我们去掉了drop的语句
-
6 end;
-
-
6 rows selected.
-
-
SQL> conn / as sysdba
-
Connected.
-
SQL>
-
SQL>
-
SQL> select owner,table_name from dba_tables where table_name='EMP1';
-
-
OWNER TABLE_NAME
-
------------------------------ ------------------------------
-
SCOTT EMP1
-
-
SQL> drop table scott.emp1;
-
-
Table dropped.
-
-
SQL> grant resource to test;
-
-
Grant succeeded.
-
-
SQL> grant execute on scott.p_emp1 to test;
-
-
Grant succeeded.
-
-
SQL> conn test/test;
-
Connected.
-
SQL> create table emp (id number) ;
-
-
Table created.
-
-
SQL> exec scott.p_emp1;
-
-
PL/SQL procedure successfully completed.
-
-
SQL> conn /as sysdba
-
Connected.
-
-
SQL> select owner,table_name from dba_tables where table_name='EMP1';
-
-
OWNER TABLE_NAME
-
------------------------------ ------------------------------
-
TEST EMP1