ORA-01001 invalid cursor - oracle

I have an "ORA-01001 invalid cursor" issue I am not able to solve.
In our production environment, we have three application server and it's pointing the single Database(Oracle 10g).
I am receiving the "ora-01001 invalid cursor" error while calling the following procedure through the jdbc,
Procedure:
CREATE OR REPLACE
PROCEDURE "GET_CUSTOMER_DETAILS"(
p_ACC_NUM IN VARCHAR2 ,
o_PRODUCT_CODE OUT VARCHAR2 ,
o_PRODUCT_TYPE OUT VARCHAR2 ,
o_NATIONALITY OUT VARCHAR2 ,
o_CUSTOMER_CAT OUT VARCHAR2 ,
o_SERVICE_STATUS OUT VARCHAR2 ,
o_CURR_PLAN OUT VARCHAR2 ,
o_ERROR_CODE OUT NUMBER ,
o_ERROR_MSG OUT VARCHAR2 )
AS
v_count INT;
v_accNum VARCHAR2(50);
v_Product_Desc VARCHAR2(50);
v_IPhone_Status VARCHAR2(50);
v_BB_Status VARCHAR2(50);
v_now DATE;
BEGIN
o_CURR_PLAN := 0;
SELECT PRODUCT_DESC,
PRODUCT_NAME,
IPHONE_STATUS,
BB_STATUS,
PARTY_NATIONALITY,
CUSTOMER_CAT,
SERVICE_STATUS,
new_postpaid_flag
INTO v_Product_Desc,
o_PRODUCT_TYPE,
v_IPhone_Status,
v_BB_Status,
o_NATIONALITY,
o_CUSTOMER_CAT,
o_SERVICE_STATUS,
o_CURR_PLAN
FROM tbl_crm_custmaster
WHERE account_number = p_ACC_NUM
AND rownum = 1;
IF (v_Product_Desc = 'WS' AND v_IPhone_Status = 'N' AND v_BB_Status = 'N') THEN
o_PRODUCT_CODE := 'WP'; --General Prepaid
elsif (v_Product_Desc = 'WS' AND v_IPhone_Status = 'N' AND v_BB_Status = 'Y') THEN
o_PRODUCT_CODE := 'WB'; --BlackBerry Prepaid
elsif (v_Product_Desc = 'WS' AND v_IPhone_Status = 'Y' AND v_BB_Status = 'N') THEN
o_PRODUCT_CODE := 'WI'; --IPhone Prepaid
elsif (v_Product_Desc = 'WS' AND v_IPhone_Status = 'Y' AND v_BB_Status = 'Y') THEN
o_PRODUCT_CODE := 'WP'; --General Prepaid
elsif (v_Product_Desc = 'GS' AND v_IPhone_Status = 'N' AND v_BB_Status = 'N') THEN
o_PRODUCT_CODE := 'GP'; --General Postpaid
elsif (v_Product_Desc = 'GS' AND v_IPhone_Status = 'N' AND v_BB_Status = 'Y') THEN
o_PRODUCT_CODE := 'GB'; --BlackBerry Postpaid
elsif (v_Product_Desc = 'GS' AND v_IPhone_Status = 'Y' AND v_BB_Status = 'N') THEN
o_PRODUCT_CODE := 'GI'; --IPhone Postpaid
elsif (v_Product_Desc = 'GS' AND v_IPhone_Status = 'Y' AND v_BB_Status = 'Y') THEN
o_PRODUCT_CODE := 'GP'; --General Postpaid
elsif (v_Product_Desc = '2P' OR v_Product_Desc = '3P') THEN
o_PRODUCT_CODE := 'EL'; --Landline associated with E-Life
elsif (v_Product_Desc = 'VO') THEN
o_PRODUCT_CODE := 'GL'; --Landline Postpaid
elsif (v_Product_Desc = 'FN') THEN
o_PRODUCT_CODE := 'WL'; --Landline Prepaid
elsif (v_Product_Desc = 'HI') THEN
o_PRODUCT_CODE := 'IN'; --Landline Prepaid
elsif (v_Product_Desc = 'EV') THEN
o_PRODUCT_CODE := 'EV'; --Landline Prepaid
END IF;
o_ERROR_CODE := 0;
o_ERROR_MSG := 'SUCCESS';
EXCEPTION
WHEN NO_DATA_FOUND THEN
o_ERROR_CODE := -1;
o_ERROR_MSG := 'NO REOCRDS FOUND';
WHEN OTHERS THEN
o_ERROR_CODE := SQLCODE;
o_ERROR_MSG := SQLERRM;
END;
Java Code 1:
public void requestBegin(SCESession mySession) {
// TODO Auto-generated method stub
ITraceInfo trace = mySession.getTraceOutput();
UserDetails userDetails = (UserDetails) mySession.getProperty(EtisalatConstants.USER_DETAILS);
CallDetailsBean detailsBean=(CallDetailsBean) mySession.getProperty(EtisalatConstants.CALLER_DETAILS_BEAN_OBJECT);
DwhEtisalatMethods etisalatMethods=null;
HashMap<String, String> response = new HashMap<String, String>();
String hostErrResponse = "", hostErrCode = "";
EtaDbImpl dao = null;
try{
//Host Reporting Start Details
etisalatMethods=new DwhEtisalatMethods();
etisalatMethods.HostStartDetails(mySession, CommonMethod.generateUniqueId(), LoggingConstants.GET_CALLER_DETAILS_CRM, LoggingConstants.NOT_APPLICABLE, LoggingConstants.DATABASE);
dao = new EtaDbImpl();
response = dao.getCustomerDetails(userDetails.getPhoneNumber(), mySession);
trace.writeln(ITraceInfo.TRACE_LEVEL_DEBUG,"DB Success:");
hostErrCode = response.get(EtisalatDbConstants.ERROR_CODE);
hostErrResponse = response.get(EtisalatDbConstants.ERROR_MSG);
trace.writeln(ITraceInfo.TRACE_LEVEL_DEBUG,"ERROR_CODE:"+hostErrCode);
trace.writeln(ITraceInfo.TRACE_LEVEL_DEBUG,"ERROR_Response:"+hostErrResponse);
if(hostErrResponse.equalsIgnoreCase(EtisalatDbConstants.DB_SUCCESS_MSG) || hostErrCode.equalsIgnoreCase(EtisalatDbConstants.DB_SUCCESS_CODE)){
userDetails.setAccountNumber(response.get(EtisalatDbConstants.ACCOUNT_NUMBER));
//userDetails.setPhoneNumber(response.get(EtisalatDbConstants.PHONE_NUMBER));
userDetails.setProductType(response.get(EtisalatDbConstants.PRODUCT_TYPE));
userDetails.setProductCode(response.get(EtisalatDbConstants.PROD_CODE));
userDetails.setNationality(response.get(EtisalatDbConstants.NATIONALITY));
userDetails.setCustomerCategory(response.get(EtisalatDbConstants.CUSTOMER_CAT));
userDetails.setCurrPlan(response.get(EtisalatDbConstants.CURR_PLAN));
userDetails.setServiceStatus(response.get(EtisalatDbConstants.SERVICE_STATUS));
//Set in Project variable
mySession.getVariableField(IProjectVariables.APP_VARIABLES, IProjectVariables.APP_VARIABLES_FIELD_ACCOUNT_NO).setValue(userDetails.getAccountNumber());
mySession.getVariableField(IProjectVariables.APP_VARIABLES, IProjectVariables.APP_VARIABLES_FIELD_PRODUCT_CODE).setValue(userDetails.getProductCode());
mySession.getVariableField(IProjectVariables.APP_VARIABLES, IProjectVariables.APP_VARIABLES_FIELD_PRODUCT_TYPE).setValue(userDetails.getProductType());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_ACCT_NO).setValue(userDetails.getAccountNumber());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_CUSTOMER_CATEGORY).setValue(userDetails.getCustomerCategory());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_NATIONALITY).setValue(userDetails.getNationality());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_PRODUCT_CODE).setValue(userDetails.getProductCode());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_PRODUCT_TYPE).setValue(userDetails.getProductType());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_SERVICE_STATUS).setValue(userDetails.getServiceStatus());
mySession.getVariableField(IProjectVariables.GET_CRMCUST_MASTER, IProjectVariables.GET_CRMCUST_MASTER_FIELD_CURR_PLAN).setValue(userDetails.getCurrPlan());
detailsBean.setAuthenticated_Type(userDetails.getProductType());
detailsBean.setAuthenticated_number(userDetails.getAccountNumber());
mySession.getVariableField(IProjectVariables.FLAGS, IProjectVariables.FLAGS_FIELD_HOSTSERVICE_STATUS).setValue(EtisalatConstants.YES);
detailsBean.setCaller_authenticated(EtisalatConstants.REPORT_YES);
//Setting the customer segment for reporting purpose
detailsBean.setCustomer_segment(userDetails.getCustomerSegment());
//Setting the available products for the caller
//detailsBean.setProduct_category(userDetails.getProductType());
detailsBean.setProduct_category(userDetails.getProductCode());
detailsBean.setAccount_number(userDetails.getAccountNumber());
detailsBean.setAuthenticated_number(userDetails.getAccountNumber());
detailsBean.setAuthenticated_Type("AUTO");
}else if(hostErrResponse.equalsIgnoreCase(EtisalatDbConstants.DB_NO_REC_MSG) || hostErrCode.equalsIgnoreCase(EtisalatDbConstants.DB_NO_REC_CODE)){
mySession.getVariableField(IProjectVariables.FLAGS, IProjectVariables.FLAGS_FIELD_HOSTSERVICE_STATUS).setValue(EtisalatConstants.NO);
trace.writeln(ITraceInfo.TRACE_LEVEL_ERROR, "No Record Found for the account_number of '"+userDetails.getPhoneNumber()+"'");
}else{
throw new Exception(hostErrResponse); //Line No: 185
}
}catch (Exception e) {
// TODO Auto-generated catch block
detailsBean.setCall_end_reason(EtisalatConstants.CALLEND_REASON_DBDOWN);
mySession.getVariableField(IProjectVariables.FLAGS, IProjectVariables.FLAGS_FIELD_HOSTSERVICE_STATUS).setValue(EtisalatConstants.NO);
trace.writeln(ITraceInfo.TRACE_LEVEL_ERROR, "Exception : There is an issue while getting customer details "+e);
e.printStackTrace();
}finally{
mySession.setProperty(EtisalatConstants.USER_DETAILS, userDetails);
mySession.setProperty(EtisalatConstants.CALLER_DETAILS_BEAN_OBJECT, detailsBean);
//Host Reporting End Details
etisalatMethods.HostEndDetails(mySession, LoggingConstants.NOT_APPLICABLE, LoggingConstants.NOT_APPLICABLE, LoggingConstants.NOT_APPLICABLE, hostErrResponse, LoggingConstants.NOT_APPLICABLE);
response = null;
etisalatMethods=null;
hostErrResponse = null;
detailsBean = null;
trace = null;
userDetails = null;
dao = null;
}
super.requestBegin(mySession);
}
Java Code 2:
public HashMap<String, String> getCustomerDetails(String acctNo, SCESession mySession){
ITraceInfo trace = mySession.getTraceOutput();
dataSource = (BasicDataSource)mySession.getProperty(DATASRC_IVR_DB);
HashMap<String, String> returnhash = new HashMap<String, String>();
//trace.writeln(ITraceInfo.TRACE_LEVEL_INFO, "Account number :"+acctNo.substring(acctNo.length()-4) );
try
{
//logger.debug(callId+" The input is:"+hm);
start=System.currentTimeMillis();
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO, "Start Time of GET_CUSTOMER_DETAILS="+start);
con=dataSource.getConnection();
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO, "Data source connection established");
proc = con.prepareCall("{ call GET_CUSTOMER_DETAILS(?, ?, ?, ?, ?, ?, ?, ?, ?) }");
if(acctNo !=null && !acctNo.trim().isEmpty()){
proc.setString(1, acctNo);
}else{
proc.setNull(1, OracleTypes.VARCHAR);
}
proc.registerOutParameter(2, Types.VARCHAR);
proc.registerOutParameter(3, Types.VARCHAR);
proc.registerOutParameter(4, Types.VARCHAR);
proc.registerOutParameter(5, Types.VARCHAR);
proc.registerOutParameter(6, Types.VARCHAR);
proc.registerOutParameter(7, Types.VARCHAR);
proc.registerOutParameter(8, Types.INTEGER);
proc.registerOutParameter(9, Types.VARCHAR);
try {
if(!QueryTimeout.equalsIgnoreCase(NO))
proc.setQueryTimeout(Integer.parseInt(QueryTimeout));
else
proc.setQueryTimeout(_2s);
} catch (NumberFormatException e) {
proc.setQueryTimeout(_2s);
}
trace.writeln(ITraceInfo.TRACE_LEVEL_DEBUG,"Time out="+QueryTimeout);
proc.execute();
returnhash.put(ERROR_CODE, proc.getString(8));
returnhash.put(ERROR_MSG, proc.getString(9));
if(returnhash.get(ERROR_MSG).equalsIgnoreCase(DB_SUCCESS_MSG) || returnhash.get(ERROR_CODE).equalsIgnoreCase(DB_SUCCESS_CODE)){
returnhash.put(ACCOUNT_NUMBER, acctNo);
//returnhash.put(PHONE_NUMBER, rs.getString(2));
returnhash.put(PROD_CODE, proc.getString(2));
returnhash.put(PRODUCT_TYPE, proc.getString(3));
returnhash.put(NATIONALITY, proc.getString(4));
returnhash.put(CUSTOMER_CAT, proc.getString(5));
returnhash.put(SERVICE_STATUS, proc.getString(6));
returnhash.put(CURR_PLAN, proc.getString(7));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,ACCOUNT_NUMBER+":"+ acctNo);
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,PROD_CODE+":" + proc.getString(2));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,PRODUCT_TYPE+":" + proc.getString(3));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,NATIONALITY+":" + proc.getString(4));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,CUSTOMER_CAT+":" + proc.getString(5));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,SERVICE_STATUS+":" + proc.getString(6));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,CURR_PLAN+":" + proc.getString(7));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,ERROR_CODE+":"+proc.getString(8));
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO,ERROR_MSG+":"+proc.getString(9));
}else{
trace.writeln(ITraceInfo.TRACE_LEVEL_DEBUG, "No records found");
}
end=System.currentTimeMillis();
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO, "end Time of GET_CUSTOMER_DETAILS="+end);
trace.writeln(ITraceInfo.TRACE_LEVEL_INFO, "Total Time of GET_CUSTOMER_DETAILS="+(end-start)+"ms");
}
catch (SQLException e)
{
returnhash.put(ERROR_CODE, "03");
returnhash.put(ERROR_MSG, e.getMessage());
trace.writeln(ITraceInfo.TRACE_LEVEL_ERROR, "SQL Exception"+e);
e.printStackTrace();
}
finally{
try{
closeResult(rs);
closeCallableStmt(proc);
closeConnection(con);
}catch(SQLException e){
returnhash.put(ERROR_CODE, "03");
returnhash.put(ERROR_MSG, e.getMessage());
trace.writeln(ITraceInfo.TRACE_LEVEL_ERROR, "SQL Exception while closing the Connection "+e);
}
if(trace != null){
trace = null;
}
if(dataSource != null){
dataSource = null;
}
}
return returnhash;
}
Java code 1 method calls the Java Code 2 method.
In java Code 1, i'm processing the data what is received from the oracle.
In java code 2, i'm calling stored procedure.
I handled the sql exception in the procedure level. If any error in the procedure, the procedure returns the oracle error code and error message as a parameter. In the java Code 2, i'm receiving the oracle error code(1001) and store that in the hashmap, after that i'm checking whether the error code is equal to 0(success).So,it prints no reocrd log. In the java Code 1, i'm receiving the hashmap. From the hashmap,i take out the error code value. if the error code is not equavalent to 0 or -1, then i'm throwing the exception what i received from the oracle(printed in trace log and stack trace log).
Trace Log
12/06/2013 06:26:35:063 INFO - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : Start Time of GET_CUSTOMER_DETAILS=1371003995063
12/06/2013 06:26:35:065 INFO - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : Data source connection established
12/06/2013 06:26:35:065 DEBUG - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : Time out=2
12/06/2013 06:26:35:067 DEBUG - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : No records found
12/06/2013 06:26:35:067 INFO - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : end Time of GET_CUSTOMER_DETAILS=1371003995067
12/06/2013 06:26:35:067 INFO - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : Total Time of GET_CUSTOMER_DETAILS=4ms
12/06/2013 06:26:35:067 DEBUG - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : DB Success:
12/06/2013 06:26:35:067 DEBUG - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : ERROR_CODE:-1001
12/06/2013 06:26:35:067 DEBUG - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : ERROR_Response:ORA-01001: invalid cursor
12/06/2013 06:26:35:067 ERROR - EC2E4987556A7FF7DA6DEE8EEE9843FC.jvm2:/ETA_MAIN : Exception : There is an issue while getting customer details java.lang.Exception: ORA-01001: invalid cursor
Stack Trace Log:
java.lang.Exception: ORA-01001: invalid cursor
at flow.DB_GetCRM_CustMaster.requestBegin(DB_GetCRM_CustMaster.java:185)
at com.avaya.sce.runtime.AppServlet.processRequest(AppServlet.java:81)
at com.avaya.sce.runtime.SCEServlet.requestHandler(SCEServlet.java:282)
at com.avaya.sce.runtime.SCEServlet.doPost(SCEServlet.java:189)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:630)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
at com.avaya.sce.runtime.SCEServlet.forward(SCEServlet.java:1303)
at com.avaya.sce.runtime.Data.evaluateActions(Data.java:211)
at flow.DB_GetCallerProfileDetails.executeDataActions(DB_GetCallerProfileDetails.java:94)
I couldn't reproduce this issue in SQLPlus, it only happens from jdbc calls from the application server 2 and application server 3, and repeating the same call usually works (but sometimes fails couple of times before succeeding). I have not used any cursor in the procedure. Please help me on this issue.

