Search code examples
javaoracle-databasestored-proceduresjdbcoracle11g

From Java Passing Values as Array to Database Stored Procedure


I have the following stored procedure in database

CREATE OR REPLACE PROCEDURE my_proc (
   my_array         IN     my_array_type,
   my_var    IN OUT VARCHAR2)
   ....
   ....

In Java I have the following code snippet to invoke the above stored procedure

 public void callProc(String prodCode, 
                      String prodName, 
                      String prodDesc, 
                      ) {
            callableStatement = 
            this.getOADBTransaction().getJdbcConnection().prepareCall("{call my_proc (?,?)}");
    Object[] object = 
      new Object[] { prodCode, prodName, prodDesc};
StructDescriptor structDescriptor = 
  StructDescriptor.createDescriptor("my_array_type",this.getOADBTransaction().getJdbcConnection());
STRUCT struct = 
 new STRUCT(structDescriptor, this.getOADBTransaction().getJdbcConnection(), 
object);
STRUCT[] structArray = { struct };
ArrayDescriptor arrayDescriptor = 
ArrayDescriptor.createDescriptor("my_array",this.getOADBTransaction().getJdbcConnection());

ARRAY array = 
new ARRAY(arrayDescriptor, this.getOADBTransaction().getJdbcConnection(), 
structArray);
callableStatement.setArray(1, array);
callableStatement.registerOutParameter(2, Types.VARCHAR);
callableStatement.execute();
....

The above method is called from another class which is inside a for loop

for(....){

Serializable[] param = 
{ prodCode, prodName, prodDesc};
db.callProc(param )
}

What I would like achieve is instead of calling db.callProc inside the for loop, I would like to use a ListArray or some other collection object and pass the value to db.callProc method and in db.callProc method I would like to iterate and pass to database procedure as an array so that my stored procedure can handle the array and do the processing.


Solution

  • First of all We will create a Pojo

    public class ParamHolder{
    
       private String param1;
    
       private String param2;
    
       private String param3;
    
       //getters and setters.
    }
    

    On the DB side create an Object of the same type

    CREATE OR REPLACE TYPE PARAM_HOLDER_OBJ 
    AS OBJECT ( PARAM1 VARCHAR2(200), PARAM2 VARCHAR2(200), PARAM3 VARCHAR3(200));
    

    Once you created the Object lets create a table of these objects

    CREATE OR REPLACE TYPE PARAM_HOLDER_OBJ_TABLE
    IS TABLE OF PARAM_HOLDER_OBJ
    

    and our procedure may take input parajm like

    custom(p_param_holder_tab IN TYPE PARAM_HOLDER_OBJ_TABLE)
    

    lets for instance assume our proc looks something like this now what we need to do is to call this proc from our java code and pass in a Array of ParamHolder.

    Code Snippet:
    //variable declaration
    //ParamHolder[] paramHolders = ..getTheParamHolderArray();
            try (Connection con = createConnWithDbDetails(getDBDetails());
                 CallableStatement stmnt =
                 con.prepareCall("{ call custom(?) }")) {
                //Create a arrayDescriptor
                ArrayDescriptor descriptor =
                    ArrayDescriptor.createDescriptor("PARAM_HOLDER_OBJ_TABLE", con);
                Array array = new ARRAY(descriptor , con, paramHolders);
                stmnt.setArray(1, array );
              }Catch(Exception e){
                  e.printStackTrace();
              }
    

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ EDITED-- 21st June 2016 For adding the calling method. 5 pm IST.

    What you can do is you can create a method like this

    public void callProc(ParamHolder[] paramHolders){
    
    try (Connection con = createConnWithDbDetails(getDBDetails());
                 CallableStatement stmnt =
                 con.prepareCall("{ call custom(?,?) }")) {
                //Create a arrayDescriptor
                ArrayDescriptor descriptor =
                    ArrayDescriptor.createDescriptor("PARAM_HOLDER_OBJ_TABLE", con);
                Array array = new ARRAY(descriptor , con, paramHolders);
                stmnt.setArray(1, array );
                stmnt.registerOutParameter(2,OracleType.VARCHAR,"p_out_var");           //Register any output variable if your procedure returns any thing.
                stmmnt.execute();                                              //this will take the Array of ParamHolder straight to the DB for processing.
                String result = stmnt.getString(2);                                  //Will fetch yuou the result form the DB to your local String.
              }Catch(Exception e){
                  e.printStackTrace();
              }
    }
    

    which will take an array of ParamHolder class which will be passed directly to your db proc and you will have the results the accordingly. as the current proc defination does not specifies any out param but you can define and register of to catch that.

    Lets Say you have a calling piece of code which will utilize it

    public class ProcDaoImpl{
    
        public void executeProc(){
    
             ParamHolder[] paramArray = new ParamHolder[]{                                          //create an array of four elements
                                          new ParamHolder("param1","param2","param3"),
                                          new ParamHolder("param1","param2","param3"),
                                          new ParamHolder("param1","param2","param3"),            
                                          new ParamHolder("param1","param2","param3")                                                   //Each array element represents a set of InputParams
                                       }
    
         //call the DB procedure now..
         SomeClass.callProc(paramArray);                                                                     // pass in the created array to it.
        }
    
    }
    

    Hope it helps. :)

    Thanks