DBMS_PARALLEL_EXECUTE 并间接给予程序资助
DBMS_PARALLEL_EXECUTE and indirectly given grants on procedure
我刚刚遇到了 DBMS_PARALLEL_EXECUTE 的一些奇怪行为(至少对我而言)。查看我的预设(作为 SYS 执行):
-- Preset
drop user usr1 cascade;
create user usr1 identified by usr1;
create or replace procedure usr1.do_stuff(p1 in number, p2 in number)
is
begin
dbms_output.put_line('I did stuff!');
end;
/
drop user usr2 cascade;
create user usr2 identified by usr2;
grant connect to usr2;
grant create job to usr2;
drop role stuff_doer cascade;
create role stuff_doer;
grant execute on usr1.do_stuff to stuff_doer;
grant stuff_doer to usr2;
所以我创建了 2 个用户,第一个有一个程序,它被赋予 stuff_doer
角色。后来这个角色给了usr2
.
然后我检查为 usr2
:
SQL*Plus: Release 11.2.0.4.0 Production on Fri May 22 12:14:10 2020
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Enter user-name: usr2@db
Enter password:
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> set serveroutput on
SQL> set linesize 400
SQL> exec usr1.do_stuff(1,1);
I did stuff!
PL/SQL procedure successfully completed.
SQL> DECLARE
2 l_task_name VARCHAR2(100) := 'task_name';
3 l_splitter VARCHAR2(4000) := 'select 1, 1 from dual';
4 l_exec_stmt VARCHAR2(1000) := 'begin usr1.do_stuff(:start_id, :end_id); end;';
5 BEGIN
6 FOR line IN (SELECT d.task_name
7 FROM user_parallel_execute_tasks d
8 WHERE d.task_name = l_task_name)
9 LOOP
10 dbms_parallel_execute.drop_task(task_name => line.task_name);
11 END LOOP;
12
13 dbms_parallel_execute.create_task(l_task_name);
14 dbms_parallel_execute.create_chunks_by_sql(task_name => l_task_name
15 ,sql_stmt => l_splitter
16 ,by_rowid => FALSE);
17
18 dbms_parallel_execute.run_task(l_task_name
19 ,l_exec_stmt
20 ,dbms_sql.native);
21
22 COMMIT;
23
24 END;
25 /
PL/SQL procedure successfully completed.
SQL> column status format A20
SQL> select status from user_parallel_execute_tasks where task_name = 'task_name';
STATUS
--------------------
FINISHED_WITH_ERROR
SQL> column status format A20
SQL> column error_code format 900000
SQL> column error_message format A60
SQL> select status, ERROR_CODE, ERROR_MESSAGE from user_parallel_execute_chunks e where e.TASK_NAME = 'task_name';
STATUS ERROR_CODE ERROR_MESSAGE
-------------------- ---------- ------------------------------------------------------------
PROCESSED_WITH_ERROR -06550 ORA-06550: line 1, column 7:
PLS-00201: identifier 'USR1.DO_STUFF' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
请参阅:当我直接执行 do_stuff
过程时 - 它按预期完成。但是当我使用 DBMS_PARALLEL_EXECUTE
时,我得到 identifier must be declared
错误。我在授予特权时遗漏了什么吗?
我找到了 here 这个短语:The CHUNK_BY_SQL, RUN_TASK, and RESUME_TASK subprograms require a query, and are executed using DBMS_SQL.
我试图明确地dbms_sql.parse
我的声明,但它也完成了。
任何帮助将不胜感激,因为我不了解当前情况。是的,我可以直接授予权限,但这对我来说仍然有些棘手。
角色在 PL/SQL 个存储单元中默认不激活(使用 Oracle 19 测试但 it's the same behaviour in older releases since very long time):
SQL> set serveroutput on
SQL> select banner from v$version where rownum=1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show user;
USER is "USR2"
SQL> select * from session_roles;
ROLE
--------------------------------------------------------------------------------
CONNECT
SELECT_CATALOG_ROLE
HS_ADMIN_SELECT_ROLE
STUFF_DOER
SQL> --
SQL> begin
2 for r in (select role from session_roles)
3 loop
4 dbms_output.put_line('role=' || r.role);
5 end loop;
6 end;
7 /
role=CONNECT
role=SELECT_CATALOG_ROLE
role=HS_ADMIN_SELECT_ROLE
role=STUFF_DOER
PL/SQL procedure successfully completed.
SQL> show errors
No errors.
SQL> create or replace procedure sr is
2 begin
3 for r in (select role from session_roles)
4 loop
5 dbms_output.put_line('role=' || r.role);
6 end loop;
7 end;
8 /
Procedure created.
SQL> show errors
No errors.
SQL>
SQL> exec sr;
PL/SQL procedure successfully completed.
SQL>
注意匿名PL/SQL(不存储在数据库中)和存储单元(procedure/function存储在数据库中)之间的区别。
这是正确的检查是USR2
可以执行程序(需要CREATE PROCEDURE
权限)
create procedure stuff as
BEGIN
usr1.do_stuff;
END;
/
SQL> show errors
Errors for PROCEDURE STUFF:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/4 PL/SQL: Statement ignored
3/4 PLS-00201: identifier 'USR1.DO_STUFF' must be declared
即答案是否定的,需要直接执行权限(不是通过 ROLE)。
我刚刚遇到了 DBMS_PARALLEL_EXECUTE 的一些奇怪行为(至少对我而言)。查看我的预设(作为 SYS 执行):
-- Preset
drop user usr1 cascade;
create user usr1 identified by usr1;
create or replace procedure usr1.do_stuff(p1 in number, p2 in number)
is
begin
dbms_output.put_line('I did stuff!');
end;
/
drop user usr2 cascade;
create user usr2 identified by usr2;
grant connect to usr2;
grant create job to usr2;
drop role stuff_doer cascade;
create role stuff_doer;
grant execute on usr1.do_stuff to stuff_doer;
grant stuff_doer to usr2;
所以我创建了 2 个用户,第一个有一个程序,它被赋予 stuff_doer
角色。后来这个角色给了usr2
.
然后我检查为 usr2
:
SQL*Plus: Release 11.2.0.4.0 Production on Fri May 22 12:14:10 2020
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Enter user-name: usr2@db
Enter password:
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> set serveroutput on
SQL> set linesize 400
SQL> exec usr1.do_stuff(1,1);
I did stuff!
PL/SQL procedure successfully completed.
SQL> DECLARE
2 l_task_name VARCHAR2(100) := 'task_name';
3 l_splitter VARCHAR2(4000) := 'select 1, 1 from dual';
4 l_exec_stmt VARCHAR2(1000) := 'begin usr1.do_stuff(:start_id, :end_id); end;';
5 BEGIN
6 FOR line IN (SELECT d.task_name
7 FROM user_parallel_execute_tasks d
8 WHERE d.task_name = l_task_name)
9 LOOP
10 dbms_parallel_execute.drop_task(task_name => line.task_name);
11 END LOOP;
12
13 dbms_parallel_execute.create_task(l_task_name);
14 dbms_parallel_execute.create_chunks_by_sql(task_name => l_task_name
15 ,sql_stmt => l_splitter
16 ,by_rowid => FALSE);
17
18 dbms_parallel_execute.run_task(l_task_name
19 ,l_exec_stmt
20 ,dbms_sql.native);
21
22 COMMIT;
23
24 END;
25 /
PL/SQL procedure successfully completed.
SQL> column status format A20
SQL> select status from user_parallel_execute_tasks where task_name = 'task_name';
STATUS
--------------------
FINISHED_WITH_ERROR
SQL> column status format A20
SQL> column error_code format 900000
SQL> column error_message format A60
SQL> select status, ERROR_CODE, ERROR_MESSAGE from user_parallel_execute_chunks e where e.TASK_NAME = 'task_name';
STATUS ERROR_CODE ERROR_MESSAGE
-------------------- ---------- ------------------------------------------------------------
PROCESSED_WITH_ERROR -06550 ORA-06550: line 1, column 7:
PLS-00201: identifier 'USR1.DO_STUFF' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL>
请参阅:当我直接执行 do_stuff
过程时 - 它按预期完成。但是当我使用 DBMS_PARALLEL_EXECUTE
时,我得到 identifier must be declared
错误。我在授予特权时遗漏了什么吗?
我找到了 here 这个短语:The CHUNK_BY_SQL, RUN_TASK, and RESUME_TASK subprograms require a query, and are executed using DBMS_SQL.
我试图明确地dbms_sql.parse
我的声明,但它也完成了。
任何帮助将不胜感激,因为我不了解当前情况。是的,我可以直接授予权限,但这对我来说仍然有些棘手。
角色在 PL/SQL 个存储单元中默认不激活(使用 Oracle 19 测试但 it's the same behaviour in older releases since very long time):
SQL> set serveroutput on
SQL> select banner from v$version where rownum=1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show user;
USER is "USR2"
SQL> select * from session_roles;
ROLE
--------------------------------------------------------------------------------
CONNECT
SELECT_CATALOG_ROLE
HS_ADMIN_SELECT_ROLE
STUFF_DOER
SQL> --
SQL> begin
2 for r in (select role from session_roles)
3 loop
4 dbms_output.put_line('role=' || r.role);
5 end loop;
6 end;
7 /
role=CONNECT
role=SELECT_CATALOG_ROLE
role=HS_ADMIN_SELECT_ROLE
role=STUFF_DOER
PL/SQL procedure successfully completed.
SQL> show errors
No errors.
SQL> create or replace procedure sr is
2 begin
3 for r in (select role from session_roles)
4 loop
5 dbms_output.put_line('role=' || r.role);
6 end loop;
7 end;
8 /
Procedure created.
SQL> show errors
No errors.
SQL>
SQL> exec sr;
PL/SQL procedure successfully completed.
SQL>
注意匿名PL/SQL(不存储在数据库中)和存储单元(procedure/function存储在数据库中)之间的区别。
这是正确的检查是USR2
可以执行程序(需要CREATE PROCEDURE
权限)
create procedure stuff as
BEGIN
usr1.do_stuff;
END;
/
SQL> show errors
Errors for PROCEDURE STUFF:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/4 PL/SQL: Statement ignored
3/4 PLS-00201: identifier 'USR1.DO_STUFF' must be declared
即答案是否定的,需要直接执行权限(不是通过 ROLE)。