Maybe types are incorrect.. can You change signature to something like that:
CREATE OR REPLACE PROCEDURE "GET_CUSTOMER_DETAILS"(
p_ACC_NUM IN VARCHAR2 ,
o_PRODUCT_CODE OUT VARCHAR2 ,
o_PRODUCT_TYPE OUT tbl_crm_custmaster.PRODUCT_NAME%type,
o_NATIONALITY OUT tbl_crm_custmaster.PARTY_NATIONALITY%type ,
o_CUSTOMER_CAT OUT tbl_crm_custmaster.CUSTOMER_CAT%type ,
o_SERVICE_STATUS OUT tbl_crm_custmaster.SERVICE_STATUS%type ,
o_CURR_PLAN OUT tbl_crm_custmaster.new_postpaid_flag%type,
o_ERROR_CODE OUT NUMBER ,
o_ERROR_MSG OUT VARCHAR2 ) AS
v_count INT;
v_accNum VARCHAR2(50);
v_Product_Desc tbl_crm_custmaster.PRODUCT_DESC%type,
v_IPhone_Status tbl_crm_custmaster.IPHONE_STATUS%type;
v_BB_Status tbl_crm_custmaster.BB_STATUS%type;
v_now DATE;

Related

How to return two types in pl/sql oracle

How to return two types in pl/sql oracle?
return number -- here I tell than function reurns number, but i want to return number and string when an exception is thrown
is
prPrice number; -- product price
curFrom number; -- price
pgcount number := 0; -- product count
noProductsOnDate EXCEPTION;
wrongCurrency EXCEPTION;
begin
SELECT COUNT(*) INTO pgcount
from Products pr, Outgoing outg, Incoming inc
where pr.PROD_ID = outg.PROD_ID and pr.PROD_ID = inc.PROD_ID and inc.inc_date > d
Having sum(inc.quantity) > sum(outg.quantity);
if pgcount = 0 or pgcount is null then
raise noProductsOnDate;
END IF;
if curTo > 2 OR curTo < 1 then
raise wrongCurrency;
end if;
If curTo = 1
then curFrom := 2;
Elsif curTo = 2
then curFrom := 1;
END IF;
select pric.Value*cour.value into prPrice from Prices pric, Cources cour
where p = pric.prod_id and pric.DAYFROM <= d and (pric.DAYTO >= d or pric.DAYTO is null) and cour.cur_idto = curTo and cour.cur_idfrom = curFrom;
return prPrice; -- here i wanna return number
exception
when noProductsOnDate then return '1q'; -- here i wanna return string (error message)
when wrongCurrency then return '2q'; -- here i wanna return string (error message)
end;
I can't return string in exception, because function return number
Maybe I doing something wrong,
Please, tell me how can I return several data types from one function, maybe I should do everything differently, but I don't understand how to do it ((
You can't do it that way, but can another way around - declare function to return varchar2. Then, in your code, you can
create function ...
return varchar2
is
begin
... do whatever you're doing
return to_char(poPrice);
exception
when ... then return '1q';
end;
I write my functions often in this form:
return 0 in case of success
return a positive number in case of a warning (often not used)
return a negative number in case of an error
And I use out parameters for the function results, in your case the price and/or a message.
Something along the lines of:
CREATE OR REPLACE FUNCTION my_function(vi_date IN DATE,
vo_price OUT NUMBER,
vo_msg OUT VARCHAR) RETURN INTEGER IS
BEGIN
...
IF pgcount = 0 OR pgcount IS NULL THEN
vo_msg := 'No products on that date.';
RETURN -20001; -- return custom error code
END IF;
...
IF vo_price < 0 THEN
vo_msg := 'Price is negative. Calculation my be wrong.';
RETURN 1; -- return warning flag (positive number)
ELSE
RETURN 0; -- means success
END IF;
EXCEPTION WHEN OTHERS THEN
-- Error. Return negative number. SQLCODE is always the negative ORA code
-- except for ORA-1403 which is strangely SQLCODE 100 instead
vo_msg := SQLERRM;
RETURN CASE WHEN SQLCODE = 100 THEN -1403 ELSE SQLCODE END;
END my_function;
Then call it like this:
DECLARE
v_code INTEGER;
v_price NUMBER (10,2);
v_msg VARCHAR(1000);
BEGIN
v_code := my_function(DATE '2022-09-29', v_price, v_msg);
IF v_code >= 0 THEN
DBMS_OUTPUT.PUT_LINE('The price is: ' || v_price);
END IF;
IF v_code <> 0 THEN
DBMS_OUTPUT.PUT_LINE('Message: ' || v_msg);
END IF;
END;

