Error calling Oracle stored procedure from Hibernate Native query - oracle

Consider the following codes:
String checkSeatQuery = "BEGIN USP_RESERVESEAT(IRESULT=>?, ICART_SESSION=>?, IEVENT_ID=>?, ISESSION_ID=>?, IPRICE_SCHEME_ID=>?, ISEAT_ID=>?, IBLOCK_ID=>?, INO_OF_SEAT=>?, IPOS=>?, ISOURCE=>?, IFLASH_SEAT_STATUS_KEY=>?); END;";
Query q = entityManager.createNativeQuery(checkSeatQuery);
q.setParameter(1, DataTypes.STRING); //value passed in: 1
q.setParameter(2, cartSessionId); //value passed in: BT71C49DD999300D33E70B69F0A43F3436
q.setParameter(3, tblEvent.getId()); //value passed in: 20
q.setParameter(4,null); //value passed in: null
q.setParameter(5, Integer.toString(tempTicket.getTblPriceSchemes().getId())); //value passed in: 366
q.setParameter(6, seatId); //value passed in: null
q.setParameter(7, blockId); //value passed in: null
q.setParameter(8, accumulatedSeat); //value passed in: 1
q.setParameter(9, pos); //value passed in: 1
q.setParameter(10, source); //value passed in: 1
q.setParameter(11, null); //value passed in: null
String outputs = (String) q.getResultList().get(0);
Oracle procedure:
DECLARE
IRESULT VARCHAR2(200);
ICART_SESSION VARCHAR2(200);
IEVENT_ID NUMBER;
ISESSION_ID NUMBER;
IPRICE_SCHEME_ID VARCHAR2(200);
ISEAT_ID VARCHAR2(200);
IBLOCK_ID NUMBER;
INO_OF_SEAT NUMBER;
IPOS NUMBER;
ISOURCE NUMBER;
IFLASH_SEAT_STATUS_KEY VARCHAR2(200);
BEGIN
ICART_SESSION := NULL;
IEVENT_ID := NULL;
ISESSION_ID := NULL;
IPRICE_SCHEME_ID := NULL;
ISEAT_ID := NULL;
IBLOCK_ID := NULL;
INO_OF_SEAT := NULL;
IPOS := NULL;
ISOURCE := NULL;
IFLASH_SEAT_STATUS_KEY := NULL;
USP_RESERVESEAT(
IRESULT => IRESULT,
ICART_SESSION => ICART_SESSION,
IEVENT_ID => IEVENT_ID,
ISESSION_ID => ISESSION_ID,
IPRICE_SCHEME_ID => IPRICE_SCHEME_ID,
ISEAT_ID => ISEAT_ID,
IBLOCK_ID => IBLOCK_ID,
INO_OF_SEAT => INO_OF_SEAT,
IPOS => IPOS,
ISOURCE => ISOURCE,
IFLASH_SEAT_STATUS_KEY => IFLASH_SEAT_STATUS_KEY
);
DBMS_OUTPUT.PUT_LINE('IRESULT = ' || IRESULT);
END;
I got the error message:
2012-05-10 15:45:16,267 WARN [org.hibernate.util.JDBCExceptionReporter] (http-localhost%2F127.0.0.1-8080-5) SQL Error: 6550, SQLState: 65000
2012-05-10 15:45:16,267 ERROR [org.hibernate.util.JDBCExceptionReporter] (http-localhost%2F127.0.0.1-8080-5) ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'USP_RESERVESEAT'
ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'USP_RESERVESEAT'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Why is that? After web searching I couldn't find much helpful information..
I am using the following:
Oracle, version: Oracle Database 11g Release 11.1.0.0.0 - Production
Hibernate 3.3.2.GA
PL/SQL:
create or replace
PROCEDURE USP_RESERVESEAT
(
IRESULT OUT VARCHAR2
, ICART_SESSION IN VARCHAR2
, IEVENT_ID IN NUMBER
, ISESSION_ID IN NUMBER
, IPRICE_SCHEME_ID IN VARCHAR2
, ISEAT_ID IN VARCHAR2
, IBLOCK_ID IN NUMBER
, INO_OF_SEAT IN NUMBER
, IPOS IN NUMBER
, ISOURCE IN NUMBER
, IFLASH_SEAT_STATUS_KEY IN VARCHAR2
)as
Iprice_scheme_id_inv VARCHAR2 (3000);
Iseat_id_inv NUMBER;
Icheck NUMBER;
IPos1 NUMBER;
IPos2 NUMBER;
Icapacity NUMBER;
Itic_sold NUMBER;
Irv_cart NUMBER;
Irefund_tic NUMBER;
Irecord NUMBER;
Irecordc NUMBER;
Inew_seat NUMBER;
Iavailable VARCHAR2 (3000);
Istatus_name VARCHAR2 (3000);
Ilatest_seat_status_key VARCHAR2 (3000);
Ilatest_seat_status_name VARCHAR2 (3000);
Ichild NUMBER;
Itotal_child NUMBER;
Icount_row NUMBER;
Ipromo_quantity NUMBER;
Iis_package NUMBER;
Itocart_seat_id NUMBER;
Ilatest_flash_seat_id VARCHAR2 (3000);
Ipromo_tic NUMBER;
Iallotment NUMBER;
Iready_to_cancel NUMBER;
Iready_to_cancel_booking_id NUMBER;
IKILL NUMBER;
BEGIN
if (ISOURCE = '0') THEN
Istatus_name := 'Internet Reserved';
else
if (ISOURCE = '1') THEN
Istatus_name := 'POS Reserved';
else
if (ISOURCE = '2') THEN
Istatus_name := 'CS Reserved';
else
if (ISOURCE = '3') THEN
Istatus_name := 'Call Centre Reserved';
else
if (ISOURCE = '4') THEN
Istatus_name := 'Promoter Reserved';
end IF;
end IF;
end IF;
end IF;
end IF;
begin
INSERT INTO tbl_cart_session
( cart_session,
event_id,
price_scheme_id,
no_of_seat,
created_date
)
VALUES
(
Icart_session,
Ievent_id,
Iprice_scheme_id,
INO_OF_SEAT,
sysdate
);
update tbl_cart_session set created_date=sysdate where cart_session=Icart_session;
select '1' into Iresult from dual;
end;
END USP_RESERVESEAT;

