advanced queuing for table replication to other database - oracle

So, I am trying to replicate the data in tables to another database using Advanced Queuing. I created a table on both databases:
create table test
(
id number(10) primary key,
text varchar2(100)
);
then I created the queue
create type table_repli_payload_type AS OBJECT
( rowid_record varchar2(100)
, tabelle VARCHAR2(255)
, schema VARCHAR2(50)
);
begin
SYS.DBMS_AQADM.create_queue_table(queue_table => 'table_repli_queue_table',
queue_payload_type => 'table_repli_payload_type',
multiple_consumers => TRUE);
SYS.DBMS_AQADM.CREATE_QUEUE (
queue_name => 'table_repli_queue',
queue_table => 'table_repli_queue_table'
);
SYS.DBMS_AQADM.START_QUEUE (
queue_name => 'table_repli_queue'
);
end;
wrote a procedure for the replication
create or replace procedure table_repli_callback(
context RAW,
reginfo SYS.AQ$_REG_INFO,
descr SYS.AQ$_DESCRIPTOR,
payload RAW,
payloadl NUMBER
) AS
r_dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T;
r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
o_payload table_repli_payload_type;
v_error varchar2(4000);
BEGIN
insert into log_table values(sysdate, 'start table_repli_callback');
r_dequeue_options.msgid := descr.msg_id;
r_dequeue_options.consumer_name := descr.consumer_name;
DBMS_AQ.DEQUEUE(
queue_name => descr.queue_name,
dequeue_options => r_dequeue_options,
message_properties => r_message_properties,
payload => o_payload,
msgid => v_message_handle
);
insert into log_table values(sysdate, 'ROWID: '||o_payload.rowid_record);
merge into test#test_link a
using (select * from test where rowid=o_payload.rowid_record) b on (a.id=b.id)
when matched then
update set text=b.text
when not matched then
insert values(b.id, b.text);
COMMIT;
exception
when others then
v_error:=sqlerrm;
insert into log_table values(sysdate, 'ERROR: '||v_error);
commit;
END;
/
and subscribed it
BEGIN
DBMS_AQADM.ADD_SUBSCRIBER (
queue_name => 'table_repli_queue',
subscriber => SYS.AQ$_AGENT(
'table_repli_queue_subscriber',
NULL,
NULL )
);
DBMS_AQ.REGISTER (
SYS.AQ$_REG_INFO_LIST(
SYS.AQ$_REG_INFO(
'table_repli_queue:table_repli_queue_subscriber',
DBMS_AQ.NAMESPACE_AQ,
'plsql://table_repli_callback',
HEXTORAW('FF')
)
),
1
);
END;
/
I played around with inserting/updating data in the TEST-table and than executing(with changing ids) this Code
DECLARE
r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
o_payload table_repli_payload_type;
v_rowid_record varchar2(100);
BEGIN
select rowid
into v_rowid_record
from test
where id=2;
o_payload := table_repli_payload_type(
v_rowid_record, '', ''
);
DBMS_AQ.ENQUEUE(
queue_name => 'table_repli_queue',
enqueue_options => r_enqueue_options,
message_properties => r_message_properties,
payload => o_payload,
msgid => v_message_handle
);
COMMIT;
END;
/
It's pretty random if it is working. He always seems to write something into TABLE_REPLI_QUEUE_TABLE, but when it is gone, about half the time there doesn't appear anything in LOG_TABLE and the data in the second database hasn't changed.

The error was a strange behavior in TOAD.
I sometimes write test scripts, with ddl, dml, selects, pl/sql-blocks in it and execute them by placing my cursor in a part of the desired command and press shift+F9. It seems like my TOAD just didn't execute the PL/SQL-block although it told me, it did.
I put the PL/SQL-block in another tab and just hit F9 and it worked fine, every time.

Related

unable to call main procedure from wrapper procedure asynchronously

