DBMS_PARALLEL_EXECUTE and indirectly given grants on procedure - oracle

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.

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).

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).

Related

ORA-00942: table or view does not exist in Package based Procedure

I have gone through similar threads but unable to understand the root cause of the error.
I have an Oracle Schema as "PRP".
PRP has one table Named : "MY_TABLE".
PRP has one package Named : "My_PKG" with authid current_user
Package contains following procedure
PROCEDURE CUSTOMER_ORDER_QUERY (
P_REPORT OUT SYS_REFCURSOR
) AS
BEGIN
OPEN P_REPORT FOR SELECT
* from MY_TABLE
END;
When I execute the procedure from the package it gives the error Table or view does not exists.
But when I prefix the schema name to the table in the procedures the cursor executes perfectly.
I have explicitly given privileges on that table to same schema.
from sys users : grant all on prp.MY_TABLE to PRP;
But none helps.
The Package and the table is in same schema.
Please help.
I did what you described; no problems.
Create user prp and grant required privileges:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> create user prp identified by prp
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;
User created.
SQL> grant create session, create table, create procedure to prp;
Grant succeeded.
Connect as prp, create table and package:
SQL> connect prp/prp
Connected.
SQL> create table my_table as
2 select 1 id, 'Little' name from dual union all
3 select 2 , 'Foot' from dual;
Table created.
SQL> create or replace package my_pkg as
2 procedure customer_order_query (p_report out sys_refcursor);
3 end;
4 /
Package created.
SQL> create or replace package body my_pkg as
2 procedure customer_order_query (p_report out sys_refcursor)
3 as
4 begin
5 open p_report for select * from my_table;
6 end;
7 end;
8 /
Package body created.
Testing:
SQL> var l_rc refcursor
SQL> exec my_pkg.customer_order_query (:l_rc);
PL/SQL procedure successfully completed.
SQL> print l_rc;
ID NAME
---------- ------
1 Little
2 Foot
SQL>
So, yes - it works. If both table and package belong to the same user (reside in the same schema), you don't need any additional privileges as you own both of them.

Trigger won' t work when logged with another user sqldeveloper