The IRESULT is an OUT parameter so you should register it like this:
String checkSeatQuery = "BEGIN USP_RESERVESEAT(IRESULT=>?, ICART_SESSION=>?, IEVENT_ID=>?, ISESSION_ID=>?, IPRICE_SCHEME_ID=>?, ISEAT_ID=>?, IBLOCK_ID=>?, INO_OF_SEAT=>?, IPOS=>?, ISOURCE=>?, IFLASH_SEAT_STATUS_KEY=>?); END;";
Query q = entityManager.createNativeQuery(checkSeatQuery);
q.registerOutParameter(1, DataTypes.STRING); //value passed in: 1
q.setParameter(2, cartSessionId); //value passed in: BT71C49DD999300D33E70B69F0A43F3436
q.setParameter(3, tblEvent.getId()); //value passed in: 20
q.setParameter(4,null); //value passed in: null
q.setParameter(5, Integer.toString(tempTicket.getTblPriceSchemes().getId())); //value passed in: 366
q.setParameter(6, seatId); //value passed in: null
q.setParameter(7, blockId); //value passed in: null
q.setParameter(8, accumulatedSeat); //value passed in: 1
q.setParameter(9, pos); //value passed in: 1
q.setParameter(10, source); //value passed in: 1
q.setParameter(11, null); //value passed in: null
String outputs = (String) q.getResultList().get(0);

Related

oracle testing function that contains cursor with sql developer

