How to run UTL_RECOMP.RECOMP_PARALLEL from a procedure? - oracle

I have a simple question: Is it possible to run UTL_RECOMP.RECOMP_PARALLEL from a procedure?
I have a Package with a procedure which should recompile all invalid objects. It looks like this:
PROCEDURE Compile ()
IS
BEGIN
EXECUTE IMMEDIATE ('BEGIN SYS.UTL_RECOMP.RECOMP_PARALLEL(4,); END;');
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
However, I always get the Error PLS-00201: identifier 'UTL_RECOMP.RECOMP_PARALLEL' must be declared
I am logged in as sys/sysdba user. That's not the problem.
Any ideas how to get this working?
Thanks!

Actually it works if the procedure is owned by SYS and you grant EXECUTE privilege to another user (doc says "You must be connected AS SYSDBA to run this script").
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show user;
USER is "SYS"
SQL> --
SQL> CREATE OR REPLACE PROCEDURE Compile
2 IS
3 BEGIN
4 SYS.UTL_RECOMP.RECOMP_PARALLEL(4);
5 END;
6 /
Procedure created.
SQL> --
SQL> grant execute on compile to c##test;
Grant succeeded.
SQL> --
SQL> connect c##test/c##test
Connected.
SQL> show user
USER is "C##TEST"
SQL> --
SQL> drop table t purge;
Table dropped.
SQL> create table t(x int);
Table created.
SQL> create or replace procedure p
2 is
3 v int;
4 begin
5 select x into v from t;
6 end;
7 /
Procedure created.
SQL> --
SQL> show errors
No errors.
SQL> --
SQL> drop table t;
Table dropped.
SQL> --
SQL> select object_name, object_type, status
2 from user_objects
3 where object_name='P';
OBJECT_NAM OBJECT_TYP STATUS
---------- ---------- ----------
P PROCEDURE INVALID
SQL> --
SQL> create table t(x int);
Table created.
SQL> --
SQL> select object_name, object_type, status
2 from user_objects
3 where object_name='P';
OBJECT_NAM OBJECT_TYP STATUS
---------- ---------- ----------
P PROCEDURE INVALID
SQL> --
SQL> exec sys.compile;
PL/SQL procedure successfully completed.
SQL> --
SQL> select object_name, object_type, status
2 from user_objects
3 where object_name='P';
OBJECT_NAM OBJECT_TYP STATUS
---------- ---------- ----------
P PROCEDURE VALID
SQL> --
These kind of procedures should be run only by SYS (like utlrp.sql) - so this is for DBA only - as documented to avoid unexpected behaviour.

You can use it in a stored procedure:
SQL> set serveroutput on
SQL> --
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show user;
USER is "SYS"
SQL> --
SQL> CREATE OR REPLACE PROCEDURE Compile
2 IS
3 BEGIN
4 UTL_RECOMP.RECOMP_PARALLEL(4);
5 EXCEPTION
6 WHEN OTHERS
7 THEN
8 DBMS_OUTPUT.PUT_LINE(SQLERRM);
9 END;
10 /
Procedure created.
SQL> --
SQL> show errors
No errors.
SQL> --
SQL> set timing on
SQL> exec compile;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.31
SQL> --
SQL> exit

Related

Restrict creation of table on sunday in oracle