First of all I am a newbie to ORACLE and I am just working for a school project.
I want to create a trigger that triggers every time someone else than the user named 'ion' performs a DDL command.
When logged on other user, to have access to Ion's tables I used this command:
alter session set current_schema = ion;
Here is the code:
set serveroutput on;
CREATE OR REPLACE TRIGGER t12
BEFORE CREATE OR DROP OR ALTER ON SCHEMA
BEGIN
dbms_output.put_line('LALA');
IF UPPER(USER) != 'ION' THEN
RAISE_APPLICATION_ERROR(-20022, 'Only Ion can do this');
ELSE
INSERT INTO audit_ion VALUES(SYS.LOGIN_USER, SYS.DATABASE_NAME, SYS.SYSEVENT, SYS.DICTIONARY_OBJ_NAME, SYSDATE);
END IF;
END;
/
alter session set current_schema = ion;
create table dummy(d integer);
And it creates the table, and not even LALA is printed, so it means it doesn't even enter the trigger. How can I do this ?
From my point of view, you should actually REVOKE all privileges you want to prevent by that trigger.
Meanwhile, as of a trigger, you should have probably checked dictionary_obj_owner instead of user.
I don't have your users (and don't feel like creating that ion) so I'm using my own scott and mike.
SQL> show user
USER is "SCOTT"
SQL> CREATE TABLE audit_ion (
2 login_user VARCHAR2(10),
3 database_name VARCHAR2(10),
4 sysevent VARCHAR2(15),
5 dictionary_obj_name VARCHAR2(20),
6 datum DATE
7 );
Table created.
SQL>
SQL> CREATE OR REPLACE TRIGGER t12 BEFORE CREATE OR DROP OR ALTER ON scott.SCHEMA BEGIN
2 dbms_output.put_line('lala');
3 --IF upper(user) != 'SCOTT' THEN
4 IF upper(dictionary_obj_owner) != 'SCOTT' then
5 raise_application_error(-20022, 'Only Scott can do this');
6 ELSE
7 INSERT INTO audit_ion VALUES (
8 sys.login_user,
9 sys.database_name,
10 sys.sysevent,
11 sys.dictionary_obj_name,
12 sysdate
13 );
14
15 END IF;
16 END;
17 /
Trigger created.
SQL>
Testing (still connected as scott):
SQL> create table trg_test (a number);
Table created.
Altering the session:
SQL> alter session set current_schema = mike;
Session altered.
SQL> create table trg_test (a number);
create table trg_test (a number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20022: Only Scott can do this
ORA-06512: at line 5
SQL> alter session set current_schema = scott;
Session altered.
SQL> select * from audit_ion;
LOGIN_USER DATABASE_N SYSEVENT DICTIONARY_OBJ_NAME DATUM
---------- ---------- --------------- -------------------- --------
SCOTT XE CREATE TRG_TEST 05.01.22
SQL>
Kind of works.

plsql procedures while executing an error invalid identifier 00904

Error message
CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
create or replace PROCEDURE ADD_DEPARTMENT
(P_DID IN DEPARTMENT.DID%TYPE,
P_DNAME IN DEPARTMENT.DNAME%TYPE,
P_DLOC IN DEPARTMENT.DLOC%TYPE,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG:=SQLERRM;
END ADD_DEPARTMENT;
iam writing a simple procedure try to excute but it shows object_id:invalid identifier how i can solve
complete procedure execution image
One of your column names may be wrong in the parameter list/insert. Try just using varchar2 for all of them and see if that helps
create or replace PROCEDURE ADD_DEPT2
(P_DEPTNO IN VARCHAR2,
P_DNAME IN VARCHAR2,
P_LOC IN VARCHAR2,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPT1(DEPTNO,DNAME,LOC)VALUES(P_DEPTNO,P_DNAME,P_LOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG :=SQLERRM;
END ADD_DEPT2;
"it will come same error can be displayed"
No, no it won't. Let's prove it by running the code you posted.
Here is your table:
SQL> CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
Table created.
SQL> INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
1 row created.
SQL> INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
1 row created.
SQL>
Here is your procedure:
SQL> create or replace PROCEDURE ADD_DEPARTMENT
2 (P_DID IN DEPARTMENT.DID%TYPE,
3 P_DNAME IN DEPARTMENT.DNAME%TYPE,
4 P_DLOC IN DEPARTMENT.DLOC%TYPE,
5 P_ERROR_MSG OUT VARCHAR2)
6 IS
7 BEGIN
8 INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
9 COMMIT;
10 EXCEPTION
11 WHEN OTHERS THEN
12 P_ERROR_MSG:=SQLERRM;
13 END ADD_DEPARTMENT;
14 /
Procedure created.
SQL>
And lo! not only does it compile but it runs without error too.
SQL> set serveroutput on
SQL> declare
2 v varchar2(128);
3 begin
4 add_department(666, 'Area 51', 'Roswell', v);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select * from department;
DID DNAME DLOC
---------- -------------------- --------------------
101 SRINATH HINDUPUR
102 SAINATH ANANTAPUR
666 Area 51 Roswell
SQL>
So once again I ask, what is the problem?
"PLS-00905: object SCOTT.ADD_DEPARTMENT is invalid"
In SQL*Plus:
Connect as SCOTT
alter procedure add_department compile;
show errors
Or apply the equivalent sequence for whatever IDE you use to write your code.

Creating stored procedure in Oracle -17110 - Warning: execution completed with warning

I tried creating following stored procedure found here using Execute Query client connected to my Oracle server (Oracle Database 11g Enterprise Edition Release 11.1.0.7.0)
CREATE PROCEDURE remove_emp (employee_id NUMBER) AS
tot_emps NUMBER;
BEGIN
DELETE FROM employees
WHERE employees.employee_id = remove_emp.employee_id;
tot_emps := tot_emps - 1;
END;
/
I'm getting following,
Procedure created.
17110 - Warning: execution completed with warning
Appreciate any help on this.
Always use SHOW ERRORS to see the complete compilation error stack.
I don't know what error you are getting, because it works for me:
SQL> CREATE PROCEDURE remove_emp (employee_id NUMBER) AS
2 tot_emps NUMBER;
3 BEGIN
4 DELETE FROM emp
5 WHERE emp.empno = remove_emp.employee_id;
6 tot_emps := tot_emps - 1;
7 END;
8 /
Procedure created.
SQL> sho err;
No errors.
SQL>
To execute:
SQL> exec remove_emp(9999);
PL/SQL procedure successfully completed.
SQL>

Automatic type generation

I've created a function in a PL/SQL package that uses a custom type defined as table of numbers. I use an object of this type in an SQL query with the SELECT COLUMN_VALUE instruction like this :
The type definition in the package:
type T_IDS is table of my_table.col_id%type;
The query inside a procedure in the package body:
l_ids_list T_IDS ;
begin
select col_ids bulk collect into T_IDS from my_table;
select sum(t.rec_value) into total_value
from my_table t where t.col_id in (
select column_value from Table(l_ids_list) );
Everything works fine and when I compile this code, I can see a new type generated under my schema_name/type section.
Once I installed this on test environment, it fails the compilation with the errors :
Error: PLS-00642: local collection types not allowed in SQL statements
Error: PL/SQL: ORA-22905: cannot access rows from a non-nested table
item
Database versions (local and test) are exactly the same, 11g. Is there a way to activate such a generation on the DBMS?
exemple to reproduce :
create table my_table (
col_id number,
rec_value number
);
insert into my_table (col_id, rec_value) values (1,100);
insert into my_table (col_id, rec_value) values (2,200);
insert into my_table (col_id, rec_value) values (3,300);
insert into my_table (col_id, rec_value) values (4,400);
commit;
package creation :
create or replace package test_pck as
type T_IDS is table of my_table.col_id%type;
procedure test_list;
end test_pck;
/
create or replace
package body test_pck as
procedure test_list is
l_ids_list T_IDS ;
total_value number;
begin
select col_id bulk collect into l_ids_list from my_table;
select sum(t.rec_value) into total_value
from my_table t where t.col_id in (
select column_value from Table(l_ids_list) );
end test_list;
end test_pck;
/
what you are doing is wrong. you should be creating SQL types and not using pl/sql types to access the TABLE function.
now as to WHY it actually sorta worked in your Dev env.
The silent pl/sql table creation is intended for pipelined functions and has been around for a while, but you're using this in a non-pipelined function and as such THIS SHOULD FAIL. In 11g release 1 (11.1.0.7 to be precise) though, a bug means that it actually compiles. If you actually tried to run it though you would get an error:
SQL> create package body foo
2 as
3
4 procedure test
5 is
6 l_ids_list T_IDS ;
7 total_value number;
8 begin
9 select col_id bulk collect into l_ids_list from my_table;
10 select sum(t.rec_value) into total_value
11 from my_table t
12 where t.col_id in (select column_value from Table(l_ids_list));
13 end;
14 end;
15 /
Package body created.
SQL> exec foo.test;
BEGIN foo.test; END;
*
ERROR at line 1:
ORA-21700: object does not exist or is marked for delete
ORA-06512: at "TEST.FOO", line 10
ORA-06512: at line 1
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
now, Oracle FIXED this buggy behaviour in 11.2.0.3. now the error is thrown at compile time:
SQL> create package body foo
2 as
3
4 procedure test
5 is
6 l_ids_list T_IDS ;
7 total_value number;
8 begin
9 select col_id bulk collect into l_ids_list from my_table;
10 select sum(t.rec_value) into total_value
11 from my_table t
12 where t.col_id in (select column_value from Table(l_ids_list));
13 end;
14 end;
15 /
Warning: Package Body created with compilation errors.
SQL> show errors
Errors for PACKAGE BODY FOO:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/3 PL/SQL: SQL Statement ignored
12/48 PL/SQL: ORA-22905: cannot access rows from a non-nested table
item
12/54 PLS-00642: local collection types not allowed in SQL statements
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
in short, create an SQL type with create type and use that instead:
SQL> create type T_IDS as table of number;
2 /
Type created.
SQL> create package body foo
2 as
3
4 procedure test
5 is
6 l_ids_list T_IDS ;
7 total_value number;
8 begin
9 select col_id bulk collect into l_ids_list from my_table;
10 select sum(t.rec_value) into total_value
11 from my_table t
12 where t.col_id in (select column_value from Table(l_ids_list));
13 end;
14 end;
15 /
Package body created.
SQL> exec foo.test
PL/SQL procedure successfully completed.
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

Resources