FileDocCategorySizeDatePackage
DatasourceCallQueryMechanism.javaAPI DocGlassfish v2 API30980Tue May 22 16:54:40 BST 2007oracle.toplink.essentials.internal.queryframework

DatasourceCallQueryMechanism

public class DatasourceCallQueryMechanism extends DatabaseQueryMechanism

Purpose: Mechanism used for call queries.

Responsibilities: Executes the appropriate call.

author
James Sutherland
since
OracleAS TopLink 10g (10.0.3)

Fields Summary
protected oracle.toplink.essentials.internal.databaseaccess.DatasourceCall
call
protected Vector
calls
Normally only a single call is used, however multiple table may require multiple calls on write.
Constructors Summary
public DatasourceCallQueryMechanism(DatabaseQuery query)
Initialize the state of the query

param
query - owner of mechanism

        super(query);
    
public DatasourceCallQueryMechanism(DatabaseQuery query, oracle.toplink.essentials.internal.databaseaccess.DatasourceCall call)
Initialize the state of the query

param
query - owner of mechanism

        super(query);
        this.call = call;
        call.setQuery(query);
    
Methods Summary
public voidaddCall(oracle.toplink.essentials.internal.databaseaccess.DatasourceCall call)
Add the call.

        getCalls().addElement(call);
        call.setQuery(getQuery());
    
public oracle.toplink.essentials.internal.databaseaccess.DatabaseCallcursorSelectAllRows()
Read all rows from the database using a cursored stream.

exception
DatabaseException - an error has occurred on the database

        try {
            return (DatabaseCall)executeCall();
        } catch (java.lang.ClassCastException e) {
            throw QueryException.mustUseCursorStreamPolicy();
        }
    
public java.lang.IntegerdeleteAll()
INTERNAL: Delete a collection of objects. Assume call is correct.

exception
DatabaseException - an error has occurred on the database

        if(((DeleteAllQuery)getQuery()).isPreparedUsingTempStorage()) {
            return deleteAllUsingTempTables();
        } else {
            if (hasMultipleCalls()) {
                Integer returnedRowCount = null;
                
                // Deletion must occur in reverse order.
                for (int index = getCalls().size() - 1; index >= 0; index--) {
                    DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                    returnedRowCount = (Integer)executeCall(databseCall);
                }
                // returns the number of rows removed from the first table in insert order
                return returnedRowCount;
            } else {
                return (Integer)executeCall();
            }
        }
    
public java.lang.IntegerdeleteAllUsingTempTables()
Execute deleteAll using temp tables

exception
DatabaseException - an error has occurred on the database.
return
the row count.

        DatabaseException ex = null;
        Integer returnedRowCount = null;
        
        // Deletion must occur in reverse order.

        // first call - crete temp table.
        // may fail in case global temp table already exists.
        try {
            DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(getCalls().size() - 1);
            executeCall(databseCall);
        } catch (DatabaseException databaseEx) {
            // ignore
        }                

        // second call - populate temp table.
        // if that fails save the exception and untill cleanup
        if(ex == null) {
            try {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(getCalls().size() - 2);
                executeCall(databseCall);
            } catch (DatabaseException databaseEx) {
                ex = databaseEx;
            }
        }
        
        // third (a call per table) - delete from original tables calls.
        // if that fails save the exception untill cleanup
        for (int index = getCalls().size() - 3; index >= 1 && ex == null; index--) {
            DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
            try {
                // returns the number of rows removed from the first table in insert order
                returnedRowCount = (Integer)executeCall(databseCall);
            } catch (DatabaseException databaseEx) {
                ex = databaseEx;
            }
        }

        // last call - cleanup temp table.
        // ignore exceptions here.
        try {
            DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(0);
            executeCall(databseCall);
        } catch (DatabaseException databaseEx) {
            // ignore
        }

        if(ex != null) {
            throw ex;
        }
        
        return returnedRowCount;
    
public java.lang.IntegerdeleteObject()
INTERNAL: Delete an object. Assume call is correct

