plsql pass failure back to executing job - oracle

I have a scheduled job in oracle that runs plsql code. I will like to be able to mark the scheduled job as failed if scheduled occur within the code, but I have failed with my googling skills.
So
if a = b then
return (and get the code to fail)
end if;
I assume I am missing something very obvious but cannot find it anywhere.
Thanks

Perhaps this will help demonstrate:
SQL> set serverout on
SQL> --
SQL> create or replace procedure my_proc(p_value number)
2 as
3 ex_custom1 exception;
4 pragma exception_init(ex_custom1,-20001);
5 ex_custom2 exception;
6 pragma exception_init(ex_custom2,-20002);
7 begin
8 if p_value = 1
9 then raise_application_error (-20001,'This is custom error 1');
10 end if;
11 --
12 if p_value = 2
13 then raise_application_error (-20002,'This is custom error 2');
14 end if;
15 --
16 dbms_output.put_line('Non-error completion');
17 exception
18 when ex_custom1
19 then
20 dbms_output.put_line( sqlerrm );
21
22 when ex_custom2
23 then
24 dbms_output.put_line( sqlerrm );
25 end;
26 /
Procedure created.
SQL> show errors
No errors.
SQL> --
SQL> exec my_proc(1);
ORA-20001: This is custom error 1
PL/SQL procedure successfully completed.
SQL> exec my_proc(2);
ORA-20002: This is custom error 2
PL/SQL procedure successfully completed.
SQL> exec my_proc(3);
Non-error completion
PL/SQL procedure successfully completed.
SQL>
SQL>
SQL>
SQL> --
SQL> drop procedure my_proc;
Procedure dropped.
SQL> --
SQL> spo off
~

Related

ORACLE PL/SQL : How to pass an exception into a procedure