Update: Function Error: PLS-00306: wrong number or types of arguments in call to 'get_bus_result_attribute'

I just think the problem of issue and change the function-to-function logic design. Then, the error as mentioned the function (get_result_attribute) - PLS-00306: wrong number or types of arguments in call to 'get_result_attribute'. May I know the function "get_result_attribute" problem in which part?
Coding for the bus station system.
FUNCTION get_bus_result_attribute (iv_result_name varchar2,
iv_result_key varchar2,
iv_result_attribute varchar2)
--define the parameter to get the "sql_result" script result
RETURN varchar2 IS
sql_result varchar2(500);
sql_return varchar2(500);
BEGIN
sql_result := 'SELECT ' || iv_result_attribute || '
FROM MyTable a,
MyTable b
WHERE a.bus_value_set_id = b.bus_value_set_id
AND b.bus_value_set_name = iv_result_name
AND a.enabled_flag = ''Y''
AND a.bus_value = iv_result_key
AND iv_result_name = get_bus_code (v_bus)
AND iv_result_key = get_bus_name(v_group)
AND iv_result_key = iv_result_attribute';
EXECUTE IMMEDIATE sql_result
INTO sql_return; --get the "sql_result" script result
return sql_return;
exception
when others then
return '';
end get_bus_result_attribute;
FUNCTION get_bus_code (v_bus varchar2)
RETURN VARCHAR2 IS
v_get_bus_code_result VARCHAR2(20) ;
BEGIN
SELECT busa.bus_code
INTO v_get_bus_code_result
FROM tbl_bus_code busa, tbl_bus_line busb
WHERE busa.bus_code_set_id = busb.bus_code_set_id
AND busb.bus_line_set_name = 'HK_BUS_CODE'
AND busa.enabled_flag = 'Y'
AND (busa.attribute4 = 'Y' OR busa.attribute5 = 'Y')
AND busa.BUS_VALUE = v_bus;
RETURN v_get_bus_code_result;
RETURN get_result_attribute('BUS_LINES', v_bus, 'attribute1'); /*BUS_GP*/
EXCEPTION
WHEN OTHERS THEN
RETURN '';
END get_bus_code;
FUNCTION get_bus_name(v_group VARCHAR2) --define the parameter and enter the value in the function 'get_bus_result_attribute'
RETURN VARCHAR2 IS
v_get_bus_div_result VARCHAR2(20) ;
BEGIN
SELECT DISTINCT CASE busa.bus_code --Bus code
WHEN '52' THEN '52X'
WHEN '58P' THEN '58'
WHEN 'K1' THEN 'K1C'
WHEN '40' THEN '40X'
WHEN '6' THEN '6X'
WHEN '7' THEN '7'
WHEN '58M' THEN '58'
ELSE ''
END bus_code --Bus code
INTO v_get_bus_div_result
FROM tbl_bus_code busa, tbl_bus_line busb
WHERE busa.bus_code_set_id = busb.bus_code_set_id
AND busb.bus_line_set_name = 'HK_BUS_LINES'
AND busa.enabled_flag = 'Y'
AND (busa.attribute4 = 'Y' OR busa.attribute5 = 'Y')
AND busa.bus_code NOT IN ('INACTIVE', 'XXX')
AND get_bus_code(busa.BUS_VALUE) = v_group
RETURN get_result_attribute('BUS_GROUP', v_group, 'attribute2');
--bus_group_dir
EXCEPTION
WHEN OTHERS THEN
RETURN '';
END get_bus_name;
FUNCTION BUS_DOC_TEXT (N_ID NUMBER, N_HEAD_ID NUMBER)
RETURN VARCHAR2 IS
v_bus_doc_text VARCHAR2(150);
BEGIN
SELECT 'BUS\'
|| get_bus_result_attribute(abc.attribute14)
|| '\'
|| abc.attribute14
|| '\'
|| abc.segment1
INTO v_bus_doc_text
FROM my_table_c abc
WHERE abc.ORG_ID = N_ID -- parameter
AND abc.bus_id = N_HEADER_ID; -- parameter
END;
RETURN v_bus_doc_text ;
END;
END;

