Solved

Background job causing mutating table


Badge +4

Hi All,

I’m new to writing background jobs so I’m hoping that I’ve just messed something up, and there’s a relatively straightforward solution to my problem. For some background, we’ve found that when attaching a document to project connected PO, that the document is only connected to the PO line:

We would like it to also be connected to the corresponding Project and Activity. 

I initially created a custom event/action to do this:

But this gave me the mutating table error. 

When looking for a way to fix this, I saw several other posts that suggested creating a background job (which I haven’t done before). I tried to piece a background job together by looking at the posts I saw but I’m still getting a mutating table error, so I feel like I’m missing something.

Here’s the code that I’m trying to use:

DECLARE

--Custom Variables
var_key_ref varchar2(2000);
var_project_id varchar2(2000) :=purchase_order_line_part_api.get_project_id(regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 2, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]*)(\^)',1, 1, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 3, 'i', 2));
var_activity_seq varchar2(2000) :=purchase_order_line_part_api.get_ACTIVITY_SEQ(regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 2, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]*)(\^)',1, 1, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 3, 'i', 2));
var_key_ref_act varchar2(2000);
var_key_ref_proj VARCHAR2(2000);


--Deferred Call Variables
attr_ VARCHAR2(32000);
sql_msg_ VARCHAR2(32000);
stmt_ VARCHAR2(32000);
job_id_ NUMBER;
error_text_ VARCHAR2(2000);

BEGIN
BEGIN

select key_ref into var_key_ref from doc_reference_object where doc_class = '&NEW:DOC_CLASS' and doc_no = '&NEW:DOC_NO' and doc_sheet = '&NEW:DOC_SHEET' and doc_rev = '&NEW:DOC_REV' and lu_name like 'PurchaseOrderLine%';
select purchase_order_line_part_api.get_project_id(regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 2, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]*)(\^)',1, 1, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 3, 'i', 2)) into var_project_id from dual;
select purchase_order_line_part_api.get_ACTIVITY_SEQ(regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 2, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]*)(\^)',1, 1, 'i', 2), regexp_substr(var_key_ref,'(=)([^=\^]+)(\^)',1, 3, 'i', 2)) into var_activity_seq from dual;
select CONCAT(CONCAT('ACTIVITY_SEQ=','&VAR_ACTIVITY_SEQ'),'^') into var_key_ref_act from dual;
select CONCAT(CONCAT('PROJECT_ID=','&VAR_PROJECT_ID'),'^') into var_key_ref_proj from dual;


--PROJECT
Doc_Reference_Object_API.Create_New_Reference('&NEW:DOC_CLASS', '&NEW:DOC_NO', '&NEW:DOC_SHEET', '&NEW:DOC_REV', 'Activity' , CONCAT(CONCAT('ACTIVITY_SEQ=','&VAR_ACTIVITY_SEQ'),'^') , null , '001');

--ACTIVITY
Doc_Reference_Object_API.Create_New_Reference('&NEW:DOC_CLASS', '&NEW:DOC_NO', '&NEW:DOC_SHEET', '&NEW:DOC_REV', 'Project' , CONCAT(CONCAT('PROJECT_ID=','&VAR_PROJECT_ID'),'^') , null , '001');

END;


client_SYS.Clear_Attr(attr_);
Client_SYS.Add_To_Attr('DOC_CLASS','&NEW:DOC_CLASS', attr_);
Client_SYS.Add_To_Attr('DOC_NO','&NEW:DOC_NO', attr_);
Client_SYS.Add_To_Attr('DOC_SHEET','&NEW:DOC_SHEET', attr_);
Client_SYS.Add_To_Attr('DOC_REV','&NEW:DOC_REV', attr_);
Client_SYS.Add_To_Attr('LU_NAME','Activity', attr_);
Client_SYS.Add_To_Attr('KEY_REF','&var_key_ref_act', attr_);



Transaction_SYS.Deferred_Call(job_id_,'Fnd_Event_Action_API.Action_Executeonlinesql','PARAMETER',attr_,'Add object connections for Project and Activity to PURCHASE_ORD documents.');
END;

 

And I’m just looking for some pointers to get this cleaned up and working. It’d also be helpful if I knew what I was doing wrong so I can avoid making that mistake again in the future.

icon

Best answer by Mathias Dahl 3 May 2022, 17:50

View original

10 replies