exception
DatabaseException - an error has occurred on the database

        if (hasMultipleCalls()) {
            Integer returnedRowCount = null;

            // Deletion must occur in reverse order.
            for (int index = getCalls().size() - 1; index >= 0; index--) {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                Integer rowCount = (Integer)executeCall(databseCall);
                if ((index == (getCalls().size() - 1)) || (rowCount.intValue() <= 0)) {// Row count returned must be from first table or zero if any are zero.
                    returnedRowCount = rowCount;
                }
            }
            return returnedRowCount;
        } else {
            return (Integer)executeCall();
        }
    
protected java.lang.ObjectexecuteCall()
Execute the call. It is assumed the call has been fully prepared.

exception
DatabaseException - an error has occurred on the database.

        return executeCall(getCall());
    
protected java.lang.ObjectexecuteCall(oracle.toplink.essentials.internal.databaseaccess.DatasourceCall databaseCall)
Execute the call. It is assumed the call has been fully prepared.

exception
DatabaseException - an error has occurred on the database.

        // For CR 2923 must move to session we will execute call on now
        // so correct DatasourcePlatform used by translate. 
        AbstractSession sessionToUse = getSession().getExecutionSession(getQuery());
        DatasourceCall clonedCall = (DatasourceCall)databaseCall.clone();
        clonedCall.setQuery(getQuery());
        clonedCall.translate(getTranslationRow(), getModifyRow(), sessionToUse);
        return sessionToUse.executeCall(clonedCall, getTranslationRow(), getQuery());
    
public java.lang.IntegerexecuteNoSelect()
Execute a non selecting call.

exception
DatabaseException - an error has occurred on the database.
return
the row count.

        return executeNoSelectCall();
    
public java.lang.IntegerexecuteNoSelectCall()
Execute a non selecting call.

exception
DatabaseException - an error has occurred on the database.
return
the row count.

        if (hasMultipleCalls()) {
            Integer returnedRowCount = null;
            for (int index = 0; index < getCalls().size(); index++) {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                Integer rowCount = (Integer)executeCall(databseCall);
                if ((index == 0) || (rowCount.intValue() <= 0)) {// Row count returned must be from first table or zero if any are zero.
                    returnedRowCount = rowCount;
                }
            }
            return returnedRowCount;
        } else {
            return (Integer)executeCall();
        }
    
public java.util.VectorexecuteSelect()
INTERNAL: Execute a selecting call.

exception
DatabaseException - an error has occurred on the database

        return executeSelectCall();
    
public java.util.VectorexecuteSelectCall()
INTERNAL: Execute a selecting call.

exception
DatabaseException - an error has occurred on the database

        if (hasMultipleCalls()) {
            Vector results = new Vector();
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databseCall = (DatasourceCall)callsEnum.nextElement();
                Helper.addAllToVector(results, (Vector)executeCall(databseCall));
            }

            return results;
        } else {
            return (Vector)executeCall();
        }
    
public oracle.toplink.essentials.internal.databaseaccess.DatasourceCallgetCall()
Return the call.

        return call;
    
public java.util.VectorgetCalls()
Normally only a single call is used, however multiple table may require multiple calls on write. This is lazy initialied to conserv space.

        if (calls == null) {
            calls = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(3);
        }
        return calls;
    
public booleanhasMultipleCalls()
Normally only a single call is used, however multiple table may require multiple calls on write. This is lazy initialied to conserv space.

        return (calls != null) && (!calls.isEmpty());
    
public voidinsertObject()
Insert the object. Assume the call is correct