I wrote a function in oracle but I cannot test it. It gives type error but I can call it from java. I want to test it in sql developer tool.I checked all parameter types but they are correct.
My function is like this:
create or replace
FUNCTION GET_STUDENT_SCORE_FN(
p_no IN VARCHAR2,
p_date IN DATE,
p_periods IN NUMBER,
p_cycle OUT VARCHAR2,
p_return_code OUT INTEGER,
p_return_desc OUT VARCHAR2)
RETURN SYS_REFCURSOR
AS
cursor_response_score SYS_REFCURSOR;
def_refcur SYS_REFCURSOR;
BEGIN
IF p_no IS NULL
THEN
p_cycle := NULL;
p_return_code := -1;
p_return_desc := ' no can not be null!';
RETURN def_refcur;
END IF;
OPEN cursor_response_score FOR
SELECT * from students;
return cursor_response_score;
END
I want to test my function.I wrote some codes like this
DECLARE
P_NO VARCHAR2(200);
P_DATE DATE;
P_PERIODS NUMBER;
P_CYCLE VARCHAR2(200);
P_RETURN_CODE NUMBER;
P_RETURN_DESC VARCHAR2(200);
v_Return SYS_REFCURSOR;
BEGIN
P_NO := '5325551374';
P_DATE := to_date('1002019','ddmmyyyy');
P_PERIODS := null;
v_Return := GET_STUDENT_SCORE_FN(
P_NO => P_NO,
P_DATE => P_DATE,
P_PERIODS => P_PERIODS,
P_CYCLE => P_CYCLE,
P_RETURN_CODE => P_RETURN_CODE,
P_RETURN_DESC => P_RETURN_DESC
);
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('P_CYCLE = ' || P_CYCLE);
*/
:P_CYCLE := P_CYCLE;
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('P_RETURN_CODE = ' || P_RETURN_CODE);
*/
:P_RETURN_CODE := P_RETURN_CODE;
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('P_RETURN_DESC = ' || P_RETURN_DESC);
*/
:P_RETURN_DESC := P_RETURN_DESC;
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('v_Return = ' || v_Return);
*/
:v_Return := v_Return; --<-- Cursor
END;
But it gives error like this when i run above query on sql developer( click: run)
ORA-06550: line 25, column 20:
PLS-00382: expression is of wrong type
ORA-06550: line 25, column 4:
PL/SQL: Statement ignored
ORA-06550: line 37, column 16:
PLS-00382: expression is of wrong type
ORA-06550: line 37, column 3:
PL/SQL: Statement ignored
I run above query in on sql page it gives
Bind Variable "P_CYCLE" is NOT DECLARED
anonymous block completed
You can test it from a SQL worksheet using variable and print:
var P_NO VARCHAR2(200);
-- has to be a string, unfortunately; var doesn't support dates directly
var P_DATE VARCHAR2(10);
var P_PERIODS NUMBER;
var P_CYCLE VARCHAR2(200);
var P_RETURN_CODE NUMBER;
var P_RETURN_DESC VARCHAR2(200);
var V_RETURN REFCURSOR;
BEGIN
:P_NO := '5325551374';
:P_DATE := '2019-02-10';
:P_PERIODS := null;
:V_RETURN := GET_STUDENT_SCORE_FN(
P_NO => :P_NO,
P_DATE => to_date(:P_DATE, 'YYYY-MM-DD'),
P_PERIODS => :P_PERIODS,
P_CYCLE => :P_CYCLE,
P_RETURN_CODE => :P_RETURN_CODE,
P_RETURN_DESC => :P_RETURN_DESC
);
END;
/
print P_CYCLE;
print P_RETURN_CODE;
print P_RETURN_DESC;
print V_RETURN;
Notice that the var and print commands don't have colons; but within the PL/SQL block (or just within SQL) they are treated as bind variables, so they do have them there.
The IN parameters don't necessarily have to be bound, so you could simplify slightly to:
var P_CYCLE VARCHAR2(200);
var P_RETURN_CODE NUMBER;
var P_RETURN_DESC VARCHAR2(200);
var V_RETURN REFCURSOR;
BEGIN
:V_RETURN := GET_STUDENT_SCORE_FN(
P_NO => '5325551374',
P_DATE => date '2019-02-10',
P_PERIODS => null,
P_CYCLE => :P_CYCLE,
P_RETURN_CODE => :P_RETURN_CODE,
P_RETURN_DESC => :P_RETURN_DESC
);
END;
/
print P_CYCLE;
print P_RETURN_CODE;
print P_RETURN_DESC;
print V_RETURN;

Only one row added "ORA-02290: check constraint (SYS_C0012762) violated ORA-01403: no data found"

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?

Can I iterate over columns of a composite type?