Question: create a pl/sql using a trigger to restrict creation of any
table on Sunday
I tried
CREATE OR REPLACE TRIGGER sunday_trigger
BEFORE CREATE ON ALSPRD
FOR EACH ROW
DECLARE
v_day DATE := TRUNC(SYSDATE);
BEGIN
IF TO_CHAR(v_day,'DY')IN ('SUN') THEN
REVOKE create table from harsh;
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error is:'||SQLERRM);
END;
It creating error ORA-30506: system triggers cannot be based on tables or views
I'd suggest a different approach.
Connected as SYS, create a trigger that prevents user (scott in my example) to create anything on desired day (I'll use Monday so that I could test whether it works as planned).
SQL> show user
USER is "SYS"
SQL>
SQL> create or replace trigger sunday_trigger
2 before create on scott.schema
3 begin
4 if to_char(sysdate, 'DY', 'nls_date_language = english') = 'MON'
5 then
6 raise_application_error(-20000, 'You can not create any objects on Monday');
7 end if;
8 end;
9 /
Trigger created.
Let's test it:
SQL> connect scott/tiger
Connected.
SQL> select to_char(sysdate, 'DY', 'nls_date_language = english') today from dual;
TODAY
------------
MON
SQL> create table so_test (id number);
create table so_test (id number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: You can not create any objects on Monday
ORA-06512: at line 4
SQL> create or replace procedure p_test is
2 begin
3 null;
4 end;
5 /
create or replace procedure p_test is
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: You can not create any objects on Monday
ORA-06512: at line 4
SQL>
Let's pretend it is tomorrow (Tuesday):
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> select sysdate from dual;
SYSDATE
--------
21.06.21
SQL> alter system set fixed_date = '22.06.21';
System altered.
SQL> connect scott/tiger
Connected.
SQL> select to_char(sysdate, 'DY', 'nls_date_language = english') today from dual;
TODAY
------------
TUE
SQL> create table so_test (id number);
Table created.
SQL> create or replace procedure p_test is
2 begin
3 null;
4 end;
5 /
Procedure created.
SQL>
Looks OK to me.
Revoke user rights to create tables from harsh.
Create another user <OWNER_PROC> with rights to create tables.
Make a procedure <CREATE_TABLE_PROC> that creates tables and in this procedure you can make any logic.
Grant execute on <OWNER_PROC>.<CREATE_TABLE_PROC> to harsh.

Disabling trigger only for specific oracle procedure

We have a requirement to disable a trigger only for a specific procedure run in ORACLE.
We have Table A and Table B.
The trigger is designed to insert into Table B for each insert or update of Table A.
The procedure makes entries to Table A.
How to enable/disable trigger in procedure?
The above link explains how to enable and disable the trigger during the procedure.
But my requirement is during this procedure run, if there are other inserts to Table A, then the trigger should run as expected.
Is this possible? Please help on how to achieve the same if possible.
You can use the DBMS_APPLICATION_INFO and SYS_CONTEXT to set any parameter in your procedure and then check for that parameter in the TRIGGER to see if you should take any action in the trigger or not as follows:
Table description:
SQL> DESC AA;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 NOT NULL NUMBER
SQL>
Trigger code:
SQL> CREATE OR REPLACE TRIGGER AA_TRG BEFORE
2 INSERT OR UPDATE ON AA
3 FOR EACH ROW
4 BEGIN
5 IF SYS_CONTEXT(
6 'USERENV',
7 'ACTION'
8 ) = 'DISABLE_TRIGGER' THEN
9 DBMS_OUTPUT.PUT_LINE('TRIGGER DISABLED');
10 ELSE
11 DBMS_OUTPUT.PUT_LINE('TRIGGER ENABLED');
12 END IF;
13
14 DBMS_APPLICATION_INFO.SET_ACTION(ACTION_NAME => NULL);
15 END;
16 /
Trigger created.
SQL>
Disabled trigger procedure code:
SQL> CREATE OR REPLACE PROCEDURE AA_DISABLED_TRIGGER_PROC AS
2 BEGIN
3 DBMS_APPLICATION_INFO.SET_ACTION(ACTION_NAME => 'DISABLE_TRIGGER');
4 INSERT INTO AA VALUES ( 3 );
5
6 ROLLBACK;
7 END;
8 /
Procedure created.
SQL>
Enabled trigger procedure code:
SQL> CREATE OR REPLACE PROCEDURE AA_ENABLED_TRIGGER_PROC AS
2 BEGIN
3 INSERT INTO AA VALUES ( 3 );
4
5 ROLLBACK;
6 END;
7 /
Procedure created.
SQL>
Calling the procedures:
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_ENABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER ENABLED
PL/SQL procedure successfully completed.
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_DISABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER DISABLED
PL/SQL procedure successfully completed.
SQL>
SQL> SET SERVEROUT ON
SQL> BEGIN
2 AA_ENABLED_TRIGGER_PROC;
3 END;
4 /
TRIGGER ENABLED
PL/SQL procedure successfully completed.
SQL>
Not possible. If trigger is disabled, then it is disabled and won't work.
But, if you alter the table and add a column which says who is inserting rows into it, then you could use trigger's WHEN clause to distinguish this procedure from other inserters and either fire the trigger or not. It means, of course, that trigger remains enabled all the time.

Procedures giving error : ORA-00955: name is already used by an existing object

CREATE TABLE product
( product_id number(10) NOT NULL,
product_name varchar2(50) NOT NULL,
price varchar2(50)
);
CREATE OR REPLACE PROCEDURE p1 (product_id in number,
product_name in varchar2,
price in number)
IS
BEGIN
INSERT INTO product values(1,'yash',100);
DBMS_OUTPUT.PUT_LINE('VALUE INSERTED');
end;
Error: ORA-00955: name is already used by an existing object
Can someone please provide me and suitable example
From the error message, the name p1 is already in use (as an object name whose type is different than a procedure). Just give the procedure a different (and more descriptive!) name:
CREATE OR REPLACE PROCEDURE insert_product
(product_id in number,
product_name in varchar2,
price in number)
IS
BEGIN
INSERT INTO product values(1,'yash',100);
DBMS_OUTPUT.PUT_LINE('VALUE INSERTED');
END;
For your this problem the solution is write the following line (EXECUTE p1;)
By typing this command you will get your desired output
You have twice asked for a 'suitable example' or 'justifying code'. I assume from that you don't understand or don't believe what has been explained about your procedure name conflicting with some other object name. So here's the example that proves it.
SQL> --
SQL> -- check that we don't own anything called MYTEST
SQL> --
SQL> select object_name
2 from user_objects
3 where upper(object_name) = 'MYTEST'
4 ;
no rows selected
SQL> --
SQL> -- create a table MYTEST
SQL> --
SQL> create table mytest (dob date);
Table created.
SQL> --
SQL> -- check objets
SQL> --
SQL> select object_type,
2 object_name
3 from user_objects
4 where upper(object_name) = 'MYTEST'
5 ;
OBJECT_TYPE OBJECT_NAME
------------------- --------------------
TABLE MYTEST
1 row selected.
SQL> --
SQL> -- create a procedure MYTEST
SQL> --
SQL> create or replace procedure mytest
2 as
3 begin
4 dbms_output.put_line('Hello world');
5 end;
6 /
create or replace procedure mytest
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
SQL> --
SQL> -- now, drop the table and try the procedure again
SQL> --
SQL> drop table mytest purge;
Table dropped.
SQL> create or replace procedure mytest
2 as
3 begin
4 dbms_output.put_line('Hello world');
5 end;
6 /
Procedure created.
SQL> --
SQL> -- cleanup
SQL> --
SQL> drop table mytest purge;
drop table mytest purge
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> drop procedure mytest;
Procedure dropped.
In your case if your procedure is named 'p1' then check:
select object_type,
object_name
from user_objects
where upper(object_name) = 'P1'
;

Can we call procedure or function from anonymous block in oracle?

Can i call a pl/sql object by procedure or function from within an anonymous block?
This is a very frequent interview question.
Thanks
Yes:
SQL> set serveroutput on
SQL> --
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show user;
USER is "C##TEST"
SQL> --
SQL> CREATE OR REPLACE PROCEDURE myproc
2 IS
3 BEGIN
4 dbms_output.put_line('myproc: OK');
5 END;
6 /
Procedure created.
SQL> --
SQL> show errors
No errors.
SQL> --
SQL> CREATE OR REPLACE FUNCTION myfunc RETURN VARCHAR2
2 IS
3 BEGIN
4 return 'myfunc: OK';
5 END;
6 /
Function created.
SQL> --
SQL> show errors
No errors.
SQL> --
SQL> begin
2 myproc;
3 end;
4 /
myproc: OK
PL/SQL procedure successfully completed.
SQL> --
SQL> declare
2 myvar VARCHAR2(50);
3 begin
4 select myfunc into myvar from dual;
5 dbms_output.put_line(myvar);
6 end;
7 /
myfunc: OK
PL/SQL procedure successfully completed.

Does altering or drop-recreating a table in oracle affects the policies defined on it

If i have a table and a defined policy on it then do I need to redefine the policy if I drop and recreate the table or alter it, provided that the alteration or the recreation of the table does not alter elements that the function needs to see?
"do I need to redefine the policy if I
drop and recreate the table"
Yes. Let's create a policy.
SQL> exec dbms_rls.add_policy('APC', 'T23', 'DEPTPOL', 'APC', 'security_policies.get_deptno_predicate')
PL/SQL procedure successfully completed.
SQL> select count(*) from user_policies;
COUNT(*)
----------
1
SQL> exec security_policies.set_deptno(20)
PL/SQL procedure successfully completed.
SQL> select count(*) from t23;
COUNT(*)
----------
6
SQL>
so that works. But if we drop and re-create the table (using a backup I prepared earlier) ...
SQL> drop table t23
2 /
Table dropped.
SQL> create table t23 as select * from t23a
2 /
Table created.
SQL> select count(*) from t23;
COUNT(*)
----------
11
SQL> exec security_policies.set_deptno(20)
PL/SQL procedure successfully completed.
SQL> select count(*) from t23;
COUNT(*)
----------
11
SQL> SQL> select count(*) from user_policies;
COUNT(*)
----------
0
SQL>
"So the question is if I must redefine
the policy even if I will not change
anything in the definition."
No. Providing the change doesn't invalidate the generated predicate altering a table doesn't drop the policy:
SQL> exec dbms_rls.add_policy('APC', 'T23', 'DEPTPOL', 'APC', 'security_policies.get_deptno_predicate')
PL/SQL procedure successfully completed.
SQL> alter table t23 modify deptno number(3,0)
2
SQL> desc t23
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME VARCHAR2(12 CHAR)
ID NUMBER
AGE NUMBER(4)
DEPTNO NUMBER(2)
SQL> alter table t23 modify deptno number(3,0)
2 /
Table altered.
SQL> exec security_policies.set_deptno(20)
PL/SQL procedure successfully completed.
SQL> select count(*) from t23;
COUNT(*)
----------
6
SQL>
Note that the change modified the column which is tested by the predicate and the policy still remains in force.
"does a 'CREATE OR REPLACE VIEW'
statement drops and recreates it or
does it alter it?"
Let's try it:
SQL> create view v23 as select * from t23;
View created.
SQL> exec dbms_rls.add_policy('APC', 'V23', 'DEPTPOLV', 'APC', 'security_policies.get_deptno_predicate')
PL/SQL procedure successfully completed.
SQL> exec security_policies.set_deptno(10)
PL/SQL procedure successfully completed.
SQL> select count(*) from v23;
COUNT(*)
----------
5
SQL> create or replace view v23 as select name, age from t23;
View created.
SQL> select count(*) from v23;
select count(*) from v23
*
ERROR at line 1:
ORA-28113: policy predicate has error
SQL>
Okay, so that's an error because the view's new projection doesn't include the column in the predicate. But it suggests teh ploicy is still in place. So let's fix that error:
SQL> create or replace view v23 as select name, age, deptno from t23;
View created.
SQL> select count(*) from v23;
COUNT(*)
----------
5
SQL>

Resources