简体   繁体   中英

How to run a Oracle PROCEDURE with Eclipselink 2.4 Returning a SYS_REFCURSOR

I would like your help a lot, I tried several things and I could not solve my problem.

I'm using: Eclipselink 2.42 and Oracle 11

I need to execute a procedure that returns a SYS_REFCURSOR , but I can not execute this procedure using eclipselink (JPA) , I tried it in several ways and it seems to me that the API is not identifying the SYS_REFCURSOR type.

Could someone please help me, I'm already out of ideas, to make this work

This is my procedure:

PROCEDURE RETRIEVE_JOBS(JOB_ID_PARAM IN  FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC
                        , JOBS_PARAM OUT SYS_REFCURSOR) IS

  vDescErro VARCHAR2(2000);

  BEGIN 
    OPEN JOBS_PARAM FOR
      SELECT * 
      FROM   dba_jobs
      --WHERE  job = NVL(pJOB,job)
      ORDER BY job;

  EXCEPTION WHEN OTHERS THEN
    vDescErro := REPLACE(SQLERRM, '"' ,' ');
    vDescerro := REPLACE(vDescErro, CHR(10),'');

END RETRIEVE_JOBS;

And Here is some Tests with the result:

StoredProcedureCall functionCall = new StoredProcedureCall();
functionCall.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
functionCall.addNamedArgument("JOB_ID_PARAM");
functionCall.useNamedCursorOutputAsResultSet("JOBS_PARAM");
DataReadQuery querytestS = new DataReadQuery();
querytestS.addArgument("JOB_ID_PARAM");
querytestS.setCall(functionCall);
// Adding arguments
List<Object> queryArgstestS = new ArrayList<Object>();
queryArgstestS.add(entrada);
querytestS.bindAllParameters();
// Executing query
session = ((JpaEntityManager)getEntityManager().getDelegate()).getActiveSession();
Object result232 = session.executeQuery(querytestS, queryArgstestS);

My error:

[EL Fine]: 2017-05-05 15:33:03.886--ServerSession(23378162)--Connection(19739591)--BEGIN FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>?, JOBS_PARAM=>?); END;
    bind => [TipoEntrada [jobId=200], => JOBS_PARAM]
[EL Fine]: 2017-05-05 15:33:03.886--ServerSession(23378162)--SELECT 1 FROM DUAL
[EL Warning]: 2017-05-05 15:33:04.06--UnitOfWork(19720277)--Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid type Column
Error Code: 17004
Call: BEGIN FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>?, JOBS_PARAM=>?); END;
    bind => [TipoEntrada [jobId=200], => JOBS_PARAM]
Query: DataReadQuery()

Second Test:

PLSQLStoredProcedureCall call2 = new PLSQLStoredProcedureCall();
call2.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
call2.addNamedArgument("JOB_ID_PARAM", TipoEntrada.getRecord());
call2.useNamedCursorOutputAsResultSet("JOBS_PARAM");
DataReadQuery   querytest = new DataReadQuery ();  
querytest.addArgument("JOB_ID_PARAM");  
querytest.setCall(call2);  
// Adding arguments  
List<Object> queryArgstest = new ArrayList<Object>();  
queryArgstest.add(entrada);  
querytest.bindAllParameters();  
// Executing query  
session = ((JpaEntityManager) 
getEntityManager().getDelegate()).getActiveSession();
Object result23 = session.executeQuery(querytest, queryArgstest);

Error Result:

Local Exception Stack: 
Exception [EclipseLink-6148] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.QueryException
Exception Description: Adding named OUT cursor arguments without DatabaseType classification to PLSQLStoredProcedureCall is not supported.
    at org.eclipse.persistence.exceptions.QueryException.addArgumentsNotSupported(QueryException.java:1417)

Now I create a OracleCursorDatabaseType:

import static org.eclipse.persistence.internal.helper.DatabaseType.DatabaseTypeHelper.databaseTypeHelper;
import static org.eclipse.persistence.internal.helper.Helper.NL;

import java.util.List;
import java.util.ListIterator;

import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.SimpleDatabaseType;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.platform.database.DatabasePlatform;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLStoredProcedureCall;
import org.eclipse.persistence.platform.database.oracle.plsql.PLSQLargument;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.sessions.DatabaseRecord;

