DBMS_PARALLEL_EXECUTE and indirectly given grants on procedure

孤者浪人 提交于 2021-01-28 03:23:28

问题


I just bumped into some strange behaviour of DBMS_PARALLEL_EXECUTE (at least for me). See my preset (executed as 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;

So I created 2 users, the first one has a procedure which is given to stuff_doer role. Later this role is given to usr2.

Then I check it as 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>

See: when I execute do_stuff procedure directly - it finishes as expected. But when I use DBMS_PARALLEL_EXECUTE I get identifier must be declared error. Am I missing something in granting privileges?

I found here this phrase: The CHUNK_BY_SQL, RUN_TASK, and RESUME_TASK subprograms require a query, and are executed using DBMS_SQL.

I tried to explicitly dbms_sql.parse my statement but it also finished OK.

Any help would be appreciated as I'm not getting current situation. And yes, I can grant privileges directly but still it's something tricky for me.


回答1:


Roles are not activited by default in PL/SQL stored units (tested with Oracle 19 but 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> 

Note the difference between anonymous PL/SQL (which is not stored in the database) and a stored unit (procedure/function stored in the database).




回答2:


This is the right check is the USR2 can execute the procedure (requires CREATE PROCEDURE privilege)

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

I.e. the answer is no, direct execute privilege is required (not via a ROLE).



来源:https://stackoverflow.com/questions/61951860/dbms-parallel-execute-and-indirectly-given-grants-on-procedure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!