Userlevel 7
Badge +30

What is causing the problem is the SELECT done against the same table (doc_reference_object) that the trigger is connected to. Luckily you don’t need that since you have access to all columns in the new record via the &NEW: place holders.

 

Badge +4

Thanks for the explanation, Mathias. I just want to make sure I’m tracking with what you’re saying. 

I initially put the SELECT in there because I need to get the KEY_REF from DOC_REFERENCE_OBJECT_TAB table in order to get the Project ID and Activity Sequence Number, and I'm not seeing KEY_REF listed as an available &NEW: field when my event uses DOCUMENT_ISSUE_HISTORY_TAB as it's table.

Would you suggest having the event use DOC_REFERENCE_OBJECT_TAB, rather than DOCUMENT_ISSUE_HISTORY_TAB, instead? I’m just sure how to get KEY_REF without a select statement.

Userlevel 7
Badge +30

My bad. I just assumed the trigger was against the doc object reference table since that would be most natural.

So, the mutating error probably comes from the fact that, when you call Doc_Reference_Object_API to create the new connection, that call in turn will insert a new history record in the history table which will make Oracle raise the mutating table error.

Now, there is a way to avoid the mutating table errors, as you have seen. I think you just have misunderstood how it should be done. So, the Transaction_SYS.Deferred_Call is what creates the background job. But from how it looks, you are not running your code in that background job. Your code is running before you create the background, a background job that, I think, does nothing 😁

I'll read up on that other post that explains how to do it, and come back with details.
 

Userlevel 7
Badge +30

Okay, found it!

@dsj wrote this nice article about different solutions to this problem:

https://dsj23.me/2021/08/27/tips-to-avoid-mutating-table-error-in-ifs-event-actions/

It’s the second option you are trying and, as I mentioned earlier, you have missed a small part of it :-) 

Look at the stmt_ variable there, what value it is given and how it is used in the later code lines.

Basically, your custom event will put the code to be run in that variable, then ask it to be run in a background job. So you need to convert your code into a string, basically. Will you be able to pull it off?

 

Badge +4

Thanks again, Mathias. I was looking at that and I see what you mean about stmt_. You’re thinking something like this?

DECLARE

--Deferred Call Variables
attr_ VARCHAR2(32000);
sql_msg_ VARCHAR2(32000);
stmt_ VARCHAR2(32000);
job_id_ NUMBER;
error_text_ VARCHAR2(2000);

BEGIN

stmt_ :='

DECLARE

--Custom Variables
var_key_ref varchar2(2000);
var_project_id varchar2(2000);
var_activity_seq varchar2(2000);

BEGIN

select key_ref into var_key_ref from doc_reference_object where doc_class = ''&NEW:DOC_CLASS'' and doc_no = ''&NEW:DOC_NO'' and doc_sheet = ''&NEW:DOC_SHEET'' and doc_rev = ''&NEW:DOC_REV'' and lu_name like ''PurchaseOrderLine%'';
select purchase_order_line_part_api.get_project_id(regexp_substr(var_key_ref,''(=)([^=\^]+)(\^)'',1, 2, ''i'', 2), regexp_substr(var_key_ref,''(=)([^=\^]*)(\^)'',1, 1, ''i'', 2), regexp_substr(var_key_ref,''(=)([^=\^]+)(\^)'',1, 3, ''i'', 2)) into var_project_id from dual;
select purchase_order_line_part_api.get_ACTIVITY_SEQ(regexp_substr(var_key_ref,''(=)([^=\^]+)(\^)'',1, 2, ''i'', 2), regexp_substr(var_key_ref,''(=)([^=\^]*)(\^)'',1, 1, ''i'', 2), regexp_substr(var_key_ref,''(=)([^=\^]+)(\^)'',1, 3, ''i'', 2)) into var_activity_seq from dual;


--PROJECT
Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Activity'' , CONCAT(CONCAT(''ACTIVITY_SEQ='',''&VAR_ACTIVITY_SEQ''),''^'') , null , ''001'');

--ACTIVITY
Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Project'' , CONCAT(CONCAT(''PROJECT_ID='',''&VAR_PROJECT_ID''),''^'') , null , ''001'');

END;';

