在创建一个其他用户的物化视图时报错,错误信息为:ORA-01031: 权限不足。
以前写过几篇文章,介绍物化视图创建所需要的权限:
建立物化视图所需权限(一):http://yangtingkun.itpub.net/post/468/50672
建立物化视图所需权限(二):http://yangtingkun.itpub.net/post/468/50707
建立物化视图所需权限(三):http://yangtingkun.itpub.net/post/468/50838
建立物化视图所需权限(四):http://yangtingkun.itpub.net/post/468/51163
但是目前碰到的问题显然和上面的普通问题有所区别。
下面看看问题的重现:
SQL> CREATE USER MV IDENTIFIED BY MV DEFAULT TABLESPACE USERS;
用户已创建。
SQL> GRANT CONNECT, RESOURCE TO MV;
授权成功。
SQL> GRANT CREATE MATERIALIZED VIEW TO MV;
授权成功。
SQL> CREATE USER USER_DBA IDENTIFIED BY USER_DBA;
用户已创建。
SQL> GRANT DBA TO USER_DBA;
授权成功。
SQL> CONN MV/MV已连接。
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY, NAME VARCHAR2(30));
表已创建。
SQL> CREATE MATERIALIZED VIEW LOG ON T;
实体化视图日志已创建。
SQL> CREATE MATERIALIZED VIEW MV_T REFRESH FAST
2 AS SELECT * FROM T;
实体化视图已创建。
用户MV创建物化视图并不会报错,下面尝试使用USER_DBA用户来创建MV用户下的物化视图:
SQL> CONN USER_DBA输入口令: 已连接。
SQL> CREATE MATERIALIZED VIEW MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
实体化视图已创建。
SQL> DROP MATERIALIZED VIEW MV_T;
实体化视图已删除。
SQL> DROP MATERIALIZED VIEW MV.MV_T;
实体化视图已删除。
SQL> CREATE MATERIALIZED VIEW MV.MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
AS SELECT * FROM MV.T
*第 2 行出现错误:
ORA-01031: 权限不足
可以看到,USER_DBA可以在当自己的SCHEMA建立物化视图,但是无法在MV用户下建立物化视图。
由于Oracle报错缺少权限,首先感觉的问题是出在USER_DBA用户上,因为MV用户自己可以建立物化视图。
尝试使用SYS来建立物化视图:
SQL> CONN / AS SYSDBA已连接。
SQL> CREATE MATERIALIZED VIEW MV.MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
实体化视图已创建。
SQL> DROP MATERIALIZED VIEW MV.MV_T;
实体化视图已删除。
SYS用户的创建成功,更加确信问题是出在USER_DBA身上,开始怀疑USER_DBA是缺少了什么权限。
可是USER_DBA已经授予了DBA角色,按道理将,一般不会缺少什么权限,难道权限还需要直接授权,而不能通过角色:
SQL> GRANT CREATE ANY TABLE TO USER_DBA;
授权成功。
SQL> GRANT SELECT ANY TABLE TO USER_DBA;
授权成功。
SQL> GRANT COMMENT ANY TABLE TO USER_DBA;
授权成功。
SQL> GRANT LOCK ANY TABLE TO USER_DBA;
授权成功。
SQL> GRANT SELECT ANY DICTIONARY TO USER_DBA;
授权成功。
SQL> CONN USER_DBA/USER_DBA已连接。
SQL> CREATE MATERIALIZED VIEW MV.MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
AS SELECT * FROM MV.T
*第 2 行出现错误:
ORA-01031: 权限不足
将一堆的ANY权限直接授权给USER_DBA,可是创建物化视图视图的时候仍然报错,缺少权限,这就没有什么道理了,难道是个bug。
查询了metalink,并未发现什么类似的描述。看来只好通过trace的方式分析一下错误了:
SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 12';
会话已更改。
SQL> CREATE MATERIALIZED VIEW MV.MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
AS SELECT * FROM MV.T
*第 2 行出现错误:
ORA-01031: 权限不足
SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF';
会话已更改。
下面查看一下trace中,错误出现在哪里:
SQL> SELECT SPID FROM V$PROCESS P, V$SESSION S
2 WHERE P.ADDR = S.PADDR
3 AND SID IN (SELECT SID FROM V$MYSTAT WHERE ROWNUM = 1);
SPID
------------
13940
SQL> HOST
[oracle@testzone ~]$ more $ORACLE_BASE/admin/testzj/udump/testzj_ora_13940.trc
/opt/ora10g/admin/testzj/udump/testzj_ora_13940.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
ORACLE_HOME = /opt/ora10g/product/10.2.0/db_1
System name: Linux
Node name: testzone
Release: 2.6.18-8.el5xen
Version: #1 SMP Tue Jun 5 23:53:34 EDT 2007
Machine: x86_64
Instance name: testzj
Redo thread mounted by this instance: 1
Oracle process number: 20
Unix process pid: 13940, image: oracle@testzone (TNS V1-V3)
*** 2008-05-08 16:05:49.580
*** ACTION NAME:() 2008-05-08 16:05:49.580
*** MODULE NAME:(SQL*Plus) 2008-05-08 16:05:49.580
*** SERVICE NAME:(SYS$USERS) 2008-05-08 16:05:49.580
*** SESSION ID:(148.437) 2008-05-08 16:05:49.580
WAIT #6: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1181869091387111
*** 2008-05-08 16:06:11.329
WAIT #6: nam='SQL*Net message from client' ela= 21238676 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1181869112626106
XCTEND rlbk=0, rd_only=1
=====================
.
.
.
=====================
PARSE ERROR #3:len=57 dep=1 uid=71 oct=3 lid=71 tim=1181869112672434 err=10980
SELECT "T"."ID" "ID","T"."NAME" "NAME" FROM "MV"."T" "T"
=====================
PARSING IN CURSOR #1 len=108 dep=2 uid=0 oct=3 lid=0 tim=1181869112673324 hv=1873661484 ad='a6554dd0'
select cc.intcol# from cdef$ c, ccol$ cc where c.obj#=cc.obj# and c.con#=cc.con# and c.type#=7 and c.obj#=:1
END OF STMT
PARSE #1:c=0,e=512,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=4,tim=1181869112673319
BINDS #1:
kkscoacd
Bind#0
oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
oacflg=00 fl2=0001 frm=00 csi=00 siz=24 off=0
kxsbbbfp=2aaaacaa0a40 bln=22 avl=04 flg=05
value=81507
EXEC #1:c=0,e=1407,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=4,tim=1181869112674805
FETCH #1:c=8000,e=301,p=0,cr=3,cu=0,mis=0,r=0,dep=2,og=4,tim=1181869112675138
STAT #1 id=1 cnt=0 pid=0 pos=1 obj=0 op='HASH JOIN (cr=3 pr=0 pw=0 time=315 us)'
STAT #1 id=2 cnt=0 pid=1 pos=1 obj=31 op='TABLE ACCESS CLUSTER CDEF$ (cr=3 pr=0 pw=0 time=43 us)'
STAT #1 id=3 cnt=1 pid=2 pos=1 obj=30 op='INDEX UNIQUE SCAN I_COBJ# (cr=2 pr=0 pw=0 time=19 us)'
STAT #1 id=4 cnt=0 pid=1 pos=2 obj=32 op='TABLE ACCESS CLUSTER CCOL$ (cr=0 pr=0 pw=0 time=0 us)'
STAT #1 id=5 cnt=0 pid=4 pos=1 obj=30 op='INDEX UNIQUE SCAN I_COBJ# (cr=0 pr=0 pw=0 time=0 us)'
=====================
PARSING IN CURSOR #2 len=87 dep=1 uid=71 oct=1 lid=71 tim=1181869112675587 hv=2894365893 ad='a0abf708'
CREATE TABLE "MV"."MV_T" ("ID","NAME") AS SELECT "T"."ID","T"."NAME" FROM "MV"."T" "T"
END OF STMT
PARSE #2:c=8000,e=3005,p=0,cr=4,cu=0,mis=1,r=0,dep=1,og=1,tim=1181869112675583
BINDS #2:
EXEC #2:c=0,e=129,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,tim=1181869112675776
ERROR #2:err=1031 tim=1740669629
EXEC #4:c=40002,e=34575,p=0,cr=78,cu=22,mis=0,r=0,dep=0,og=1,tim=1181869112675848
ERROR #4:err=1031 tim=1740669629
STAT #5 id=1 cnt=0 pid=0 pos=1 obj=178 op='TABLE ACCESS BY INDEX ROWID SNAP$ (cr=1 pr=0 pw=0 time=22 us)'
STAT #5 id=2 cnt=0 pid=1 pos=1 obj=181 op='INDEX UNIQUE SCAN I_SNAP1 (cr=1 pr=0 pw=0 time=12 us)'
WAIT #4: nam='log file sync' ela= 95 buffer#=1861 p2=0 p3=0 obj#=-1 tim=1181869112676218
WAIT #4: nam='SQL*Net break/reset to client' ela= 4 driver id=1650815232 break?=1 p3=0 obj#=-1 tim=1181869112676272
WAIT #4: nam='SQL*Net break/reset to client' ela= 68 driver id=1650815232 break?=0 p3=0 obj#=-1 tim=1181869112676360
WAIT #4: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1181869112676382
*** 2008-05-08 16:06:24.825
WAIT #4: nam='SQL*Net message from client' ela= 13130207 driver id=1650815232 #bytes=1 p3=0 obj#=-1 tim=1181869125806625
=====================
PARSING IN CURSOR #7 len=55 dep=0 uid=72 oct=42 lid=72 tim=1181869125806851 hv=524428051 ad='0'
ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF'
END OF STMT
PARSE #7:c=0,e=111,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=1181869125806846
EXEC #7:c=0,e=56,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=1181869125806968
从上面的trace信息文件,错误出现在建表过程中,可是直接尝试上面的建表语句是不报错的:
[oracle@testzone ~]$ exit
exit
SQL> CREATE TABLE "MV"."MV_T" ("ID","NAME") AS SELECT "T"."ID","T"."NAME" FROM "MV"."T" "T";
表已创建。
SQL> DROP TABLE MV.MV_T;
表已删除。
难道是因为MV用户的权限必须直接授权,而不能通过角色获取:
SQL> SELECT * FROM DBA_SYS_PRIVS WHERE GRANTEE = 'MV';
GRANTEE PRIVILEGE ADM
------------------------------ ---------------------------------------- ---
MV CREATE MATERIALIZED VIEW NO
MV UNLIMITED TABLESPACE NO
SQL> GRANT CREATE TABLE TO MV;
授权成功。
SQL> CREATE MATERIALIZED VIEW MV.MV_T REFRESH FAST
2 AS SELECT * FROM MV.T;
实体化视图已创建。
问题居然是出在MV用户下,创建其他用户下的物化视图,不仅需要这个用户拥有CREATE TABLE权限,而且要求这个权限不能是通过角色获得,必须直接授权。
从这个要求可以推测,当建立其他用户下的物化视图,多半是通过存储过程实现的,因为这个授权的要求很显然是符合存储过程授权规则。
至于SYS用户为什么不需要目标用户直接授权CREATE TABLE,根据Tom的描述,SYS用户是特殊的,普通的规则在SYS身上并不适用。