I want to call main procedure from the wrapper procedure. Wrapper procedure I'm able to output with dbms output print line but I'm unable to print within the main proc, looks like the main proc is not called from wrapper procedure. Please help me
Below is the table script
CREATE TABLE ASYNC_SAMPLE_TAB
( attribute1 varchar2(50),
attribute2 varchar2(50)
);
Below is my package specification
CREATE OR REPLACE PACKAGE XX_ASYNC_DEMO_PKG
IS
PROCEDURE MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
);
PROCEDURE WRAPPER_MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
);
END XX_ASYNC_DEMO_PKG;
Below is my package bofy
CREATE OR REPLACE PACKAGE BODY XX_ASYNC_DEMO_PKG
IS
PROCEDURE WRAPPER_MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('-- START OF WRAPPER PROC---' || SYSTIMESTAMP);
dbms_scheduler.create_job(
job_name => 'ASYNC_MAIN_PROC' || '_' || attribute1,
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN
MAIN_PROC(''' || attribute1 || ''', ''' || attribute2 || ''');
END;',
start_date => systimestamp ,
auto_drop => true,
enabled => true
);
DBMS_OUTPUT.PUT_LINE('-- END OF WRAPPER PROC---' || SYSTIMESTAMP);
END;
PROCEDURE MAIN_PROC(
attribute1 IN VARCHAR2,
attribute2 IN VARCHAR2
)
AS
sql_stmt VARCHAR2(200);
BEGIN
DBMS_OUTPUT.PUT_LINE('-- START OF MAIN PROC---' || SYSTIMESTAMP);
DBMS_SESSION.sleep(10);
sql_stmt := 'INSERT INTO ASYNC_SAMPLE_TAB VALUES (:1, :2)';
EXECUTE IMMEDIATE sql_stmt USING attribute1, attribute2;
DBMS_OUTPUT.PUT_LINE('-- END OF MAIN PROC---' || SYSTIMESTAMP);
END;
END XX_ASYNC_DEMO_PKG;
Below is the command with which I'm trying to test above solution
exec XX_ASYNC_DEMO_PKG.WRAPPER_MAIN_PROC('Test101_1', 'Test101_2');
As described in the documentation, the main purpose of DBMS_OUTPUT is debug messages to trace execution flow. It's also said there that it doesn't immediately return anything to the caller, but text is placed into the buffer and may be retrieved from there by the caller or the program itself (though, you cannot "get into" any other program flow and get anything from the executing code until the called unit is complete).
Scheduler doesn't retrieve the content of the buffer after it completes the job, so DBMS_OUTPUT.PUT* called inside a background job has no effect and you cannot see any result.
You may use some logging table (with separate logging procedure executed in autonomous transaction not to have an influence or be influenced by the main transaction) or external file and UTL_FILE to send results here. Or use a general table that should be processed by the job and check results after it finishes.
UPD:
Below is a complete setup to demonstrate how to pass parameters to a callable and see its results.
We'll log results into this table:
create table log_table (
ts timestamp,
val number,
job_name varchar2(30)
)
Then this procedure will be used to perform an action:
create or replace procedure proc_insert(
p_val in number,
p_job_name in varchar2
) as
begin
insert into log_table(ts, val, job_name)
values (systimestamp, p_val, p_job_name);
commit;
end;
This procedure will call our action procedure in a background job. We need to specify a number of parameters to override default values in a callable when creating a job. And then use DBMS_SCHEDULER.SET_JOB_[ARGUMENT|ANYDATA]_VALUE depending on the parameter type.
create or replace procedure proc_insert_async(
p_call_id varchar2,
p_val number,
r_job_name out varchar2
) as
l_job_prefix constant varchar2(20) := 'LOG_TABLE_';
l_job_name varchar2(100) := l_job_prefix || p_call_id;
begin
dbms_scheduler.create_job(
job_name => l_job_name,
job_type => 'STORED_PROCEDURE',
/*Callable unit - out API procedure*/
job_action => 'TEST_EAS.PROC_INSERT',
/*Number of args to be passed to the proc*/
number_of_arguments => 2,
/*Run immediately*/
start_date => sysdate,
enabled => false,
auto_drop => true
);
/*Pass parameters to the callable*/
dbms_scheduler.set_job_anydata_value (
job_name => l_job_name,
argument_position => 1,
argument_value => sys.anydata.convertNumber(p_val)
);
dbms_scheduler.set_job_argument_value(
job_name => l_job_name,
argument_position => 2,
argument_value => l_job_name
);
/*Start job*/
dbms_scheduler.enable(
name => l_job_name
);
r_job_name := l_job_name;
end;
Finally, test this in action (sleep is added due to async nature of inserts to wait for results).
declare
l_job_name varchar2(100);
begin
proc_insert_async(
p_call_id => 'test1',
p_val => 1,
r_job_name => l_job_name
);
dbms_output.put_line(l_job_name);
proc_insert_async(
p_call_id => 'test2',
p_val => 10,
r_job_name => l_job_name
);
dbms_output.put_line(l_job_name);
dbms_session.sleep(3);
end;
/
LOG_TABLE_test1
LOG_TABLE_test2
PL/SQL procedure successfully completed.
select *
from log_table
TS
VAL
JOB_NAME
25.11.22 10:52:37,310403000
10
LOG_TABLE_test2
25.11.22 10:52:37,302992000
1
LOG_TABLE_test1

