Backup procedure using Datapump API - plsql

Hi I try to create Oracle procedure which take backup from user schema (POSData) and place it in directory called "Backups", POSData grant read, write on directory "Backups" using this code from system user.
DECLARE
h2 NUMBER;
BEGIN
h2 := DBMS_DATAPUMP.OPEN('EXPORT', 'SCHEMA');
DBMS_DATAPUMP.ADD_FILE(h2,'POSData.dmp','Backups');
DBMS_DATAPUMP.METADATA_FILTER(h2,'SCHEMA_EXP','IN (''POSData'')');
DBMS_DATAPUMP.START_JOB(h2);
dbms_datapump.detach(h2);
END;
but I always get this error
Error starting at line : 1 in command -
DECLARE
h2 NUMBER;
BEGIN
h2 := DBMS_DATAPUMP.OPEN('EXPORT', 'SCHEMA');
DBMS_DATAPUMP.ADD_FILE(h2,'POSData.dmp','Backups');
DBMS_DATAPUMP.METADATA_FILTER(h2,'SCHEMA_EXP','IN (''POSData'')');
DBMS_DATAPUMP.START_JOB(h2);
dbms_datapump.detach(h2);
END;
Error report -
ORA-39001: invalid argument value
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 79
ORA-06512: at "SYS.DBMS_DATAPUMP", line 3507
ORA-06512: at "SYS.DBMS_DATAPUMP", line 3756
ORA-06512: at line 5
39001. 00000 - "invalid argument value"
*Cause: The user specified API parameters were of the wrong type or
value range. Subsequent messages supplied by
DBMS_DATAPUMP.GET_STATUS will further describe the error.
*Action: Correct the bad argument and retry the API.
help please?

DBMS_DATAPUMP has some really good error messages, but you have to dig in to get them. In the example below, I added a nested procedure output_expdp_error to dump the detailed message. You should of course modify this to do appropriate logging for your environment:
DECLARE
h1 NUMBER;
l_filename VARCHAR2( 100 ) := 'deleteme.dmp';
l_directory VARCHAR2( 100 ) := 'CIFS_DIR';
PROCEDURE output_expdpd_error( p_handle IN NUMBER ) AS
-- *******************************************************************
-- Output EXPDP Error
-- Purpose:
-- Send detailed EXPDP error to DBMS_OUTPUT
-- Modified:
-- 2020.03.02 - BFL Created
-- Notes:
-- Borrowed from: https://docs.oracle.com/database/121/SUTIL/GUID-5AAC848B-5A2B-4FD1-97ED-D3A048263118.htm#SUTIL977
-- *******************************************************************
l_status ku$_status; --ku$_jobstatus;
l_logentry ku$_logentry;
l_job_state VARCHAR2( 30 );
l_ind NUMBER;
l_pos NUMBER;
l_length NUMBER;
l_linesize CONSTANT NUMBER := 1000;
l_message VARCHAR2( 1000 );
BEGIN
-- Original had "if sqlcode = dbms_datapump.success_with_info_num" but this
-- hides some errors. Just always process the handle.
DBMS_OUTPUT.put_line( 'Data Pump job started with info available:' );
DBMS_DATAPUMP.get_status( p_handle
, DBMS_DATAPUMP.ku$_status_job_error
, 0
, l_job_state
, l_status );
IF (BITAND( l_status.mask, DBMS_DATAPUMP.ku$_status_job_error ) != 0)
THEN
l_logentry := l_status.error;
IF l_logentry IS NOT NULL
THEN
l_ind := l_logentry.FIRST;
WHILE l_ind IS NOT NULL
LOOP
l_pos := 1;
l_length := LENGTH( l_logentry( l_ind ).logtext );
l_length := CASE WHEN l_linesize < l_length THEN l_linesize ELSE l_length END;
WHILE l_length > 0
LOOP
l_message :=
SUBSTR( l_logentry( l_ind ).logtext
, l_pos
, l_length );
DBMS_OUTPUT.put_line( l_message );
l_pos := l_pos + l_linesize;
l_length := LENGTH( l_logentry( l_ind ).logtext ) + 1 - l_pos;
END LOOP;
l_ind := l_logentry.NEXT( l_ind );
END LOOP;
END IF;
END IF;
END;
BEGIN
DBMS_OUTPUT.put_line( 'open' );
h1 := DBMS_DATAPUMP.open( 'EXPORT', 'SCHEMA' );
DBMS_OUTPUT.put_line( 'add_file' );
DBMS_DATAPUMP.add_file( handle => h1
, filename => l_filename
, directory => l_directory
, filetype => DBMS_DATAPUMP.ku$_file_type_dump_file
, reusefile => 1 );
DBMS_OUTPUT.put_line( 'hr filter' );
DBMS_DATAPUMP.metadata_filter( h1
, 'SCHEMA_EXPR'
, 'IN (''BOGUS'')' );
DBMS_OUTPUT.put_line( 'BOGUS filter' );
DBMS_DATAPUMP.metadata_filter( h1
, 'SCHEMA_EXPR'
, 'IN (''BOGUS'')' );
DBMS_OUTPUT.put_line( 'start_job' );
DBMS_DATAPUMP.start_job( h1 );
DBMS_DATAPUMP.detach( h1 );
EXCEPTION
WHEN OTHERS
THEN
DECLARE
l_message VARCHAR2( 1000 );
BEGIN
output_expdpd_error( p_handle => h1 );
DBMS_DATAPUMP.detach( h1 );
l_message :=
SUBSTR(
SQLERRM
|| UTL_TCP.crlf
|| DBMS_UTILITY.format_error_backtrace
|| UTL_TCP.crlf
|| UTL_TCP.crlf
, 1
, 1000 );
DBMS_OUTPUT.put_line( l_message );
raise_application_error( -20000, l_message );
END;
END;
When I ran this with the non-existent schema, I got the wonderfully specific error message:
ORA-39001: invalid argument value
ORA-39170: Schema expression IN ('BOGUS') does not correspond to any schemas.
ORA-39001: invalid argument value
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 79
ORA-06512: at "SYS.DBMS_DATAPUMP", line 3507
ORA-06512: at "SYS.DBMS_DATAPUMP", line 4825
ORA-06512: at line 76

I found the solution for my problem and here the code
DECLARE
h1 number;
errorvarchar varchar2(100):= 'ERROR';
tryGetStatus number := 0;
begin
h1 := dbms_datapump.open (operation => 'EXPORT', job_mode => 'SCHEMA', job_name => 'EXPORT_JOB_SQLDEV_2344', version => 'COMPATIBLE');
tryGetStatus := 1;
dbms_datapump.set_parallel(handle => h1, degree => 1);
dbms_datapump.add_file(handle => h1, filename => 'EXPDAT.LOG', directory => 'BACKUPS', filetype => 3);
dbms_datapump.set_parameter(handle => h1, name => 'KEEP_MASTER', value => 0);
dbms_datapump.metadata_filter(handle => h1, name => 'SCHEMA_EXPR', value => 'IN(''POSDATA'')');
dbms_datapump.add_file(handle => h1, filename => 'POSData.DMP', directory => 'BACKUPS', filesize => '100M', filetype => 1, reusefile => 1);
dbms_datapump.set_parameter(handle => h1, name => 'INCLUDE_METADATA', value => 1);
dbms_datapump.set_parameter(handle => h1, name => 'DATA_ACCESS_METHOD', value => 'AUTOMATIC');
dbms_datapump.set_parameter(handle => h1, name => 'ESTIMATE', value => 'BLOCKS');
dbms_datapump.start_job(handle => h1, skip_current => 0, abort_step => 0);
dbms_datapump.detach(handle => h1);
errorvarchar := 'NO_ERROR';
EXCEPTION
WHEN OTHERS THEN
BEGIN
IF ((errorvarchar = 'ERROR')AND(tryGetStatus=1)) THEN
DBMS_DATAPUMP.DETACH(h1);
END IF;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
RAISE;
END;

Related

PL SQL Apex_JSON - Parse element name

I am trying to get the value from the following array -
{
"list:" [
{
"User.name":"AAA"
},
{
"User.Name":"BBB"
}
]
}
I tried to get the Name value but I got null -
for i in 1..Apex_Json.get_count('list') loop
l_name := Apex_Json.Get_varchar2('list[%d].User.Name', i);
end loop;
How can I get the name value?
"list" is json array of elements. AFAIK you can't access an element directly but you can loop through the array to check if an element with a specific name exists. Here is an example:
DECLARE
l_json_text VARCHAR2(4000);
l_json_values apex_json.t_values;
l_name VARCHAR2(4000);
BEGIN
l_json_text := q'!
{
"list": [
{
"User.name":"AAA"
},
{
"User.Name":"BBB"
}
]
}
!';
apex_json.parse(
p_values => l_json_values,
p_source => l_json_text
);
-- get nr of elements in the array and loop through it.
FOR r IN 1 .. APEX_JSON.get_count(p_path => 'list', p_values => l_json_values) LOOP
-- get the value for User.Name for this array index.
-- If it is doesn't exist it will be NULL
l_name := apex_json.get_varchar2(p_path => 'list[%d]."User.name"', p0 => r, p_values => l_json_values);
IF l_name IS NOT NULL THEN
DBMS_OUTPUT.put_line('"User.name":'||l_name);
END IF;
END LOOP;
END;
/
Note that there is a typo in your question json: "list:" [ should be "list": [

Oracle - check if queue table exists before flushing it

How do you check if the queue table exist before flushing it.
I have used the below syntax to create queue table
CREATE type Message_typ as object (
subject VARCHAR2(30),
text VARCHAR2(80));
BEGIN
dbms_aqadm.CREATE_QUEUE_TABLE (
queue_table => 'XX'
,queue_payload_type => 'Message_typ'
);
END;
And the below code to purge the flush table:
declare
l_type dbms_aqadm.aq$_purge_options_t;
begin
l_type.block := true;
l_type.delivery_mode := dbms_aq.buffered;
dbms_aqadm.purge_queue_table(queue_table => 'XX',
purge_condition => '',
purge_options => l_type);
l_type.block := true;
l_type.delivery_mode := dbms_aq.persistent;
dbms_aqadm.purge_queue_table(queue_table => 'XX',
purge_condition => '',
purge_options => l_type);
end;
Please guide how to check if the queue table exists and if exists do a purge.
Thanks.

DBMS Job with function

I have this DBMS Job that run at the end of day to clean the data and I have this function available CLEAN_SNAPSHOT_DATA_F(7).
I try running this script below.
begin
sys.dbms_job.submit(job => :job,
what => 'select OPTIEXEC_ADMIN.CLEAN_SNAPSHOT_DATA_F(7) from dual',
next_date => to_date('11-06-2016', 'dd-mm-yyyy'),
interval => 'SYSDATE + 24/24');
commit;
end;
But the error return ORA-01008: not all variables bound
Can you advice what the issue about the script?
Try this . Hope it helps.
DECLARE
jb_av NUMBER;
BEGIN
sys.dbms_job.submit(job => jb_av,
what => 'DECLARE lv_var VARCHAR2(32676); BEGIN select OPTIEXEC_ADMIN.CLEAN_SNAPSHOT_DATA_F(7) INTO lv_var from dual;END;',
next_date => to_date('11-06-2016', 'dd-mm-yyyy'),
interval => 'SYSDATE + 24/24');
COMMIT;
END;

PL/SQL procedure output stored in file and then email in Oracle 11g

I have a procedure where I am checking whether there are new codes. If there are then insert them into a table. And also save the new data into a csv or txt file and email them to me.
I can't get the logic for how to redirect the new data to file or just even put the data as simple text in the email. Thanks
create or replace
PROCEDURE new_codes_test( today_date IN VARCHAR2 DEFAULT NULL, v_proc_return OUT NUMBER) AS
sql_str VARCHAR2(4000);
.....
BEGIN
v_start_time := SYSDATE;
v_proc_return := 0;
....
INSERT INTO NEW_CODES_test
SELECT DISTINCT Sy_ID ,P_CODE, SYSDATE
FROM X.B
WHERE NOT EXISTS (SELECT DISTINCT Sy_ID, P_CODE
FROM X.C
WHERE today = today_date) ;
COMMIT;
--SELECT ___ into ___ from X.B;
sql_str := 'UTL_MAIL.send(sender => ''
,recipients => ''
,cc => ''
,subject => 'New codes'
,MESSAGE => '' )';
--EXECUTE IMMEDIATE sql_str;
p_proc_return := v_proc_return;
EXCEPTIONS
....
END;
To write to a file the UTL_FILE package will come in handy. To write an email you'll need to put the text to be sent into some sort of string before passing it to the MESSAGE argument of UTL_MAIL.SEND. You'll also need to be sure UTL_MAIL is installed and set up on your server; see this FAQ.
So something like the following may be useful:
CREATE OR REPLACE FUNCTION NEW_CODES_TEST(today_date IN VARCHAR2)
RETURN NUMBER
AS
strMessage VARCHAR2(32767);
nRows NUMBER := 0;
fHandle UTL_FILE.FILE_TYPE;
BEGIN
v_start_time := SYSDATE;
fHandle := UTL_FILE.FOPEN(someDirectory, someFilename, 'w');
FOR aRow IN (SELECT DISTINCT SY_ID ,P_CODE
FROM X.B
WHERE NOT EXISTS (SELECT DISTINCT Sy_ID, P_CODE
FROM X.C
WHERE today = today_date)
LOOP
INSERT INTO NEW_CODES_test
VALUES (aRow.SY_ID, aRow.P_CODE, SYSDATE);
UTL_FILE.PUT_LINE(fHandle, aRow.SY_ID || ', ' || aRow.P_CODE);
strMessage := strMessage || 'Added ' || aRow.SY_ID || ', ' ||
aRow.P_CODE || CHR(10);
nRows := nRows + 1;
END LOOP;
COMMIT;
UTL_FILE.FCLOSE(fHandle);
UTL_MAIL.SEND(sender => 'me#mycompany.com',
recipients => 'you#someplaceelse.net',
subject => 'New codes',
message => strMessage);
RETURN 0;
EXCEPTIONS
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
RETURN SQLCODE;
END NEW_CODES_TEST;
Share and enjoy.

What is the syntax for creating a queue subscriber in PL/SQL?

I'm trying to create a queue and a callback that triggers when a message is queued, but I can't get the callback to trigger. What am I doing wrong?
I have a trigger that enqueues a message, and I can see it on the queue message table, and I can dequeue it by hand and process it, I just can't get the callback to fire on enqueue.
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE (
queue_table => 'queue_message_table',
queue_payload_type => 'queue_message_type',
multiple_consumers => TRUE);
DBMS_AQADM.CREATE_QUEUE (
queue_name => 'message_queue',
queue_table => 'queue_message_table');
DBMS_AQADM.START_QUEUE (queue_name => 'message_queue');
END;
CREATE OR REPLACE PROCEDURE queue_callback(
context RAW, reginfo SYS.AQ$_REG_INFO, descr SYS.AQ$_DESCRIPTOR, payload RAW, payloadl NUMBER) AS
queue_options DBMS_AQ.DEQUEUE_OPTIONS_T;
message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
my_message queue_message_type;
ret varchar2(200);
message_id RAW(16);
BEGIN
DBMS_OUTPUT.PUT_LINE('Callback');
queue_options.msgid := descr.msg_id;
queue_options.consumer_name := descr.consumer_name;
DBMS_AQ.DEQUEUE(
queue_name => descr.queue_name,
dequeue_options => queue_options,
message_properties => message_properties,
payload => my_message,
msgid => message_id );
ret := handle_message(my_message);
commit;
END;
BEGIN
DBMS_AQADM.ADD_SUBSCRIBER (queue_name => 'message_queue',
subscriber => SYS.AQ$_AGENT('queue_subscriber', 'message_queue',NULL));
DBMS_AQ.REGISTER (
SYS.AQ$_REG_INFO_LIST(
SYS.AQ$_REG_INFO(
'MESSAGE_QUEUE:QUEUE_SUBSCRIBER',
DBMS_AQ.NAMESPACE_AQ,
'plsql://QUEUE_CALLBACK',
HEXTORAW('FF')
)
), 1
);
END;
At first glance, it appears you're neither starting the queue (dbms_aqadm.start_queue), neither are you enqueueing anything to it (dbms_aq.enqueue).
I'd recommend following this demo.
You need to be careful with the database version. some bugs has been reported about issues with Oracle Aq.
In particular I've followed this link to built my own sample, executing the demo in a Oracle 11gR2 enterprise database. I was abled to enqueue, dequeue, purge the queue but the listener created with Dbms_Aq.Register didn't work.
I ran the same example downloading a Oracle 11g R2 xe database and it worked.
The same example was runned in a Oracle 10gR2 instance and it works perfectly.
There are some things that you need to be careful on using aq:
use the appropriate parameters adding the subscriber
use the appropriate namespace registering the listener with Dbms_Aq.Register
use the multiple consumers flag declaring the queue table
use the appropriate permissions to packages and to handle the queues
use the qualified name of the queues in some cases if it didn't works.
'
First create the schema
connect / as sysdba
-- #?/rdbms/admin/dbmsaqad.sql --(install if you don't have aq installed yet)
-- create the user and permissions
create user aqadmin identified by aqadmin default tablespace users temporary tablespace temp;
GRANT create session TO aqadmin;
grant connect, resource to aqadmin;
GRANT aq_administrator_role TO aqadmin IDENTIFIED BY aqadmin;
GRANT execute ON dbms_aq TO aqadmin;
GRANT execute ON dbms_aqadm TO aqadmin;
Create the ddl objects
CREATE TABLE demo_queue_message_table
( message VARCHAR2(4000) );
Create the aq-objects
create or replace type demo_queue_payload_type as object(message varchar2(4000)) ;
/
begin
DBMS_AQADM.CREATE_QUEUE_TABLE (queue_table => 'demo_queue_table', queue_payload_type => 'demo_queue_payload_type',multiple_consumers => TRUE);
DBMS_AQADM.CREATE_QUEUE (queue_name => 'demo_queue', queue_table => 'demo_queue_table');
DBMS_AQADM.START_QUEUE('demo_queue');
end;
/
CREATE or replace PROCEDURE demo_queue_callback_procedure(
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 demo_queue_payload_type;
BEGIN
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 demo_queue_message_table ( message )
VALUES ( 'Message [' || o_payload.message || '] ' ||
'dequeued at [' || TO_CHAR( SYSTIMESTAMP,
'DD-MON-YYYY HH24:MI:SS.FF3' ) || ']' );
COMMIT;
END;
/
BEGIN
DBMS_AQADM.ADD_SUBSCRIBER (
queue_name => 'demo_queue',
subscriber => SYS.AQ$_AGENT(
'demo_queue_subscriber',
NULL,
NULL )
);
DBMS_AQ.REGISTER (
SYS.AQ$_REG_INFO_LIST(
SYS.AQ$_REG_INFO(
'DEMO_QUEUE:DEMO_QUEUE_SUBSCRIBER',
DBMS_AQ.NAMESPACE_AQ,
'plsql://DEMO_QUEUE_CALLBACK_PROCEDURE',
HEXTORAW('FF')
)
),
1
);
END;
/
And finally test the queue
DECLARE
r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
o_payload demo_queue_payload_type;
BEGIN
o_payload := demo_queue_payload_type(
TO_CHAR(SYSTIMESTAMP, 'DD-MON-YYYY HH24:MI:SS.FF3' )
);
DBMS_AQ.ENQUEUE(
queue_name => 'demo_queue',
enqueue_options => r_enqueue_options,
message_properties => r_message_properties,
payload => o_payload,
msgid => v_message_handle
);
COMMIT;
END;
/

Resources