Question

Good Afternoon.

I have been working with Oracle Advanced Queues to create a messaging system that we can use to determine when new lines are passed into the databse, when updates occur and when deletes occur.

I am using a single consumer queue and using correlations to control what data is looked for at certain times and my payload is of xmltype.

To generate the xml, I originally was using an xmlsequence to generate the message as below.

<MESSAGE>
<LOCATIONS>
  <LOCATION_ID>9999</LOCATION_ID>
  <LOC_TYPE>S</LOC_TYPE>
  <NAME>Test Location</NAME>
  <RETAILER_UNIT_CODE>T&amp;L</RETAILER_UNIT_CODE>
  <REGION_CODE>SA</REGION_CODE>
  <DELETE_FLAG>N</DELETE_FLAG>
  <EXTERNAL_WHSE_FLAG>N</EXTERNAL_WHSE_FLAG>
  <CREATED_BY>SYSADMIN</CREATED_BY>
  <CREATED_DATE>04/MAR/08</CREATED_DATE>
  <STATE_CODE>SA</STATE_CODE>
  <ADDRESS>223 Road Ridsonville</ADDRESS>
  <POSTCODE>1234</POSTCODE>
  <PHONE_NUM>08 </PHONE_NUM>
  <LAST_MODIFIED_BY>SYSADMIN</LAST_MODIFIED_BY>
  <LAST_MODIFIED_DATE>21/APR/09</LAST_MODIFIED_DATE>
  <POS_CODE>TRANS</POS_CODE>
  <SOP_FLAG>N</SOP_FLAG>
</LOCATIONS>
</MESSAGE>

However, it has come to my attention that xmlsequence leaves out null elements, which is not ideal, as when it comes time for the messages to be picked up at the other end, they cannot be mapped on data field easily. To try and work around this, I have tried to employ the use of DBMS_XMLGEN within my trigger, as it allows the handling of nulls in exactly the way I would want it handled.

ctx := dbms_xmlgen.newContext('SELECT * FROM LOCATIONS WHERE LOCATION_ID = ' || :new.LOCATION_ID);
dbms_xmlgen.setrowsettag(ctx, 'MESSAGE');
dbms_xmlgen.setrowtag(ctx, 'LOCATIONS');
dbms_xmlgen.setnullhandling(ctx, dbms_xmlgen.EMPTY_TAG);
l_xml:=dbms_xmlgen.getxmltype(ctx);

The problem with this approach is that it will generate an exception, as it is trying to operate on the same table that the trigger has been executed from.

ORA-04091: table RIT.LOCATIONS is mutating, trigger/function may not see it

So I moved on to trying to use the new and old objects to get the data out and place it in to the context, but I am running in to a few hiccups with the values that are null, as they are playing havoc with my concatenating them in to the query string.

...
REFERENCING NEW AS NEW OLD AS OLD
for each row 
DECLARE
l_xml   xmltype;
ctx       dbms_xmlgen.ctxHandle;
begin
ctx := dbms_xmlgen.newContext('SELECT   '||:new.id||'as id, '||:new.nullfield||' as nullfield from dual');
dbms_xmlgen.setrowsettag(ctx, 'MESSAGE');
dbms_xmlgen.setrowtag(ctx, 'INT_CREDIT_CLAIMS');
dbms_xmlgen.setnullhandling(ctx, dbms_xmlgen.EMPTY_TAG);
l_xml:=dbms_xmlgen.getxmltype(ctx);
...
end;

So my question is: How can I go about solving this so that I can see my empty elements for my xml type?

I'm also open to suggestions along the way on how to solve it and will be checking back for any clarification requests.

Was it helpful?

Solution

to generate a simple row in XML you can use xmlelement:

SQL> CREATE TABLE emp AS SELECT * FROM scott.emp;

Table created

SQL> CREATE TABLE message (xml XMLTYPE);

Table created

SQL> CREATE OR REPLACE TRIGGER trg_b4_emp
  2     BEFORE UPDATE ON emp
  3     FOR EACH ROW
  4  BEGIN
  5     INSERT INTO message VALUES (
  6       xmlelement("MESSAGE",
  7           xmlelement("EMP",
  8              xmlelement("empno", :new.empno),
  9              xmlelement("comm", :new.comm)
 10           )
 11        )
 12     );
 13  END;
 14  /

SQL> update emp set comm=NULL;

14 rows updated

SQL> select * from message where rownum = 1;

XML
----------------------------------------------------------------
<MESSAGE><EMP><empno>7369</empno><comm></comm></EMP></MESSAGE>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top