exception
DatabaseException - an error has occurred on the database

        Class cls = ((DatabaseQuery)getQuery()).getReferenceClass();
        boolean usesSequencing = getDescriptor().usesSequenceNumbers();
        boolean shouldAcquireValueAfterInsert = false;
        if (usesSequencing) {
            shouldAcquireValueAfterInsert = getSession().getSequencing().shouldAcquireValueAfterInsert(cls);
        }
        Collection returnFields = null;

        // Check to see if sequence number should be retrieved after insert
        if (usesSequencing && !shouldAcquireValueAfterInsert) {
            // This is the normal case.  Update object with sequence number before insert.
            updateObjectAndRowWithSequenceNumber();
        }

        if (hasMultipleCalls()) {
            for (int index = 0; index < getCalls().size(); index++) {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                executeCall(databseCall);
                if (returnFields != null) {
                    updateObjectAndRowWithReturnRow(returnFields, index == 0);
                }
                if ((index == 0) && usesSequencing && shouldAcquireValueAfterInsert) {
                    updateObjectAndRowWithSequenceNumber();
                }
            }
        } else {
            executeCall();
            if (returnFields != null) {
                updateObjectAndRowWithReturnRow(returnFields, true);
            }
            if (usesSequencing && shouldAcquireValueAfterInsert) {
                updateObjectAndRowWithSequenceNumber();
            }
        }

        // Bug 3110860: RETURNINGPOLICY-OBTAINED PK CAUSES LOB TO BE INSERTED INCORRECTLY
        // The deferred locator SELECT calls should be generated and executed after ReturningPolicy
        // merges PK obtained from the db into the object held by the query.
        //
        //Oracle thin driver handles LOB differently. During the insert, empty lob would be
        //insert first, and then the LOb locator is retrieved and LOB data are written through
        //the locator.
        // 
        // Bug 2804663 - LOBValueWriter is no longer a singleton, so we execute any deferred
        // select calls through the DatabaseAccessor which holds the writer instance
        AbstractSession executionSession = getSession().getExecutionSession(getQuery());
        executionSession.getAccessor().flushSelectCalls(executionSession);
    
public booleanisCallQueryMechanism()
Return true if this is a call query mechanism

        return true;
    
public voidprepare()
INTERNAL: This is different from 'prepareForExecution' in that this is called on the original query, and the other is called on the copy of the query. This query is copied for concurrency so this prepare can only setup things that will apply to any future execution of this query.

        if ((!hasMultipleCalls()) && (getCall() == null)) {
            throw QueryException.sqlStatementNotSetProperly(getQuery());
        }
    
public voidprepareCall()
INTERNAL: This is different from 'prepareForExecution' in that this is called on the original query, and the other is called on the copy of the query. This query is copied for concurrency so this prepare can only setup things that will apply to any future execution of this query.

        DatabaseQuery query = getQuery();
        AbstractSession executionSession = getSession().getExecutionSession(query);
        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall call = (DatasourceCall)callsEnum.nextElement();
                call.prepare(executionSession);
            }
        } else if (getCall() != null) {
            getCall().prepare(executionSession);
        }
    
public voidprepareCursorSelectAllRows()
Pre-build configure the call.

        getCall().returnCursor();
        prepareCall();
    
public voidprepareDeleteAll()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall call = (DatasourceCall)callsEnum.nextElement();
                call.returnNothing();
            }
        } else {
            getCall().returnNothing();
        }
        prepareCall();
    
public voidprepareDeleteObject()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall call = (DatasourceCall)callsEnum.nextElement();
                call.returnNothing();
            }
        } else {
            getCall().returnNothing();
        }
        prepareCall();
    
public voidprepareDoesExist(DatabaseField field)
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                ((DatasourceCall)callsEnum.nextElement()).returnOneRow();
            }
        } else {
            getCall().returnOneRow();
        }
        prepareCall();
    
public voidprepareExecuteNoSelect()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                ((DatasourceCall)callsEnum.nextElement()).returnNothing();
            }
        } else {
            getCall().returnNothing();
        }
        prepareCall();
    
public voidprepareExecuteSelect()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databseCall = (DatasourceCall)callsEnum.nextElement();
                databseCall.returnManyRows();
            }
        } else {
            getCall().returnManyRows();
        }
        prepareCall();
    
public voidprepareInsertObject()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                ((DatasourceCall)callsEnum.nextElement()).returnNothing();
            }
        } else {
            getCall().returnNothing();
        }
        prepareCall();
    
protected voidprepareReportQueryItems()
Prepare the report items. Indexes of results needs to be calculates

        //calculate indexes after normalize to insure expressions are set up correctly
        int itemOffset = 0;
        for (Iterator items = ((ReportQuery)getQuery()).getItems().iterator(); items.hasNext();){
            ReportItem item = (ReportItem) items.next();
            item.setResultIndex(itemOffset);
            if (item.getAttributeExpression() != null){
                JoinedAttributeManager joinManager = item.getJoinedAttributeManager();
                if (joinManager.hasJoinedExpressions()){
                    itemOffset = joinManager.computeJoiningMappingIndexes(true, getSession(),itemOffset);
                }else{
                    if (item.getDescriptor() != null){
                        itemOffset += item.getDescriptor().getAllFields().size();
                    }else {
                        ++itemOffset; //only a single attribute can be selected
                    }
                }
            }
        }
        
    