how to create a export table job in oracle 12c

I want to create a export table job, but I can't understand why its not working.
my table is Department
create table department (id number, name varchar2(200));
I want to export a csv file for per day at 9:00 pm. I need to create it.
I only know:
0. create a directory
create a PROCEDURE
create a DBMS_SCHEDULER.CREATE_PROGRAM
create a DBMS_SCHEDULER.CREATE_SCHEDULE
create a DBMS_SCHEDULER.CREATE_JOB
excute the job
thanks
Yes, you can use DBMS_SCHEDULER by creating in such a way
DECLARE
v_job_name VARCHAR2(32) := 'jb_exp_emp_data';
BEGIN
DBMS_SCHEDULER.CREATE_JOB(job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'exp_emp_data',
start_date => TO_DATE('11-12-2021 21:00:10',
'DD-MM-YYYY HH24:MI:SS'),
repeat_interval => 'FREQ=DAILY; BYHOUR=21;',
auto_drop => false,
comments => 'Exports the content of the department table every day at 9:00PM o''clock ');
DBMS_SCHEDULER.ENABLE(v_job_name);
END;
/
that starts at the time defined by the start_date parameter, then repeats on every upcoming days at 9pm in the future.
I followed the steps below and it was successful ...
Create a directory (path of export file):
CREATE OR REPLACE DIRECTORY CSVDIR AS 'D:\';
Create a procedure:
Create Or Replace Procedure exp_emp_data Is
today varchar2(200);
fileName varchar2(200);
n_file utl_file.file_type;
v_string Varchar2(4000);
Cursor c_emp Is
Select
id, name
From
department;
Begin
select to_char(sysdate,'yyyymmdd','nls_calendar=persian') into today from dual;
fileName := 'empdata' || today || '.csv';
n_file := utl_file.fopen('CSVDIR', fileName, 'w', 4000);
v_string := 'ID, Name';
utl_file.put_line(n_file, v_string);
-- open the cursor and concatenate fields using comma
For cur In c_emp Loop
v_string := cur.id
|| ','
|| cur.name;
-- write each row
utl_file.put_line(n_file, v_string);
End Loop;
-- close the file
utl_file.fclose(n_file);
Exception
When Others Then
-- on error, close the file if open
If utl_file.is_open(n_file) Then
utl_file.fclose(n_file);
End If;
End;
/
-------- Test
Begin
exp_emp_data;
End;
/
Create a program:
BEGIN
DBMS_SCHEDULER.CREATE_PROGRAM (
program_name => 'PROG_EXPORT_TABLE',
program_action => 'exp_emp_data',
program_type => 'STORED_PROCEDURE');
END;
/
Create a job:
BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'JOB_EXPORT_TABLE',
job_type => 'STORED_PROCEDURE',
job_action => 'PROG_EXPORT_TABLE',
start_date => '16-nov-2021 11:50:00 pm',
repeat_interval => 'FREQ=DAILY;BYHOUR=23;BYMINUTE=59',
enabled => true
);
END;
/
And enabled it:
exec dbms_scheduler.enable('JOB_EXPORT_TABLE');

Using APEX_DATA_EXPORT to store PDF files in DB

