summaryrefslogtreecommitdiff
path: root/storage/ndb/src/ndbapi/NdbTransaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/ndbapi/NdbTransaction.cpp')
-rw-r--r--storage/ndb/src/ndbapi/NdbTransaction.cpp2124
1 files changed, 2124 insertions, 0 deletions
diff --git a/storage/ndb/src/ndbapi/NdbTransaction.cpp b/storage/ndb/src/ndbapi/NdbTransaction.cpp
new file mode 100644
index 00000000000..67581e4a0f8
--- /dev/null
+++ b/storage/ndb/src/ndbapi/NdbTransaction.cpp
@@ -0,0 +1,2124 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+#include <NdbTransaction.hpp>
+#include <NdbOperation.hpp>
+#include <NdbScanOperation.hpp>
+#include <NdbIndexScanOperation.hpp>
+#include <NdbIndexOperation.hpp>
+#include "NdbApiSignal.hpp"
+#include "TransporterFacade.hpp"
+#include "API.hpp"
+#include "NdbBlob.hpp"
+#include <ndb_limits.h>
+
+#include <signaldata/TcKeyConf.hpp>
+#include <signaldata/TcIndx.hpp>
+#include <signaldata/TcCommit.hpp>
+#include <signaldata/TcKeyFailConf.hpp>
+#include <signaldata/TcHbRep.hpp>
+
+/*****************************************************************************
+NdbTransaction( Ndb* aNdb );
+
+Return Value: None
+Parameters: aNdb: Pointers to the Ndb object
+Remark: Creates a connection object.
+*****************************************************************************/
+NdbTransaction::NdbTransaction( Ndb* aNdb ) :
+ theSendStatus(NotInit),
+ theCallbackFunction(NULL),
+ theCallbackObject(NULL),
+ theTransArrayIndex(0),
+ theStartTransTime(0),
+ theErrorLine(0),
+ theErrorOperation(NULL),
+ theNdb(aNdb),
+ theNext(NULL),
+ theFirstOpInList(NULL),
+ theLastOpInList(NULL),
+ theFirstExecOpInList(NULL),
+ theLastExecOpInList(NULL),
+ theCompletedFirstOp(NULL),
+ theCompletedLastOp(NULL),
+ theNoOfOpSent(0),
+ theNoOfOpCompleted(0),
+ theNoOfOpFetched(0),
+ theMyRef(0),
+ theTCConPtr(0),
+ theTransactionId(0),
+ theGlobalCheckpointId(0),
+ theStatus(NotConnected),
+ theCompletionStatus(NotCompleted),
+ theCommitStatus(NotStarted),
+ theMagicNumber(0xFE11DC),
+ theTransactionIsStarted(false),
+ theDBnode(0),
+ theReleaseOnClose(false),
+ // Scan operations
+ m_waitForReply(true),
+ m_theFirstScanOperation(NULL),
+ m_theLastScanOperation(NULL),
+ m_firstExecutedScanOp(NULL),
+ // Scan operations
+ theScanningOp(NULL),
+ theBuddyConPtr(0xFFFFFFFF),
+ theBlobFlag(false),
+ thePendingBlobOps(0)
+{
+ theListState = NotInList;
+ theError.code = 0;
+ theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
+
+#define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz)
+
+ CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
+ CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
+}//NdbTransaction::NdbTransaction()
+
+/*****************************************************************************
+~NdbTransaction();
+
+Remark: Deletes the connection object.
+*****************************************************************************/
+NdbTransaction::~NdbTransaction()
+{
+ DBUG_ENTER("NdbTransaction::~NdbTransaction");
+ theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
+ DBUG_VOID_RETURN;
+}//NdbTransaction::~NdbTransaction()
+
+/*****************************************************************************
+void init();
+
+Remark: Initialise connection object for new transaction.
+*****************************************************************************/
+void
+NdbTransaction::init()
+{
+ theListState = NotInList;
+ theInUseState = true;
+ theTransactionIsStarted = false;
+ theNext = NULL;
+
+ theFirstOpInList = NULL;
+ theLastOpInList = NULL;
+
+ theScanningOp = NULL;
+
+ theFirstExecOpInList = NULL;
+ theLastExecOpInList = NULL;
+
+ theCompletedFirstOp = NULL;
+ theCompletedLastOp = NULL;
+
+ theGlobalCheckpointId = 0;
+ theCommitStatus = Started;
+ theCompletionStatus = NotCompleted;
+ m_abortOption = AbortOnError;
+
+ theError.code = 0;
+ theErrorLine = 0;
+ theErrorOperation = NULL;
+
+ theReleaseOnClose = false;
+ theSimpleState = true;
+ theSendStatus = InitState;
+ theMagicNumber = 0x37412619;
+ // Scan operations
+ m_waitForReply = true;
+ m_theFirstScanOperation = NULL;
+ m_theLastScanOperation = NULL;
+ m_firstExecutedScanOp = 0;
+ theBuddyConPtr = 0xFFFFFFFF;
+ //
+ theBlobFlag = false;
+ thePendingBlobOps = 0;
+}//NdbTransaction::init()
+
+/*****************************************************************************
+setOperationErrorCode(int error);
+
+Remark: Sets an error code on the connection object from an
+ operation object.
+*****************************************************************************/
+void
+NdbTransaction::setOperationErrorCode(int error)
+{
+ DBUG_ENTER("NdbTransaction::setOperationErrorCode");
+ setErrorCode(error);
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+setOperationErrorCodeAbort(int error);
+
+Remark: Sets an error code on the connection object from an
+ operation object.
+*****************************************************************************/
+void
+NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
+{
+ DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
+ if (abortOption == -1)
+ abortOption = m_abortOption;
+ if (theTransactionIsStarted == false) {
+ theCommitStatus = Aborted;
+ } else if ((abortOption == AbortOnError) &&
+ (theCommitStatus != Committed) &&
+ (theCommitStatus != Aborted)) {
+ theCommitStatus = NeedAbort;
+ }//if
+ setErrorCode(error);
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+setErrorCode(int anErrorCode);
+
+Remark: Sets an error indication on the connection object.
+*****************************************************************************/
+void
+NdbTransaction::setErrorCode(int error)
+{
+ DBUG_ENTER("NdbTransaction::setErrorCode");
+ DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
+
+ if (theError.code == 0)
+ theError.code = error;
+
+ DBUG_VOID_RETURN;
+}//NdbTransaction::setErrorCode()
+
+int
+NdbTransaction::restart(){
+ DBUG_ENTER("NdbTransaction::restart");
+ if(theCompletionStatus == CompletedSuccess){
+ releaseCompletedOperations();
+ Uint64 tTransid = theNdb->theFirstTransId;
+ theTransactionId = tTransid;
+ if ((tTransid & 0xFFFFFFFF) == 0xFFFFFFFF) {
+ theNdb->theFirstTransId = (tTransid >> 32) << 32;
+ } else {
+ theNdb->theFirstTransId = tTransid + 1;
+ }
+ theCommitStatus = Started;
+ theCompletionStatus = NotCompleted;
+ theTransactionIsStarted = false;
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("error",("theCompletionStatus != CompletedSuccess"));
+ DBUG_RETURN(-1);
+}
+
+/*****************************************************************************
+void handleExecuteCompletion(void);
+
+Remark: Handle time-out on a transaction object.
+*****************************************************************************/
+void
+NdbTransaction::handleExecuteCompletion()
+{
+ /***************************************************************************
+ * Move the NdbOperation objects from the list of executing
+ * operations to list of completed
+ **************************************************************************/
+ NdbOperation* tFirstExecOp = theFirstExecOpInList;
+ NdbOperation* tLastExecOp = theLastExecOpInList;
+ if (tLastExecOp != NULL) {
+ tLastExecOp->next(theCompletedFirstOp);
+ theCompletedFirstOp = tFirstExecOp;
+ if (theCompletedLastOp == NULL)
+ theCompletedLastOp = tLastExecOp;
+ theFirstExecOpInList = NULL;
+ theLastExecOpInList = NULL;
+ }//if
+ theSendStatus = InitState;
+ return;
+}//NdbTransaction::handleExecuteCompletion()
+
+/*****************************************************************************
+int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
+
+Return Value: Return 0 : execute was successful.
+ Return -1: In all other case.
+Parameters : aTypeOfExec: Type of execute.
+Remark: Initialise connection object for new transaction.
+*****************************************************************************/
+int
+NdbTransaction::execute(ExecType aTypeOfExec,
+ AbortOption abortOption,
+ int forceSend)
+{
+ DBUG_ENTER("NdbTransaction::execute");
+ DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
+ aTypeOfExec, abortOption));
+
+ if (! theBlobFlag)
+ DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
+
+ /*
+ * execute prepared ops in batches, as requested by blobs
+ * - blob error does not terminate execution
+ * - blob error sets error on operation
+ * - if error on operation skip blob calls
+ */
+
+ ExecType tExecType;
+ NdbOperation* tPrepOp;
+ NdbOperation* tCompletedFirstOp = NULL;
+ NdbOperation* tCompletedLastOp = NULL;
+
+ int ret = 0;
+ do {
+ tExecType = aTypeOfExec;
+ tPrepOp = theFirstOpInList;
+ while (tPrepOp != NULL) {
+ if (tPrepOp->theError.code == 0) {
+ bool batch = false;
+ NdbBlob* tBlob = tPrepOp->theBlobList;
+ while (tBlob != NULL) {
+ if (tBlob->preExecute(tExecType, batch) == -1)
+ ret = -1;
+ tBlob = tBlob->theNext;
+ }
+ if (batch) {
+ // blob asked to execute all up to here now
+ tExecType = NoCommit;
+ break;
+ }
+ }
+ tPrepOp = tPrepOp->next();
+ }
+
+ // save rest of prepared ops if batch
+ NdbOperation* tRestOp= 0;
+ NdbOperation* tLastOp= 0;
+ if (tPrepOp != NULL) {
+ tRestOp = tPrepOp->next();
+ tPrepOp->next(NULL);
+ tLastOp = theLastOpInList;
+ theLastOpInList = tPrepOp;
+ }
+
+ if (tExecType == Commit) {
+ NdbOperation* tOp = theCompletedFirstOp;
+ while (tOp != NULL) {
+ if (tOp->theError.code == 0) {
+ NdbBlob* tBlob = tOp->theBlobList;
+ while (tBlob != NULL) {
+ if (tBlob->preCommit() == -1)
+ ret = -1;
+ tBlob = tBlob->theNext;
+ }
+ }
+ tOp = tOp->next();
+ }
+ }
+
+ // completed ops are in unspecified order
+ if (theCompletedFirstOp != NULL) {
+ if (tCompletedFirstOp == NULL) {
+ tCompletedFirstOp = theCompletedFirstOp;
+ tCompletedLastOp = theCompletedLastOp;
+ } else {
+ tCompletedLastOp->next(theCompletedFirstOp);
+ tCompletedLastOp = theCompletedLastOp;
+ }
+ theCompletedFirstOp = NULL;
+ theCompletedLastOp = NULL;
+ }
+
+ if (executeNoBlobs(tExecType, abortOption, forceSend) == -1)
+ ret = -1;
+#ifdef ndb_api_crash_on_complex_blob_abort
+ assert(theFirstOpInList == NULL && theLastOpInList == NULL);
+#else
+ theFirstOpInList = theLastOpInList = NULL;
+#endif
+
+ {
+ NdbOperation* tOp = theCompletedFirstOp;
+ while (tOp != NULL) {
+ if (tOp->theError.code == 0) {
+ NdbBlob* tBlob = tOp->theBlobList;
+ while (tBlob != NULL) {
+ // may add new operations if batch
+ if (tBlob->postExecute(tExecType) == -1)
+ ret = -1;
+ tBlob = tBlob->theNext;
+ }
+ }
+ tOp = tOp->next();
+ }
+ }
+
+ // add saved prepared ops if batch
+ if (tPrepOp != NULL && tRestOp != NULL) {
+ if (theFirstOpInList == NULL)
+ theFirstOpInList = tRestOp;
+ else
+ theLastOpInList->next(tRestOp);
+ theLastOpInList = tLastOp;
+ }
+ assert(theFirstOpInList == NULL || tExecType == NoCommit);
+ } while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
+
+ if (tCompletedFirstOp != NULL) {
+ tCompletedLastOp->next(theCompletedFirstOp);
+ theCompletedFirstOp = tCompletedFirstOp;
+ if (theCompletedLastOp == NULL)
+ theCompletedLastOp = tCompletedLastOp;
+ }
+#if ndb_api_count_completed_ops_after_blob_execute
+ { NdbOperation* tOp; unsigned n = 0;
+ for (tOp = theCompletedFirstOp; tOp != NULL; tOp = tOp->next()) n++;
+ ndbout << "completed ops: " << n << endl;
+ }
+#endif
+ DBUG_RETURN(ret);
+}
+
+int
+NdbTransaction::executeNoBlobs(ExecType aTypeOfExec,
+ AbortOption abortOption,
+ int forceSend)
+{
+ DBUG_ENTER("NdbTransaction::executeNoBlobs");
+ DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
+ aTypeOfExec, abortOption));
+
+//------------------------------------------------------------------------
+// We will start by preparing all operations in the transaction defined
+// since last execute or since beginning. If this works ok we will continue
+// by calling the poll with wait method. This method will return when
+// the NDB kernel has completed its task or when 10 seconds have passed.
+// The NdbTransactionCallBack-method will receive the return code of the
+// transaction. The normal methods of reading error codes still apply.
+//------------------------------------------------------------------------
+ Ndb* tNdb = theNdb;
+
+ m_waitForReply = false;
+ executeAsynchPrepare(aTypeOfExec, NULL, NULL, abortOption);
+ if (m_waitForReply){
+ while (1) {
+ int noOfComp = tNdb->sendPollNdb((3 * WAITFOR_RESPONSE_TIMEOUT),
+ 1, forceSend);
+ if (noOfComp == 0) {
+ /**
+ * This timeout situation can occur if NDB crashes.
+ */
+ ndbout << "This timeout should never occur, execute(..)" << endl;
+ setOperationErrorCodeAbort(4012); // Error code for "Cluster Failure"
+ DBUG_RETURN(-1);
+ }//if
+
+ /*
+ * Check that the completed transactions include this one. There
+ * could be another thread running asynchronously. Even in pure
+ * async case rollback is done synchronously.
+ */
+ if (theListState != NotInList)
+ continue;
+#ifdef VM_TRACE
+ unsigned anyway = 0;
+ for (unsigned i = 0; i < theNdb->theNoOfPreparedTransactions; i++)
+ anyway += theNdb->thePreparedTransactionsArray[i] == this;
+ for (unsigned i = 0; i < theNdb->theNoOfSentTransactions; i++)
+ anyway += theNdb->theSentTransactionsArray[i] == this;
+ for (unsigned i = 0; i < theNdb->theNoOfCompletedTransactions; i++)
+ anyway += theNdb->theCompletedTransactionsArray[i] == this;
+ if (anyway) {
+ theNdb->printState("execute %x", this);
+ abort();
+ }
+#endif
+ if (theReturnStatus == ReturnFailure) {
+ DBUG_RETURN(-1);
+ }//if
+ break;
+ }
+ }
+ thePendingBlobOps = 0;
+ DBUG_RETURN(0);
+}//NdbTransaction::execute()
+
+/*****************************************************************************
+void executeAsynchPrepare(ExecType aTypeOfExec,
+ NdbAsynchCallback callBack,
+ void* anyObject,
+ CommitType aTypeOfCommit);
+
+Return Value: No return value
+Parameters : aTypeOfExec: Type of execute.
+ anyObject: An object provided in the callback method
+ callBack: The callback method
+ aTypeOfCommit: What to do when read/updated/deleted records
+ are missing or inserted records already exist.
+
+Remark: Prepare a part of a transaction in an asynchronous manner.
+*****************************************************************************/
+void
+NdbTransaction::executeAsynchPrepare( ExecType aTypeOfExec,
+ NdbAsynchCallback aCallback,
+ void* anyObject,
+ AbortOption abortOption)
+{
+ DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
+ DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: %x, anyObject: %x",
+ aTypeOfExec, aCallback, anyObject));
+
+ /**
+ * Reset error.code on execute
+ */
+ if (theError.code != 0)
+ DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
+ theError.code = 0;
+ NdbScanOperation* tcOp = m_theFirstScanOperation;
+ if (tcOp != 0){
+ // Execute any cursor operations
+ while (tcOp != NULL) {
+ int tReturnCode;
+ tReturnCode = tcOp->executeCursor(theDBnode);
+ if (tReturnCode == -1) {
+ DBUG_VOID_RETURN;
+ }//if
+ tcOp = (NdbScanOperation*)tcOp->next();
+ } // while
+ m_theLastScanOperation->next(m_firstExecutedScanOp);
+ m_firstExecutedScanOp = m_theFirstScanOperation;
+ // Discard cursor operations, since these are also
+ // in the complete operations list we do not need
+ // to release them.
+ m_theFirstScanOperation = m_theLastScanOperation = NULL;
+ }
+
+ bool tTransactionIsStarted = theTransactionIsStarted;
+ NdbOperation* tLastOp = theLastOpInList;
+ Ndb* tNdb = theNdb;
+ CommitStatusType tCommitStatus = theCommitStatus;
+ Uint32 tnoOfPreparedTransactions = tNdb->theNoOfPreparedTransactions;
+
+ theReturnStatus = ReturnSuccess;
+ theCallbackFunction = aCallback;
+ theCallbackObject = anyObject;
+ m_abortOption = abortOption;
+ m_waitForReply = true;
+ tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this;
+ theTransArrayIndex = tnoOfPreparedTransactions;
+ theListState = InPreparedList;
+ tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1;
+
+ if ((tCommitStatus != Started) ||
+ (aTypeOfExec == Rollback)) {
+/*****************************************************************************
+ * Rollback have been ordered on a started transaction. Call rollback.
+ * Could also be state problem or previous problem which leads to the
+ * same action.
+ ****************************************************************************/
+ if (aTypeOfExec == Rollback) {
+ if (theTransactionIsStarted == false || theSimpleState) {
+ theCommitStatus = Aborted;
+ theSendStatus = sendCompleted;
+ } else {
+ theSendStatus = sendABORT;
+ }
+ } else {
+ theSendStatus = sendABORTfail;
+ }//if
+ if (theCommitStatus == Aborted){
+ DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
+ setErrorCode(4350);
+ }
+ DBUG_VOID_RETURN;
+ }//if
+ if (tTransactionIsStarted == true) {
+ if (tLastOp != NULL) {
+ if (aTypeOfExec == Commit) {
+/*****************************************************************************
+ * Set commit indicator on last operation when commit has been ordered
+ * and also a number of operations.
+******************************************************************************/
+ tLastOp->theCommitIndicator = 1;
+ }//if
+ } else {
+ if (aTypeOfExec == Commit && !theSimpleState) {
+ /**********************************************************************
+ * A Transaction have been started and no more operations exist.
+ * We will use the commit method.
+ *********************************************************************/
+ theSendStatus = sendCOMMITstate;
+ DBUG_VOID_RETURN;
+ } else {
+ /**********************************************************************
+ * We need to put it into the array of completed transactions to
+ * ensure that we report the completion in a proper way.
+ * We cannot do this here since that would endanger the completed
+ * transaction array since that is also updated from the receiver
+ * thread and thus we need to do it under mutex lock and thus we
+ * set the sendStatus to ensure that the send method will
+ * put it into the completed array.
+ **********************************************************************/
+ theSendStatus = sendCompleted;
+ DBUG_VOID_RETURN; // No Commit with no operations is OK
+ }//if
+ }//if
+ } else if (tTransactionIsStarted == false) {
+ NdbOperation* tFirstOp = theFirstOpInList;
+ if (tLastOp != NULL) {
+ tFirstOp->setStartIndicator();
+ if (aTypeOfExec == Commit) {
+ tLastOp->theCommitIndicator = 1;
+ }//if
+ } else {
+ /***********************************************************************
+ * No operations are defined and we have not started yet.
+ * Simply return OK. Set commit status if Commit.
+ ***********************************************************************/
+ if (aTypeOfExec == Commit) {
+ theCommitStatus = Committed;
+ }//if
+ /***********************************************************************
+ * We need to put it into the array of completed transactions to
+ * ensure that we report the completion in a proper way. We
+ * cannot do this here since that would endanger the completed
+ * transaction array since that is also updated from the
+ * receiver thread and thus we need to do it under mutex lock
+ * and thus we set the sendStatus to ensure that the send method
+ * will put it into the completed array.
+ ***********************************************************************/
+ theSendStatus = sendCompleted;
+ DBUG_VOID_RETURN;
+ }//if
+ }
+
+ NdbOperation* tOp = theFirstOpInList;
+ theCompletionStatus = NotCompleted;
+ while (tOp) {
+ int tReturnCode;
+ NdbOperation* tNextOp = tOp->next();
+
+ tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId);
+ if (tReturnCode == -1) {
+ theSendStatus = sendABORTfail;
+ DBUG_VOID_RETURN;
+ }//if
+
+ /*************************************************************************
+ * Now that we have successfully prepared the send of this operation we
+ * move it to the list of executing operations and remove it from the
+ * list of defined operations.
+ ************************************************************************/
+ tOp = tNextOp;
+ }
+
+ NdbOperation* tLastOpInList = theLastOpInList;
+ NdbOperation* tFirstOpInList = theFirstOpInList;
+
+ theFirstOpInList = NULL;
+ theLastOpInList = NULL;
+ theFirstExecOpInList = tFirstOpInList;
+ theLastExecOpInList = tLastOpInList;
+
+ theCompletionStatus = CompletedSuccess;
+ theNoOfOpSent = 0;
+ theNoOfOpCompleted = 0;
+ theSendStatus = sendOperations;
+ NdbNodeBitmask::clear(m_db_nodes);
+ NdbNodeBitmask::clear(m_failed_db_nodes);
+ DBUG_VOID_RETURN;
+}//NdbTransaction::executeAsynchPrepare()
+
+void NdbTransaction::close()
+{
+ theNdb->closeTransaction(this);
+}
+
+int NdbTransaction::refresh(){
+ return sendTC_HBREP();
+}
+
+/*****************************************************************************
+int sendTC_HBREP();
+
+Return Value: No return value.
+Parameters : None.
+Remark: Order NDB to refresh the timeout counter of the transaction.
+******************************************************************************/
+int
+NdbTransaction::sendTC_HBREP() // Send a TC_HBREP signal;
+{
+ NdbApiSignal* tSignal;
+ Ndb* tNdb = theNdb;
+ Uint32 tTransId1, tTransId2;
+
+ tSignal = tNdb->getSignal();
+ if (tSignal == NULL) {
+ return -1;
+ }
+
+ if (tSignal->setSignal(GSN_TC_HBREP) == -1) {
+ return -1;
+ }
+
+ TcHbRep * const tcHbRep = CAST_PTR(TcHbRep, tSignal->getDataPtrSend());
+
+ tcHbRep->apiConnectPtr = theTCConPtr;
+
+ tTransId1 = (Uint32) theTransactionId;
+ tTransId2 = (Uint32) (theTransactionId >> 32);
+ tcHbRep->transId1 = tTransId1;
+ tcHbRep->transId2 = tTransId2;
+
+ TransporterFacade *tp = TransporterFacade::instance();
+ tp->lock_mutex();
+ const int res = tp->sendSignal(tSignal,theDBnode);
+ tp->unlock_mutex();
+ tNdb->releaseSignal(tSignal);
+
+ if (res == -1){
+ return -1;
+ }
+
+ return 0;
+}//NdbTransaction::sendTC_HBREP()
+
+/*****************************************************************************
+int doSend();
+
+Return Value: Return 0 : send was successful.
+ Return -1: In all other case.
+Remark: Send all operations belonging to this connection.
+ The caller of this method has the responsibility to remove the
+ object from the prepared transactions array on the Ndb-object.
+*****************************************************************************/
+int
+NdbTransaction::doSend()
+{
+ DBUG_ENTER("NdbTransaction::doSend");
+
+ /*
+ This method assumes that at least one operation have been defined. This
+ is ensured by the caller of this routine (=execute).
+ */
+
+ switch(theSendStatus){
+ case sendOperations: {
+ NdbOperation * tOp = theFirstExecOpInList;
+ do {
+ NdbOperation* tNextOp = tOp->next();
+ const Uint32 lastFlag = ((tNextOp == NULL) ? 1 : 0);
+ const int tReturnCode = tOp->doSend(theDBnode, lastFlag);
+ if (tReturnCode == -1) {
+ theReturnStatus = ReturnFailure;
+ break;
+ }//if
+ tOp = tNextOp;
+ } while (tOp != NULL);
+ Ndb* tNdb = theNdb;
+ theSendStatus = sendTC_OP;
+ theTransactionIsStarted = true;
+ tNdb->insert_sent_list(this);
+ DBUG_RETURN(0);
+ }//case
+ case sendABORT:
+ case sendABORTfail:{
+ /***********************************************************************
+ * Rollback have been ordered on a not started transaction.
+ * Simply return OK and set abort status.
+ ***********************************************************************/
+ if (theSendStatus == sendABORTfail) {
+ theReturnStatus = ReturnFailure;
+ }//if
+ if (sendROLLBACK() == 0) {
+ DBUG_RETURN(0);
+ }//if
+ break;
+ }//case
+ case sendCOMMITstate:
+ if (sendCOMMIT() == 0) {
+ DBUG_RETURN(0);
+ }//if
+ break;
+ case sendCompleted:
+ theNdb->insert_completed_list(this);
+ DBUG_RETURN(0);
+ default:
+ ndbout << "Inconsistent theSendStatus = "
+ << (Uint32) theSendStatus << endl;
+ abort();
+ break;
+ }//switch
+ setOperationErrorCodeAbort(4002);
+ theReleaseOnClose = true;
+ theTransactionIsStarted = false;
+ theCommitStatus = Aborted;
+ DBUG_RETURN(-1);
+}//NdbTransaction::doSend()
+
+/**************************************************************************
+int sendROLLBACK();
+
+Return Value: Return -1 if send unsuccessful.
+Parameters : None.
+Remark: Order NDB to rollback the transaction.
+**************************************************************************/
+int
+NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
+{
+ Ndb* tNdb = theNdb;
+ if ((theTransactionIsStarted == true) &&
+ (theCommitStatus != Committed) &&
+ (theCommitStatus != Aborted)) {
+/**************************************************************************
+ * The user did not perform any rollback but simply closed the
+ * transaction. We must rollback Ndb since Ndb have been contacted.
+ *************************************************************************/
+ NdbApiSignal tSignal(tNdb->theMyRef);
+ Uint32 tTransId1, tTransId2;
+ TransporterFacade *tp = TransporterFacade::instance();
+ int tReturnCode;
+
+ tTransId1 = (Uint32) theTransactionId;
+ tTransId2 = (Uint32) (theTransactionId >> 32);
+ tSignal.setSignal(GSN_TCROLLBACKREQ);
+ tSignal.setData(theTCConPtr, 1);
+ tSignal.setData(tTransId1, 2);
+ tSignal.setData(tTransId2, 3);
+ tReturnCode = tp->sendSignal(&tSignal,theDBnode);
+ if (tReturnCode != -1) {
+ theSendStatus = sendTC_ROLLBACK;
+ tNdb->insert_sent_list(this);
+ return 0;
+ }//if
+ /*********************************************************************
+ * It was not possible to abort the transaction towards the NDB kernel
+ * and thus we put it into the array of completed transactions that
+ * are ready for reporting to the application.
+ *********************************************************************/
+ return -1;
+ } else {
+ /*
+ It is not necessary to abort the transaction towards the NDB kernel and
+ thus we put it into the array of completed transactions that are ready
+ for reporting to the application.
+ */
+ theSendStatus = sendCompleted;
+ tNdb->insert_completed_list(this);
+ return 0;
+ ;
+ }//if
+}//NdbTransaction::sendROLLBACK()
+
+/***************************************************************************
+int sendCOMMIT();
+
+Return Value: Return 0 : send was successful.
+ Return -1: In all other case.
+Parameters : None.
+Remark: Order NDB to commit the transaction.
+***************************************************************************/
+int
+NdbTransaction::sendCOMMIT() // Send a TC_COMMITREQ signal;
+{
+ NdbApiSignal tSignal(theNdb->theMyRef);
+ Uint32 tTransId1, tTransId2;
+ TransporterFacade *tp = TransporterFacade::instance();
+ int tReturnCode;
+
+ tTransId1 = (Uint32) theTransactionId;
+ tTransId2 = (Uint32) (theTransactionId >> 32);
+ tSignal.setSignal(GSN_TC_COMMITREQ);
+ tSignal.setData(theTCConPtr, 1);
+ tSignal.setData(tTransId1, 2);
+ tSignal.setData(tTransId2, 3);
+
+ tReturnCode = tp->sendSignal(&tSignal,theDBnode);
+ if (tReturnCode != -1) {
+ theSendStatus = sendTC_COMMIT;
+ theNdb->insert_sent_list(this);
+ return 0;
+ } else {
+ return -1;
+ }//if
+}//NdbTransaction::sendCOMMIT()
+
+/******************************************************************************
+void release();
+
+Remark: Release all operations.
+******************************************************************************/
+void
+NdbTransaction::release(){
+ releaseOperations();
+ if ( (theTransactionIsStarted == true) &&
+ ((theCommitStatus != Committed) &&
+ (theCommitStatus != Aborted))) {
+ /************************************************************************
+ * The user did not perform any rollback but simply closed the
+ * transaction. We must rollback Ndb since Ndb have been contacted.
+ ************************************************************************/
+ execute(Rollback);
+ }//if
+ theMagicNumber = 0xFE11DC;
+ theInUseState = false;
+#ifdef VM_TRACE
+ if (theListState != NotInList) {
+ theNdb->printState("release %x", this);
+ abort();
+ }
+#endif
+}//NdbTransaction::release()
+
+void
+NdbTransaction::releaseOps(NdbOperation* tOp){
+ while (tOp != NULL) {
+ NdbOperation* tmp = tOp;
+ tOp->release();
+ tOp = tOp->next();
+ theNdb->releaseOperation(tmp);
+ }//while
+}
+
+/******************************************************************************
+void releaseOperations();
+
+Remark: Release all operations.
+******************************************************************************/
+void
+NdbTransaction::releaseOperations()
+{
+ // Release any open scans
+ releaseScanOperations(m_theFirstScanOperation);
+ releaseScanOperations(m_firstExecutedScanOp);
+
+ releaseOps(theCompletedFirstOp);
+ releaseOps(theFirstOpInList);
+ releaseOps(theFirstExecOpInList);
+
+ theCompletedFirstOp = NULL;
+ theCompletedLastOp = NULL;
+ theFirstOpInList = NULL;
+ theFirstExecOpInList = NULL;
+ theLastOpInList = NULL;
+ theLastExecOpInList = NULL;
+ theScanningOp = NULL;
+ m_theFirstScanOperation = NULL;
+ m_theLastScanOperation = NULL;
+ m_firstExecutedScanOp = NULL;
+}//NdbTransaction::releaseOperations()
+
+void
+NdbTransaction::releaseCompletedOperations()
+{
+ releaseOps(theCompletedFirstOp);
+ theCompletedFirstOp = NULL;
+ theCompletedLastOp = NULL;
+}//NdbTransaction::releaseOperations()
+
+/******************************************************************************
+void releaseScanOperations();
+
+Remark: Release all cursor operations.
+ (NdbScanOperation and NdbIndexOperation)
+******************************************************************************/
+void
+NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
+{
+ while(cursorOp != 0){
+ NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
+ cursorOp->release();
+ theNdb->releaseScanOperation(cursorOp);
+ cursorOp = next;
+ }
+}//NdbTransaction::releaseScanOperations()
+
+/*****************************************************************************
+NdbOperation* getNdbOperation(const char* aTableName);
+
+Return Value Return a pointer to a NdbOperation object if getNdbOperation
+ was succesful.
+ Return NULL : In all other case.
+Parameters: aTableName : Name of the database table.
+Remark: Get an operation from NdbOperation idlelist and get the
+ NdbTransaction object
+ who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbOperation object.
+ synchronous
+******************************************************************************/
+NdbOperation*
+NdbTransaction::getNdbOperation(const char* aTableName)
+{
+ if (theCommitStatus == Started){
+ NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
+ if (table != 0){
+ return getNdbOperation(table);
+ } else {
+ setErrorCode(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }//if
+ }
+
+ setOperationErrorCodeAbort(4114);
+
+ return NULL;
+}//NdbTransaction::getNdbOperation()
+
+/*****************************************************************************
+NdbOperation* getNdbOperation(int aTableId);
+
+Return Value Return a pointer to a NdbOperation object if getNdbOperation
+ was succesful.
+ Return NULL: In all other case.
+Parameters: tableId : Id of the database table beeing deleted.
+Remark: Get an operation from NdbOperation object idlelist and
+ get the NdbTransaction object who was fetch by
+ startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbOperation
+ object, synchronous.
+*****************************************************************************/
+NdbOperation*
+NdbTransaction::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
+{
+ NdbOperation* tOp;
+
+ if (theScanningOp != NULL){
+ setErrorCode(4607);
+ return NULL;
+ }
+
+ tOp = theNdb->getOperation();
+ if (tOp == NULL)
+ goto getNdbOp_error1;
+ if (aNextOp == NULL) {
+ if (theLastOpInList != NULL) {
+ theLastOpInList->next(tOp);
+ theLastOpInList = tOp;
+ } else {
+ theLastOpInList = tOp;
+ theFirstOpInList = tOp;
+ }//if
+ tOp->next(NULL);
+ } else {
+ // add before the given op
+ if (theFirstOpInList == aNextOp) {
+ theFirstOpInList = tOp;
+ } else {
+ NdbOperation* aLoopOp = theFirstOpInList;
+ while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
+ aLoopOp = aLoopOp->next();
+ assert(aLoopOp != NULL);
+ aLoopOp->next(tOp);
+ }
+ tOp->next(aNextOp);
+ }
+ if (tOp->init(tab, this) != -1) {
+ return tOp;
+ } else {
+ theNdb->releaseOperation(tOp);
+ }//if
+ return NULL;
+
+ getNdbOp_error1:
+ setOperationErrorCodeAbort(4000);
+ return NULL;
+}//NdbTransaction::getNdbOperation()
+
+NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
+{
+ if (table)
+ return getNdbOperation(& NdbTableImpl::getImpl(*table));
+ else
+ return NULL;
+}//NdbTransaction::getNdbOperation()
+
+// NdbScanOperation
+/*****************************************************************************
+NdbScanOperation* getNdbScanOperation(const char* aTableName);
+
+Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
+ Return NULL : In all other case.
+Parameters: aTableName : Name of the database table.
+Remark: Get an operation from NdbScanOperation idlelist and get the NdbTransaction object
+ who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbOperation object.synchronous
+******************************************************************************/
+NdbScanOperation*
+NdbTransaction::getNdbScanOperation(const char* aTableName)
+{
+ if (theCommitStatus == Started){
+ NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
+ if (tab != 0){
+ return getNdbScanOperation(tab);
+ } else {
+ setOperationErrorCodeAbort(theNdb->theDictionary->m_error.code);
+ return NULL;
+ }//if
+ }
+
+ setOperationErrorCodeAbort(4114);
+ return NULL;
+}//NdbTransaction::getNdbScanOperation()
+
+/*****************************************************************************
+NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
+
+Return Value Return a pointer to a NdbIndexScanOperation object if getNdbIndexScanOperation was succesful.
+ Return NULL : In all other case.
+Parameters: anIndexName : Name of the index to use.
+ aTableName : Name of the database table.
+Remark: Get an operation from NdbIndexScanOperation idlelist and get the NdbTransaction object
+ who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbIndexScanOperation object.synchronous
+******************************************************************************/
+NdbIndexScanOperation*
+NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
+ const char* aTableName)
+{
+ NdbIndexImpl* index =
+ theNdb->theDictionary->getIndex(anIndexName, aTableName);
+ if (index == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return 0;
+ }
+ NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
+ if (table == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return 0;
+ }
+
+ return getNdbIndexScanOperation(index, table);
+}
+
+NdbIndexScanOperation*
+NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
+ const NdbTableImpl* table)
+{
+ if (theCommitStatus == Started){
+ const NdbTableImpl * indexTable = index->getIndexTable();
+ if (indexTable != 0){
+ NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
+ if(tOp)
+ {
+ tOp->m_currentTable = table;
+ }
+ return tOp;
+ } else {
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+ }//if
+ }
+
+ setOperationErrorCodeAbort(4114);
+ return NULL;
+}//NdbTransaction::getNdbIndexScanOperation()
+
+NdbIndexScanOperation*
+NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
+{
+ if (index)
+ {
+ const NdbDictionary::Table *table=
+ theNdb->theDictionary->getTable(index->getTable());
+
+ if (table)
+ return getNdbIndexScanOperation(index, table);
+
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}
+
+NdbIndexScanOperation*
+NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
+ const NdbDictionary::Table * table)
+{
+ if (index && table)
+ return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
+ & NdbTableImpl::getImpl(*table));
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}//NdbTransaction::getNdbIndexScanOperation()
+
+/*****************************************************************************
+NdbScanOperation* getNdbScanOperation(int aTableId);
+
+Return Value Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
+ Return NULL: In all other case.
+Parameters: tableId : Id of the database table beeing deleted.
+Remark: Get an operation from NdbScanOperation object idlelist and get the NdbTransaction
+ object who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbScanOperation object, synchronous.
+*****************************************************************************/
+NdbIndexScanOperation*
+NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
+{
+ NdbIndexScanOperation* tOp;
+
+ tOp = theNdb->getScanOperation();
+ if (tOp == NULL)
+ goto getNdbOp_error1;
+
+ if (tOp->init(tab, this) != -1) {
+ define_scan_op(tOp);
+ return tOp;
+ } else {
+ theNdb->releaseScanOperation(tOp);
+ }//if
+ return NULL;
+
+getNdbOp_error1:
+ setOperationErrorCodeAbort(4000);
+ return NULL;
+}//NdbTransaction::getNdbScanOperation()
+
+void
+NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
+ NdbOperation* tmp= list;
+ if(tmp == op)
+ list = op->next();
+ else {
+ while(tmp && tmp->next() != op) tmp = tmp->next();
+ if(tmp)
+ tmp->next(op->next());
+ }
+ op->next(NULL);
+}
+
+void
+NdbTransaction::define_scan_op(NdbIndexScanOperation * tOp){
+ // Link scan operation into list of cursor operations
+ if (m_theLastScanOperation == NULL)
+ m_theFirstScanOperation = m_theLastScanOperation = tOp;
+ else {
+ m_theLastScanOperation->next(tOp);
+ m_theLastScanOperation = tOp;
+ }
+ tOp->next(NULL);
+}
+
+NdbScanOperation*
+NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
+{
+ if (table)
+ return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
+ else
+ return NULL;
+}//NdbTransaction::getNdbScanOperation()
+
+
+// IndexOperation
+/*****************************************************************************
+NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
+ const char* aTableName);
+
+Return Value Return a pointer to a NdbOperation object if getNdbIndexOperation was succesful.
+ Return NULL : In all other case.
+Parameters: aTableName : Name of the database table.
+Remark: Get an operation from NdbIndexOperation idlelist and get the NdbTransaction object
+ who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbIndexOperation object.synchronous
+******************************************************************************/
+NdbIndexOperation*
+NdbTransaction::getNdbIndexOperation(const char* anIndexName,
+ const char* aTableName)
+{
+ if (theCommitStatus == Started) {
+ NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
+ NdbIndexImpl * index;
+
+ if (table == 0)
+ {
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+
+ if (table->m_frm.get_data())
+ {
+ // This unique index is defined from SQL level
+ static const char* uniqueSuffix= "$unique";
+ char uniqueIndexName[MAX_TAB_NAME_SIZE];
+
+ strxnmov(uniqueIndexName, MAX_TAB_NAME_SIZE, anIndexName, uniqueSuffix, NullS);
+ index = theNdb->theDictionary->getIndex(uniqueIndexName,
+ aTableName);
+ }
+ else
+ index = theNdb->theDictionary->getIndex(anIndexName,
+ aTableName);
+ if(table != 0 && index != 0){
+ return getNdbIndexOperation(index, table);
+ }
+
+ if(index == 0){
+ setOperationErrorCodeAbort(4243);
+ return NULL;
+ }
+
+ setOperationErrorCodeAbort(4243);
+ return NULL;
+ }
+
+ setOperationErrorCodeAbort(4114);
+ return 0;
+}//NdbTransaction::getNdbIndexOperation()
+
+/*****************************************************************************
+NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
+
+Return Value Return a pointer to a NdbIndexOperation object if getNdbIndexOperation was succesful.
+ Return NULL: In all other case.
+Parameters: tableId : Id of the database table beeing deleted.
+Remark: Get an operation from NdbIndexOperation object idlelist and get the NdbTransaction
+ object who was fetch by startTransaction pointing to this operation
+ getOperation will set the theTableId in the NdbIndexOperation object, synchronous.
+*****************************************************************************/
+NdbIndexOperation*
+NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
+ const NdbTableImpl * aTable,
+ NdbOperation* aNextOp)
+{
+ NdbIndexOperation* tOp;
+
+ tOp = theNdb->getIndexOperation();
+ if (tOp == NULL)
+ goto getNdbOp_error1;
+ if (aNextOp == NULL) {
+ if (theLastOpInList != NULL) {
+ theLastOpInList->next(tOp);
+ theLastOpInList = tOp;
+ } else {
+ theLastOpInList = tOp;
+ theFirstOpInList = tOp;
+ }//if
+ tOp->next(NULL);
+ } else {
+ // add before the given op
+ if (theFirstOpInList == aNextOp) {
+ theFirstOpInList = tOp;
+ } else {
+ NdbOperation* aLoopOp = theFirstOpInList;
+ while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
+ aLoopOp = aLoopOp->next();
+ assert(aLoopOp != NULL);
+ aLoopOp->next(tOp);
+ }
+ tOp->next(aNextOp);
+ }
+ if (tOp->indxInit(anIndex, aTable, this)!= -1) {
+ return tOp;
+ } else {
+ theNdb->releaseOperation(tOp);
+ }//if
+ return NULL;
+
+ getNdbOp_error1:
+ setOperationErrorCodeAbort(4000);
+ return NULL;
+}//NdbTransaction::getNdbIndexOperation()
+
+NdbIndexOperation*
+NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
+{
+ if (index)
+ {
+ const NdbDictionary::Table *table=
+ theNdb->theDictionary->getTable(index->getTable());
+
+ if (table)
+ return getNdbIndexOperation(index, table);
+
+ setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
+ return NULL;
+ }
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}
+
+NdbIndexOperation*
+NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
+ const NdbDictionary::Table * table)
+{
+ if (index && table)
+ return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
+ & NdbTableImpl::getImpl(*table));
+
+ setOperationErrorCodeAbort(4271);
+ return NULL;
+}//NdbTransaction::getNdbIndexOperation()
+
+
+/*******************************************************************************
+int receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
+
+Return Value: Return 0 : receiveDIHNDBTAMPER was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark: Sets theRestartGCI in the NDB object.
+*******************************************************************************/
+int
+NdbTransaction::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
+{
+ if (theStatus != Connecting) {
+ return -1;
+ } else {
+ theNdb->RestartGCI((Uint32)aSignal->readData(2));
+ theStatus = Connected;
+ }//if
+ return 0;
+}//NdbTransaction::receiveDIHNDBTAMPER()
+
+/*******************************************************************************
+int receiveTCSEIZECONF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCSEIZECONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark: Sets TC Connect pointer at reception of TCSEIZECONF.
+*******************************************************************************/
+int
+NdbTransaction::receiveTCSEIZECONF(NdbApiSignal* aSignal)
+{
+ if (theStatus != Connecting)
+ {
+ return -1;
+ } else
+ {
+ theTCConPtr = (Uint32)aSignal->readData(2);
+ theStatus = Connected;
+ }
+ return 0;
+}//NdbTransaction::receiveTCSEIZECONF()
+
+/*******************************************************************************
+int receiveTCSEIZEREF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCSEIZEREF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark: Sets TC Connect pointer.
+*******************************************************************************/
+int
+NdbTransaction::receiveTCSEIZEREF(NdbApiSignal* aSignal)
+{
+ DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
+ if (theStatus != Connecting)
+ {
+ DBUG_RETURN(-1);
+ } else
+ {
+ theStatus = ConnectFailure;
+ theNdb->theError.code = aSignal->readData(2);
+ DBUG_PRINT("info",("error code %d, %s",
+ theNdb->getNdbError().code,
+ theNdb->getNdbError().message));
+ DBUG_RETURN(0);
+ }
+}//NdbTransaction::receiveTCSEIZEREF()
+
+/*******************************************************************************
+int receiveTCRELEASECONF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCRELEASECONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark: DisConnect TC Connect pointer to NDBAPI.
+*******************************************************************************/
+int
+NdbTransaction::receiveTCRELEASECONF(NdbApiSignal* aSignal)
+{
+ if (theStatus != DisConnecting)
+ {
+ return -1;
+ } else
+ {
+ theStatus = NotConnected;
+ }
+ return 0;
+}//NdbTransaction::receiveTCRELEASECONF()
+
+/*******************************************************************************
+int receiveTCRELEASEREF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCRELEASEREF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark: DisConnect TC Connect pointer to NDBAPI Failure.
+*******************************************************************************/
+int
+NdbTransaction::receiveTCRELEASEREF(NdbApiSignal* aSignal)
+{
+ if (theStatus != DisConnecting) {
+ return -1;
+ } else {
+ theStatus = ConnectFailure;
+ theNdb->theError.code = aSignal->readData(2);
+ return 0;
+ }//if
+}//NdbTransaction::receiveTCRELEASEREF()
+
+/******************************************************************************
+int receiveTC_COMMITCONF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTC_COMMITCONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+******************************************************************************/
+int
+NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
+{
+ if(checkState_TransId(&commitConf->transId1)){
+ theCommitStatus = Committed;
+ theCompletionStatus = CompletedSuccess;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+ return -1;
+}//NdbTransaction::receiveTC_COMMITCONF()
+
+/******************************************************************************
+int receiveTC_COMMITREF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTC_COMMITREF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+******************************************************************************/
+int
+NdbTransaction::receiveTC_COMMITREF(NdbApiSignal* aSignal)
+{
+ const TcCommitRef * ref = CAST_CONSTPTR(TcCommitRef, aSignal->getDataPtr());
+ if(checkState_TransId(&ref->transId1)){
+ setOperationErrorCodeAbort(ref->errorCode);
+ theCommitStatus = Aborted;
+ theCompletionStatus = CompletedFailure;
+ theReturnStatus = ReturnFailure;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTC_COMMITREF()
+
+/******************************************************************************
+int receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCROLLBACKCONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+******************************************************************************/
+int
+NdbTransaction::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
+{
+ if(checkState_TransId(aSignal->getDataPtr() + 1)){
+ theCommitStatus = Aborted;
+ theCompletionStatus = CompletedSuccess;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCROLLBACKCONF()
+
+/*******************************************************************************
+int receiveTCROLLBACKREF(NdbApiSignal* aSignal);
+
+Return Value: Return 0 : receiveTCROLLBACKREF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+*******************************************************************************/
+int
+NdbTransaction::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
+{
+ if(checkState_TransId(aSignal->getDataPtr() + 1)){
+ setOperationErrorCodeAbort(aSignal->readData(4));
+ theCommitStatus = Aborted;
+ theCompletionStatus = CompletedFailure;
+ theReturnStatus = ReturnFailure;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCROLLBACKREF()
+
+/*****************************************************************************
+int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
+
+Return Value: Return 0 : send was succesful.
+ Return -1: In all other case.
+Parameters: aSignal: the signal object that contains the
+ TCROLLBACKREP signal from TC.
+Remark: Handles the reception of the ROLLBACKREP signal.
+*****************************************************************************/
+int
+NdbTransaction::receiveTCROLLBACKREP( NdbApiSignal* aSignal)
+{
+ /****************************************************************************
+Check that we are expecting signals from this transaction and that it doesn't
+belong to a transaction already completed. Simply ignore messages from other
+transactions.
+ ****************************************************************************/
+ if(checkState_TransId(aSignal->getDataPtr() + 1)){
+ theError.code = aSignal->readData(4);// Override any previous errors
+
+ /**********************************************************************/
+ /* A serious error has occured. This could be due to deadlock or */
+ /* lack of resources or simply a programming error in NDB. This */
+ /* transaction will be aborted. Actually it has already been */
+ /* and we only need to report completion and return with the */
+ /* error code to the application. */
+ /**********************************************************************/
+ theCompletionStatus = CompletedFailure;
+ theCommitStatus = Aborted;
+ theReturnStatus = ReturnFailure;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCROLLBACKREP()
+
+/*******************************************************************************
+int receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
+
+Return Value: Return 0 : receiveTCKEYCONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+*******************************************************************************/
+int
+NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
+{
+ NdbReceiver* tOp;
+ const Uint32 tTemp = keyConf->confInfo;
+ /***************************************************************************
+Check that we are expecting signals from this transaction and that it
+doesn't belong to a transaction already completed. Simply ignore messages
+from other transactions.
+ ***************************************************************************/
+ if(checkState_TransId(&keyConf->transId1)){
+
+ const Uint32 tNoOfOperations = TcKeyConf::getNoOfOperations(tTemp);
+ const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
+
+ const Uint32* tPtr = (Uint32 *)&keyConf->operations[0];
+ Uint32 tNoComp = theNoOfOpCompleted;
+ for (Uint32 i = 0; i < tNoOfOperations ; i++) {
+ tOp = theNdb->void2rec(theNdb->int2void(*tPtr++));
+ const Uint32 tAttrInfoLen = *tPtr++;
+ if (tOp && tOp->checkMagicNumber()) {
+ Uint32 done = tOp->execTCOPCONF(tAttrInfoLen);
+ if(tAttrInfoLen > TcKeyConf::SimpleReadBit){
+ Uint32 node = tAttrInfoLen & (~TcKeyConf::SimpleReadBit);
+ NdbNodeBitmask::set(m_db_nodes, node);
+ if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done)
+ {
+ done = 1;
+ tOp->setErrorCode(4119);
+ theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ }
+ }
+ tNoComp += done;
+ } else {
+ return -1;
+ }//if
+ }//for
+ Uint32 tNoSent = theNoOfOpSent;
+ theNoOfOpCompleted = tNoComp;
+ Uint32 tGCI = keyConf->gci;
+ if (tCommitFlag == 1) {
+ theCommitStatus = Committed;
+ theGlobalCheckpointId = tGCI;
+ } else if ((tNoComp >= tNoSent) &&
+ (theLastExecOpInList->theCommitIndicator == 1)){
+
+
+ if (m_abortOption == AO_IgnoreError && theError.code != 0){
+ /**
+ * There's always a TCKEYCONF when using IgnoreError
+ */
+ return -1;
+ }
+/**********************************************************************/
+// We sent the transaction with Commit flag set and received a CONF with
+// no Commit flag set. This is clearly an anomaly.
+/**********************************************************************/
+ theError.code = 4011;
+ theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ theCommitStatus = Aborted;
+ return 0;
+ }//if
+ if (tNoComp >= tNoSent) {
+ return 0; // No more operations to wait for
+ }//if
+ // Not completed the reception yet.
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCKEYCONF()
+
+/*****************************************************************************
+int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
+
+Return Value: Return 0 : receive was completed.
+ Return -1: In all other case.
+Parameters: aSignal: the signal object that contains the
+ TCKEY_FAILCONF signal from TC.
+Remark: Handles the reception of the TCKEY_FAILCONF signal.
+*****************************************************************************/
+int
+NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
+{
+ NdbOperation* tOp;
+ /*
+ Check that we are expecting signals from this transaction and that it
+ doesn't belong to a transaction already completed. Simply ignore
+ messages from other transactions.
+ */
+ if(checkState_TransId(&failConf->transId1)){
+ /*
+ A node failure of the TC node occured. The transaction has
+ been committed.
+ */
+ theCommitStatus = Committed;
+ tOp = theFirstExecOpInList;
+ while (tOp != NULL) {
+ /*
+ * Check if the transaction expected read values...
+ * If it did some of them might have gotten lost even if we succeeded
+ * in committing the transaction.
+ */
+ switch(tOp->theOperationType){
+ case NdbOperation::UpdateRequest:
+ case NdbOperation::InsertRequest:
+ case NdbOperation::DeleteRequest:
+ case NdbOperation::WriteRequest:
+ tOp = tOp->next();
+ break;
+ case NdbOperation::ReadRequest:
+ case NdbOperation::ReadExclusive:
+ case NdbOperation::OpenScanRequest:
+ case NdbOperation::OpenRangeScanRequest:
+ theCompletionStatus = CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ setOperationErrorCodeAbort(4115);
+ tOp = NULL;
+ break;
+ case NdbOperation::NotDefined:
+ case NdbOperation::NotDefined2:
+ assert(false);
+ break;
+ }//if
+ }//while
+ theReleaseOnClose = true;
+ return 0;
+ } else {
+#ifdef VM_TRACE
+ ndbout_c("Recevied TCKEY_FAILCONF wo/ operation");
+#endif
+ }
+ return -1;
+}//NdbTransaction::receiveTCKEY_FAILCONF()
+
+/*************************************************************************
+int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
+
+Return Value: Return 0 : receive was completed.
+ Return -1: In all other case.
+Parameters: aSignal: the signal object that contains the
+ TCKEY_FAILREF signal from TC.
+Remark: Handles the reception of the TCKEY_FAILREF signal.
+**************************************************************************/
+int
+NdbTransaction::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
+{
+ /*
+ Check that we are expecting signals from this transaction and
+ that it doesn't belong to a transaction already
+ completed. Simply ignore messages from other transactions.
+ */
+ if(checkState_TransId(aSignal->getDataPtr()+1)){
+ /*
+ We received an indication of that this transaction was aborted due to a
+ node failure.
+ */
+ if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
+ /*
+ We were in the process of sending a rollback anyways. We will
+ report it as a success.
+ */
+ theCompletionStatus = NdbTransaction::CompletedSuccess;
+ } else {
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theError.code = 4031;
+ }//if
+ theReleaseOnClose = true;
+ theCommitStatus = NdbTransaction::Aborted;
+ return 0;
+ } else {
+#ifdef VM_TRACE
+ ndbout_c("Recevied TCKEY_FAILREF wo/ operation");
+#endif
+ }
+ return -1;
+}//NdbTransaction::receiveTCKEY_FAILREF()
+
+/******************************************************************************
+int receiveTCINDXCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
+
+Return Value: Return 0 : receiveTCINDXCONF was successful.
+ Return -1: In all other case.
+Parameters: aSignal: The signal object pointer.
+Remark:
+******************************************************************************/
+int
+NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf,
+ Uint32 aDataLength)
+{
+ if(checkState_TransId(&indxConf->transId1)){
+ const Uint32 tTemp = indxConf->confInfo;
+ const Uint32 tNoOfOperations = TcIndxConf::getNoOfOperations(tTemp);
+ const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
+
+ const Uint32* tPtr = (Uint32 *)&indxConf->operations[0];
+ Uint32 tNoComp = theNoOfOpCompleted;
+ for (Uint32 i = 0; i < tNoOfOperations ; i++) {
+ NdbReceiver* tOp = theNdb->void2rec(theNdb->int2void(*tPtr));
+ tPtr++;
+ const Uint32 tAttrInfoLen = *tPtr;
+ tPtr++;
+ if (tOp && tOp->checkMagicNumber()) {
+ tNoComp += tOp->execTCOPCONF(tAttrInfoLen);
+ } else {
+ return -1;
+ }//if
+ }//for
+ Uint32 tNoSent = theNoOfOpSent;
+ Uint32 tGCI = indxConf->gci;
+ theNoOfOpCompleted = tNoComp;
+ if (tCommitFlag == 1) {
+ theCommitStatus = Committed;
+ theGlobalCheckpointId = tGCI;
+ } else if ((tNoComp >= tNoSent) &&
+ (theLastExecOpInList->theCommitIndicator == 1)){
+ /**********************************************************************/
+ // We sent the transaction with Commit flag set and received a CONF with
+ // no Commit flag set. This is clearly an anomaly.
+ /**********************************************************************/
+ theError.code = 4011;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theCommitStatus = NdbTransaction::Aborted;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ return 0;
+ }//if
+ if (tNoComp >= tNoSent) {
+ return 0; // No more operations to wait for
+ }//if
+ // Not completed the reception yet.
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCINDXCONF()
+
+/*****************************************************************************
+int receiveTCINDXREF( NdbApiSignal* aSignal)
+
+Return Value: Return 0 : send was succesful.
+ Return -1: In all other case.
+Parameters: aSignal: the signal object that contains the
+ TCINDXREF signal from TC.
+Remark: Handles the reception of the TCINDXREF signal.
+*****************************************************************************/
+int
+NdbTransaction::receiveTCINDXREF( NdbApiSignal* aSignal)
+{
+ if(checkState_TransId(aSignal->getDataPtr()+1)){
+ theError.code = aSignal->readData(4); // Override any previous errors
+
+ /**********************************************************************/
+ /* A serious error has occured. This could be due to deadlock or */
+ /* lack of resources or simply a programming error in NDB. This */
+ /* transaction will be aborted. Actually it has already been */
+ /* and we only need to report completion and return with the */
+ /* error code to the application. */
+ /**********************************************************************/
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theCommitStatus = NdbTransaction::Aborted;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ return 0;
+ } else {
+#ifdef NDB_NO_DROPPED_SIGNAL
+ abort();
+#endif
+ }
+
+ return -1;
+}//NdbTransaction::receiveTCINDXREF()
+
+/*******************************************************************************
+int OpCompletedFailure();
+
+Return Value: Return 0 : OpCompleteSuccess was successful.
+ Return -1: In all other case.
+Parameters: aErrorCode: The error code.
+Remark: An operation was completed with failure.
+*******************************************************************************/
+int
+NdbTransaction::OpCompleteFailure(Uint8 abortOption, bool setFailure)
+{
+ Uint32 tNoComp = theNoOfOpCompleted;
+ Uint32 tNoSent = theNoOfOpSent;
+ if (setFailure)
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ tNoComp++;
+ theNoOfOpCompleted = tNoComp;
+ if (tNoComp == tNoSent) {
+ //------------------------------------------------------------------------
+ //If the transaction consists of only simple reads we can set
+ //Commit state Aborted. Otherwise this simple operation cannot
+ //decide the success of the whole transaction since a simple
+ //operation is not really part of that transaction.
+ //------------------------------------------------------------------------
+ if (abortOption == AO_IgnoreError){
+ /**
+ * There's always a TCKEYCONF when using IgnoreError
+ */
+ return -1;
+ }
+
+ return 0; // Last operation received
+ } else if (tNoComp > tNoSent) {
+ setOperationErrorCodeAbort(4113); // Too many operations,
+ // stop waiting for more
+ return 0;
+ } else {
+ return -1; // Continue waiting for more signals
+ }//if
+}//NdbTransaction::OpCompleteFailure()
+
+/******************************************************************************
+int OpCompleteSuccess();
+
+Return Value: Return 0 : OpCompleteSuccess was successful.
+ Return -1: In all other case.
+Remark: An operation was completed with success.
+*******************************************************************************/
+int
+NdbTransaction::OpCompleteSuccess()
+{
+ Uint32 tNoComp = theNoOfOpCompleted;
+ Uint32 tNoSent = theNoOfOpSent;
+ tNoComp++;
+ theNoOfOpCompleted = tNoComp;
+ if (tNoComp == tNoSent) { // Last operation completed
+ return 0;
+ } else if (tNoComp < tNoSent) {
+ return -1; // Continue waiting for more signals
+ } else {
+ setOperationErrorCodeAbort(4113); // Too many operations,
+ // stop waiting for more
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ return 0;
+ }//if
+}//NdbTransaction::OpCompleteSuccess()
+
+/******************************************************************************
+ int getGCI();
+
+Remark: Get global checkpoint identity of the transaction
+*******************************************************************************/
+int
+NdbTransaction::getGCI()
+{
+ if (theCommitStatus == NdbTransaction::Committed) {
+ return theGlobalCheckpointId;
+ }//if
+ return 0;
+}//NdbTransaction::getGCI()
+
+/*******************************************************************************
+Uint64 getTransactionId(void);
+
+Remark: Get the transaction identity.
+*******************************************************************************/
+Uint64
+NdbTransaction::getTransactionId()
+{
+ return theTransactionId;
+}//NdbTransaction::getTransactionId()
+
+NdbTransaction::CommitStatusType
+NdbTransaction::commitStatus()
+{
+ return theCommitStatus;
+}//NdbTransaction::commitStatus()
+
+int
+NdbTransaction::getNdbErrorLine()
+{
+ return theErrorLine;
+}
+
+NdbOperation*
+NdbTransaction::getNdbErrorOperation()
+{
+ return theErrorOperation;
+}//NdbTransaction::getNdbErrorOperation()
+
+const NdbOperation *
+NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
+ if(current == 0)
+ return theCompletedFirstOp;
+ return current->theNext;
+}
+
+#ifdef VM_TRACE
+#define CASE(x) case x: ndbout << " " << #x; break
+void
+NdbTransaction::printState()
+{
+ ndbout << "con=" << hex << this << dec;
+ ndbout << " node=" << getConnectedNodeId();
+ switch (theStatus) {
+ CASE(NotConnected);
+ CASE(Connecting);
+ CASE(Connected);
+ CASE(DisConnecting);
+ CASE(ConnectFailure);
+ default: ndbout << (Uint32) theStatus;
+ }
+ switch (theListState) {
+ CASE(NotInList);
+ CASE(InPreparedList);
+ CASE(InSendList);
+ CASE(InCompletedList);
+ default: ndbout << (Uint32) theListState;
+ }
+ switch (theSendStatus) {
+ CASE(NotInit);
+ CASE(InitState);
+ CASE(sendOperations);
+ CASE(sendCompleted);
+ CASE(sendCOMMITstate);
+ CASE(sendABORT);
+ CASE(sendABORTfail);
+ CASE(sendTC_ROLLBACK);
+ CASE(sendTC_COMMIT);
+ CASE(sendTC_OP);
+ default: ndbout << (Uint32) theSendStatus;
+ }
+ switch (theCommitStatus) {
+ CASE(NotStarted);
+ CASE(Started);
+ CASE(Committed);
+ CASE(Aborted);
+ CASE(NeedAbort);
+ default: ndbout << (Uint32) theCommitStatus;
+ }
+ switch (theCompletionStatus) {
+ CASE(NotCompleted);
+ CASE(CompletedSuccess);
+ CASE(CompletedFailure);
+ CASE(DefinitionFailure);
+ default: ndbout << (Uint32) theCompletionStatus;
+ }
+ ndbout << endl;
+}
+#undef CASE
+#endif
+
+int
+NdbTransaction::report_node_failure(Uint32 id){
+ NdbNodeBitmask::set(m_failed_db_nodes, id);
+ if(!NdbNodeBitmask::get(m_db_nodes, id))
+ {
+ return 0;
+ }
+
+ /**
+ * Arrived
+ * TCKEYCONF TRANSIDAI
+ * 1) - -
+ * 2) - X
+ * 3) X -
+ * 4) X X
+ */
+ NdbOperation* tmp = theFirstExecOpInList;
+ const Uint32 len = TcKeyConf::SimpleReadBit | id;
+ Uint32 tNoComp = theNoOfOpCompleted;
+ Uint32 tNoSent = theNoOfOpSent;
+ Uint32 count = 0;
+ while(tmp != 0)
+ {
+ if(tmp->theReceiver.m_expected_result_length == len &&
+ tmp->theReceiver.m_received_result_length == 0)
+ {
+ count++;
+ tmp->theError.code = 4119;
+ }
+ tmp = tmp->next();
+ }
+ tNoComp += count;
+ theNoOfOpCompleted = tNoComp;
+ if(count)
+ {
+ theReturnStatus = NdbTransaction::ReturnFailure;
+ if(tNoComp == tNoSent)
+ {
+ theError.code = 4119;
+ theCompletionStatus = NdbTransaction::CompletedFailure;
+ return 1;
+ }
+ }
+ return 0;
+}