public voidprepareReportQuerySelectAllRows()
Pre-build configure the call.

        prepareReportQueryItems();
        prepareExecuteSelect();
    
public voidprepareReportQuerySubSelect()
Prepare for a sub select using a call.

        prepareReportQueryItems();
        prepareCall();
    
public voidprepareSelectAllRows()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databseCall = (DatasourceCall)callsEnum.nextElement();
                databseCall.returnManyRows();
            }
        } else {
            getCall().returnManyRows();
        }
        prepareCall();
    
public voidprepareSelectOneRow()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databseCall = (DatasourceCall)callsEnum.nextElement();
                databseCall.returnOneRow();
            }
        } else {
            getCall().returnOneRow();
        }
        prepareCall();
    
public voidprepareUpdateAll()
Pre-build configure the call.

        if (getCall() != null) {
            getCall().returnNothing();
        }

        prepareCall();
    
public voidprepareUpdateObject()
Pre-build configure the call.

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall call = (DatasourceCall)callsEnum.nextElement();
                call.returnNothing();
            }
        } else if (getCall() != null) {
            getCall().returnNothing();
        }
        prepareCall();
    
public java.util.VectorselectAllReportQueryRows()
Read all rows from the database. Assume call is correct returns the required fields.

return
Vector containing the database rows
exception
DatabaseException - an error has occurred on the database

        return executeSelect();
    
public java.util.VectorselectAllRows()
Read all rows from the database. Assume call is correct returns the required fields.

return
Vector containing the database rows
exception
DatabaseException - an error has occurred on the database

        return executeSelectCall();
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordselectOneRow()
Read a single row from the database. Assume call is correct.

return
row containing data
exception
DatabaseException - an error has occurred on the database

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databaseCall = (DatasourceCall)callsEnum.nextElement();
                AbstractRecord result = (AbstractRecord)executeCall(databaseCall);
                if (result != null) {
                    return result;
                }
            }

            return null;
        } else {
            return (AbstractRecord)executeCall();
        }
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordselectRowForDoesExist(DatabaseField field)
Perform a does exist check

param
field - the field used for does exist check
return
the associated row from the database
exception
DatabaseException - an error has occurred on the database

        if (hasMultipleCalls()) {
            for (Enumeration callsEnum = getCalls().elements(); callsEnum.hasMoreElements();) {
                DatasourceCall databaseCall = (DatasourceCall)callsEnum.nextElement();
                AbstractRecord result = (AbstractRecord)executeCall(databaseCall);
                if (result != null) {
                    return result;
                }
            }

            return null;
        } else {
            return (AbstractRecord)executeCall();
        }
    
public voidsetCall(oracle.toplink.essentials.internal.databaseaccess.DatasourceCall call)
Set the call.

        this.call = call;
        if (call != null) {
            call.setQuery(getQuery());
        }
    
protected voidsetCalls(java.util.Vector calls)
Normally only a single call is used, however multiple table may require multiple calls on write. This is lazy initialied to conserv space.

        this.calls = calls;
    
public java.lang.IntegerupdateAll()
Update the rows on the database. Assume the call is correct.

exception
DatabaseException - an error has occurred on the database.

        if(((UpdateAllQuery)getQuery()).isPreparedUsingTempStorage() && getSession().getPlatform().supportsTempTables()) {
            return updateAllUsingTempTables();
        } else {
            Integer rowCount = executeNoSelectCall();
            if(((UpdateAllQuery)getQuery()).isPreparedUsingTempStorage()) {
                // the query was prepared using Oracle anonymous block 
                AbstractRecord outputRow = (AbstractRecord)getQuery().getProperty("output");
                rowCount = (Integer)outputRow.get("ROW_COUNT");
            }
            return rowCount;
        }
    
public java.lang.IntegerupdateAllUsingTempTables()
Execute updateAll using temp tables