SQL state [99999]; error code [17004]; Type de colonne non valide: 1111

I have this call to PL/SQL function
FUNCTION F_IsDemandeDeLitFromHosp(i_NoMvtHosp IN MVTHOSP.NOMVTHOSP%TYPE
)RETURN BOOLEAN
IS
v_Found NUMBER := 0;
BEGIN
BEGIN
SELECT COUNT(1) INTO v_Found
FROM ICSF.T_DEMANDE_LIT D, MVTUS U, MVTHOSP H
WHERE H.NOMVTHOSP = i_NoMvtHosp
AND H.NOMVTHOSP = U.NOMVTHOSP
AND U.NOMVTUS = D.NOMVTUS
AND U.RANG <> '0000000000'
AND H.RANG = '0000100000'
AND NVL (D.ETAT, ' ') <> 'X'
AND NVL (U.ETAT, ' ') <> 'X'
AND NVL (H.ETAT, ' ') <> 'X'
AND ROWNUM = 1;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END;
IF v_Found > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END F_IsDemandeDeLitFromHosp;
I try to write a service to get the boolean in return. i_NoMvtHosp is a CHAR(10 BYTE) and here is the call of my function:
#Override
public DemandeDeLitFromHospit isDemandeDelitFromHosp(String noMvtHosp) {
final ProcedureRequest request = new ProcedureRequest(PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getPackageName(), PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getMethodeName());
request.addInParam("i_NoMvtHosp", noMvtHosp);
DemandeDeLitFromHospit demande = new DemandeDeLitFromHospit();
demande.setIsDemandeDeLitFromHosp((Boolean)callFunction(request, new CallableStatementCallback<Boolean>() {
public Boolean doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
cs.execute();
return Boolean.valueOf(cs.getResultSet().toString());
}
}));
return demande;
}
And I've got this error:
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL []; SQL state [99999]; error code [17004]; Type de colonne non valide: 1111; nested exception is java.sql.SQLException: Type de colonne non valide: 1111
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:1032)
at fr.mckesson.framework.persistence.plsql.AbstractProcedureDao.callFunction(AbstractProcedureDao.java:317)
at fr.mckesson.business.venue.clinique.evenement.dao.implementation.DemandeLitDAO.isDemandeDelitFromHosp(DemandeLitDAO.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Where am i wrong ?
Your code is failing on error code [17004]; invalid column type: 1111 . This error happens because your code uses a datatype which JDBC doesn't recognise.
This is probably because your function returns BOOLEAN. Boolean is not a valid SQL datatype. You wouldn't be able to call that a function in a straightforward Oracle SQL query either.
It is true that JDBC does provide a mapping of bit to Java boolean and Boolean, but that will only work for database products which support that non-standard datatype, and Oracle isn't one of them.

Oracle JDBC call PL/SQL procedure with input parameter a table of records

I am trying to call the following pl/sql procedure from JDBC.
create or replace PACKAGE test AS
type testrec_r is record (
val1 number,
val2 varchar2(100)
);
type testarr_t is table of testrec_r index by binary_integer;
function test_func(i_data in testarr_t, o_sum out number, o_totallength out number) return number;
END test;
This is how I tried to invoke it, but without success:
StructDescriptor recDescriptor = StructDescriptor.createDescriptor("test.testrec_r", conn);
STRUCT[] RECORDS_ARRAY = new STRUCT[2];
for (int i = 0; i < 2; i++) {
STRUCT oracle_record = new STRUCT(recDescriptor, conn, new
Object[] {i, "test"});
RECORDS_ARRAY[i] = oracle_record;
}
CallableStatement stmt = conn.prepareCall("{ call TEST.TEST_FUNC(?, ?, ?) }");
ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor("TEST.TESTARR_T", conn);
ARRAY oracle_array = new ARRAY(arrayDescriptor, conn, RECORDS_ARRAY);
// Bind the input record
stmt.setArray(1, oracle_array);
stmt.registerOutParameter(2, Types.NUMERIC);
stmt.registerOutParameter(3, Types.NUMERIC);
stmt.executeUpdate();
double out1 = stmt.getDouble(2);
double out2 = stmt.getDouble(3);
return new Object[] { out1, out2 };
I just have read that oracle jdbc does not support pl/sql struct types. So, this fails with "invalid name pattern: test.testrec_r"
How can I call this procedure from Java? Ideally would be to only use a java libray/API, but as this seems almost imposible, which is the best workaround to wrap the pl/sql package in simple sql call and to invoke it?
P.S I am using Spring JDBCTemplate for database connection.
You cannot use PL/SQL types because they known to PL/SQL alone (since 12c this is no more strictly true - see UPD). Also any type created within a package is not visible by java directly.
You should create a SQL type at schema level. SQL types are visible to all and usable by all.
create or replace and compile java source named "ArrayOfRecTest" as
import java.io.*;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
public class ArrayOfRecTest
{
public static void passArrayOfRec() throws SQLException
{
Connection conn = new OracleDriver().defaultConnection();
StructDescriptor sd = StructDescriptor.createDescriptor("MYREC_TYPE", conn);
ArrayDescriptor ad = ArrayDescriptor.createDescriptor("MYRECARR_TYPE", conn);
STRUCT[] recarr = new STRUCT[2];
for (int i = 0; i < 2; i++) { recarr[i] = new STRUCT(sd, conn, new Object[] {i+1, "value " + (i+1)}); }
ARRAY oracle_array = new ARRAY(ad, conn, recarr);
CallableStatement stmt = conn.prepareCall("{ ? = call testpkg.showArrOfRec(?, ?, ?) }");
stmt.registerOutParameter(1, Types.INTEGER);
stmt.setObject(2, oracle_array);
stmt.registerOutParameter(3, Types.INTEGER);
stmt.registerOutParameter(4, Types.INTEGER);
stmt.execute();
int sizeofArr = stmt.getInt(1);
int total = stmt.getInt(3);
int totalLength = stmt.getInt(4);
System.out.println("passArrayOfRec(total,len)=(" + total + "," + totalLength + ") " + sizeofArr + " records were shown");
}
}
/
create or replace force type myrec_type as object( id number, value varchar2(100));
/
create or replace type myrecarr_type as table of myrec_type;
/
create or replace package testpkg as
procedure passArrayOfRec as language java name 'ArrayOfRecTest.passArrayOfRec()' ;
function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number;
end testpkg;
/
create or replace package body testpkg as
--OP stuff
type testrec_r is record (val1 number, val2 varchar2(100));
type testarr_t is table of testrec_r index by binary_integer;
function test_func(data in testarr_t, total out number, totallength out number) return number is
begin
<<for_each>> for i in data.first..data.last loop
dbms_output.put_line('data(' || i || ')[val1,val2]=[' || data(i).val1 || ',' || data(i).val2 || ']');
total := nvl(total,0) + data(i).val1;
totallength := nvl(totallength,0) + length(data(i).val2);
end loop for_each;
return data.count;
end test_func;
--end OP stuff
function showArrOfRec(ra myrecarr_type, total out number, totallength out number) return number is
data testarr_t;
begin
for i in ra.first..ra.last loop data(i).val1 := ra(i).id; data(i).val2 := ra(i).value; end loop;
return test_func(data, total, totalLength);
end showArrOfRec;
end testpkg;
/
exec testpkg.passArrayOfRec;
Output:
data(1)[val1,val2]=[1,value 1]
data(2)[val1,val2]=[2,value 2]
passArrayOfRec(total,len)=(3,14) 2 records were shown
UPD New in 12cR1: Using PL/SQL Types

Exception block in PLSQL exiting the block

I am using the following code block to update my front end segment.
But when i am compiling this
DECLARE
p_person_id NUMBER := NULL;
p_business_group_id NUMBER;
p_id_flex_num NUMBER;
------------------
p_analysis_criteria_id NUMBER := NULL;
p_person_analysis_id NUMBER := NULL;
p_per_object_version_number NUMBER := NULL;
v_err VARCHAR2 (1000) := NULL;
p_medical_id VARCHAR2 (100) := NULL;
BEGIN
FOR i IN (SELECT *
FROM xx_hr_upload_master_data_new
WHERE person_id IS NOT NULL
AND business_group_id IS NOT NULL
AND medical_id IS NOT NULL)
LOOP
p_id_flex_num := 50530;
BEGIN
SELECT sv.segment1, NVL (sit.object_version_number, 1),
sit.analysis_criteria_id, MAX (sit.person_analysis_id)
INTO p_medical_id, p_per_object_version_number,
p_analysis_criteria_id, p_person_analysis_id
FROM fnd_id_flex_structures_tl sttl,
fnd_id_flex_structures st,
per_person_analyses sit,
per_analysis_criteria sv
WHERE sttl.id_flex_structure_name = 'ISPs Medical Data'
AND sttl.LANGUAGE = USERENV ('LANG')
AND st.id_flex_code = sttl.id_flex_code
AND st.id_flex_num = sttl.id_flex_num
AND st.id_flex_num = sit.id_flex_num
AND st.id_flex_num = sv.id_flex_num
AND sit.analysis_criteria_id = sv.analysis_criteria_id
AND sit.person_id = i.person_id
--and sv.SEGMENT1 = '4602001140'
GROUP BY sv.segment1,
NVL (sit.object_version_number, 1),
sit.analysis_criteria_id;
EXCEPTION
WHEN OTHERS
THEN
p_medical_id := NULL;
p_per_object_version_number := 1;
p_person_analysis_id := NULL;
p_analysis_criteria_id := NULL;
p_person_analysis_id := NULL;
p_per_object_version_number := NULL;
p_person_id := NULL;
END;
BEGIN
------------------------------------------------
IF (p_medical_id IS NULL AND p_analysis_criteria_id IS NULL)
THEN
-- create a new record in the SIT (Special Information Type)table .
p_person_id := i.person_id;
p_medical_id := TO_CHAR (i.medical_id);
-----------------------------
hr_sit_api.create_sit
(p_validate => FALSE,
p_person_id => p_person_id,
p_business_group_id => i.business_group_id,
p_id_flex_num => p_id_flex_num,
p_effective_date => TRUNC (SYSDATE),
p_date_from => TRUNC (SYSDATE),
p_segment1 => p_medical_id,
p_analysis_criteria_id => p_analysis_criteria_id,
p_person_analysis_id => p_person_analysis_id,
p_pea_object_version_number => p_per_object_version_number
);
ELSE
-- employee has previous Billing_Acc_Num then update that number in the SIT table .
hr_sit_api.update_sit
(p_validate => FALSE,
p_person_analysis_id => p_person_analysis_id,
p_pea_object_version_number => p_per_object_version_number,
p_date_from => TRUNC (SYSDATE),
p_segment1 => p_medical_id,
p_analysis_criteria_id => p_analysis_criteria_id
);
END IF;
UPDATE xx_hr_upload_master_data_new xx
SET xx.error_msg = 'Done',
xx.emp_data = 'Done'
WHERE xx.business_group_id = i.business_group_id
AND xx.employee_number = i.employee_number;
EXCEPTION
WHEN OTHERS
THEN
p_analysis_criteria_id := NULL;
p_person_analysis_id := NULL;
p_per_object_version_number := NULL;
p_person_id := NULL;
p_medical_id := NULL;
v_err := NULL;
v_err := SQLERRM;
UPDATE xx_hr_upload_master_data_new xx
SET xx.error_msg = v_err
WHERE xx.business_group_id = i.business_group_id
AND xx.employee_number = i.employee_number;
END;
END LOOP;
COMMIT;
END;
Now when the select query is not fetching anything, the exception block is entered where all the variables are initiated to null.
I want that after this the begin where the create api is called inside the condition IF (p_medical_id IS NULL AND p_analysis_criteria_id IS NULL)
should be entered. But this is not happening and the program exits after this exception block after entering the exception block.
A hint might be:
The first select will not raise any exception if it gets no result. If it gets no result then the for-loop just won't be entered, so the only thing that will happen is the commit.
(The select inside the for-loop will raise an exception if it gets 0 rows or more than 1 row. The reason is 'select ... into ...': When using 'into' the select must return exact 1 row.)

Resources