Oracle trigger call procedure which starts a workflow - plsql

I have the following issue:
I created a trigger which is activated when a row is inserted into the table.
The trigger then starts a procedure.
The procedure then starts a workflow.
When I start the procedure it works fine. But when I start the trigger by entering a new row I got the following error:
Zeile 12: ORA-20001: Task not found - Please check the Task Type, Name and Location are correct.
ORA-06512: in "OWBSYS.WB_RT_API_EXEC", Zeile 759
ORA-06512: in "OWB***.EXECUTE_WF_ABC", Zeile 10
ORA-06512: in "OWB***.START_EXECUTE_WF_ABC", Zeile 7
ORA-06512: in "OWB***.ABC_WORKFLOW", Zeile 2
This is my trigger:
create or replace
TRIGGER ABC_WORKFLOW
BEFORE INSERT
ON OWB***.STG_ABC
FOR EACH ROW
BEGIN
OWB***.EXECUTE_WF_ABC;
END ;
This is my procedure:
create or replace
PROCEDURE EXECUTE_WF_ABC
AS
status NUMBER;
-- paramlist VARCHAR2(30000 CHAR);
BEGIN
owbsys.wb_rt_script_util.set_workspace ('OWBREPOWN.OWB***');
status :=
owbsys.wb_rt_api_exec.run_task (
p_location_name => 'OWF_LOCATION',
p_task_type => 'PROCESS',
p_task_name => 'WF_ABC',
-- p_custom_params => paramlist ,
p_system_params => '',
p_oem_friendly => 0 ,
p_background => 1); -- execute in background
DBMS_OUTPUT.put_line (status);
COMMIT;
--- EXCEPTION
--- when others then
--- message;
--- null;
END;
Did I miss something here?
Thanks in advance.

if your table is the TASK table, then your trigger is firing BEFORE the row exists, so if that workflow is checking for data in the row you're inserting then there is no wonder it's failing.
also COMMIT; in a trigger is really bad (and would fail if you inserted more than 1 row).

Related

Warning: Trigger created with compilation errors?

I am trying to implement Trigger that raises an User Defined Error Message and does not allow the update and Insert operation in the database.I am new to pl/sql i refereed some code from the internet and try to implement.My code is running is fine as i can not update/insert into database but still i am unable to get my user defined message and also i am getting this warning.
Warning: Trigger created with compilation errors ?
This is the table :
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER(5)
NAME VARCHAR2(20)
SALARY NUMBER(10)
DEPOT_ADDRESS VARCHAR2(15)
here is my code :
create or replace trigger cleaner_before_update_insert
for update or insert on cleaner
compound trigger
count binary_integer;
before statement is
begin
count:=0;
end before statement;
after each row is
begin
count :=count +1;
end after each row;
after statement is
begin
if count > 0 then
raise_application_error( -20001,'Update/insert operation can not be completed ');
end if;
end after statement;
end cleaner_before_update;
/
can anyone help me figure out what is the problem here and way to fix it.
thanks in advance.
Even after compilation of the code it is giving me this error.
ORA-06512: at "SYSTEM.CLEANER_BEFORE_UPDATE_INSERT", line 18
ORA-04088: error during execution of trigger
'SYSTEM.CLEANER_BEFORE_UPDATE_INSERT'
There are couple of problems with your TRIGGER block.
The name of the Trigger cleaner_before_update_insert does not match with the cleaner_before_update after the final end statement.
COUNT is an SQL keyword which is not allowed to be used as a variable in PL/SQL.You would receive the error - Error(10,11): PLS-00204: function or pseudo-column 'COUNT' may be used inside a SQL statement only
So, here is the modified code.
CREATE OR REPLACE TRIGGER cleaner_before_update_insert FOR UPDATE OR
INSERT ON cleaner compound TRIGGER
v_count binary_integer;
before STATEMENT
IS
BEGIN
v_count:=0;
END before STATEMENT;
AFTER EACH row
IS
BEGIN
v_count :=v_count +1;
END AFTER EACH row;
AFTER STATEMENT
IS
BEGIN
IF v_count > 0 THEN
raise_application_error( -20001,'Update/insert operation can not be completed ');
END IF;
END AFTER STATEMENT;
END cleaner_before_update_insert;
/

