Implementation of ODCITableDescribe in a Java Stored Procedure

155 Views Asked by At

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.

0

There are 0 best solutions below