I am trying to figure out how to use APEX_DATA_EXPORT API to store PDF file in database table. I created a table with one column as a blob.
Has anyone tried to use APEX_DATA_EXPORT to store data in database?
DECLARE
l_context apex_exec.t_context;
l_export apex_data_export.t_export;
BEGIN
apex_session.create_session (
p_app_id => 130408,
p_page_id => 1,
p_username => 'EXAMPLE USER' );
l_context := apex_exec.open_query_context(
p_location => apex_exec.c_location_local_db,
p_sql_query => 'select * from emp' );
l_export := apex_data_export.export (
p_context => l_context,
p_format => nvl(:format, apex_data_export.c_format_pdf),
p_file_name => 'employees' );
apex_exec.close( l_context );
apex_data_export.download(
p_export => l_export,
--p_content_disposition => apex_data_export.c_inline,
p_stop_apex_engine => false);
insert into pdf_test4 (pdf) values l_export;
EXCEPTION
when others THEN
apex_exec.close( l_context );
raise;
END;
I managed to get it working for Excel so I guess it would work the same for pdf (change p_format)
DECLARE
v_sql varchar2(32000) := 'select * from my_data_table';
v_sql_trimmed varchar2(32000);
l_query_output CLOB;
p_file_id number;
l_file_name varchar2(200) := 'My File - '||sysdate;
p_status varchar2(100);
p_tag_id number;
l_context apex_exec.t_context;
l_export apex_data_export.t_export;
BEGIN
begin
l_context := apex_exec.open_query_context(
p_location => apex_exec.c_location_local_db,
p_sql_query => v_sql );
l_export := apex_data_export.export (
p_context => l_context,
p_format => apex_data_export.c_format_xlsx,
p_file_name => l_file_name );
apex_exec.close( l_context );
insert into my_files_table columns (file_blob,filename,file_mimetype,TAG,LOG,TAG_ID) values (l_export.content_blob , l_export.file_name,l_export.mime_type,'Latest','Y',1);
EXCEPTION
when others THEN
apex_exec.close( l_context );
raise;
END;
end;

Updating blob shows PL/SQL success but no content change