import oracle.jdbc.OracleTypes;

@SuppressWarnings("rawtypes")
public class OracleCursorDatabaseType implements SimpleDatabaseType {

    public boolean isComplexDatabaseType() {
        return false;
    }

    public boolean isJDBCType() {
        return false;
    }

    public int getSqlCode() {
        return OracleTypes.CURSOR;
    }

    public int getConversionCode() {
        return getSqlCode();
    }

    public String getTypeName() {
        return "SYS_REFCURSOR";
    }

    public int computeInIndex(PLSQLargument inArg, int newIndex, ListIterator<PLSQLargument> i) {
        inArg.outIndex = newIndex;
        return ++newIndex;
    }

    public int computeOutIndex(PLSQLargument outArg, int newIndex, ListIterator<PLSQLargument> iterator) {
        outArg.outIndex = newIndex;
        return newIndex;
    }

    public void buildInDeclare(StringBuilder sb, PLSQLargument inArg) {
        System.out.println("buildInDeclare");
    }

    public void buildOutDeclare(StringBuilder sb, PLSQLargument outArg) {
        sb.append(" ");
        sb.append(databaseTypeHelper.buildTarget(outArg));
        sb.append(" ");
        sb.append(getTypeName());
        sb.append(";");
        sb.append(NL);
    }

    public void buildBeginBlock(StringBuilder sb, PLSQLargument arg, PLSQLStoredProcedureCall call) {
        System.out.println("buildBeginBlock");

    }

    public void buildOutAssignment(StringBuilder sb, PLSQLargument outArg, PLSQLStoredProcedureCall call) {
        String target = databaseTypeHelper.buildTarget(outArg);
        sb.append(" :");
        sb.append(outArg.outIndex);
        sb.append(" := ");
        sb.append(target);
        sb.append(";");
        sb.append(NL);
    }

    public void translate(PLSQLargument arg, AbstractRecord translationRow, AbstractRecord copyOfTranslationRow, List<DatabaseField> copyOfTranslationFields, List<DatabaseField> translationRowFields,
            List translationRowValues, StoredProcedureCall call) {
        // TODO Auto-generated method stub
        System.out.println("translate");
    }

    public void buildOutputRow(PLSQLargument outArg, AbstractRecord outputRow, DatabaseRecord newOutputRow, List<DatabaseField> outputRowFields, List outputRowValues) {
        databaseTypeHelper.buildOutputRow(outArg, outputRow, newOutputRow, outputRowFields, outputRowValues);
    }

    public void logParameter(StringBuilder sb, Integer direction, PLSQLargument arg, AbstractRecord translationRow, DatabasePlatform platform) {
        System.out.println("logParameter");
    }
}

First Test:

PLSQLStoredProcedureCall call2 = new PLSQLStoredProcedureCall();
call2.setProcedureName("FAC_JOB_INTEGRATION.RETRIEVE_JOBS");
call2.addNamedArgument("JOB_ID_PARAM", TipoEntrada.getRecord());
call2.addNamedOutputArgument("JOBS_PARAM", new OracleCursorDatabaseType());
// Preparing the query  
DataReadQuery   querytest = new DataReadQuery ();  
querytest.addArgument("JOB_ID_PARAM");  
querytest.setCall(call2);  
// Adding arguments  
List<Object> queryArgstest = new ArrayList<Object>();  
queryArgstest.add(entrada);  
querytest.bindAllParameters();  
// Executing query  
session = ((JpaEntityManager) getEntityManager().getDelegate()).getActiveSession();
Object result23 = session.executeQuery(querytest, queryArgstest);

The PROCEDURE is Run without problems, but not return the cursor values:

Log Execution:

[EL Fine]: 2017-05-05 15:51:55.933--ServerSession(23378162)--Connection(15936168)--
DECLARE
  JOB_ID_PARAMTARGET FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC;
  JOB_ID_PARAMCOMPAT FACT_JOB_ENTRY := :1;
 JOBS_PARAMTARGET SYS_REFCURSOR;
  FUNCTION EL_SQL2PL_1(aSqlItem FACT_JOB_ENTRY) 
  RETURN FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC IS
    aPlsqlItem FAC_JOB_INTEGRATION.FACT_JOB_ENTRY_REC;
  BEGIN
    aPlsqlItem.JOB := aSqlItem.JOB;
    RETURN aPlsqlItem;
  END EL_SQL2PL_1;