exception
DatabaseException - an error has occurred on the database.
return
the row count.

        int nTables = getCalls().size() / 4;
        DatabaseException ex = null;
        Integer returnedRowCount = null;
        
        // first quarter - crete temp tables calls.
        // may fail in case global temp table already exists.
        for (int index = 0; index < nTables; index++) {
            try {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                executeCall(databseCall);
            } catch (DatabaseException databaseEx) {
                // ignore
            }
        }

        // second quarter - populate temp tables calls.
        // if that fails save the exception and untill cleanup
        for (int index = nTables; index < nTables*2 && ex == null; index++) {
            try {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                executeCall(databseCall);
            } catch (DatabaseException databaseEx) {
                ex = databaseEx;
            }
        }
        
        // third quarter - update original tables calls.
        // if that fails save the exception and untill cleanup
        for (int index = nTables*2; index < nTables*3 && ex == null; index++) {
            try {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                Integer rowCount = (Integer)executeCall(databseCall);
                if ((index == nTables*2) || (rowCount.intValue() <= 0)) {// Row count returned must be from first table or zero if any are zero.
                    returnedRowCount = rowCount;
                }
            } catch (DatabaseException databaseEx) {
                ex = databaseEx;
            }
        }
        
        // last quarter - cleanup temp tables calls.
        // ignore exceptions here.
        for (int index = nTables*3; index < nTables*4; index++) {
            try {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                executeCall(databseCall);
                } catch (DatabaseException databaseEx) {
                    // ignore
                }
        }

        if(ex != null) {
            throw ex;
        }
        
        return returnedRowCount;
    
protected voidupdateForeignKeyFieldShallow(WriteObjectQuery writeQuery)
Update the foreign key fields when resolving a bi-directonal reference in a UOW. This is rare to occur for non-relational, however if it does each of the calls must be re-executed.

        // For CR 2923 must move to session we will execute call on now
        // so correct DatasourcePlatform used by translate. 
        AbstractSession sessionToUse = getSession().getExecutionSession(getQuery());

        // yes - this is a bit ugly...
        Vector calls = ((DatasourceCallQueryMechanism)this.getDescriptor().getQueryManager().getUpdateQuery().getQueryMechanism()).getCalls();
        for (Enumeration stream = calls.elements(); stream.hasMoreElements();) {
            DatasourceCall call = (DatasourceCall)((DatasourceCall)stream.nextElement()).clone();
            call.setQuery(writeQuery);
            sessionToUse.executeCall(call, this.getTranslationRow(), writeQuery);
        }
    
public java.lang.IntegerupdateObject()
Update the object. Assume the call is correct.

exception
DatabaseException - an error has occurred on the database.
return
the row count.

        Collection returnFields = null;
        Integer returnedRowCount = null;
        if (hasMultipleCalls()) {
            for (int index = 0; index < getCalls().size(); index++) {
                DatasourceCall databseCall = (DatasourceCall)getCalls().elementAt(index);
                Integer rowCount = (Integer)executeCall(databseCall);
                if ((index == 0) || (rowCount.intValue() <= 0)) {// Row count returned must be from first table or zero if any are zero.
                    returnedRowCount = rowCount;
                }
                if (returnFields != null) {
                    updateObjectAndRowWithReturnRow(returnFields, false);
                }
            }
        } else {
            returnedRowCount = (Integer)executeCall();
            if (returnFields != null) {
                updateObjectAndRowWithReturnRow(returnFields, false);
            }
        }

        //Oracle thin driver handles LOB differently. During the insert, empty lob would be
        //insert first, and then the LOb locator is retrieved and LOB data are written through
        //the locator.
        // 
        // Bug 2804663 - LOBValueWriter is no longer a singleton, so we execute any deferred
        // select calls through the DatabaseAccessor which holds the writer instance
        //
        // Building of SELECT statements is no longer done in DatabaseAccessor.basicExecuteCall
        // because DatabaseCall.isUpdateCall() can't recognize update in case StoredProcedureCall
        // is used.
        AbstractSession executionSession = getSession().getExecutionSession(getQuery());
        executionSession.getAccessor().flushSelectCalls(executionSession);
        return returnedRowCount;