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;
Related
I'm trying to detect Insert, Update or Delete on a Table. I know I can't use QRCN for this so I'm trying to use OCN. What I'm trying to achieve is... when an Insert/Update is detected call "callback_iu" when a Delete is detected call 'callback_d'.
DECLARE
qosflags NUMBER;
reginfo_iu cq_notification$_reg_info;
reginfo_d cq_notification$_reg_info;
regid_iu NUMBER;
regid_d NUMBER;
v_cursor SYS_REFCURSOR;
opfilter_iu NUMBER;
opfilter_d NUMBER;
BEGIN
qosflags := DBMS_CQ_NOTIFICATION.QOS_ROWIDS;
opfilter_iu := DBMS_CQ_NOTIFICATION.INSERTOP + DBMS_CQ_NOTIFICATION.UPDATEOP;
opfilter_d := DBMS_CQ_NOTIFICATION.DELETEOP;
reginfo_iu := cq_notification$_reg_info('callback_iu', qosflags,0, opfilter_iu, 0);
regid_iu := DBMS_CQ_NOTIFICATION.NEW_REG_START(reginfo_iu);
OPEN v_cursor FOR
SELECT DBMS_CQ_NOTIFICATION.QOS_ROWIDS, department_id, department_name, manager_id, location_id
FROM HR.departments
CLOSE v_cursor;
DBMS_CQ_NOTIFICATION.REG_END;
reginfo_d := cq_notification$_reg_info('callback_d', qosflags,0, opfilter_d, 0);
regid_d := DBMS_CQ_NOTIFICATION.NEW_REG_START(reginfo_d);
OPEN v_cursor FOR
SELECT DBMS_CQ_NOTIFICATION.QOS_ROWIDS, department_id, department_name, manager_id, location_id
FROM HR.departments
CLOSE v_cursor;
DBMS_CQ_NOTIFICATION.REG_END;
END;
I know that I can get ROWID and the "real_id" using QRCN like this:
CREATE OR REPLACE PROCEDURE chnf_callback
(ntfnds IN CQ_NOTIFICATION$_DESCRIPTOR)
IS
event_type NUMBER;
tbname VARCHAR2(60);
numtables NUMBER;
operation_type NUMBER;
numrows NUMBER;
row_id VARCHAR2(2000);
numqueries NUMBER;
qid NUMBER;
real_id NUMBER;
BEGIN
event_type := ntfnds.event_type;
numqueries :=0;
IF (event_type = DBMS_CQ_NOTIFICATION.EVENT_QUERYCHANGE) THEN
numqueries := ntfnds.query_desc_array.count;
FOR i in 1..numqueries LOOP
qid := ntfnds.QUERY_DESC_ARRAY(i).queryid;
numtables := 0;
numtables := ntfnds.QUERY_DESC_ARRAY(i).table_desc_array.count;
FOR j IN 1..numtables LOOP
tbname := ntfnds.QUERY_DESC_ARRAY(i).table_desc_array(j).table_name;
operation_type := ntfnds.QUERY_DESC_ARRAY(i).table_desc_array(j).Opflags;
IF (bitand(operation_type, DBMS_CQ_NOTIFICATION.ALL_ROWS) = 0)
THEN
numrows := ntfnds.query_desc_array(i).table_desc_array(j).numrows;
ELSE
numrows :=0; /* ROWID INFO NOT AVAILABLE */
END IF;
/* The body of the loop is not executed when numrows is ZERO */
FOR k IN 1..numrows LOOP
Row_id := ntfnds.query_desc_array(i).table_desc_array(j).row_desc_array(k).row_id;
select department_id into real_id from hr.departments where rowid = Row_id;
-->INSERT IN NFROWCHANGES<--
INSERT INTO nfrowchanges VALUES(qid, tbname, Row_id, real_id);
END LOOP; /* loop over rows */
END LOOP; /* loop over tables */
END LOOP; /* loop over queries */
END IF;
COMMIT;
END;
I also know that I can check operation_type to know if it's an Insert (2) or Update (4), but I can't make it work with Delete.
So how can I get ROWID and the "real_id" using OCN and pass it to UTL_HTTP.REQ on the callback?
DECLARE req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
BEGIN
req := utl_http.begin_request(
url => 'localhost:3000/departments/'||real_id,
method => 'GET'
);
resp := utl_http.get_response(r => req);
utl_http.end_response(r => resp);
END;
I still don't know how to work with OCN, in this solution I'm using QRCN. Since I can't get row_id when a row is deleted, instead of deleting the row I created a new column called "Active", so when I want to "delete" a row I change "Active" from "Yes" to "No".
So here is the solution to send the "real_id" from the Inserted/Updated/"Deleted" row using UTL_HTTP.
anonymous block:
DECLARE
l_reginfo CQ_NOTIFICATION$_REG_INFO;
l_cursor SYS_REFCURSOR;
l_regid NUMBER;
qosflags NUMBER;
BEGIN
qosflags := DBMS_CQ_NOTIFICATION.QOS_QUERY + DBMS_CQ_NOTIFICATION.QOS_ROWIDS;
l_reginfo := cq_notification$_reg_info ('query_callback', qosflags, 0, 0, 0);
l_regid := dbms_cq_notification.new_reg_start(l_reginfo);
OPEN l_cursor FOR
SELECT
id,
city_name,
country_name,
votes,
active
FROM hr.jsao_super_cities
WHERE active = 'YES';
CLOSE l_cursor;
dbms_cq_notification.reg_end;
END;
/
callback:
CREATE OR REPLACE PROCEDURE query_callback
(ntfnds IN CQ_NOTIFICATION$_DESCRIPTOR)
IS
event_type NUMBER;
numtables NUMBER;
operation_type NUMBER;
numrows NUMBER;
row_id VARCHAR2(2000);
is_active VARCHAR2(20);
numqueries NUMBER;
real_id NUMBER;
l_req UTL_HTTP.REQ;
l_resp UTL_HTTP.RESP;
BEGIN
event_type := ntfnds.event_type;
numqueries :=0;
IF (event_type = DBMS_CQ_NOTIFICATION.EVENT_QUERYCHANGE) THEN
numqueries := ntfnds.query_desc_array.count;
FOR i in 1..numqueries LOOP
numtables := 0;
numtables := ntfnds.QUERY_DESC_ARRAY(i).table_desc_array.count;
FOR j IN 1..numtables LOOP
operation_type := ntfnds.QUERY_DESC_ARRAY(i).table_desc_array(j).Opflags;
IF (bitand(operation_type, DBMS_CQ_NOTIFICATION.ALL_ROWS) = 0)
THEN
numrows := ntfnds.query_desc_array(i).table_desc_array(j).numrows;
ELSE
numrows :=0;
END IF;
FOR k IN 1..numrows LOOP
Row_id := ntfnds.query_desc_array(i).table_desc_array(j).row_desc_array(k).row_id;
--getting "real_id"
select id into real_id from hr.jsao_super_cities where rowid = Row_id;
-- 2 = insert
IF(operation_type = 2) THEN
l_req := utl_http.begin_request(
url => 'localhost:3000/city/'||real_id,
method => 'GET'
);
l_resp := utl_http.get_response(r => l_req);
utl_http.end_response(r => l_resp);
-- 4 = update
ELSIF (operation_type = 4) THEN
select active into is_active from hr.jsao_super_cities where id = real_id;
IF (is_active = 'YES') THEN
l_req := utl_http.begin_request(
url => 'localhost:3000/city/'||real_id,
method => 'GET'
);
l_resp := utl_http.get_response(r => l_req);
utl_http.end_response(r => l_resp);
ELSIF (is_active = 'NO') THEN
l_req := utl_http.begin_request(
url => 'localhost:3000/delete/'||real_id,
method => 'GET'
);
l_resp := utl_http.get_response(r => l_req);
utl_http.end_response(r => l_resp);
END IF;
END IF;
END LOOP; /* loop over rows */
END LOOP; /* loop over tables */
END LOOP; /* loop over queries */
END IF;
END query_callback;
/
I hope this can help someone else.
I created a package which loads data from a staging table to a live table in Oracle DB. The package comprises of four functions which perform live load, update, insert and error check on the records. For some reason, I am only able to load one record from the staging table and then the following error occurs:
ORA-02290: check constraint (VIQDATA.SYS_C0012762) violated ORA-01403: no data found
create or replace PACKAGE VAL_PROC
AS
pi_sif_id NUMBER := 0;
CURSOR v_d_c (pi_sif_id NUMBER)
IS
SELECT *
FROM S_V_C_R
WHERE SIF_ID =PI_SIF_ID
AND SVC_PROCESS_FLAG='N';
TYPE v_d_c_t IS TABLE OF v_d_c%ROWTYPE;
FUNCTION vr_live_load (pi_sif_id NUMBER,
po_err_msg OUT VARCHAR2,
po_success_count OUT NUMBER,
po_failed_count OUT NUMBER)
RETURN NUMBER;
FUNCTION check_error_record (p_v_d_r IN vr_dtl_cur%ROWTYPE,
lv_prc_code OUT VARCHAR2,
lv_err_flag OUT VARCHAR2)
RETURN NUMBER;
FUNCTION insert_v (p_v_d_r IN v_d_c%ROWTYPE, po_err_msg OUT VARCHAR2, po_prc_code OUT VARCHAR2)
RETURN NUMBER;
FUNCTION update_v (p_v_d_r IN v_d_c%ROWTYPE, po_err_msg OUT VARCHAR2, po_prc_code OUT VARCHAR2)
RETURN NUMBER;
END VAL_PROC;
create or replace PACKAGE BODY VAL_PROC
AS
LV_X1_ID SERIALS.X1_ID%TYPE;
LV_VC_ID VR_COM.X1_ID%TYPE; --change name of this variable later
FUNCTION vr_live_load(pi_sif_id NUMBER, --live load function
po_err_msg OUT VARCHAR2,
po_success_count OUT NUMBER,
po_failed_count OUT NUMBER)
RETURN NUMBER
IS
v_d_r v_d_c_tbl;
dup_prc NUMBER := 0;
E_DUP_PRC EXCEPTION;
RETVAL NUMBER;
pi_d_co VARCHAR2(10);
ERR_FLAG VARCHAR2 (1);
ret_prc_code VARCHAR2 (15);
lv_err_code VARCHAR2 (1000);
lv_found NUMBER;
lv_PRS_ID NUMBER;
lv_sif_filename VARCHAR2 (200);
lv_proc_success_count NUMBER := 0;
lv_proc_failed_count1 NUMBER := 0;
BEGIN
BEGIN
SELECT COUNT (1)
INTO DUP_PRC
FROM s_fi
WHERE SIF_ID = PI_SIF_ID AND s_p_f = 'P';
IF dup_prc > 0
THEN
RAISE e_dup_prc;
END IF;
SELECT sif_filename
INTO lv_sif_filename
FROM s_fi
WHERE sif_id = pi_sif_id;
INSERT INTO p_s (PCG_CODE,
SIF_ID,
PRS_START_DATETIME,
sif_filename)
VALUES ('V_ODL',
pi_sif_id,
SYSDATE,
lv_sif_filename)
RETURNING PRS_ID
INTO lv_PRS_ID;
COMMIT;
OPEN v_d_c(pi_sif_id);
LOOP
FETCH v_d_c
BULK COLLECT INTO v_d_r
LIMIT 1000;
FOR i IN 1 .. v_d_r.COUNT
LOOP
retval :=
check_error_record (p_v_d_r => v_d_r(i),
lv_prc_code => ret_prc_code,
lv_err_flag => err_flag);
IF retval = 0
THEN
IF ERR_FLAG = 'N'
THEN
BEGIN
SELECT 1
INTO lv_found
FROM VR_COM
WHERE X1_ID = LV_X1_ID; --v_d_r(i).SVC_d_co = D.X1_ID;
retval :=
update_vr (p_v_d_r => v_d_r (i),
po_err_msg => lv_err_code,
po_prc_code => ret_prc_code);
UPDATE STG_COM_RECORDS
SET PRC_CODE = ret_prc_code,
S_E_M = lv_err_code,
S_P_F = 'P'
WHERE S_ID = v_d_r (i).S_ID;
IF retval = 0
THEN
lv_proc_success_count := lv_proc_success_count + 1;
ELSE
lv_proc_failed_count1 := lv_proc_failed_count1 + 1;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
retval :=
insert_v (
p_v_d_r => v_d_r (i),
po_err_msg => lv_err_code,
po_prc_code => ret_prc_code);
UPDATE STG_COM_RECORDS
SET PRC_CODE = ret_prc_code,
S_E_M = lv_err_code,
S_P_F = 'P'
WHERE S_ID = v_d_r(i).S_ID;
IF retval = 0
THEN
lv_proc_success_count :=
lv_proc_success_count + 1;
ELSE
lv_proc_failed_count1 :=
lv_proc_failed_count1 + 1;
END IF;
END;
ELSE /*update table with prc_code when err_flag <> 'N' */
UPDATE STG_COM_RECORDS
SET PRC_CODE = ret_prc_code,
S_E_M = lv_err_code,
S_P_F = 'E'
WHERE S_ID = v_d_r (i).S_ID;
lv_proc_failed_count1 := lv_proc_failed_count1 + 1;
END IF;
ELSE --if check_error_record return non-zero value
UPDATE STG_COM_RECORDS
SET PRC_CODE = ret_prc_code,
S_E_M = lv_err_code,
S_P_F = 'E'
WHERE S_ID = v_d_r (i).S_ID;
lv_proc_failed_count1 := lv_proc_failed_count1 + 1;
END IF;
COMMIT;
END LOOP;
EXIT WHEN v_d_c%NOTFOUND;
END LOOP;
CLOSE v_d_c;
COMMIT;
EXCEPTION
WHEN e_dup_prc
THEN --file already processed
UPDATE s_fi
SET s_p_f = 'E'
WHERE sif_id = pi_sif_id;
COMMIT;
po_err_msg := 'This File has previously been processed.';
END;
UPDATE s_fi
SET s_p_f = 'P'
WHERE sif_id = pi_sif_id;
UPDATE p_s
SET PLS_END_DATETIME = SYSDATE, PRS_ERRORED = 'Successful'
WHERE PRS_ID = lv_PRS_ID;
--Populate file load summary
BEGIN
p_p_f_l_s (P_SIF_ID => pi_sif_id);
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
COMMIT;
po_success_count := lv_proc_success_count;
po_failed_count := lv_proc_failed_count1;
RETURN 0;
EXCEPTION
WHEN OTHERS
THEN
lv_err_code := SQLERRM;
UPDATE s_fi
SET s_p_f = 'E'
WHERE sif_id = pi_sif_id;
UPDATE p_s
SET PLS_END_DATETIME = SYSDATE, PRS_ERRORED = lv_err_code
WHERE PRS_ID = lv_PRS_ID;
COMMIT;
po_err_msg := SQLERRM;
CLOSE v_d_c;
RETURN SQLCODE;
END vr_live_load;
FUNCTION insert_v (p_v_d_r IN v_d_c%ROWTYPE, po_err_msg OUT VARCHAR2,po_prc_code OUT VARCHAR2) --inserts records to live table
RETURN NUMBER
IS
RETNUM number := 0;
begin
INSERT INTO VR_COM (VC_ID,
co_pe,
COUNTRY_CODE,
X1_ID,
TIME_PERIOD
)
VALUES (VC_ID_SQ.NEXTVAL,
p_v_d_r.s_perc,
p_v_d_r.s_coun,
(select X1_ID from SERIALS where d_co=p_v_d_r.SVC_d_co),
p_v_d_r.s_time
);
po_prc_code := 'S11';
RETURN retnum;
EXCEPTION
WHEN OTHERS
THEN
PO_ERR_MSG := SQLERRM;
PO_PRC_CODE := 'O11';
DBMS_OUTPUT.PUT_LINE('SQLERRM :'||SQLERRM);
RETURN SQLCODE;
END insert_v;
FUNCTION update_vr (p_v_d_r IN v_d_c%ROWTYPE, po_err_msg OUT VARCHAR2, po_prc_code OUT VARCHAR2) --update the live table if data matches by ID
RETURN NUMBER
IS
LV_d_co SERIALS.d_co%TYPE;
BEGIN
SELECT VRC.X1_ID, D.d_co
INTO LV_VC_ID, LV_d_co
FROM VR_COM VRC, SERIALS D
WHERE VRC.X1_ID = D.X1_ID;
update VR_COM
set co_pe = p_v_d_r.s_perc,
COUNTRY_CODE = p_v_d_r.s_coun,
TIME_PERIOD = p_v_d_r.s_time
WHERE X1_ID = LV_VC_ID;
return 0;
EXCEPTION
WHEN OTHERS
THEN
po_err_msg := SQLERRM;
PO_PRC_CODE := 'O11';
DBMS_OUTPUT.PUT_LINE('SQLERRM :'||SQLERRM);
RETURN SQLCODE;
END update_vr;
FUNCTION check_error_record (p_v_d_r IN v_d_c%ROWTYPE,
lv_prc_code OUT VARCHAR2,
lv_err_flag OUT VARCHAR2) --check error
RETURN NUMBER
IS
--LV_d_co SERIALS.d_co%TYPE;
retnum NUMBER := 0;
lv_found VARCHAR2 (10);
LV_FLAG varchar2 (2);
LV_PROC_FLAG VARCHAR2 (2);
BEGIN
lv_prc_code := NULL;
lv_err_flag := NULL;
BEGIN
IF LV_X1_ID IS NOT NULL THEN
SELECT d_co, d_a_s_c
INTO LV_X1_ID, LV_FLAG
FROM SERIALS
WHERE p_v_d_r.SVC_d_co =d_co;
END IF;
lv_err_flag := 'N';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
lv_prc_code := 'P5';
lv_err_flag := 'Y';
lv_proc_flag := 'E';
END;
IF p_v_d_r.SVC_d_co IS NULL
THEN
lv_prc_code := 'V2';
lv_err_flag := 'Y';
ELSIF p_v_d_r.s_perc IS NULL
THEN
lv_prc_code := 'V6';
lv_err_flag := 'Y';
ELSIF p_v_d_r.s_time IS NULL
THEN
lv_prc_code := 'V4';
lv_err_flag := 'Y';
ELSIF p_v_d_r.s_coun IS NULL
THEN
lv_prc_code := 'V1';
lv_err_flag := 'Y';
ELSE
lv_prc_code := 'S11';
lv_err_flag := 'N';
end if;
RETURN retnum;
EXCEPTION
WHEN OTHERS
THEN
lv_err_flag := 'Y';
RETURN SQLCODE;
END check_error_record;
END VAL_PROC;
P.S SYS_C0012762 constraint Check SVC_PROCESS_FLAG IN ('E', 'N', 'S')
Looks like you are trying to introduce a new value into that flag.
At the moment, the database table only allows a value of E, N or S in the column SVC_PROCESS_FLAG.
If you're trying to put a value of P in that field, you would need to replace the check constraint to also allow it as valid.
how to modify an existing check constraint?
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';
I have a package specification:
G_PKG_NAME CONSTANT VARCHAR2(30) := 'XX_CUST_PKG';
PROCEDURE customer_load
( errbuff OUT NOCOPY VARCHAR2
, retcode OUT NOCOPY VARCHAR2);
And body with procedure which calls to HZ_PARTY_V2PUB API. It uses cursor to take data from a table and then sends it to API :
PROCEDURE create_customer
( errbuff OUT NOCOPY VARCHAR2
, retcode OUT NOCOPY VARCHAR2)
IS
ERR_SOURCE CONSTANT VARCHAR2(100) := G_PKG_NAME ||'.create_customer';
CURSOR c_load
IS
SELECT rowid row_id
, person_first_name
, person_last_name
, title
, known_as
, person_identifier
, gender
FROM xx_customer_info
WHERE NVL(status_flag, 'X') <> 'S';
r_load c_load%ROWTYPE;
--p_init_msg_list VARCHAR2(1) := FND_API.G_TRUE;
v_gender VARCHAR2(30); --hz_parties.sex%TYPE;
v_title VARCHAR2(60); --hz_parties.title%TYPE;
--API record type
person_rec HZ_PARTY_V2PUB.PERSON_REC_TYPE;
-- API output variables
x_return_status VARCHAR2(1);
x_msg_count NUMBER;
x_msg_data VARCHAR2(2000);
x_party_id NUMBER;
x_party_number VARCHAR2(30);
x_profile_id NUMBER;
EXC_VALDN_ERR EXCEPTION;
BEGIN
errbuff := ' ';
retcode := RTN_SUCCESS;
msg_log ('Inside '||ERR_SOURCE);
FOR r_load in c_load LOOP
BEGIN
x_msg_data := NULL;
x_return_status := fnd_api.G_RET_STS_SUCCESS;
fnd_msg_pub.initialize;
-- example validation:
IF r_load.person_first_name IS NULL THEN
x_msg_data := ' "First name" cannot be null';
RAISE EXC_VALDN_ERR;
END IF;
-- Same validation for person_last_name here
-- Record Type:
person_rec.person_first_name := r_load.person_first_name;
person_rec.person_last_name := r_load.person_last_name;
person_rec.person_title := v_title;
person_rec.known_as := null;
person_rec.gender := v_gender;
person_rec.created_by_module := 'TCA_V2_API';
HZ_PARTY_V2PUB.create_person ( p_init_msg_list => FND_API.G_TRUE
, p_person_rec => person_rec
, x_party_id => x_party_id
, x_party_number => x_party_number
, x_profile_id => x_profile_id
, x_return_status => x_return_status
, x_msg_count => x_msg_count
, x_msg_data => x_msg_data);
msg_log('==========================');
msg_log('first name / last_name : '||r_load.person_first_name||' | '||r_load.person_last_name);
msg_log('x_return_status: '||x_return_status);
msg_log('x_msg_count: '||x_msg_count);
msg_log('x_msg_data: '||x_msg_data);
IF NVL(x_return_status, FND_API.G_RET_STS_ERROR) <> FND_API.G_RET_STS_SUCCESS THEN
IF NVL(x_msg_count, 0) > 1 THEN
FOR i IN 1..x_msg_count LOOP
x_msg_data := x_msg_data||i||'. '||substr(fnd_msg_pub.get(p_encoded => fnd_api.g_false ), 1, 255)||' , ';
msg_log(x_msg_data);
END LOOP;
END IF;
END IF;
msg_log('==========================');
EXCEPTION
WHEN OTHERS THEN
x_msg_data := 'EXC: '||NVL(x_msg_data, SQLERRM);
x_return_status := FND_API.G_RET_STS_ERROR;
END;
UPDATE xx_customer_info
SET status_flag = x_return_status
, error_message = x_msg_data
WHERE rowid = r_load.row_id;
END LOOP;
COMMIT;
msg_log ('Exit '||ERR_SOURCE);
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
msg_log('ERROR : '||ERR_SOURCE||' : '||NVL(SQLERRM, x_msg_data));
errbuff := 'ERROR : '||ERR_SOURCE||' : '||NVL(SQLERRM, x_msg_data);
retcode := RTN_ERROR;
END create_customer;
It should return errors or success.
When I test and run this in anonymous block:
begin
XX_CUST_PKG.create_customer;
end;
I get error message PLS-00306: wrong number or types of arguments in call to 'CREATE_CUSTOMER'. I can't see clearly where this error is referring to. I only have 2 OUT parameters, it should only give errbuff (which is x_msg_data) and retcode which is RTN_SUCCESS, RTN_WARNING or RTN_ERROR (I have this declared as constants '0', '1', '2') to output.
This was rewritten from initial package to the above example code, so that it handles exceptions, and few things had to be modified, but now I'm confused when testing it.
What did I leave out?
Any help?
The error you get is a PL/SQL compilation error, as you can see the error code starts with PLS-XXXX.. So it is not returned from your procedure. You missed to send the variables to hold the values from your procedure (out arguments)
Declare
errbuf varchar2(4000);
retcode varchar2(10);
begin
XX_CUST_PKG.create_customer(errbuf,retcode);
--printing the values
DBMS_OUTPUT.PUT_LINE(retcode||' '||errbuf);
end;
/