How to remove extra information form error message after executing a package body?

I want to remove extra information form error message after executing a package body.
Example:
If I run a anonymous block then the error message come like -
ERROR at line 1:
ORA-20010: Object ID PE556092 is not Produced by the Template TP000036
ORA-06512: at "EXAMPLE.TESTPROC", line 5
ORA-06512: at line 1
But i want to show only the below error message:
ORA-20010: Object ID PE556092 is not Produced by the Template TP000036
You can use the below to get the Error Code and Message respectively:
dbms_output.put_line('Error code: '||sqlcode);
dbms_output.put_line('Error msg: '||sqlerrm);
Read more about SQLERRM.
You can do that by defining an exception and mapping it to the SQLCODE of the raised error. Then you handle the logic in the exception handler.
Example, here I map to error -20010 (the one you are using):
declare
err_obj_not_produced exception;
pragma exception_init (err_obj_not_produced, -20010);
l_object varchar2 (50);
l_template varchar2 (50);
begin
run_your_code ('With values');
exception
when err_obj_not_produced then
return 'Object ID ' || l_object || ' is not Produced by the Template ' || l_template;
end;
Another one way to hide information about previous errors. Suppose you have two procedures:
create or replace procedure proc1 is
begin
raise no_data_found;
end;
/
create or replace procedure proc2 is
begin
proc1;
exception
when no_data_found then
raise_application_error(-20010, 'There is no spoon, Neo.');
end;
/
when you run a block in SQL*Plus, you get:
SQL> begin
proc2;
end;
/
begin
*
ERROR at line 1:
ORA-20010: There is no spoon, Neo.
ORA-06512: at "DEV.PROC2", line 6
ORA-06512: at line 2
You can change proc2 like this:
create or replace procedure proc2 is
begin
proc1;
end;
/
And call it like this with desired result:
SQL> begin
begin
proc2;
exception
when no_data_found then
raise_application_error(-20010, 'There is no spoon, Neo.', false);
end;
exception
when others then
dbms_output.put_line(SQLERRM);
end;
/
ORA-20010: There is no spoon, Neo.
PL/SQL procedure successfully completed.
This example shows how third parameter of raise_application_error procedure works. If you pass false, procedure deletes information about previously raised exceptions from error stack. It also will be impossible to get this information using dbms_utility.format_error_backtrace.
As Jon Heller noticed in comments, hiding information about exceptions is a bad practice (and using when others then without raise too, as Jeffry Kemp noticed), so, I hope you know what you are doing. This way or another, it is a shooting yourself in the foot.

Highest record in PL/SQL

I have created a query that displays highest returned items from a table. My query it works perfectly with no errors! However, I want an efficient way of converting the query to PL/SQL block. The purpose of conversion is to handle errors.
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (
SELECT MAX(ITEM_NUM) FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
Here's a way we do some exception handling in packages. I altered it to use your code as an example. Maybe you can use some ideas from it.
At the top, set a CONSTANT to the name of the procedure, and some variables to catch Oracle SQL error number and message in. Then in the body of the procedure, there is an anonymous block containing the select. First we set a variable to indicate where we are (err_loc) in case there are multiple locations where an error could be caught in one block. Then the select is issued. If an error occurs, it's caught by the EXCEPTION clause. Error info from Oracle is caught in the err* variables, the err_string is built and then emailed via the UTL_MAIL package. RAISE raises the error so the program halts. It's set up like this to be generic as possible, we can drop in the template, change the MBR_NAME, SQL, err_loc and that's it.
PROCEDURE TEST_PROC AS
MBR_NAME CONSTANT VARCHAR2(100) := 'TEST_PROC'; -- For use in error handling. Package member name.
err_nbr NUMBER; -- Holds a SQL error number if an exception occurs.
err_msg VARCHAR2(1000); -- Holds a SQL error message if an exception occurs.
err_string VARCHAR2(2000);
BEGIN
BEGIN
err_loc := 'Selecting max quantity'; -- Email subject
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (SELECT MAX(ITEM_NUM)
FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
EXCEPTION
WHEN OTHERS THEN
err_nbr := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 1000);
err_string := 'ERROR: ' || err_nbr || ' occurred: ' || err_msg;
-- PKG_NAME and err_email_recip set in the body.
UTL_MAIL.send(sender => PKG_NAME||'.'||MBR_NAME||'#yourcompany.com',
recipients => err_email_recip,
subject => 'ERROR '|| err_loc,
message => CHR(13))||err_string);
RAISE;
END;
END TEST_PROC;
Have a look at cursors and records.
That way you have fetch data from the query and process the line if needed.
I don't have a database by hand to test my code, but this might give you an idea how a cursor and record work.
In order to capture a EXCEPTION you could add an exception handler and let it log the record you where busy with when the exception occured.
DECLARE
CURSOR CursorName IS
SELECT ColumnOne
FROM TableA
WHERE Name = 'Me';
RecordNumber CursorName%ROWTYPE;
BEGIN
-- Fetch the records from the cursor.
OPEN CursorName;
LOOP
FETCH CursorName INTO RecordNumber;
-- Do something with the record.
EXIT WHEN CursorName %NOTFOUND;
END LOOP;
CLOSE CursorName;
END;
/
Adding a error handeling would be done right above END:
EXCEPTION
WHEN OTHERS THEN
-- Log error message.
END;
/
Link: Error handeling
Does that answer you question a bit?

oracle 10g ddl auditing: ora-00604 error occurred at recursive sql on dbms_metadata

I want to audit all new tables created in my database by the application team.
The sql_text column of dba_audit_trail is empty, so I created a procedure and trigger.
CREATE TABLE bhattd.ddl_logger (
obj_operation varchar2(25),
obj_owner varchar2(25),
obj_name varchar2(25),
obj_type varchar2(25),
obj_text clob,
obj_when timestamp);
CREATE OR REPLACE PROCEDURE get_ddl (o_name varchar2, o_owner varchar2, l_sysevent varchar2) authid current_user IS
count_tab number;
BEGIN
SELECT COUNT(*) INTO count_tab FROM sys.dba_tables WHERE table_name = o_name and owner = o_owner;
IF count_tab = 1 THEN
INSERT INTO bhattd.ddl_logger VALUES (l_sysevent, o_owner, o_name, 'TABLE', sys.dbms_metadata.get_ddl('TABLE',o_name,o_owner), systimestamp);
END IF;
END;
1st question: If I create a table in my own schema (bhattd) then the procedure works without "authid current_user". If I execute
get_ddl('S_UCM_PRIVACY','SIEBEL','CREATE');
then it fails unless I include "authid current_user" in the procedure definition, even though I have the DBA role. Why is this happening?
Next, I created the trigger:
CREATE OR REPLACE TRIGGER ddl_trigger1 AFTER CREATE ON DATABASE
DECLARE
l_sysevent varchar2(25);
BEGIN
SELECT ora_sysevent INTO l_sysevent FROM dual;
IF ( l_sysevent = 'CREATE' )
THEN
BEGIN
bhattd.get_ddl(ora_dict_obj_name,ora_dict_obj_owner,l_sysevent);
END;
END IF;
END;
Now, if I try to create a table under schema "SCOTT", I get this error:
ORA-00604: error occurred at recursive SQL level 1
ORA-31603: object "T1" of type TABLE not found in schema "SCOTT"
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 105
ORA-06512: at "SYS.DBMS_METADATA", line 2806
ORA-06512: at "SYS.DBMS_METADATA", line 4333
ORA-06512: at line 1
ORA-06512: at "BHATTD.GET_DDL", line 8
ORA-06512: at line 8
2nd question: I think it should have worked without "authid current_user" based on definer's rights. Then after adding "authid current_user", I think this should work based on invoker's rights (I have the DBA role, which includes execute on dbms_metadata, plus I own the table, procedure, and trigger). Why is this happening?
Thank you in advance for your response.

How to retrieve calendaring expression from DB table

I am making a job with a determined repeat_interval. My goal was to retrieve this value from a table, so that I could change this value in the table afterwards and modify the job accordingly. For this, I made the following trigger:
CREATE OR REPLACE TRIGGER config_table_aur AFTER
UPDATE OF value ON config_table FOR EACH row WHEN (new.property = 'job_interval') DECLARE v_job NUMBER;
BEGIN
dbms_job.submit (v_job, 'begin
update_interval (' || :new.value || ');
end;');
END;
And this trigger calls the following procedure:
CREATE OR REPLACE
PROCEDURE update_interval(
p_new_interval IN config_table.value%type)
AS
BEGIN
dbms_scheduler.set_attribute ('jobu', 'repeat_interval', p_new_interval);
END update_interval;
Where p_new_interval is the value I'm retrieving from the table. The problem that I'm having is that if I try setting a value in the table like this:
FREQ=DAILY; INTERVAL=1;
Then I get an error saying:
Fila 1: ORA-06550: line 2, column 46:
PLS-00103: Encountered the symbol ";" when expecting one of the following:
year month day hour minute second
The symbol ";" was ignored.
ORA-06512: at "SYS.DBMS_JOB", line 82
ORA-06512: at "SYS.DBMS_JOB", line 140
ORA-06512: at "SOMESCHEMA.CONFIG_TABLE_AUR", line 3
ORA-04088: error during execution of trigger 'SOMESCHEMA.CONFIG_TABLE_AUR'
I guess the problem is that the attribute value contains semicolons ';' because if I don't use them I don't get the error.
Do you have any suggestions to circumvent this problem?
Thank you
I guess the problem is that the attribute value contains semicolons ';' because if I don't use them I don't get the error.
Do you have any suggestions to circumvent this problem?
Err ... Your question makes no sense. You know the problem but you don't want to fix the syntax error you have in the repeat_interval calendaring syntax ?
For this simple example your trigger looks unnecessary complex (but you might have a valid reason to use DBMS_JOB though). Here is an example that first sets a scheduled job to run at every minute on 30th second and then later changes the repeat_interval via configuration table to run every 10 seconds:
--
-- scheduler configuration via tailored config table
--
create table scheduler_config (
Job_name varchar2(100) not null,
repeat_interval varchar2(100) not null
);
insert into scheduler_config values('logger1', 'FREQ=SECONDLY; BYSECOND=30');
commit;
create or replace trigger scheduler_config_trg
after update of repeat_interval
on scheduler_config
for each row
declare
pragma autonomous_transaction;
begin
-- Note: throws an exception if no such job
dbms_scheduler.set_attribute(name => :new.job_name,
attribute => 'repeat_interval',
value => :new.repeat_interval);
end;
/
show errors
--
-- a simple job we want to schedule
--
create table scheduler_log (
job_name varchar2(100),
time timestamp(3),
text varchar2(4000)
);
begin
dbms_scheduler.create_job(
job_name => 'logger1',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN insert into scheduler_log values(''logger1'', systimestamp, ''Executed!''); commit; END;',
start_date => systimestamp,
repeat_interval => 'FREQ=SECONDLY; BYSECOND=30',
end_date => null,
enabled => true,
comments => 'Testing configuration');
end;
/
--
-- check how much work has been done and when
--
col job_name for a10
col time for a25
col text for a20
select * from scheduler_log order by time;
--
-- I want more job for my money !
--
update scheduler_config
set repeat_interval = 'FREQ=SECONDLY; INTERVAL=10'
where job_name = 'logger1';
commit;
--
-- remove the job
--
exec dbms_scheduler.drop_job('logger1')

Resources