Recently I am trying to expand my knowledge about communication between databases in Oracle and I would like to get answer for few questions:
Problem
I am sending query through one database to another via LINK, for instance:
insert into testme#linkme values (1, ‘Hello World’);
where testme is destination table in second database and linkme is my link.
Questions
When sending query, are my data vulnerable (are they encrypted somehow during this process)?
If yes, could you briefly tell me more?
If no, is there any way to make this process safe?
Also, do you know any tools that I could use to test what happens with my data during sending process?
create or replace PACKAGE BODY "PKG_LOGI_PWD_REG"
as
FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2
IS
l_decrypted RAW(32);
l_decrypted_string VARCHAR2(32);
L_USER varchar2(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY raw(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
BEGIN
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
l_decrypted := dbms_crypto.decrypt
( SRC => P_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
l_decrypted_string := utl_i18n.raw_to_char
( data => l_decrypted ,
src_charset => 'AL32UTF8' );
RETURN l_decrypted_string;
end DECRYPT_VAL;
FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN VARCHAR2
is
L_VAL RAW(32);
L_ENCRYPTED raw(32);
L_CHARACTER_SET varchar2(10);
L_STRING varchar2(32);
L_KEY RAW(250);
L_ENCRYPTION_TYPE PLS_INTEGER;
begin
L_KEY := UTL_I18N.STRING_TO_RAW
( data => '98345678901234567890123456789012',
DST_CHARSET => 'AL32UTF8' );
L_ENCRYPTION_TYPE := dbms_crypto.encrypt_aes256
+ DBMS_CRYPTO.CHAIN_CBC
+ DBMS_CRYPTO.PAD_PKCS5;
L_VAL := utl_i18n.string_to_raw
( data => p_val,
dst_charset => 'AL32UTF8' );
L_ENCRYPTED := dbms_crypto.encrypt
( SRC => L_VAL,
TYP => L_ENCRYPTION_TYPE,
key => L_KEY );
return L_ENCRYPTED;
EXCEPTION when OTHERS then
RETURN SQLCODE||'-'||SQLERRM;
end ENCRYPT_VAL;
end PKG_LOGI_PWD_REG;
Related
I have MY_OBJ_TABLE type and would like to dump variable content of such either into text or xml format.
The thing is, function processing such request should be able to receive any type of table of objects, not just the MY_OBJ_TABLE.
I have looked into passAnyObject.sql which looks like a step in the right direction. Advices and solutions are greatly appreciated.
CREATE OR REPLACE TYPE "MY_OBJ" FORCE AS OBJECT (
key VARCHAR2(20),
value VARCHAR2(1000),
CONSTRUCTOR FUNCTION MY_OBJ RETURN SELF AS RESULT,
MEMBER PROCEDURE init_my_obj
);
CREATE OR REPLACE TYPE BODY "MY_OBJ" AS
CONSTRUCTOR FUNCTION MY_OBJ RETURN SELF AS RESULT
AS
BEGIN
init_my_obj ();
return;
END MY_OBJ;
MEMBER PROCEDURE init_my_obj
AS
BEGIN
key := NULL;
value := NULL;
END init_my_obj;
END;
CREATE OR REPLACE TYPE MY_OBJ_TABLE IS
TABLE OF MY_OBJ;
If you want an XML solution then:
CREATE TYPE MY_OBJ AS OBJECT (
key VARCHAR2(20),
value VARCHAR2(1000)
);
CREATE TYPE MY_OBJ_TABLE IS TABLE OF MY_OBJ;
Then you can use:
SELECT XMLELEMENT(
"OBJECTS",
XMLAGG(
XMLTYPE(VALUE(t))
)
).getClobVal() AS output
FROM TABLE(
MY_OBJ_TABLE(
MY_OBJ('a', 'one'),
MY_OBJ('b', 'two')
)
) t;
Which outputs:
OUTPUT
<OBJECTS><MY_OBJ> <KEY>a</KEY> <VALUE>one</VALUE></MY_OBJ><MY_OBJ> <KEY>b</KEY> <VALUE>two</VALUE></MY_OBJ></OBJECTS>
fiddle
You cannot achieve your goal using ANYDATA.
You can parse an individual object to a string using ANYDATA and reflection as described in my previous answer.
However, if you want to parse a collection then:
you can convert it to ANYDATA using ANYDATA.ConvertCollection( your_collection );
then when processing it you can set the evaluation mode to PIECEWISE (documentation) which will let you iterate through individual elements...
but there are no Get* methods (documentation) that allow you to extract an element as an abstract ANYDATA type; you MUST extract it as the concrete underlying type so any procedure you create must know the data type of the collection that you are passing in at compile time.
I did try to work through the problem but the functionality is not there to support an abstract solution. This is as far as I got:
CREATE PACKAGE reflection IS
TYPE type_info IS RECORD(
prec PLS_INTEGER,
scale PLS_INTEGER,
len PLS_INTEGER,
csid PLS_INTEGER,
csfrm PLS_INTEGER,
schema_name VARCHAR2(30),
type_name VARCHAR2(30),
version VARCHAR2(100),
count PLS_INTEGER
);
TYPE attr_info IS RECORD(
prec PLS_INTEGER,
scale PLS_INTEGER,
len PLS_INTEGER,
csid PLS_INTEGER,
csfrm PLS_INTEGER,
attr_elt_type ANYTYPE,
aname VARCHAR2(30)
);
FUNCTION get_size(
p_anydata IN ANYDATA
) RETURN PLS_INTEGER;
FUNCTION get_Object_At(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN ANYDATA;
FUNCTION get_attr_name_at(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN VARCHAR2;
FUNCTION get_attr_value_at(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN VARCHAR2;
END;
/
Then:
CREATE PACKAGE BODY reflection IS
DEBUG BOOLEAN := FALSE;
PROCEDURE get_type(
i_anydata IN ANYDATA,
o_typeid OUT PLS_INTEGER,
o_anytype OUT ANYTYPE
)
IS
BEGIN
o_typeid := i_anydata.GetType( typ => o_anytype );
END;
FUNCTION is_Object(
p_typeid PLS_INTEGER
) RETURN BOOLEAN
IS
BEGIN
RETURN p_typeid = DBMS_TYPES.TYPECODE_OBJECT;
END;
FUNCTION is_Collection(
p_typeid PLS_INTEGER
) RETURN BOOLEAN
IS
BEGIN
RETURN p_typeid = DBMS_TYPES.TYPECODE_NAMEDCOLLECTION;
END;
FUNCTION get_info(
p_anytype IN ANYTYPE
) RETURN type_info
IS
v_typeid PLS_INTEGER;
v_type_info REFLECTION.TYPE_INFO;
BEGIN
v_typeid := p_anytype.GetInfo (
v_type_info.prec,
v_type_info.scale,
v_type_info.len,
v_type_info.csid,
v_type_info.csfrm,
v_type_info.schema_name,
v_type_info.type_name,
v_type_info.version,
v_type_info.count
);
RETURN v_type_info;
END;
FUNCTION get_size(
p_anydata IN ANYDATA
) RETURN PLS_INTEGER
IS
v_anytype ANYTYPE;
v_typeid PLS_INTEGER;
BEGIN
Get_Type( p_anydata, v_typeid, v_anytype );
RETURN Get_Info( v_anytype ).COUNT;
END;
FUNCTION get_Object_At(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN ANYDATA
IS
v_anydata ANYDATA := p_anydata;
v_anytype ANYTYPE;
v_typeid PLS_INTEGER;
BEGIN
Get_Type( v_anydata, v_typeid, v_anytype );
IF NOT is_Collection(v_typeid) THEN
RAISE_APPLICATION_ERROR(-20000, 'Not a collection');
END IF;
v_anydata.PIECEWISE;
FOR i IN 1 .. p_index LOOP
DECLARE
v_attr_typeid PLS_INTEGER;
v_attr_info REFLECTION.ATTR_INFO;
v_result_code PLS_INTEGER;
v_value ANYDATA;
v_object MY_OBJ;
BEGIN
v_result_code := v_anydata.GetObject( v_object );
v_value := ANYDATA.ConvertObject( v_object );
-- TODO: there is no Get* function that returns an ANYDATA type that
-- would allow abstract parsing to continue. For example:
--
-- v_result_code := v_anydata.Get( v_value );
--
-- You would need to use:
--
-- DECLARE
-- v_object MY_OBJ;
-- BEGIN
-- v_result_code := v_anydata.GetObject( v_object );
-- v_value := ANYDATA.ConvertObject( v_object );
-- END;
--
-- But that hard-codes the concrete object type.
IF i = p_index THEN
RETURN v_value;
END IF;
END;
END LOOP;
RETURN NULL;
END;
FUNCTION get_attr_name_at(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN VARCHAR2
IS
v_anydata ANYDATA := p_anydata;
v_anytype ANYTYPE;
v_typeid PLS_INTEGER;
v_type_info REFLECTION.TYPE_INFO;
v_output VARCHAR2(4000);
v_attr_typeid PLS_INTEGER;
v_attr_info REFLECTION.ATTR_INFO;
BEGIN
Get_Type( v_anydata, v_typeid, v_anytype );
IF NOT is_Object(v_typeid) THEN
RAISE_APPLICATION_ERROR(-20000, 'Not an object');
END IF;
v_type_info := Get_Info( v_anytype );
IF p_index < 1 OR p_index > v_type_info.COUNT THEN
RETURN NULL;
END IF;
v_anydata.PIECEWISE;
v_attr_typeid := v_anytype.getAttrElemInfo(
pos => p_index,
prec => v_attr_info.prec,
scale => v_attr_info.scale,
len => v_attr_info.len,
csid => v_attr_info.csid,
csfrm => v_attr_info.csfrm,
attr_elt_type => v_attr_info.attr_elt_type,
aname => v_attr_info.aname
);
RETURN v_attr_info.aname;
END;
FUNCTION get_attr_value_at(
p_anydata IN ANYDATA,
p_index IN PLS_INTEGER DEFAULT 1
) RETURN VARCHAR2
IS
v_anydata ANYDATA := p_anydata;
v_typeid PLS_INTEGER;
v_anytype ANYTYPE;
v_type_info REFLECTION.TYPE_INFO;
v_output VARCHAR2(4000);
BEGIN
Get_Type( v_anydata, v_typeid, v_anytype );
IF NOT is_Object(v_typeid) THEN
RAISE_APPLICATION_ERROR(-20000, 'Not an object');
END IF;
v_type_info := Get_Info( v_anytype );
IF p_index < 1 OR p_index > v_type_info.COUNT THEN
RETURN NULL;
END IF;
v_anydata.PIECEWISE;
FOR i IN 1 .. p_index LOOP
DECLARE
v_attr_typeid PLS_INTEGER;
v_attr_info REFLECTION.ATTR_INFO;
v_result_code PLS_INTEGER;
BEGIN
v_attr_typeid := v_anytype.getAttrElemInfo(
pos => i,
prec => v_attr_info.prec,
scale => v_attr_info.scale,
len => v_attr_info.len,
csid => v_attr_info.csid,
csfrm => v_attr_info.csfrm,
attr_elt_type => v_attr_info.attr_elt_type,
aname => v_attr_info.aname
);
IF DEBUG THEN
DBMS_OUTPUT.PUT_LINE(
'Attribute ' || i || ': '
|| v_attr_info.aname
|| ' (type ' || v_attr_typeid || ')'
);
END IF;
CASE v_attr_typeid
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
DECLARE
v_value NUMBER;
BEGIN
v_result_code := v_anydata.GetNumber( v_value );
IF i = p_index THEN
RETURN TO_CHAR( v_value );
END IF;
END;
WHEN DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DECLARE
v_value VARCHAR2(4000);
BEGIN
v_result_code := v_anydata.GetVarchar2( v_value );
IF i = p_index THEN
RETURN v_value;
END IF;
END;
WHEN DBMS_TYPES.TYPECODE_DATE THEN
DECLARE
v_value DATE;
BEGIN
v_result_code := v_anydata.GetDate( v_value );
IF i = p_index THEN
RETURN TO_CHAR( v_value, 'YYYY-MM-DD HH24:MI:SS' );
END IF;
END;
ELSE
NULL;
END CASE;
END;
END LOOP;
RETURN NULL;
END;
END;
/
Then you can parse your object using:
DECLARE
objs MY_OBJ_TABLE;
idx PLS_INTEGER := 1;
p_anydata ANYDATA;
p_attr_name VARCHAR2(30);
p_attr_value VARCHAR2(4000);
p_element ANYDATA;
BEGIN
dbms_output.enable;
objs := MY_OBJ_TABLE(
MY_OBJ('a', 'one'),
MY_OBJ('b', 'two'),
MY_OBJ('c', 'three')
);
p_anydata := ANYDATA.ConvertCollection( objs );
-- Still not worked out how to get the collection size from the ANYDATA.
FOR i IN 1 .. objs.count LOOP
DECLARE
p_element ANYDATA := REFLECTION.get_Object_at(p_anydata, i);
BEGIN
DBMS_OUTPUT.PUT_LINE( 'My Obj ' || i || ':' );
FOR attr_no IN 1 .. REFLECTION.get_size( p_element ) LOOP
p_attr_name := REFLECTION.get_attr_name_at( p_element, attr_no );
p_attr_value := REFLECTION.get_attr_value_at( p_element, attr_no );
DBMS_OUTPUT.PUT_LINE( ' ' || p_attr_name || ': ' || p_attr_value );
END LOOP;
END;
END LOOP;
END;
/
You will note in the middle of the package body the MY_OBJ type has to be hard-coded and there is not a solution in the Oracle documentation to support an abstract solution.
fiddle
I'm Using DBMS_LDAP package to get Users and Computers with attribute objectSid, it is a binary. Using DBMS_LDAP.GET_VALUES_BLOB and RAWTOHEX I can get HEX. How I can convert to SID String (SID Structure). There is any function?
For example from 010500000000000515000000e967bb98d6b7d7bf82051e6c28060000 to S-1-5-21-2562418665-3218585558-1813906818-1576.
I've put together this code using the following sources to guide me:
Get objectGUID: https://joelitechlife.ca/2021/04/28/dbms_ldap-example/
ObjectSid WiKi: https://ldapwiki.com/wiki/ObjectSID
Converting SID Binary and String Forms: https://devblogs.microsoft.com/oldnewthing/20040315-00/?p=40253
CREATE OR REPLACE FUNCTION get_objectsid (p_samaccount IN VARCHAR2)
RETURN VARCHAR2 AS
v_objectguid VARCHAR2(100) := NULL;
v_ldap_host VARCHAR2(256) := 'server.domain.base';
v_ldap_port VARCHAR2(256) := '389';
v_ldap_user VARCHAR2(256) := 'CN=Oracle Services,OU=OtherAccounts,OU=Corporate,OU=Locations,DC=domain,DC=base';
v_ldap_passwd VARCHAR2(256) := 'password';
v_ldap_base VARCHAR2(256) := 'DC=domain,DC=base';
v_result PLS_INTEGER;
v_session DBMS_LDAP.session;
v_search_attrs DBMS_LDAP.string_collection;
v_search_results DBMS_LDAP.MESSAGE;
v_entry DBMS_LDAP.MESSAGE;
v_values DBMS_LDAP.BINVAL_COLLECTION;
v_ber_element dbms_ldap.ber_element;
v_attr_name VARCHAR2(256);
l_revision number;
l_num_dashes number;
l_sid_issue_authority number;
l_object_sid varchar2(100);
function endian_value(p_string varchar2, p_endian_type varchar2)
return varchar2
as
l_step number := 2;
l_val varchar2(4000);
begin
if upper(p_endian_type) = 'L' then
for i in 1..length(p_string) / 2
loop
l_val := substr(p_string, i * l_step - 1, 2)||l_val;
dbms_output.put_line('endian of '||l_val);
end loop;
else
l_val := p_string;
end if;
return to_number(l_val, 'xxxxxxxxxxxxxxxx');
end;
function process_left(p_string in out varchar2, p_len int)
return varchar2
as
l_rtn varchar2(100);
begin
l_rtn := substr(p_string, 1, p_len);
p_string := substr(p_string, p_len + 1);
return l_rtn;
end;
BEGIN
-- Choose to raise exceptions.
DBMS_LDAP.use_exception := TRUE;
-- initiating the connection to the LDAP server
v_session := DBMS_LDAP.init(hostname => v_ldap_host, portnum => v_ldap_port);
-- binding the user
v_result := DBMS_LDAP.simple_bind_s(ld => v_session,
dn => v_ldap_user,
passwd => v_ldap_passwd);
-- attribute name to search
v_search_attrs(1) := 'objectSid';
v_result := DBMS_LDAP.search_s( ld => v_session,
base => v_ldap_base,
scope => DBMS_LDAP.SCOPE_SUBTREE,
FILTER => '(&(objectClass=user)(samaccountName='||p_samaccount||'))',
attrs => v_search_attrs,
attronly => 0,
res => v_search_results);
-- expecting there will be only one entry matched , one attribute objectGUID only
IF dbms_ldap.count_entries(ld => v_session, msg => v_search_results) > 0
THEN
v_entry := DBMS_LDAP.first_entry(ld => v_session, msg => v_search_results);
v_attr_name := dbms_ldap.first_attribute(ld => v_session,
ldapentry => v_entry,
ber_elem => v_ber_element);
v_values := dbms_ldap.get_values_len (ld => v_session,
ldapentry => v_entry,
attr => v_attr_name);
IF v_values.COUNT > 0
THEN
FOR i IN v_values.FIRST .. v_values.LAST
LOOP
select rawtohex(v_values(i)) into v_objectguid from dual;
END LOOP;
END IF;
dbms_output.put_line(v_objectguid);
l_revision := to_number(process_left(v_objectguid, 2), '00');
l_num_dashes := to_number(process_left(v_objectguid, 2), '00');
l_sid_issue_authority := endian_value(process_left(v_objectguid, 12), 'b');
l_object_sid := 'S-'||l_revision||'-'||l_sid_issue_authority;
for i in 1..to_number(l_num_dashes)
loop
l_object_sid := l_object_sid||'-'||endian_value(process_left(v_objectguid, 8), 'l');
end loop;
dbms_output.put_line(l_object_sid);
END IF;
IF l_object_sid IS NULL THEN
l_object_sid:='No_objectsid';
END IF;
IF v_entry IS NOT NULL THEN
v_result := DBMS_LDAP.msgfree(v_entry);
END IF;
v_result := DBMS_LDAP.unbind_s(ld => v_session);
RETURN l_object_sid;
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_object_sid:='---NoSid---';
RETURN l_object_sid;
END get_objectsid;
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;
I am running a PL/SQL procedure with DBMS_PARALLEL_EXECUTE. I get stuck with ORA-29494: invalid state for run task error. My code is as below:
Below is the sample output for the DBMS_OUTPUT statement:
PROCESSING
5743
PROCESSING
5744
When I individually run the create task, chunk task and run task with input rowid from the user_parallel_execute_chunks, It works just fine for individual chunks. Also without loop, the task runs for all the chunks and ends with an error saying chunk_not_found. To handle that I used the loop, But I am not able to make it work
CREATE OR REPLACE PROCEDURE code_parse_wrapper AS
l_sql_stmt VARCHAR2(32767);
l_chunk_id NUMBER;
l_start_rowid ROWID;
l_end_rowid ROWID;
l_any_rows BOOLEAN;
l_try NUMBER;
l_status NUMBER;
l_stmt CLOB;
V_CHUNK_ID NUMBER;
V_STATUS VARCHAR2(30);
BEGIN
BEGIN
dbms_parallel_execute.drop_task(task_name => 'parallel_processing');
DBMS_OUTPUT.PUT_LINE('TASK DROPPED');
END;
BEGIN
dbms_parallel_execute.create_task(task_name => 'parallel_processing');
DBMS_OUTPUT.PUT_LINE('TASK CREATED');
END;
-- Create Chunks
BEGIN
dbms_parallel_execute.create_chunks_by_rowid
(
'parallel_processing',
'SchemaName',
'ORDER_DETAIL',
FALSE,
50000
);
END;
BEGIN
LOOP
dbms_parallel_execute.get_rowid_chunk
(
task_name => 'parallel_processing',
chunk_id => l_chunk_id,
start_rowid => l_start_rowid,
end_rowid => l_end_rowid,
any_rows => l_any_rows
);
select STATUS INTO V_STATUS from user_parallel_execute_tasks where task_name = 'parallel_processing';
DBMS_OUTPUT.PUT_LINE(V_STATUS);
l_sql_stmt := ' begin CODE_PARSE6_AK( :start_id, :end_id ); end;';
DBMS_OUTPUT.PUT_LINE(l_chunk_id);
-- DBMS_OUTPUT.PUT_LINE(l_sql_stmt);
IF (l_any_rows = false) THEN
EXIT;
END IF;
BEGIN
-- Get next unassigned chunk.
-- EXECUTE IMMEDIATE 'l_sql_stmt USING l_start_rowid, l_end_rowid';
dbms_parallel_execute.run_task('parallel_processing',
l_sql_stmt,
DBMS_SQL.NATIVE,
parallel_level => 10
);
l_try := 0;
l_status := dbms_parallel_execute.task_status('parallel_processing');
WHILE(l_try < 2 and l_status != dbms_parallel_execute.finished) LOOP
l_try := l_try + 1;
dbms_parallel_execute.resume_task('parallel_processing');
l_status := dbms_parallel_execute.task_status('parallel_processing');
dbms_parallel_execute.set_chunk_status
(
task_name => 'parallel_processing',
chunk_id => l_chunk_id,
status => dbms_parallel_execute.processed
);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
-- Record chunk error.
dbms_parallel_execute.set_chunk_status
(
task_name => 'parallel_processing',
chunk_id => l_chunk_id,
status => dbms_parallel_execute.processed_with_error,
err_num => SQLCODE,
err_msg => SQLERRM
);
END;
COMMIT;
END LOOP;
END;
END;
Note sure why are doing get_rowid_chunk, set_chunk_status etc. I would use by_row => TRUE with create_chunks_by_rowid.
I think, you can use a simpler, cleaner piece of code here ... I have been using it for years without any issues. One can reuse this mostly by changing DML in l_sql_stmt.
DECLARE
l_task VARCHAR2(30) := 'parallel_processing';
l_sql_stmt VARCHAR2(32767);
l_try NUMBER;
l_status NUMBER;
BEGIN
DBMS_PARALLEL_EXECUTE.create_task (task_name => l_task);
DBMS_PARALLEL_EXECUTE.create_chunks_by_rowid(task_name => l_task,
table_owner => 'SCHEMANAME',
table_name => 'ORDER_DETAIL',
by_row => TRUE,
chunk_size => 10000);
l_sql_stmt := 'begin CODE_PARSE6_AK( :start_id, :end_id ); end;';
DBMS_PARALLEL_EXECUTE.run_task(task_name => l_task,
sql_stmt => l_sql_stmt,
language_flag => DBMS_SQL.NATIVE,
parallel_level => 10);
-- If there is error, RESUME it for at most 2 times.
l_try := 0;
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task);
WHILE(l_try < 2 and l_status != DBMS_PARALLEL_EXECUTE.FINISHED)
Loop
l_try := l_try + 1;
DBMS_PARALLEL_EXECUTE.resume_task(l_task);
l_status := DBMS_PARALLEL_EXECUTE.task_status(l_task);
END LOOP;
DBMS_PARALLEL_EXECUTE.drop_task(l_task);
END;
/
Oracle keeps giving me this error:
ORA-30625: method dispatch on NULL SELF argument is disallowed
I trying it with soap_api
The code follows:
FUNCTION add_numbers (p_int_1 IN NUMBER,
p_int_2 IN NUMBER)
RETURN NUMBER
AS
l_request soap_api.t_request;
l_response soap_api.t_response;
l_return VARCHAR2(32767);
l_url VARCHAR2(32767);
l_namespace VARCHAR2(32767);
l_method VARCHAR2(32767);
l_soap_action VARCHAR2(32767);
l_result_name VARCHAR2(32767);
BEGIN
l_url := 'http://192.168.1.23:8080/TestWebservice.asmx';
l_namespace := 'xmlns="http://192.168.1.23:8080/TestWebservice.asmx"';
l_method := 'add';
l_soap_action := 'http://tempuri.org/add';
l_result_name := 'return';
l_request := soap_api.new_request(p_method => l_method,
p_namespace => l_namespace);
soap_api.add_parameter(p_request => l_request,
p_name => 'int1',
p_type => 'xsd:integer',
p_value => p_int_1);
soap_api.add_parameter(p_request => l_request,
p_name => 'int2',
p_type => 'xsd:integer',
p_value => p_int_2);
l_response := soap_api.invoke(p_request => l_request,
p_url => l_url,
p_action => l_soap_action);
l_return := soap_api.get_return_value(p_response => l_response,
p_name => l_result_name,
p_namespace => l_namespace);
RETURN l_return;
END;
Review the return name the next line
l_result_name := 'return';
In my case change this and solved!!
l_result_name := 'Return';