Attempting to update pictures in a blob column for multiple rows, I receive successful messages with no error and yet changes have not been rendered. I restarted Oracle service and machine and still nothing propagated. Yes, as shown I am committing and I have tried only one blob to no avail.
Is it the temporary dest_lob object? The readonly type? Do I have to release the temp blob?
Is it the appropriate schema not set? I am calling it with schema user.
Do previous blob content have to be NULL? The Hamlet.jpg attempt (ID = 101) maintains NULL in Picture blob column.
Is it a caching issue with Oracle? Do I have to refresh something like the tablespace file?
Is it the multiple BEGIN ... END calls?
Table
SQL > desc Characters;
Name Null? Type
----------------------------------------------------------------
ID NOT NULL NUMBER(5)
CHARACTER VARCHAR2(255 CHAR)
DESCRIPTION VARCHAR2(1000 CHAR)
SOURCE VARCHAR2(255 CHAR)
QUOTE VARCHAR2(1500 CHAR)
PICTURE BLOB
LINKIMAGE VARCHAR2(255 CHAR)
PL-SQL
CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 15;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82;
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
END;
/
sqlplus command line call (of above script)
SQL> #/path/to/script.sql
Console Output
Directory created.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
SQL Blob data check
SELECT ID FROM Characters
WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR
DBMS_LOB.GETLENGTH(Picture) IS NULL;
Output
ID
----------
15
44
82
101
Environment
Ubuntu 16.04 LTS, 64-bit
Intel Celeron, 4-processor, 64-GB HD, 2-GB RAM
Oracle 11g Express:
SQL > select * from v$version
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
With help from this other forum thread, I found my issue. Instead of using the following LOB methods:
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
Simply replace with the FILE version and remove the CREATETEMPORARY():
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
And in hindsight this makes somewhat sense since I am reading form a file object, src_bfile, and not an actual blob object.
With the following updated PL/SQL routine, blob columns successfully render.
CREATE OR REPLACE DIRECTORY MY_DIR AS '/path/to/pictures';
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'HenryCorwin.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 44 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'CGreen.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 15 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'SevenOfNine.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 82 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
Also, if blob column is NULL like my Hamlet.jpg attempt the above procedure will fail with
ORA-06502: PL/SQL: numeric or value error: invalid LOB locator
specified:
ORA-22275 ORA-06512: at "SYS.DBMS_LOB", line 928 ORA-06512:
at line 7
To resolve, update with EMPTY_BLOB() prior to updating the blob with the intended object.
UPDATE CHARACTERS SET Picture = EMPTY_BLOB() WHERE ID = 101;
DECLARE
src_bfile BFILE := BFILENAME('MY_DIR', 'Hamlet.jpg');
dest_blob BLOB;
BEGIN
SELECT PICTURE into dest_blob FROM CHARACTERS WHERE ID = 101 FOR UPDATE;
DBMS_LOB.FILEOPEN(src_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.FILECLOSE(src_bfile);
COMMIT;
END;
/
Successful messages render and final query returns a sight to sore eyes:
SQL > SELECT ID FROM Characters WHERE DBMS_LOB.GETLENGTH(Picture) = 0 OR DBMS_LOB.GETLENGTH(Picture) IS NULL;
no rows selected
SQL > SQL> SELECT DBMS_LOB.GETLENGTH(Picture) FROM Characters WHERE ID IN (15, 44, 82, 101);
DBMS_LOB.GETLENGTH(PICTURE)
---------------------------
365256
412300
381586
404241
I'll suggest you do an dbms_lob.erase, which seems to be necessary:
SELECT PICTURE INTO dest_blob FROM CHARACTERS WHERE ID = 15
FOR UPDATE;
dest_length := DBMS_LOB.GETLENGTH(dest_blob);
IF dest_length <> 0 THEN
DBMS_LOB.ERASE(dest_blob,dest_length,1);
END IF;
-- then do as you wrote:
DBMS_LOB.OPEN(src_bfile, DBMS_LOB.LOB_READONLY);
DBMS_LOB.CREATETEMPORARY( dest_blob, TRUE);
DBMS_LOB.LoadFromFile( DEST_LOB => dest_blob,
SRC_LOB => src_bfile,
AMOUNT => DBMS_LOB.GETLENGTH(src_bfile) );
DBMS_LOB.CLOSE(src_bfile);
COMMIT;
Hope this helps (stolen from here)

Selecting an oracle xmltype table field into an xmltype variable results in a null object

This has been bugging me for a while. I'm using oracle streams to write messages to an oracle AQ queue as part of a stored procedure. Below is the stored proc with relevent sections shown:
CREATE OR REPLACE PROCEDURE ESBEVENT.esb_dml_handler(in_any IN ANYDATA) IS
l_enqueue_options dbms_aq.enqueue_options_t;
l_message_properties dbms_aq.message_properties_t;
l_message sys.aq$_jms_text_message;
l_msgid raw(16);
l_xmlmsg SYS.XMLTYPE;
err_num NUMBER;
err_msg VARCHAR2(100);
BEGIN
BEGIN
l_message := sys.aq$_jms_text_message.construct;
l_xmlmsg := DBMS_STREAMS.CONVERT_LCR_TO_XML(in_any);
l_message.set_text(l_xmlmsg.getClobVal());
dbms_aq.enqueue
( queue_name => 'esbevent.esb_jms_queue'
, enqueue_options => l_enqueue_options
, message_properties => l_message_properties
, payload => l_message
, msgid => l_msgid
);
COMMIT;
err_num := '';
err_msg := 'Message Queued Successfully';
EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 1000);
INSERT INTO esbevent.esb_dml_handler_error_t VALUES (SYSDATE, err_num||' - '||err_msg );
END;
INSERT INTO esbevent.esb_jms_msg_memento_t VALUES (esb_jms_msg_memento_seq.nextval, SYSDATE, l_xmlmsg, err_num||' - '||err_msg );
COMMIT;
END;
Following the enqueue I store the message that was sent as an XMLTYPE in the table esb_jms_msg_memento_t. This is to enable resends if we have issues in subsequent processing. I'm now trying to write a block that will extract the XMLTYPE field data and write it again to the AQ. This is currently as follows:
DECLARE
l_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
l_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
l_message SYS.aq$_jms_text_message;
l_msgid RAW (16);
l_xmlmsg XMLTYPE;
BEGIN
SELECT msg_payload
INTO l_xmlmsg
FROM esb_jms_msg_memento_t
WHERE UNIQUE_ID = '815929';
l_message.set_text (l_xmlmsg.getClobVal ()); --null self error here
DBMS_AQ.enqueue (queue_name => 'esbevent.esb_jms_queue',
enqueue_options => l_enqueue_options,
message_properties => l_message_properties,
payload => l_message,
msgid => l_msgid);
COMMIT;
END;
When i run this I get the error:
ORA-30625: method dispatch on NULL SELF argument is disallowed
ORA-06512: at line 22
It appears I can insert and XMLTYPE variable to an XMLTYPE field but not the other way around???
As soon as I post I solve it...
forgot to construct the l_message:
l_message := sys.aq$_jms_text_message.construct;
doh!

Resources