sql_msg_ := Message_SYS.Construct('UPD');
Message_SYS.Add_Attribute(sql_msg_, 'SQL', stmt_);
Client_SYS.Clear_Attr(attr_);
Client_SYS.Add_To_Attr('SQL_DATA_', sql_msg_, attr_);
Client_SYS.Add_To_Attr('MSG_', '', attr_);
Transaction_SYS.Deferred_Call(job_id_,'Fnd_Event_Action_API.Action_Executeonlinesql','PARAMETER',attr_,'Add object connections for Project and Activity to PURCHASE_ORD documents.');
END;

This will run as a background job but it’s returning the following error:

ORA-01403: no data found
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 2025
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2313
ORA-01403: no data found
ORA-06512: at line 12
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2309
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2318
ORA-06512: at line 1
ORA-06512: at "SYS.DBMS_SQL", line 1721
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 2015
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 282
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 2025
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2313
ORA-06512: at line 12
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2309
ORA-06512: at "IFSAPP.FND_EVENT_ACTION_API", line 2318
ORA-06512: at line 1
ORA-06512: at "SYS.DBMS_SQL", line 1721
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 2015
ORA-06512: at "IFSAPP.TRANSACTION_SYS", line 282
ORA-06512: at "IFSAPP.DEFERRED_JOB_API", line 2080

 

Badge +4

I’ve narrowed the error down to this:

select key_ref into var_key_ref from doc_reference_object where doc_class = ''&NEW:DOC_CLASS'' and doc_no = ''&NEW:DOC_NO'' and doc_sheet = ''&NEW:DOC_SHEET'' and doc_rev = ''&NEW:DOC_REV'' and lu_name like ''PurchaseOrderLine%''

If I hard code the key_ref into my code then everything works. I’m just not sure why this is returning no data.

 

Edit: Nevermind. The problem was I did PurchaseOrderLine% when I should’ve just done PurchaseOrder.

Userlevel 7
Badge +30

Did you solve it now? If you got the background job to work you might want to consider switching to use doc_reference_object_tab as the table to trigger on. Then you can skip one of the select statements (you will have direct access to the key_ref column) and keep the code simpler.
 

Badge +4

Hi Mathias,

 

I did get everything to work as a background job. Thanks so much for your help!

I’m not totally over the finish line yet, though. I’m running into an issue where these snippets of code:

--PROJECT																															
Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Activity'' , CONCAT(CONCAT(''ACTIVITY_SEQ='',''&VAR_ACTIVITY_SEQ''),''^'') , null , ''001'');

--ACTIVITY
Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Project'' , CONCAT(CONCAT(''PROJECT_ID='',''&VAR_PROJECT_ID''),''^'') , null , ''001'');

Shows up in Database Background Job as:


-Doc_Reference_Object_API.Create_New_Reference('PURCHASE_ORD', '1725450', '1', '1', 'Activity' , var_activity_key , null , '001');
-
---ACTIVITY
-Doc_Reference_Object_API.Create_New_Reference('PURCHASE_ORD', '1725450', '1', '1', 'Project' , CONCAT(CONCAT('PROJECT_ID=','&VAR_PROJECT_ID'),'^') , null , '001');
-
-END;
MSG_

Basically, instead of returning the value of the &VAR_ACTIVITY_SEQ and &VAR_PROJECT_ID variables, IFS is returning &VAR_ACTIVITY_SEQ and &VAR_PROJECT_ID as literal values. 

Userlevel 7
Badge +30

Good to hear it's progressing! 😃

As for the problem, you can only use the &-syntax for variables you set up in the custom event definition. So, to take an example, for the variable var_activity_seq you should just use it as it is without anything around it.

So, instead of this:

Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Activity'' , CONCAT(CONCAT(''ACTIVITY_SEQ='',''&VAR_ACTIVITY_SEQ''),''^'') , null , ''001'');

You should use this:

Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Activity'' , CONCAT(CONCAT(''ACTIVITY_SEQ='',var_activity_seq),''^'') , null , ''001'');

Or even this (I think it's easier to not use the CONCAT function and use the concatenation operator || instead):

Doc_Reference_Object_API.Create_New_Reference(''&NEW:DOC_CLASS'', ''&NEW:DOC_NO'', ''&NEW:DOC_SHEET'', ''&NEW:DOC_REV'', ''Activity'' , ''ACTIVITY_SEQ='' || var_activity_seq || ''^'') , null , ''001'');

I hope I got that right. Did not test it…

 

Userlevel 7
Badge +30

@TODDUNCLIFFE 

Did that work out for you?

 

Reply