Skip to Main Content
  • Questions
  • calling a procedure with PL/SQL table as out parameter from JDBC

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Ravi Chandra.

Asked: January 16, 2003 - 8:31 pm UTC

Last updated: June 02, 2004 - 8:41 am UTC

Version: 8.17

Viewed 1000+ times

You Asked

Hi,
I am facing a problem when using PL/SQL tables as out parameters in a procedure and calling the procedure from my JDBC code..

I created one object and a sql table of this object as follows

create or replace type myObjType as object
(
att1 number,
att2 varchar2(10)
);
/
create or replace type myTableType is table of myObjType;
/

I created a package in which the procedure has a table type as out parameter
the package is as follows

create or replace package testPkg
as
procedure foo( p_num in number, p_tbl in out myTableType );
end testPkg;
/

create or replace package body testPkg
as
procedure foo( p_num in number, p_tbl out myTableType )
as
begin
for i in 1 .. p_num loop
p_tbl(i).att1 := i;
p_tbl(i).att2 := 'Output ' || i;
end loop;
end;
end testPkg;
/

i am call this procedure from the JDBC code, which is as follows

import java.sql.*;
import java.io.*;
import java.util.*;
import java.math.BigDecimal;
import oracle.sql.*;
import oracle.jdbc.driver.*;

public class TestInOut extends Object
{
public static void main(String[] args) throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@inyo:1531:YEMCSA_D","dspcs", "f0rtun3");

StructDescriptor structdesc
= StructDescriptor.createDescriptor("MYOBJTYPE", conn);

Object[] attributes = new Object[2];
attributes[0] = new BigDecimal(1);
attributes[1] = "RAV";

Object [] test = new Object[1];
test[0] = new oracle.sql.STRUCT(structdesc, conn, attributes);

ArrayDescriptor outAD
= ArrayDescriptor.createDescriptor("MYTABLETYPE", conn);

oracle.sql.ARRAY inArray = new oracle.sql.ARRAY(outAD, conn, test);

OracleCallableStatement cs
= (OracleCallableStatement)conn.prepareCall
("{CALL TESTPKG.FOO(?,?)}");

cs.setInt (1, 5);
cs.setObject(2, inArray, OracleTypes.ARRAY);
cs.registerOutParameter(2, OracleTypes.ARRAY, "MYTABLETYPE");
cs.execute();
oracle.sql.ARRAY outArray = (oracle.sql.ARRAY)cs.getARRAY(2);
ResultSet rset = outArray.getResultSet();

int i = 0;
while (rset.next())
{
System.out.println(" array e1 ( "+ i + " )" +rset.getInt(1));
System.out.println(" array e2 ( "+ i + " )" +rset.getInt(2));
System.out.println(" array e3 ( "+ i + " )" +rset.getString(3));
i++;
}
cs.close();
conn.close();
}
}

i am getting ORA-06530 error..

I have tried the same by defining the table type as follows inside the same package

type myTableType is table of myObjType index by binary_integer;

then i am getting invalid name pattern: DSPCS.MYTABLETYPE

even though i mentioned the name of table type as
TESTPKG.MYTABLETYPE

i am able to pass table type as in parameters to a procedure but am not able to retrieve as out paramenter..

i cannot user indexed plsql tables as it requires JDBC OCI driver.. our application is a web application and so we decided to use thin driver..
i am confined to use 8.1.7

pls give guide me with a the solution..

thank you
rav

and Tom said...

Well -- a WEB application, running on an app server -- would be best served with the OCI thick driver. It will perform faster, it has more options and you only need to install it on a handful of app servers.

I would only use the thin jdbc for client deployments -- thick is the only sensible one for all server installs.

Please make sure the code you POST is the code you RUN.... the spec and body above do not match

anyway - suggest you either

o use jpublisher and let it generate the java
o use "single dimension" objects instead of collections of collections of objects
o use a REF CURSOR.

I'll demonstrate a ref cursor as I believe that is by far the easiest method.


Here is the PLSQL (yours compiles but does not run)

create or replace type myObjType as object
(
att1 number,
att2 varchar2(10)
);
/
create or replace type myTableType is table of myObjType;
/

create or replace package testPkg
as
type rc is ref cursor;

procedure foo( p_num in number, p_tbl in out rc );
end testPkg;
/

create or replace package body testPkg
as

procedure foo( p_num in number, p_tbl in out rc )
as
l_tbl myTableType := myTableType();
begin
for i in 1 .. p_num loop
l_tbl.extend;
l_tbl(i) := myObjType( i, 'Output ' || i );
end loop;

open p_tbl
for
select *
from TABLE( cast(l_tbl as myTableType) );
end;


end testPkg;
/

And here is the much simplified java code:

import java.sql.*;
import java.io.*;
import java.util.*;
import java.math.BigDecimal;
import oracle.sql.*;
import oracle.jdbc.driver.*;

public class TestInOut extends Object
{
public static void main(String[] args) throws SQLException
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection conn = DriverManager.getConnection
("jdbc:oracle:thin:@aria-dev:1521:ora817dev","scott", "tiger");

OracleCallableStatement cs
= (OracleCallableStatement)conn.prepareCall
("{CALL TESTPKG.FOO(?,?)}");

cs.setInt (1, 5);
cs.registerOutParameter(2, OracleTypes.CURSOR );
cs.execute();
ResultSet rset = (ResultSet)cs.getObject(2);

for( int i = 0; rset.next(); i++ )
{
System.out.println(" array e1 ( "+ i + " )" +rset.getInt(1));
System.out.println(" array e2 ( "+ i + " )" +rset.getString(2));
}
cs.close();
conn.close();
}
}






Rating

  (3 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Alternate Solution to original question

A reader, January 17, 2003 - 8:06 pm UTC

The reason why the original JAVA code did not work is that you were trying to read from the ARRAY's ResultSet beyond
the maximum index.

ResultSet rset = outArray.getResultSet();

rs.getObject (1) yields the index of the array
rs.getObject (2) yields an Object of type oracle.sql.STRUCT

There is no rs.getObject (3) however.

You can read the attributes from the STRUCT

STRUCT s = (STRUCT) rset.getObject (2);
Object [] attrs = s.getAttributes ();
attrs [0] maps to your att1
attrs [1] maps to your att2

After correcting the PL/SQL in the package body (IN OUT Parameter and p_tbl.EXTEND) you get exactly what you expected.

But I would definitely prefer Tom's solution in this case.

Thank You for ur handy solution

Ravi Chandra, January 17, 2003 - 8:42 pm UTC

Hi Tom,
Ur solution was very handy.
I implemented in my application and is working fine.

Thank You very much
Rav

A reader, June 02, 2004 - 8:41 am UTC


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library