Is there a way to pass exception into a procedure to call "raise" after doing some actions to process exception. So that the outer code block will get the exact exception that was raised
Something like this:
begin
...
exception
when others then
error_handler( err );
end;
procedure error_handler ( err ) is
begin
/*
here some code to handle and log the exception...
*/
raise err;
end;
Or the only way is to pass SQLCODE and SQLERRM into the procedure and later call raise_application_error( SQLCODE, SQLERRM )?
If I understood you correctly, this is what you're asking.
Sample log table:
SQL> create table err_log
2 (program varchar2(30),
3 datum date,
4 sqlcode number
5 );
Table created.
Logging procedure should be an autonomous transaction so that you could commit in it, without affecting main transaction.
SQL> create or replace procedure error_handler
2 (p_program in varchar2, p_sqlcode in number)
3 is
4 pragma autonomous_transaction;
5 begin
6 insert into err_log (program, datum, sqlcode)
7 values (p_program, sysdate, p_sqlcode);
8 commit;
9 end;
10 /
Procedure created.
Another procedure (whose execution you're logging); it'll raise division by zero. See lines #8 and #9 which call the logging procedure and then just re-raise the error:
SQL> create or replace procedure p_test is
2 l_program varchar2(30) := 'P_TEST';
3 l_value number;
4 begin
5 l_value := 1 / 0;
6 exception
7 when others then
8 error_handler(l_program, sqlcode);
9 raise;
10 end p_test;
11 /
Procedure created.
OK, everything is set. Let's try it:
SQL> exec p_test;
BEGIN p_test; END;
*
ERROR at line 1:
ORA-01476: divisor is equal to zero --> this is result of RAISE in line #9
ORA-06512: at "SCOTT.P_TEST", line 9
ORA-06512: at "SCOTT.P_TEST", line 5
ORA-06512: at line 1
Log table contents:
SQL> select * from err_log;
PROGRAM DATUM SQLCODE
------------------------------ ------------------- ----------
P_TEST 01.11.2022 11:13:31 -1476
SQL>
You asked, literally:
How to pass an exception into a procedure?
You can't, as far as I can tell:
SQL> create or replace procedure error_handler_text
2 (p_err in exception) --> if this is what you asked
3 is
4 begin
5 null;
6 end;
7 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE ERROR_HANDLER_TEXT:
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/13 PLS-00103: Encountered the symbol "EXCEPTION" when expecting one
of the following:
out <an identifier> <a double-quoted delimited-identifier>
table columns long double ref char standard time timestamp
interval date binary national character nchar
The symbol "<an identifier> was inserted before "EXCEPTION" to
continue.
SQL>

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.

Need Assistance with PL/SQL Syntax

Can someone please pinpoint the syntax error in the below code.
DECLARE
plsql_blk VARCHAR2 (250);
begin
plsql_blk := 'begin DBMS_STATS.DELETE_TABLE_STATS ('||''''|| OWNER ||''''||','||''''|| TABLE_NAME ||''''||');'
from dba_tables
where owner = 'SYSADM'
and table_name like 'AS_TAO%'
or table_name like 'AS_BP_XLBP_TAO%'
order by table_name; end;';
execute immediate plsql_blk;
end;
/
Thanks in advance.
That would be "too many errors" error (only if it existed).
you can't execute a procedure which "looks like" a SELECT statement. Where did FROM clause come from (as well as the rest of that piece of code)?
if you are using OR among other conditions, you have to enclose it into parenthesis, otherwise you'll get false result
I didn't count them, but it looks as if you got lost in that many single quotes. Instead of that, consider using the q-quoting mechanism which helps A LOT
Let's try to make it work. I don't have your users nor tables so I'll do that in Scott's sample schema.
First, gather statistics (otherwise there's nothing to delete):
SQL> exec dbms_stats.gather_table_stats('SCOTT', 'EMP');
PL/SQL procedure successfully completed.
SQL>
This is a procedure which shows some statistics (why a procedure? So that I wouldn't have to copy/paste the whole code once again at the end of this demonstration):
SQL> create or replace procedure p_getstat(par_table in varchar2)
2 is
3 l_numrows number;
4 l_numblks number;
5 l_avgrlen number;
6 l_cachedblk number;
7 l_cachehit number;
8 begin
9 dbms_stats.get_table_stats
10 (ownname => 'SCOTT',
11 tabname => dbms_assert.simple_sql_name(par_table),
12 numrows => l_numrows,
13 numblks => l_numblks,
14 avgrlen => l_avgrlen,
15 cachedblk => l_cachedblk,
16 cachehit => l_cachehit
17 );
18 dbms_output.put_line(par_table || ' has ' || l_numrows || ' row(s)');
19 end;
20 /
Procedure created.
Let's try it:
SQL> set serveroutput on
SQL>
SQL> exec p_getstat('EMP');
EMP has 14 row(s)
PL/SQL procedure successfully completed.
SQL>
Now, your procedure, fixed. You overcomplicated it by putting everything into dynamic SQL. Loop through tables you're interested in, but execute only the necessary part in dynamic fashion:
SQL> create or replace procedure p_delstat (par_owner in varchar2)
2 is
3 l_str varchar2(200);
4 begin
5 for cur_r in (select owner, table_name
6 from all_tables
7 where owner = dbms_assert.simple_sql_name(par_owner)
8 and ( table_name like 'EMP%'
9 or table_name like 'AS_BP_XLBP_TAO%'
10 )
11 order by table_name
12 )
13 loop
14 l_str := 'begin dbms_stats.delete_table_stats(:a, :b); end;';
15 execute immediate l_str using cur_r.owner, cur_r.table_name;
16 end loop;
17 end;
18 /
Procedure created.
Does it work?
SQL> exec p_delstat('SCOTT');
PL/SQL procedure successfully completed.
SQL>
Seems so; at least, didn't raise any error. Let's check whether statistics for previously mentioned EMP table still exist:
SQL> exec p_getstat('EMP');
BEGIN p_getstat('EMP'); END;
*
ERROR at line 1:
ORA-20000: Unable to get values for table EMP
ORA-06512: at "SYS.DBMS_STATS", line 7688
ORA-06512: at "SCOTT.P_GETSTAT", line 9
ORA-06512: at line 1
SQL>
Nope, statistics is gone. Looks like we've done it correctly.
Adjust that code so that it works in your database, with your user(s) and your table(s).

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.

PL/SQL: How to enable all triggers in the schema?

I'm trying to make a procedure that uses a cursor that enables all triggers in my schema to be enabled. However, I'm getting this Error at line 16: PL/SQL: SQL Statement ignored which is the line that I use fetch for.
CREATE OR REPLACE PROCEDURE enable_trigg_proc
IS
v_trigger_name trigger_name.user_triggers%TYPE;
CURSOR enable_trigg_cur
IS
SELECT TRIGGER_NAME INTO v_trigger_name
FROM user_triggers
WHERE STATUS = 'DISABLED';
BEGIN
OPEN enable_trigg_cur;
LOOP
FETCH enable_trigg_cur INTO v_trigger_name ;
EXIT WHEN enable_trigg_cur%NOTFOUND;
EXECUTE IMMEDIATE 'ALTER TRIGGER v_trigger_name ENABLE';
END LOOP;
close enable_trigg_cur;
END;
You don't need that much code:
SQL> begin
2 for cur_r in (select trigger_name from user_triggers) loop
3 execute immediate 'alter trigger ' || cur_r.trigger_name || ' enable';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
What's wrong with your code? INTO is required in PL/SQL's SELECT statement, but not within the cursor declaration. Also, you declared the variable in the wrong manner; should be
SQL> CREATE OR REPLACE PROCEDURE enable_trigg_proc
2 IS
3 CURSOR enable_trigg_cur
4 IS
5 SELECT TRIGGER_NAME
6 FROM user_triggers
7 WHERE STATUS = 'DISABLED';
8
9 v_trigger_name user_triggers.trigger_name%TYPE;
10 BEGIN
11 OPEN enable_trigg_cur;
12 LOOP
13 FETCH enable_trigg_cur INTO v_trigger_name ;
14 EXIT WHEN enable_trigg_cur%NOTFOUND;
15
16 EXECUTE IMMEDIATE 'ALTER TRIGGER ' || v_trigger_name || ' ENABLE';
17 END LOOP;
18 close enable_trigg_cur;
19 END;
20 /
Procedure created.
SQL> exec enable_trigg_proc;
PL/SQL procedure successfully completed.
SQL>

Resources