Let's say I have the following table named bar:
key | columnA | columnB | columnC
A | B | C | D
E | F | G | H
I want to write a function taking a key and a string and doing the following (best described by examples):
Input: ('A', '${columnB} - ${columnA}') / Output : 'C - B'
Input: ('B', 'Hello ${columnC}') / Output: 'Hello H'
For the moment, I have this implementation:
CREATE OR REPLACE FUNCTION foo
( param_key IN VARCHAR2
, format_string IN VARCHAR2
)
RETURN VARCHAR2
IS
my_row bar%ROWTYPE;
retval VARCHAR2(4000);
BEGIN
BEGIN SELECT * INTO my_row FROM bar WHERE "key" = param_key;
EXCEPTION WHEN NO_DATA_FOUND THEN RETURN NULL;
END;
retval := format_string;
retval := REPLACE(retval, '${columnA}', my_row.columnA);
retval := REPLACE(retval, '${columnB}', my_row.columnB);
retval := REPLACE(retval, '${columnC}', my_row.columnC);
RETURN retval;
END;
/
I would like to avoid enumerating all columns one by one in the last part, because the structure of my table can change (new columns for instance). Is there a way to iterate on all columns of my_row, and to replace ${the column name} with the value stored in that column, in a generic way?
Thank you
Another way to achieve this.
Create xmltype from table row.
Create xsl-transform from format_string.
Transform xml using xsl
declare
v_string_format varchar2(200) := '{columnA} + {columnB} + {columnA}{columnB}';
v_key varchar2(10) := 'A';
v_cursor sys_refcursor;
l_xml xmltype;
v_xslt VARCHAR2(500):='<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/ROWSET/ROW">{patern}</xsl:template></xsl:stylesheet>';
begin
-- create xsl transform
v_string_format := upper(v_string_format);
v_string_format := REPLACE(v_string_format,'{','<xsl:value-of select="');
v_string_format := REPLACE(v_string_format,'}','"/>');
v_xslt := replace(v_xslt,'{patern}',v_string_format);
dbms_output.put_line(v_string_format);
-- open cursor for table
open v_cursor for select * from bar where key = v_key;
-- get v_cursor as xmltype.
l_xml := xmltype(v_cursor);
-- print xml
dbms_output.put_line(l_xml.getClobVal());
-- tranform xml and print result
dbms_output.put_line(l_xml.transform(xmltype(v_xslt)).getClobVal());
close v_cursor;
end;
A more efficient solution is this one. For sure you have to write more code and it uses the full scope of dynamic SQL.
CREATE OR REPLACE FUNCTION foo (param_key IN VARCHAR2, format_string IN VARCHAR2)
RETURN VARCHAR2 IS
retval VARCHAR2(4000) := format_string;
cur SYS_REFCURSOR;
curId INTEGER;
descTab DBMS_SQL.DESC_TAB;
colCnt NUMBER;
numvar NUMBER;
datevar DATE;
namevar VARCHAR2(4000);
tsvar TIMESTAMP;
BEGIN
OPEN cur FOR SELECT * FROM bar WHERE "key" = param_key;
curId := DBMS_SQL.TO_CURSOR_NUMBER(cur);
DBMS_SQL.DESCRIBE_COLUMNS(curId, colCnt, descTab);
-- Define columns
FOR i IN 1..colcnt LOOP
IF desctab(i).col_type = DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, numvar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, datevar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, tsvar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.DEFINE_COLUMN(curid, i, namevar, 4000);
--ELSIF desctab(i).col_type = ... THEN
--DBMS_SQL.DEFINE_COLUMN(curid, i, ...);
END IF;
END LOOP;
-- Fetch Rows
IF DBMS_SQL.FETCH_ROWS(curid) > 0 THEN
-- Fetch only the first row and do not consider if further rows exist,
-- otherwise use WHILE DBMS_SQL.FETCH_ROWS(curid) > 0 LOOP
FOR i IN 1..colcnt LOOP
IF desctab(i).col_type = DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.COLUMN_VALUE(curid, i, namevar);
retval := REPLACE(retval, '${'||desctab(i).col_name||'}', namevar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.COLUMN_VALUE(curid, i, numvar);
retval := REPLACE(retval, '${'||desctab(i).col_name||'}', numvar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.COLUMN_VALUE(curid, i, datevar);
retval := REPLACE(retval, '${'||desctab(i).col_name||'}', datevar);
ELSIF desctab(i).col_type = DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.COLUMN_VALUE(curid, i, tsvar);
retval := REPLACE(retval, '${'||desctab(i).col_name||'}', tsvar);
--ELSIF desctab(i).col_type = ... THEN
--DBMS_SQL.COLUMN_VALUE(curid, i, ...);
--retval := REPLACE(retval, '${'||desctab(i).col_name||'}', ...);
END IF;
END LOOP;
ELSE
retval := NULL;
END IF;
DBMS_SQL.CLOSE_CURSOR(curId);
RETURN retval;
END;
You can get the result you are after using dynamic queries...
CREATE OR REPLACE FUNCTION foo
( param_key IN VARCHAR2
, format_string IN VARCHAR2
)
RETURN VARCHAR2
IS
retval VARCHAR2(4000) := format_string;
cols SYS.ODCIVARCHAR2LIST;
BEGIN
SELECT COLUMN_NAME
BULK COLLECT INTO cols
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'bar'
ORDER BY COLUMN_ID;
FOR i IN 1 .. cols.COUNT LOOP
EXECUTE IMMEDIATE 'SELECT REPLACE( :1, ''${' || cols(i) || '}'', ' || cols(i) || ' ) FROM bar WHERE key = :2'
INTO retval
USING retval, param_key;
END LOOP;
RETURN retval;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END;
/
... but:
This uses dynamic SQL to query the table directly and does not use a %ROWTYPE record.
You may not have access to USER_TAB_COLUMNS (or may need ALL_TAB_COLUMNS) and the DBA might not want you to have access to the data dictionary tables.
It is probably (almost certainly) very inefficient.
I've seen this done before and never let it pass a code review (writing out the explicit column names has always seemed preferable).
So, while it is possible, I would say don't do this.

Oracle procedure to create_person fails with PLS-00306 error

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;
/

Stored procedure. RefCursor declaration issue

I'm trying to write a stored procedure, where I use a refcursor, but when I try to run it, Oracle tells me that the refcursor is not declared
Package:
create or replace package types
as
type cursorType is ref cursor;
end;
/
Procedure:
CREATE OR REPLACE PROCEDURE p_lista_veic_aluguer (
ESCRITORIO IN INT,
CATEGORIA IN CHAR,
DATA_INI IN DATE,
DATA_FIM IN DATE,
RETVAL IN OUT types.cursorType
) is
BEGIN
open retval for
SELECT B.COD_Veiculo,B.Marca
FROM VEICULO B
LEFT JOIN ALUGUER A
ON A.COD_VEICULO = B.COD_VEICULO
AND (data_ini BETWEEN A.DATA_LEVANTAMENTO AND A.DATA_ENTREGA
OR data_fim BETWEEN A.DATA_LEVANTAMENTO AND A.DATA_ENTREGA)
WHERE A.COD_VEICULO IS NULL
AND B.DATA_MANUTENCAO IS NULL
AND B.CATEGORIA = categoria
ORDER BY f_menor_dist(B.ESCRITORIO_ATUAL,escritorio) ASC;
END p_lista_veic_aluguer;
/
Testing :
SET DEFINE OFF;;
DECLARE
ESCRITORIO NUMBER;
CATEGORIA CHAR(200);
DATA_INI DATE;
DATA_FIM DATE;
variable RETVAL TYPES.cursorType;
BEGIN
ESCRITORIO := 22;
CATEGORIA := 'A';
DATA_INI := '2012/11/23';
DATA_FIM := '2012/11/30';
P_LISTA_VEIC_ALUGUER( ESCRITORIO => ESCRITORIO,
CATEGORIA => CATEGORIA,
DATA_INI => DATA_INI,
DATA_FIM => DATA_FIM,
RETVAL => RETVAL );
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('RETVAL = ' || RETVAL);
*/
print retval;
END;
Error:
Error report: ORA-06550: linha 6, coluna 19: PLS-00103: Encountered
the symbol "TYPES" when expecting one of the following:
:= . ( # % ; not null range default character The symbol ":=" was
substituted for "TYPES" to continue. ORA-06550: linha 16, coluna 9:
PLS-00103: Encountered the symbol "RETVAL" when expecting one of the
following:
:= . ( # % ; The symbol ":=" was substituted for "RETVAL" to
continue.
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
SET DEFINE OFF;
variable RETVAL refcursor;
DECLARE
ESCRITORIO NUMBER;
CATEGORIA CHAR(200);
DATA_INI DATE;
DATA_FIM DATE;
BEGIN
ESCRITORIO := 22;
CATEGORIA := 'A';
DATA_INI := '2012/11/23';
DATA_FIM := '2012/11/30';
P_LISTA_VEIC_ALUGUER( ESCRITORIO => ESCRITORIO,
CATEGORIA => CATEGORIA,
DATA_INI => DATA_INI,
DATA_FIM => DATA_FIM,
RETVAL => RETVAL );
/* Legacy output:
DBMS_OUTPUT.PUT_LINE('RETVAL = ' || RETVAL);
*/
print retval;
END;
Try this it will work.

Resources