The current question is the second part of this ODCI related question.
I have implemented a collection type in Oracle SQL which is practically defined as a type and a table of that type.
CREATE TYPE row_type AS OBJECT
(
C1 VARCHAR2(50),
C2 VARCHAR2(50),
C3 VARCHAR2(50)
);
/
CREATE TYPE row_type_set AS TABLE OF row_type;
Also, I have defined an ODCI type with its implementation as a Java Stored Procedure within database:
SQL:
CREATE OR REPLACE TYPE ODCIImpl AS OBJECT (
key INTEGER,
STATIC FUNCTION ODCITableStart(sctx OUT ODCIImpl, cur SYS_REFCURSOR)
RETURN NUMBER
AS LANGUAGE JAVA
NAME 'ODCIImpl.ODCITableStart(oracle.sql.STRUCT[], java.sql.ResultSet) return java.math.BigDecimal',
MEMBER FUNCTION ODCITableFetch(self IN OUT ODCIImpl, nrows IN NUMBER,
outSet OUT row_type_set) RETURN NUMBER
AS LANGUAGE JAVA
NAME 'ODCIImpl.ODCITableFetch(java.math.BigDecimal, oracle.sql.ARRAY[]) return java.math.BigDecimal',
MEMBER FUNCTION ODCITableClose(self IN ODCIImpl) RETURN NUMBER
AS LANGUAGE JAVA
NAME 'ODCIImpl.ODCITableClose() return java.math.BigDecimal'
);
/
Java Stored Procedure:
import java.io.*;
import java.util.*;
import oracle.sql.*;
import java.sql.*;
import java.math.BigDecimal;
import oracle.CartridgeServices.*;
// stored context type
public class StoredCtx
{
ResultSet rset;
public StoredCtx(ResultSet rs) { rset=rs; }
}
// implementation type
public class ODCIImpl implements SQLData
{
private BigDecimal key;
final static BigDecimal SUCCESS = new BigDecimal(0);
final static BigDecimal ERROR = new BigDecimal(1);
final static int MAX_COLUMNS = 3;
// Implement SQLData interface.
String sql_type;
public String getSQLTypeName() throws SQLException
{
return sql_type;
}
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
sql_type = typeName;
key = stream.readBigDecimal();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeBigDecimal(key);
}
// type methods implementing ODCITable interface
static public BigDecimal ODCITableStart(STRUCT[] sctx,ResultSet rset)
throws SQLException
{
Connection conn = DriverManager.getConnection("jdbc:default:connection:");
// create a stored context and store the result set in it
StoredCtx ctx=new StoredCtx(rset);
// register stored context with cartridge services
int key;
try {
key = ContextManager.setContext(ctx);
} catch (CountException ce) {
return ERROR;
}
// create a ODCIImpl instance and store the key in it
Object[] impAttr = new Object[1];
impAttr[0] = new BigDecimal(key);
StructDescriptor sd = new StructDescriptor("ODCIIMPL",conn);
sctx[0] = new STRUCT(sd,conn,impAttr);
return SUCCESS;
}
public BigDecimal ODCITableFetch(BigDecimal nrows, ARRAY[] outSet)
throws SQLException
{
Connection conn = DriverManager.getConnection("jdbc:default:connection:");
// retrieve stored context using the key
StoredCtx ctx;
try {
ctx=(StoredCtx)ContextManager.getContext(key.intValue());
} catch (InvalidKeyException ik ) {
return ERROR;
}
// get the nrows parameter, but return up to 10 rows
int nrowsval = nrows.intValue();
// create a vector for the fetched rows
Vector v = new Vector(nrowsval);
int i=0;
StructDescriptor outDesc =
StructDescriptor.createDescriptor("ROW_TYPE", conn);
Object[] out_attr = new Object[MAX_COLUMNS];
ResultSetMetaData rsmd = ctx.rset.getMetaData();
int columnsNumber = rsmd.getColumnCount();
while(nrowsval>0 && ctx.rset.next()){
for(int j = 0; j < columnsNumber; j++) {
if(j == MAX_COLUMNS)
break;
out_attr[j] = (Object)ctx.rset.getString(j+1);
}
v.add((Object)new STRUCT(outDesc, conn, out_attr));
i+=1;
nrowsval-=1;
}
// return if no rows found
if(i==0) return SUCCESS;
// create the output ARRAY using the vector
Object out_arr[] = v.toArray();
ArrayDescriptor ad = new ArrayDescriptor("ROW_TYPE_SET",conn);
outSet[0] = new ARRAY(ad,conn,out_arr);
return SUCCESS;
}
public BigDecimal ODCITableClose() throws SQLException {
// retrieve stored context using the key, and remove from ContextManager
StoredCtx ctx;
try {
ctx=(StoredCtx)ContextManager.clearContext(key.intValue());
} catch (InvalidKeyException ik ) {
return ERROR;
}
// close the result set
Statement stmt = ctx.rset.getStatement();
ctx.rset.close();
if(stmt!=null) stmt.close();
return SUCCESS;
}
}
After all of this, I've implemented a pipelined function that can be called using a cursor.
CREATE OR REPLACE FUNCTION Exec_Remote_SQL_JSP(p SYS_REFCURSOR) RETURN row_type_set
PIPELINED USING ODCIImpl;
/
My question now is how can we implement an ODCITableDescribe method in a Java Stored Procedure in order to output any data type in the emulated table? First of all, is it possible at all? I didn't seem to find any relevant information about this on the Oracle documentation from here and here
If it is possible to do so, it is self-explainable that we do not need anymore the collection types mentioned at the beginning. The emulated table should have the same size and data types as the table from which we intend to select information.