BEGIN
  JOB_ID_PARAMTARGET := EL_SQL2PL_1(JOB_ID_PARAMCOMPAT);
  FAC_JOB_INTEGRATION.RETRIEVE_JOBS(JOB_ID_PARAM=>JOB_ID_PARAMTARGET, JOBS_PARAM=>JOBS_PARAMTARGET);
 :2 := JOBS_PARAMTARGET;
END;
  bind => [:1 => TipoEntrada [jobId=200], ]

Object Value:

[DatabaseRecord(JOBS_PARAM => [])]

Update 1

I'm trying a different way, now using the ScrollableCursor of eclipselink, I can execute the procedure and return a Cursor, however when trying to go through it I'm having a result set close.

I tried several ways to make it open, including having a Persistence Unit (RESOURCE_LOCAL), but I was not successful.

Anyone have any tips?

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.4.2.v20130514-5956486): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLException: Result set already closed

EntityManagerFactory createEntityManagerFactory = Persistence.createEntityManagerFactory("localFactPU");

        //EntityManager em = FJPAManager.getInstance().getEntityManagerContext("localFactPU").getEntityManager();

        EntityManager em = createEntityManagerFactory.createEntityManager();
        em.getTransaction().begin();

        em.getTransaction().isActive();
        System.out.println(em.isOpen());


        //em.getTransaction().begin();

        ReadAllQuery databaseQuery = new ReadAllQuery(DBAJobsOracleEntity.class);
        databaseQuery.useCursoredStream();
        StoredProcedureCall calles = new StoredProcedureCall();
        calles.setProcedureName("FAC_JOB_INTEGRATION.TEST_ESTEVAO");
        calles.useNamedCursorOutputAsResultSet("JOBS_PARAM");
        databaseQuery.setCall(calles);

        databaseQuery.useCursoredStream();
        databaseQuery.useScrollableCursor(1000);
        //session = ((JpaEntityManager) getEntityManager().getDelegate()).getActiveSession();
        //session.executeQuery(databaseQuery);


        //JpaQuery  queryess = (JpaQuery) ((JpaEntityManager)getEntityManager().getDelegate()).createQuery(databaseQuery);
        JpaQuery  queryess = (JpaQuery) ((JpaEntityManager)em.getDelegate()).createQuery(databaseQuery);
        queryess.setHint(QueryHints.CURSOR, true);
        queryess.setHint(QueryHints.CURSOR_INITIAL_SIZE, 2);
        queryess.setHint(QueryHints.CURSOR_PAGE_SIZE, 5);
        queryess.setHint(QueryHints.RESULT_SET_CONCURRENCY, ResultSetConcurrency.ReadOnly);

        String resultSetType = ResultSetType.DEFAULT;
        queryess.setHint(QueryHints.RESULT_SET_TYPE, resultSetType);
        ScrollableCursor scrollableCursor = (ScrollableCursor)queryess.getResultCursor();

        DatabaseSessionImpl databaseSession = ((JpaEntityManager)em.getDelegate()).getDatabaseSession();
        scrollableCursor.setSession(databaseSession);

        scrollableCursor.next();
        scrollableCursor.close();

Can you try as

StoredProcedureQuery query = em.createNamedStoredProcedureQuery("RETRIEVE_JOBS");
query.setParameter("JOB_ID_PARAM", 9999);
query.execute();
List<YourClass.class> result = (List<YourClass.class>)query.getOutputParameterValue("JOBS_PARAM");

Or in your Entity class try as

   @NamedStoredProcedureQuery(name = "findJobs", 
                           procedureName = "RETRIEVE_JOBS", 
                           resultClass = <YourEntityClassName>.class, 
                           parameters = { 
            @StoredProcedureParameter(queryParameter = "JobId", name = "JOB_ID_PARAM", 
                                      direction = Direction.IN, 
                                      type = String.class)
            , 
            @StoredProcedureParameter(queryParameter = 
                                     "my_cursor", 
                                     name = 
                                     "JOBS_PARAM", 
                                     direction = 
                                     Direction.OUT_CURSOR)})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM