1 /* Copyright (c) 2003-2007 MySQL AB
2    Use is subject to license terms
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include <ndb_global.h>
18 #include <NdbOut.hpp>
19 #include <NdbTransaction.hpp>
20 #include <NdbOperation.hpp>
21 #include <NdbScanOperation.hpp>
22 #include <NdbIndexScanOperation.hpp>
23 #include <NdbIndexOperation.hpp>
24 #include "NdbApiSignal.hpp"
25 #include "TransporterFacade.hpp"
26 #include "API.hpp"
27 #include "NdbBlob.hpp"
28 
29 #include <signaldata/TcKeyConf.hpp>
30 #include <signaldata/TcIndx.hpp>
31 #include <signaldata/TcCommit.hpp>
32 #include <signaldata/TcKeyFailConf.hpp>
33 #include <signaldata/TcHbRep.hpp>
34 #include <signaldata/TcRollbackRep.hpp>
35 
36 /*****************************************************************************
37 NdbTransaction( Ndb* aNdb );
38 
39 Return Value:  None
40 Parameters:    aNdb: Pointers to the Ndb object
41 Remark:        Creates a connection object.
42 *****************************************************************************/
NdbTransaction(Ndb * aNdb)43 NdbTransaction::NdbTransaction( Ndb* aNdb ) :
44   theSendStatus(NotInit),
45   theCallbackFunction(NULL),
46   theCallbackObject(NULL),
47   theTransArrayIndex(0),
48   theStartTransTime(0),
49   theErrorLine(0),
50   theErrorOperation(NULL),
51   theNdb(aNdb),
52   theNext(NULL),
53   theFirstOpInList(NULL),
54   theLastOpInList(NULL),
55   theFirstExecOpInList(NULL),
56   theLastExecOpInList(NULL),
57   theCompletedFirstOp(NULL),
58   theCompletedLastOp(NULL),
59   theNoOfOpSent(0),
60   theNoOfOpCompleted(0),
61   theMyRef(0),
62   theTCConPtr(0),
63   theTransactionId(0),
64   theGlobalCheckpointId(0),
65   p_latest_trans_gci(0),
66   theStatus(NotConnected),
67   theCompletionStatus(NotCompleted),
68   theCommitStatus(NotStarted),
69   theMagicNumber(0xFE11DC),
70   theTransactionIsStarted(false),
71   theDBnode(0),
72   theReleaseOnClose(false),
73   // Scan operations
74   m_waitForReply(true),
75   m_theFirstScanOperation(NULL),
76   m_theLastScanOperation(NULL),
77   m_firstExecutedScanOp(NULL),
78   // Scan operations
79   theScanningOp(NULL),
80   theBuddyConPtr(0xFFFFFFFF),
81   theBlobFlag(false),
82   thePendingBlobOps(0)
83 {
84   theListState = NotInList;
85   theError.code = 0;
86   //theId = NdbObjectIdMap::InvalidId;
87   theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
88 
89 #define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz)
90 
91   CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
92   CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
93 }//NdbTransaction::NdbTransaction()
94 
95 /*****************************************************************************
96 ~NdbTransaction();
97 
98 Remark:        Deletes the connection object.
99 *****************************************************************************/
~NdbTransaction()100 NdbTransaction::~NdbTransaction()
101 {
102   DBUG_ENTER("NdbTransaction::~NdbTransaction");
103   theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
104   DBUG_VOID_RETURN;
105 }//NdbTransaction::~NdbTransaction()
106 
107 /*****************************************************************************
108 void init();
109 
110 Remark:         Initialise connection object for new transaction.
111 *****************************************************************************/
112 int
init()113 NdbTransaction::init()
114 {
115   theListState            = NotInList;
116   theInUseState           = true;
117   theTransactionIsStarted = false;
118   theNext		  = NULL;
119 
120   theFirstOpInList	  = NULL;
121   theLastOpInList	  = NULL;
122 
123   theScanningOp            = NULL;
124 
125   theFirstExecOpInList	  = NULL;
126   theLastExecOpInList	  = NULL;
127 
128   theCompletedFirstOp	  = NULL;
129   theCompletedLastOp	  = NULL;
130 
131   theGlobalCheckpointId   = 0;
132   p_latest_trans_gci      =
133     theNdb->theImpl->m_ndb_cluster_connection.get_latest_trans_gci();
134   theCommitStatus         = Started;
135   theCompletionStatus     = NotCompleted;
136 
137   theError.code		  = 0;
138   theErrorLine		  = 0;
139   theErrorOperation	  = NULL;
140 
141   theReleaseOnClose       = false;
142   theSimpleState          = true;
143   theSendStatus           = InitState;
144   theMagicNumber          = 0x37412619;
145   // Scan operations
146   m_waitForReply            = true;
147   m_theFirstScanOperation = NULL;
148   m_theLastScanOperation  = NULL;
149   m_firstExecutedScanOp   = 0;
150   theBuddyConPtr            = 0xFFFFFFFF;
151   //
152   theBlobFlag = false;
153   thePendingBlobOps = 0;
154   if (theId == NdbObjectIdMap::InvalidId)
155   {
156     theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
157     if (theId == NdbObjectIdMap::InvalidId)
158     {
159       theError.code = 4000;
160       return -1;
161     }
162   }
163   return 0;
164 
165 }//NdbTransaction::init()
166 
167 /*****************************************************************************
168 setOperationErrorCode(int error);
169 
170 Remark:        Sets an error code on the connection object from an
171                operation object.
172 *****************************************************************************/
173 void
setOperationErrorCode(int error)174 NdbTransaction::setOperationErrorCode(int error)
175 {
176   DBUG_ENTER("NdbTransaction::setOperationErrorCode");
177   setErrorCode(error);
178   DBUG_VOID_RETURN;
179 }
180 
181 /*****************************************************************************
182 setOperationErrorCodeAbort(int error);
183 
184 Remark:        Sets an error code on the connection object from an
185                operation object.
186 *****************************************************************************/
187 void
setOperationErrorCodeAbort(int error,int abortOption)188 NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
189 {
190   DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
191   if (theTransactionIsStarted == false) {
192     theCommitStatus = Aborted;
193   } else if ((theCommitStatus != Committed) &&
194              (theCommitStatus != Aborted)) {
195     theCommitStatus = NeedAbort;
196   }//if
197   setErrorCode(error);
198   DBUG_VOID_RETURN;
199 }
200 
201 /*****************************************************************************
202 setErrorCode(int anErrorCode);
203 
204 Remark:        Sets an error indication on the connection object.
205 *****************************************************************************/
206 void
setErrorCode(int error)207 NdbTransaction::setErrorCode(int error)
208 {
209   DBUG_ENTER("NdbTransaction::setErrorCode");
210   DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
211 
212   if (theError.code == 0)
213     theError.code = error;
214 
215   DBUG_VOID_RETURN;
216 }//NdbTransaction::setErrorCode()
217 
218 int
restart()219 NdbTransaction::restart(){
220   DBUG_ENTER("NdbTransaction::restart");
221   if(theCompletionStatus == CompletedSuccess){
222     releaseCompletedOperations();
223     Uint64 tTransid = theNdb->theFirstTransId;
224     theTransactionId = tTransid;
225     if ((tTransid & 0xFFFFFFFF) == 0xFFFFFFFF) {
226       theNdb->theFirstTransId = (tTransid >> 32) << 32;
227     } else {
228       theNdb->theFirstTransId = tTransid + 1;
229     }
230     theCommitStatus = Started;
231     theCompletionStatus = NotCompleted;
232     theTransactionIsStarted = false;
233     DBUG_RETURN(0);
234   }
235   DBUG_PRINT("error",("theCompletionStatus != CompletedSuccess"));
236   DBUG_RETURN(-1);
237 }
238 
239 /*****************************************************************************
240 void handleExecuteCompletion(void);
241 
242 Remark:        Handle time-out on a transaction object.
243 *****************************************************************************/
244 void
handleExecuteCompletion()245 NdbTransaction::handleExecuteCompletion()
246 {
247   /***************************************************************************
248    *	  Move the NdbOperation objects from the list of executing
249    *      operations to list of completed
250    **************************************************************************/
251   NdbOperation* tFirstExecOp = theFirstExecOpInList;
252   NdbOperation* tLastExecOp = theLastExecOpInList;
253   if (tLastExecOp != NULL) {
254     tLastExecOp->next(theCompletedFirstOp);
255     theCompletedFirstOp = tFirstExecOp;
256     if (theCompletedLastOp == NULL)
257       theCompletedLastOp = tLastExecOp;
258     theFirstExecOpInList = NULL;
259     theLastExecOpInList = NULL;
260   }//if
261   theSendStatus = InitState;
262   return;
263 }//NdbTransaction::handleExecuteCompletion()
264 
265 /*****************************************************************************
266 int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
267 
268 Return Value:  Return 0 : execute was successful.
269                Return -1: In all other case.
270 Parameters :   aTypeOfExec: Type of execute.
271 Remark:        Initialise connection object for new transaction.
272 *****************************************************************************/
273 int
execute(ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)274 NdbTransaction::execute(ExecType aTypeOfExec,
275 			NdbOperation::AbortOption abortOption,
276 			int forceSend)
277 {
278   NdbError savedError= theError;
279   DBUG_ENTER("NdbTransaction::execute");
280   DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
281 		       aTypeOfExec, abortOption));
282 
283   if (! theBlobFlag)
284     DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
285 
286   /*
287    * execute prepared ops in batches, as requested by blobs
288    * - blob error does not terminate execution
289    * - blob error sets error on operation
290    * - if error on operation skip blob calls
291    */
292 
293   ExecType tExecType;
294   NdbOperation* tPrepOp;
295   NdbOperation* tCompletedFirstOp = NULL;
296   NdbOperation* tCompletedLastOp = NULL;
297 
298   int ret = 0;
299   do {
300     tExecType = aTypeOfExec;
301     tPrepOp = theFirstOpInList;
302     while (tPrepOp != NULL) {
303       if (tPrepOp->theError.code == 0) {
304         bool batch = false;
305         NdbBlob* tBlob = tPrepOp->theBlobList;
306         while (tBlob != NULL) {
307           if (tBlob->preExecute(tExecType, batch) == -1)
308 	  {
309             ret = -1;
310 	    if(savedError.code==0)
311 	      savedError= theError;
312 	  }
313           tBlob = tBlob->theNext;
314         }
315         if (batch) {
316           // blob asked to execute all up to here now
317           tExecType = NoCommit;
318           break;
319         }
320       }
321       tPrepOp = tPrepOp->next();
322     }
323 
324     // save rest of prepared ops if batch
325     NdbOperation* tRestOp= 0;
326     NdbOperation* tLastOp= 0;
327     if (tPrepOp != NULL) {
328       tRestOp = tPrepOp->next();
329       tPrepOp->next(NULL);
330       tLastOp = theLastOpInList;
331       theLastOpInList = tPrepOp;
332     }
333 
334     if (tExecType == Commit) {
335       NdbOperation* tOp = theCompletedFirstOp;
336       while (tOp != NULL) {
337         if (tOp->theError.code == 0) {
338           NdbBlob* tBlob = tOp->theBlobList;
339           while (tBlob != NULL) {
340             if (tBlob->preCommit() == -1)
341 	    {
342 	      ret = -1;
343 	      if(savedError.code==0)
344 		savedError= theError;
345 	    }
346             tBlob = tBlob->theNext;
347           }
348         }
349         tOp = tOp->next();
350       }
351     }
352 
353     // completed ops are in unspecified order
354     if (theCompletedFirstOp != NULL) {
355       if (tCompletedFirstOp == NULL) {
356         tCompletedFirstOp = theCompletedFirstOp;
357         tCompletedLastOp = theCompletedLastOp;
358       } else {
359         tCompletedLastOp->next(theCompletedFirstOp);
360         tCompletedLastOp = theCompletedLastOp;
361       }
362       theCompletedFirstOp = NULL;
363       theCompletedLastOp = NULL;
364     }
365 
366     if (executeNoBlobs(tExecType,
367 		       NdbOperation::DefaultAbortOption,
368 		       forceSend) == -1)
369     {
370       if(savedError.code==0)
371 	savedError= theError;
372 
373       DBUG_RETURN(-1);
374     }
375 
376 #ifdef ndb_api_crash_on_complex_blob_abort
377     assert(theFirstOpInList == NULL && theLastOpInList == NULL);
378 #else
379     theFirstOpInList = theLastOpInList = NULL;
380 #endif
381 
382     {
383       NdbOperation* tOp = theCompletedFirstOp;
384       while (tOp != NULL) {
385         if (tOp->theError.code == 0) {
386           NdbBlob* tBlob = tOp->theBlobList;
387           while (tBlob != NULL) {
388             // may add new operations if batch
389             if (tBlob->postExecute(tExecType) == -1)
390 	    {
391               ret = -1;
392 	      if(savedError.code==0)
393 		savedError= theError;
394 	    }
395             tBlob = tBlob->theNext;
396           }
397         }
398         tOp = tOp->next();
399       }
400     }
401 
402     // add saved prepared ops if batch
403     if (tPrepOp != NULL && tRestOp != NULL) {
404       if (theFirstOpInList == NULL)
405         theFirstOpInList = tRestOp;
406       else
407         theLastOpInList->next(tRestOp);
408       theLastOpInList = tLastOp;
409     }
410     assert(theFirstOpInList == NULL || tExecType == NoCommit);
411   } while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
412 
413   if (tCompletedFirstOp != NULL) {
414     tCompletedLastOp->next(theCompletedFirstOp);
415     theCompletedFirstOp = tCompletedFirstOp;
416     if (theCompletedLastOp == NULL)
417       theCompletedLastOp = tCompletedLastOp;
418   }
419 #if ndb_api_count_completed_ops_after_blob_execute
420   { NdbOperation* tOp; unsigned n = 0;
421     for (tOp = theCompletedFirstOp; tOp != NULL; tOp = tOp->next()) n++;
422     ndbout << "completed ops: " << n << endl;
423   }
424 #endif
425 
426   if(savedError.code!=0 && theError.code==4350) // Trans already aborted
427       theError= savedError;
428 
429   DBUG_RETURN(ret);
430 }
431 
432 int
executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)433 NdbTransaction::executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,
434 			       NdbOperation::AbortOption abortOption,
435 			       int forceSend)
436 {
437   DBUG_ENTER("NdbTransaction::executeNoBlobs");
438   DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
439 		       aTypeOfExec, abortOption));
440 
441 //------------------------------------------------------------------------
442 // We will start by preparing all operations in the transaction defined
443 // since last execute or since beginning. If this works ok we will continue
444 // by calling the poll with wait method. This method will return when
445 // the NDB kernel has completed its task or when 10 seconds have passed.
446 // The NdbTransactionCallBack-method will receive the return code of the
447 // transaction. The normal methods of reading error codes still apply.
448 //------------------------------------------------------------------------
449   Ndb* tNdb = theNdb;
450 
451   Uint32 timeout = theNdb->theImpl->m_transporter_facade->m_waitfor_timeout;
452   m_waitForReply = false;
453   executeAsynchPrepare(aTypeOfExec, NULL, NULL, abortOption);
454   if (m_waitForReply){
455     while (1) {
456       int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
457       if (noOfComp == 0) {
458         /*
459          * Just for fun, this is only one of two places where
460          * we could hit this error... It's quite possible we
461          * hit it in Ndbif.cpp in Ndb::check_send_timeout()
462          *
463          * We behave rather similarly in both places.
464          * Hitting this is certainly a bug though...
465          */
466         g_eventLogger.error("WARNING: Timeout in executeNoBlobs() waiting for "
467                             "response from NDB data nodes. This should NEVER "
468                             "occur. You have likely hit a NDB Bug. Please "
469                             "file a bug.");
470         DBUG_PRINT("error",("This timeout should never occure, execute()"));
471         g_eventLogger.error("Forcibly trying to rollback txn (%p"
472                             ") to try to clean up data node resources.",
473                             this);
474         executeNoBlobs(NdbTransaction::Rollback);
475         theError.code = 4012;
476         theError.status= NdbError::PermanentError;
477         theError.classification= NdbError::TimeoutExpired;
478         setOperationErrorCodeAbort(4012); // ndbd timeout
479         DBUG_RETURN(-1);
480       }//if
481 
482       /*
483        * Check that the completed transactions include this one.  There
484        * could be another thread running asynchronously.  Even in pure
485        * async case rollback is done synchronously.
486        */
487       if (theListState != NotInList)
488         continue;
489 #ifdef VM_TRACE
490       unsigned anyway = 0;
491       for (unsigned i = 0; i < theNdb->theNoOfPreparedTransactions; i++)
492         anyway += theNdb->thePreparedTransactionsArray[i] == this;
493       for (unsigned i = 0; i < theNdb->theNoOfSentTransactions; i++)
494         anyway += theNdb->theSentTransactionsArray[i] == this;
495       for (unsigned i = 0; i < theNdb->theNoOfCompletedTransactions; i++)
496         anyway += theNdb->theCompletedTransactionsArray[i] == this;
497       if (anyway) {
498         theNdb->printState("execute %x", this);
499         abort();
500       }
501 #endif
502       if (theReturnStatus == ReturnFailure) {
503         DBUG_RETURN(-1);
504       }//if
505       break;
506     }
507   }
508   thePendingBlobOps = 0;
509   DBUG_RETURN(0);
510 }//NdbTransaction::execute()
511 
512 /*****************************************************************************
513 void executeAsynchPrepare(ExecType           aTypeOfExec,
514                           NdbAsynchCallback  callBack,
515                           void*              anyObject,
516                           CommitType         aTypeOfCommit);
517 
518 Return Value:  No return value
519 Parameters :   aTypeOfExec:   Type of execute.
520                anyObject:     An object provided in the callback method
521                callBack:      The callback method
522                aTypeOfCommit: What to do when read/updated/deleted records
523                               are missing or inserted records already exist.
524 
525 Remark:        Prepare a part of a transaction in an asynchronous manner.
526 *****************************************************************************/
527 void
executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption)528 NdbTransaction::executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,
529                                      NdbAsynchCallback  aCallback,
530                                      void*              anyObject,
531                                      NdbOperation::AbortOption abortOption)
532 {
533   DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
534   DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: 0x%lx, anyObject: Ox%lx",
535 		       aTypeOfExec, (long) aCallback, (long) anyObject));
536 
537   /**
538    * Reset error.code on execute
539    */
540   if (theError.code != 0)
541     DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
542   /**
543    * for timeout (4012) we want sendROLLBACK to behave differently.
544    * Else, normal behaviour of reset errcode
545    */
546   if (theError.code != 4012)
547     theError.code = 0;
548   NdbScanOperation* tcOp = m_theFirstScanOperation;
549   if (tcOp != 0){
550     // Execute any cursor operations
551     while (tcOp != NULL) {
552       int tReturnCode;
553       tReturnCode = tcOp->executeCursor(theDBnode);
554       if (tReturnCode == -1) {
555         DBUG_VOID_RETURN;
556       }//if
557       tcOp = (NdbScanOperation*)tcOp->next();
558     } // while
559     m_theLastScanOperation->next(m_firstExecutedScanOp);
560     m_firstExecutedScanOp = m_theFirstScanOperation;
561     // Discard cursor operations, since these are also
562     // in the complete operations list we do not need
563     // to release them.
564     m_theFirstScanOperation = m_theLastScanOperation = NULL;
565   }
566 
567   bool tTransactionIsStarted = theTransactionIsStarted;
568   NdbOperation*	tLastOp = theLastOpInList;
569   Ndb* tNdb = theNdb;
570   CommitStatusType tCommitStatus = theCommitStatus;
571   Uint32 tnoOfPreparedTransactions = tNdb->theNoOfPreparedTransactions;
572 
573   theReturnStatus     = ReturnSuccess;
574   theCallbackFunction = aCallback;
575   theCallbackObject   = anyObject;
576   m_waitForReply = true;
577   tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this;
578   theTransArrayIndex = tnoOfPreparedTransactions;
579   theListState = InPreparedList;
580   tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1;
581 
582   if ((tCommitStatus != Started) ||
583       (aTypeOfExec == Rollback)) {
584 /*****************************************************************************
585  *	Rollback have been ordered on a started transaction. Call rollback.
586  *      Could also be state problem or previous problem which leads to the
587  *      same action.
588  ****************************************************************************/
589     if (aTypeOfExec == Rollback) {
590       if (theTransactionIsStarted == false || theSimpleState) {
591 	theCommitStatus = Aborted;
592 	theSendStatus = sendCompleted;
593       } else {
594 	theSendStatus = sendABORT;
595       }
596     } else {
597       theSendStatus = sendABORTfail;
598     }//if
599     if (theCommitStatus == Aborted){
600       DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
601       setErrorCode(4350);
602     }
603     DBUG_VOID_RETURN;
604   }//if
605   if (tTransactionIsStarted == true) {
606     if (tLastOp != NULL) {
607       if (aTypeOfExec == Commit) {
608 /*****************************************************************************
609  *	Set commit indicator on last operation when commit has been ordered
610  *      and also a number of operations.
611 ******************************************************************************/
612         tLastOp->theCommitIndicator = 1;
613       }//if
614     } else {
615       if (aTypeOfExec == Commit && !theSimpleState) {
616 	/**********************************************************************
617 	 *   A Transaction have been started and no more operations exist.
618 	 *   We will use the commit method.
619 	 *********************************************************************/
620         theSendStatus = sendCOMMITstate;
621 	DBUG_VOID_RETURN;
622       } else {
623 	/**********************************************************************
624 	 * We need to put it into the array of completed transactions to
625 	 * ensure that we report the completion in a proper way.
626 	 * We cannot do this here since that would endanger the completed
627 	 * transaction array since that is also updated from the receiver
628 	 * thread and thus we need to do it under mutex lock and thus we
629 	 * set the sendStatus to ensure that the send method will
630 	 * put it into the completed array.
631 	 **********************************************************************/
632         theSendStatus = sendCompleted;
633 	DBUG_VOID_RETURN; // No Commit with no operations is OK
634       }//if
635     }//if
636   } else if (tTransactionIsStarted == false) {
637     NdbOperation* tFirstOp = theFirstOpInList;
638     if (tLastOp != NULL) {
639       tFirstOp->setStartIndicator();
640       if (aTypeOfExec == Commit) {
641         tLastOp->theCommitIndicator = 1;
642       }//if
643     } else {
644       /***********************************************************************
645        *    No operations are defined and we have not started yet.
646        *    Simply return OK. Set commit status if Commit.
647        ***********************************************************************/
648       if (aTypeOfExec == Commit) {
649         theCommitStatus = Committed;
650       }//if
651       /***********************************************************************
652        * We need to put it into the array of completed transactions to
653        * ensure that we report the completion in a proper way. We
654        * cannot do this here since that would endanger the completed
655        * transaction array since that is also updated from the
656        * receiver thread and thus we need to do it under mutex lock
657        * and thus we set the sendStatus to ensure that the send method
658        * will put it into the completed array.
659        ***********************************************************************/
660       theSendStatus = sendCompleted;
661       DBUG_VOID_RETURN;
662     }//if
663   }
664 
665   NdbOperation* tOp = theFirstOpInList;
666   theCompletionStatus = NotCompleted;
667   while (tOp) {
668     int tReturnCode;
669     NdbOperation* tNextOp = tOp->next();
670     tReturnCode = tOp->prepareSend(theTCConPtr, theTransactionId, abortOption);
671     if (tReturnCode == -1) {
672       theSendStatus = sendABORTfail;
673       DBUG_VOID_RETURN;
674     }//if
675 
676     /*************************************************************************
677      * Now that we have successfully prepared the send of this operation we
678      * move it to the list of executing operations and remove it from the
679      * list of defined operations.
680      ************************************************************************/
681     tOp = tNextOp;
682   }
683 
684   NdbOperation* tLastOpInList = theLastOpInList;
685   NdbOperation* tFirstOpInList = theFirstOpInList;
686 
687   theFirstOpInList = NULL;
688   theLastOpInList = NULL;
689   theFirstExecOpInList = tFirstOpInList;
690   theLastExecOpInList = tLastOpInList;
691 
692   theCompletionStatus = CompletedSuccess;
693   theNoOfOpSent		= 0;
694   theNoOfOpCompleted	= 0;
695   theSendStatus = sendOperations;
696   NdbNodeBitmask::clear(m_db_nodes);
697   NdbNodeBitmask::clear(m_failed_db_nodes);
698   DBUG_VOID_RETURN;
699 }//NdbTransaction::executeAsynchPrepare()
700 
701 void
executeAsynch(ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption,int forceSend)702 NdbTransaction::executeAsynch(ExecType aTypeOfExec,
703                               NdbAsynchCallback aCallback,
704                               void* anyObject,
705                               NdbOperation::AbortOption abortOption,
706                               int forceSend)
707 {
708   executeAsynchPrepare(aTypeOfExec, aCallback, anyObject, abortOption);
709   theNdb->sendPreparedTransactions(forceSend);
710 }
711 
close()712 void NdbTransaction::close()
713 {
714   theNdb->closeTransaction(this);
715 }
716 
refresh()717 int NdbTransaction::refresh(){
718   return sendTC_HBREP();
719 }
720 
721 /*****************************************************************************
722 int sendTC_HBREP();
723 
724 Return Value:  No return value.
725 Parameters :   None.
726 Remark:        Order NDB to refresh the timeout counter of the transaction.
727 ******************************************************************************/
728 int
sendTC_HBREP()729 NdbTransaction::sendTC_HBREP()		// Send a TC_HBREP signal;
730 {
731   NdbApiSignal* tSignal;
732   Ndb* tNdb = theNdb;
733   Uint32 tTransId1, tTransId2;
734 
735   tSignal = tNdb->getSignal();
736   if (tSignal == NULL) {
737     return -1;
738   }
739 
740   if (tSignal->setSignal(GSN_TC_HBREP) == -1) {
741     return -1;
742   }
743 
744   TcHbRep * const tcHbRep = CAST_PTR(TcHbRep, tSignal->getDataPtrSend());
745 
746   tcHbRep->apiConnectPtr = theTCConPtr;
747 
748   tTransId1 = (Uint32) theTransactionId;
749   tTransId2 = (Uint32) (theTransactionId >> 32);
750   tcHbRep->transId1      = tTransId1;
751   tcHbRep->transId2      = tTransId2;
752 
753   TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
754   tp->lock_mutex();
755   const int res = tp->sendSignal(tSignal,theDBnode);
756   tp->unlock_mutex();
757   tNdb->releaseSignal(tSignal);
758 
759   if (res == -1){
760     return -1;
761   }
762 
763   return 0;
764 }//NdbTransaction::sendTC_HBREP()
765 
766 /*****************************************************************************
767 int doSend();
768 
769 Return Value:  Return 0 : send was successful.
770                Return -1: In all other case.
771 Remark:        Send all operations belonging to this connection.
772                The caller of this method has the responsibility to remove the
773                object from the prepared transactions array on the Ndb-object.
774 *****************************************************************************/
775 int
doSend()776 NdbTransaction::doSend()
777 {
778   DBUG_ENTER("NdbTransaction::doSend");
779 
780   /*
781   This method assumes that at least one operation have been defined. This
782   is ensured by the caller of this routine (=execute).
783   */
784 
785   switch(theSendStatus){
786   case sendOperations: {
787     NdbOperation * tOp = theFirstExecOpInList;
788     do {
789       NdbOperation* tNextOp = tOp->next();
790       const Uint32 lastFlag = ((tNextOp == NULL) ? 1 : 0);
791       const int tReturnCode = tOp->doSend(theDBnode, lastFlag);
792       if (tReturnCode == -1) {
793         theReturnStatus = ReturnFailure;
794         break;
795       }//if
796       tOp = tNextOp;
797     } while (tOp != NULL);
798     Ndb* tNdb = theNdb;
799     theSendStatus = sendTC_OP;
800     theTransactionIsStarted = true;
801     tNdb->insert_sent_list(this);
802     DBUG_RETURN(0);
803   }//case
804   case sendABORT:
805   case sendABORTfail:{
806   /***********************************************************************
807    * Rollback have been ordered on a not started transaction.
808    * Simply return OK and set abort status.
809    ***********************************************************************/
810     if (theSendStatus == sendABORTfail) {
811       theReturnStatus = ReturnFailure;
812     }//if
813     if (sendROLLBACK() == 0) {
814       DBUG_RETURN(0);
815     }//if
816     break;
817   }//case
818   case sendCOMMITstate:
819     if (sendCOMMIT() == 0) {
820       DBUG_RETURN(0);
821     }//if
822     break;
823   case sendCompleted:
824     theNdb->insert_completed_list(this);
825     DBUG_RETURN(0);
826   default:
827     ndbout << "Inconsistent theSendStatus = "
828 	   << (Uint32) theSendStatus << endl;
829     abort();
830     break;
831   }//switch
832   setOperationErrorCodeAbort(4002);
833   theReleaseOnClose = true;
834   theTransactionIsStarted = false;
835   theCommitStatus = Aborted;
836   DBUG_RETURN(-1);
837 }//NdbTransaction::doSend()
838 
839 /**************************************************************************
840 int sendROLLBACK();
841 
842 Return Value:  Return -1 if send unsuccessful.
843 Parameters :   None.
844 Remark:        Order NDB to rollback the transaction.
845 **************************************************************************/
846 int
sendROLLBACK()847 NdbTransaction::sendROLLBACK()      // Send a TCROLLBACKREQ signal;
848 {
849   Ndb* tNdb = theNdb;
850   if ((theTransactionIsStarted == true) &&
851       (theCommitStatus != Committed) &&
852       (theCommitStatus != Aborted)) {
853 /**************************************************************************
854  *	The user did not perform any rollback but simply closed the
855  *      transaction. We must rollback Ndb since Ndb have been contacted.
856  *************************************************************************/
857     NdbApiSignal tSignal(tNdb->theMyRef);
858     Uint32 tTransId1, tTransId2;
859     TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
860     int	  tReturnCode;
861 
862     tTransId1 = (Uint32) theTransactionId;
863     tTransId2 = (Uint32) (theTransactionId >> 32);
864     tSignal.setSignal(GSN_TCROLLBACKREQ);
865     tSignal.setData(theTCConPtr, 1);
866     tSignal.setData(tTransId1, 2);
867     tSignal.setData(tTransId2, 3);
868     if(theError.code == 4012)
869     {
870       g_eventLogger.error("Sending TCROLLBACKREQ with Bad flag");
871       tSignal.setLength(tSignal.getLength() + 1); // + flags
872       tSignal.setData(0x1, 4); // potentially bad data
873     }
874     tReturnCode = tp->sendSignal(&tSignal,theDBnode);
875     if (tReturnCode != -1) {
876       theSendStatus = sendTC_ROLLBACK;
877       tNdb->insert_sent_list(this);
878       return 0;
879     }//if
880    /*********************************************************************
881     * It was not possible to abort the transaction towards the NDB kernel
882     * and thus we put it into the array of completed transactions that
883     * are ready for reporting to the application.
884     *********************************************************************/
885     return -1;
886   } else {
887     /*
888      It is not necessary to abort the transaction towards the NDB kernel and
889      thus we put it into the array of completed transactions that are ready
890      for reporting to the application.
891      */
892     theSendStatus = sendCompleted;
893     tNdb->insert_completed_list(this);
894     return 0;
895     ;
896   }//if
897 }//NdbTransaction::sendROLLBACK()
898 
899 /***************************************************************************
900 int sendCOMMIT();
901 
902 Return Value:  Return 0 : send was successful.
903                Return -1: In all other case.
904 Parameters :   None.
905 Remark:        Order NDB to commit the transaction.
906 ***************************************************************************/
907 int
sendCOMMIT()908 NdbTransaction::sendCOMMIT()    // Send a TC_COMMITREQ signal;
909 {
910   NdbApiSignal tSignal(theNdb->theMyRef);
911   Uint32 tTransId1, tTransId2;
912   TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
913   int	  tReturnCode;
914 
915   tTransId1 = (Uint32) theTransactionId;
916   tTransId2 = (Uint32) (theTransactionId >> 32);
917   tSignal.setSignal(GSN_TC_COMMITREQ);
918   tSignal.setData(theTCConPtr, 1);
919   tSignal.setData(tTransId1, 2);
920   tSignal.setData(tTransId2, 3);
921 
922   tReturnCode = tp->sendSignal(&tSignal,theDBnode);
923   if (tReturnCode != -1) {
924     theSendStatus = sendTC_COMMIT;
925     theNdb->insert_sent_list(this);
926     return 0;
927   } else {
928     return -1;
929   }//if
930 }//NdbTransaction::sendCOMMIT()
931 
932 /******************************************************************************
933 void release();
934 
935 Remark:         Release all operations.
936 ******************************************************************************/
937 void
release()938 NdbTransaction::release(){
939   releaseOperations();
940   if ( (theTransactionIsStarted == true) &&
941        ((theCommitStatus != Committed) &&
942 	(theCommitStatus != Aborted))) {
943     /************************************************************************
944      *	The user did not perform any rollback but simply closed the
945      *      transaction. We must rollback Ndb since Ndb have been contacted.
946      ************************************************************************/
947     if (!theSimpleState)
948     {
949       execute(Rollback);
950     }
951   }//if
952   theMagicNumber = 0xFE11DC;
953   theInUseState = false;
954 #ifdef VM_TRACE
955   if (theListState != NotInList) {
956     theNdb->printState("release %x", this);
957     abort();
958   }
959 #endif
960 }//NdbTransaction::release()
961 
962 void
releaseOps(NdbOperation * tOp)963 NdbTransaction::releaseOps(NdbOperation* tOp){
964   while (tOp != NULL) {
965     NdbOperation* tmp = tOp;
966     tOp->release();
967     tOp = tOp->next();
968     theNdb->releaseOperation(tmp);
969   }//while
970 }
971 
972 /******************************************************************************
973 void releaseOperations();
974 
975 Remark:         Release all operations.
976 ******************************************************************************/
977 void
releaseOperations()978 NdbTransaction::releaseOperations()
979 {
980   // Release any open scans
981   releaseScanOperations(m_theFirstScanOperation);
982   releaseScanOperations(m_firstExecutedScanOp);
983 
984   releaseOps(theCompletedFirstOp);
985   releaseOps(theFirstOpInList);
986   releaseOps(theFirstExecOpInList);
987 
988   theCompletedFirstOp = NULL;
989   theCompletedLastOp = NULL;
990   theFirstOpInList = NULL;
991   theFirstExecOpInList = NULL;
992   theLastOpInList = NULL;
993   theLastExecOpInList = NULL;
994   theScanningOp = NULL;
995   m_theFirstScanOperation = NULL;
996   m_theLastScanOperation = NULL;
997   m_firstExecutedScanOp = NULL;
998 }//NdbTransaction::releaseOperations()
999 
1000 void
releaseCompletedOperations()1001 NdbTransaction::releaseCompletedOperations()
1002 {
1003   releaseOps(theCompletedFirstOp);
1004   theCompletedFirstOp = NULL;
1005   theCompletedLastOp = NULL;
1006 }//NdbTransaction::releaseOperations()
1007 
1008 /******************************************************************************
1009 void releaseScanOperations();
1010 
1011 Remark:         Release all cursor operations.
1012                 (NdbScanOperation and NdbIndexOperation)
1013 ******************************************************************************/
1014 void
releaseScanOperations(NdbIndexScanOperation * cursorOp)1015 NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
1016 {
1017   while(cursorOp != 0){
1018     NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
1019     cursorOp->release();
1020     theNdb->releaseScanOperation(cursorOp);
1021     cursorOp = next;
1022   }
1023 }//NdbTransaction::releaseScanOperations()
1024 
1025 /*****************************************************************************
1026 void releaseScanOperation();
1027 
1028 Remark:         Release scan op when hupp'ed trans closed (save memory)
1029 ******************************************************************************/
1030 void
releaseExecutedScanOperation(NdbIndexScanOperation * cursorOp)1031 NdbTransaction::releaseExecutedScanOperation(NdbIndexScanOperation* cursorOp)
1032 {
1033   DBUG_ENTER("NdbTransaction::releaseExecutedScanOperation");
1034   DBUG_PRINT("enter", ("this: 0x%lx  op: 0x%lx", (long) this, (long) cursorOp));
1035 
1036   releaseScanOperation(&m_firstExecutedScanOp, 0, cursorOp);
1037 
1038   DBUG_VOID_RETURN;
1039 }//NdbTransaction::releaseExecutedScanOperation()
1040 
1041 bool
releaseScanOperation(NdbIndexScanOperation ** listhead,NdbIndexScanOperation ** listtail,NdbIndexScanOperation * op)1042 NdbTransaction::releaseScanOperation(NdbIndexScanOperation** listhead,
1043 				     NdbIndexScanOperation** listtail,
1044 				     NdbIndexScanOperation* op)
1045 {
1046   if (* listhead == op)
1047   {
1048     * listhead = (NdbIndexScanOperation*)op->theNext;
1049     if (listtail && *listtail == op)
1050     {
1051       assert(* listhead == 0);
1052       * listtail = 0;
1053     }
1054 
1055   }
1056   else
1057   {
1058     NdbIndexScanOperation* tmp = * listhead;
1059     while (tmp != NULL)
1060     {
1061       if (tmp->theNext == op)
1062       {
1063 	tmp->theNext = (NdbIndexScanOperation*)op->theNext;
1064 	if (listtail && *listtail == op)
1065 	{
1066 	  assert(op->theNext == 0);
1067 	  *listtail = tmp;
1068 	}
1069 	break;
1070       }
1071       tmp = (NdbIndexScanOperation*)tmp->theNext;
1072     }
1073     if (tmp == NULL)
1074       op = NULL;
1075   }
1076 
1077   if (op != NULL)
1078   {
1079     op->release();
1080     theNdb->releaseScanOperation(op);
1081     return true;
1082   }
1083 
1084   return false;
1085 }
1086 
1087 /*****************************************************************************
1088 NdbOperation* getNdbOperation(const char* aTableName);
1089 
1090 Return Value    Return a pointer to a NdbOperation object if getNdbOperation
1091                 was succesful.
1092                 Return NULL : In all other case.
1093 Parameters:     aTableName : Name of the database table.
1094 Remark:         Get an operation from NdbOperation idlelist and get the
1095                 NdbTransaction object
1096 		who was fetch by startTransaction pointing to this  operation
1097 		getOperation will set the theTableId in the NdbOperation object.
1098                 synchronous
1099 ******************************************************************************/
1100 NdbOperation*
getNdbOperation(const char * aTableName)1101 NdbTransaction::getNdbOperation(const char* aTableName)
1102 {
1103   if (theCommitStatus == Started){
1104     NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1105     if (table != 0){
1106       return getNdbOperation(table);
1107     } else {
1108       setErrorCode(theNdb->theDictionary->getNdbError().code);
1109       return NULL;
1110     }//if
1111   }
1112 
1113   setOperationErrorCodeAbort(4114);
1114 
1115   return NULL;
1116 }//NdbTransaction::getNdbOperation()
1117 
1118 /*****************************************************************************
1119 NdbOperation* getNdbOperation(int aTableId);
1120 
1121 Return Value    Return a pointer to a NdbOperation object if getNdbOperation
1122                 was succesful.
1123                 Return NULL: In all other case.
1124 Parameters:     tableId : Id of the database table beeing deleted.
1125 Remark:         Get an operation from NdbOperation object idlelist and
1126                 get the NdbTransaction object who was fetch by
1127                 startTransaction pointing to this operation
1128   	        getOperation will set the theTableId in the NdbOperation
1129                 object, synchronous.
1130 *****************************************************************************/
1131 NdbOperation*
getNdbOperation(const NdbTableImpl * tab,NdbOperation * aNextOp)1132 NdbTransaction::getNdbOperation(const NdbTableImpl * tab, NdbOperation* aNextOp)
1133 {
1134   NdbOperation* tOp;
1135 
1136   if (theScanningOp != NULL){
1137     setErrorCode(4607);
1138     return NULL;
1139   }
1140 
1141   tOp = theNdb->getOperation();
1142   if (tOp == NULL)
1143     goto getNdbOp_error1;
1144   if (aNextOp == NULL) {
1145     if (theLastOpInList != NULL) {
1146        theLastOpInList->next(tOp);
1147        theLastOpInList = tOp;
1148     } else {
1149        theLastOpInList = tOp;
1150        theFirstOpInList = tOp;
1151     }//if
1152     tOp->next(NULL);
1153   } else {
1154     // add before the given op
1155     if (theFirstOpInList == aNextOp) {
1156       theFirstOpInList = tOp;
1157     } else {
1158       NdbOperation* aLoopOp = theFirstOpInList;
1159       while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1160         aLoopOp = aLoopOp->next();
1161       assert(aLoopOp != NULL);
1162       aLoopOp->next(tOp);
1163     }
1164     tOp->next(aNextOp);
1165   }
1166   if (tOp->init(tab, this) != -1) {
1167     return tOp;
1168   } else {
1169     theNdb->releaseOperation(tOp);
1170   }//if
1171   return NULL;
1172 
1173  getNdbOp_error1:
1174   setOperationErrorCodeAbort(4000);
1175   return NULL;
1176 }//NdbTransaction::getNdbOperation()
1177 
getNdbOperation(const NdbDictionary::Table * table)1178 NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
1179 {
1180   if (table)
1181     return getNdbOperation(& NdbTableImpl::getImpl(*table));
1182   else
1183     return NULL;
1184 }//NdbTransaction::getNdbOperation()
1185 
1186 // NdbScanOperation
1187 /*****************************************************************************
1188 NdbScanOperation* getNdbScanOperation(const char* aTableName);
1189 
1190 Return Value    Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1191                 Return NULL : In all other case.
1192 Parameters:     aTableName : Name of the database table.
1193 Remark:         Get an operation from NdbScanOperation idlelist and get the NdbTransaction object
1194 		who was fetch by startTransaction pointing to this  operation
1195 		getOperation will set the theTableId in the NdbOperation object.synchronous
1196 ******************************************************************************/
1197 NdbScanOperation*
getNdbScanOperation(const char * aTableName)1198 NdbTransaction::getNdbScanOperation(const char* aTableName)
1199 {
1200   if (theCommitStatus == Started){
1201     NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
1202     if (tab != 0){
1203       return getNdbScanOperation(tab);
1204     } else {
1205       setOperationErrorCodeAbort(theNdb->theDictionary->m_error.code);
1206       return NULL;
1207     }//if
1208   }
1209 
1210   setOperationErrorCodeAbort(4114);
1211   return NULL;
1212 }//NdbTransaction::getNdbScanOperation()
1213 
1214 /*****************************************************************************
1215 NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
1216 
1217 Return Value    Return a pointer to a NdbIndexScanOperation object if getNdbIndexScanOperation was succesful.
1218                 Return NULL : In all other case.
1219 Parameters:     anIndexName : Name of the index to use.
1220                 aTableName : Name of the database table.
1221 Remark:         Get an operation from NdbIndexScanOperation idlelist and get the NdbTransaction object
1222 		who was fetch by startTransaction pointing to this  operation
1223 		getOperation will set the theTableId in the NdbIndexScanOperation object.synchronous
1224 ******************************************************************************/
1225 NdbIndexScanOperation*
getNdbIndexScanOperation(const char * anIndexName,const char * aTableName)1226 NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
1227 					const char* aTableName)
1228 {
1229   NdbIndexImpl* index =
1230     theNdb->theDictionary->getIndex(anIndexName, aTableName);
1231   if (index == 0)
1232   {
1233     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1234     return 0;
1235   }
1236   NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1237   if (table == 0)
1238   {
1239     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1240     return 0;
1241   }
1242 
1243   return getNdbIndexScanOperation(index, table);
1244 }
1245 
1246 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbIndexImpl * index,const NdbTableImpl * table)1247 NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
1248 					const NdbTableImpl* table)
1249 {
1250   if (theCommitStatus == Started){
1251     const NdbTableImpl * indexTable = index->getIndexTable();
1252     if (indexTable != 0){
1253       NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
1254       if(tOp)
1255       {
1256 	tOp->m_currentTable = table;
1257         // Mark that this really an NdbIndexScanOperation
1258         tOp->m_type = NdbOperation::OrderedIndexScan;
1259       }
1260       return tOp;
1261     } else {
1262       setOperationErrorCodeAbort(4271);
1263       return NULL;
1264     }//if
1265   }
1266 
1267   setOperationErrorCodeAbort(4114);
1268   return NULL;
1269 }//NdbTransaction::getNdbIndexScanOperation()
1270 
1271 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index)1272 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
1273 {
1274   if (index)
1275   {
1276     const NdbDictionary::Table *table=
1277       theNdb->theDictionary->getTable(index->getTable());
1278 
1279     if (table)
1280       return getNdbIndexScanOperation(index, table);
1281 
1282     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1283     return NULL;
1284   }
1285   setOperationErrorCodeAbort(4271);
1286   return NULL;
1287 }
1288 
1289 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1290 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
1291 					const NdbDictionary::Table * table)
1292 {
1293   if (index && table)
1294     return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
1295 				    & NdbTableImpl::getImpl(*table));
1296   setOperationErrorCodeAbort(4271);
1297   return NULL;
1298 }//NdbTransaction::getNdbIndexScanOperation()
1299 
1300 /*****************************************************************************
1301 NdbScanOperation* getNdbScanOperation(int aTableId);
1302 
1303 Return Value    Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1304                 Return NULL: In all other case.
1305 Parameters:     tableId : Id of the database table beeing deleted.
1306 Remark:         Get an operation from NdbScanOperation object idlelist and get the NdbTransaction
1307                 object who was fetch by startTransaction pointing to this  operation
1308   	        getOperation will set the theTableId in the NdbScanOperation object, synchronous.
1309 *****************************************************************************/
1310 NdbIndexScanOperation*
getNdbScanOperation(const NdbTableImpl * tab)1311 NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
1312 {
1313   NdbIndexScanOperation* tOp;
1314 
1315   tOp = theNdb->getScanOperation();
1316   if (tOp == NULL)
1317     goto getNdbOp_error1;
1318 
1319   if (tOp->init(tab, this) != -1) {
1320     define_scan_op(tOp);
1321     // Mark that this NdbIndexScanOperation is used as NdbScanOperation
1322     tOp->m_type = NdbOperation::TableScan;
1323     return tOp;
1324   } else {
1325     theNdb->releaseScanOperation(tOp);
1326   }//if
1327   return NULL;
1328 
1329 getNdbOp_error1:
1330   setOperationErrorCodeAbort(4000);
1331   return NULL;
1332 }//NdbTransaction::getNdbScanOperation()
1333 
1334 void
remove_list(NdbOperation * & list,NdbOperation * op)1335 NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
1336   NdbOperation* tmp= list;
1337   if(tmp == op)
1338     list = op->next();
1339   else {
1340     while(tmp && tmp->next() != op) tmp = tmp->next();
1341     if(tmp)
1342       tmp->next(op->next());
1343   }
1344   op->next(NULL);
1345 }
1346 
1347 void
define_scan_op(NdbIndexScanOperation * tOp)1348 NdbTransaction::define_scan_op(NdbIndexScanOperation * tOp){
1349   // Link scan operation into list of cursor operations
1350   if (m_theLastScanOperation == NULL)
1351     m_theFirstScanOperation = m_theLastScanOperation = tOp;
1352   else {
1353     m_theLastScanOperation->next(tOp);
1354     m_theLastScanOperation = tOp;
1355   }
1356   tOp->next(NULL);
1357 }
1358 
1359 NdbScanOperation*
getNdbScanOperation(const NdbDictionary::Table * table)1360 NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
1361 {
1362   if (table)
1363     return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
1364   else
1365     return NULL;
1366 }//NdbTransaction::getNdbScanOperation()
1367 
1368 
1369 // IndexOperation
1370 /*****************************************************************************
1371 NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
1372 					const char* aTableName);
1373 
1374 Return Value    Return a pointer to a NdbOperation object if getNdbIndexOperation was succesful.
1375                 Return NULL : In all other case.
1376 Parameters:     aTableName : Name of the database table.
1377 Remark:         Get an operation from NdbIndexOperation idlelist and get the NdbTransaction object
1378 		who was fetch by startTransaction pointing to this operation
1379 		getOperation will set the theTableId in the NdbIndexOperation object.synchronous
1380 ******************************************************************************/
1381 NdbIndexOperation*
getNdbIndexOperation(const char * anIndexName,const char * aTableName)1382 NdbTransaction::getNdbIndexOperation(const char* anIndexName,
1383                                     const char* aTableName)
1384 {
1385   if (theCommitStatus == Started) {
1386     NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
1387     NdbIndexImpl * index;
1388 
1389     if (table == 0)
1390     {
1391       setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1392       return NULL;
1393     }
1394 
1395     if (table->m_frm.get_data())
1396     {
1397       // This unique index is defined from SQL level
1398       static const char* uniqueSuffix= "$unique";
1399       BaseString uniqueIndexName(anIndexName);
1400       uniqueIndexName.append(uniqueSuffix);
1401       index = theNdb->theDictionary->getIndex(uniqueIndexName.c_str(),
1402 					      aTableName);
1403     }
1404     else
1405       index = theNdb->theDictionary->getIndex(anIndexName,
1406 					      aTableName);
1407     if(table != 0 && index != 0){
1408       return getNdbIndexOperation(index, table);
1409     }
1410 
1411     if(index == 0){
1412       setOperationErrorCodeAbort(4243);
1413       return NULL;
1414     }
1415 
1416     setOperationErrorCodeAbort(4243);
1417     return NULL;
1418   }
1419 
1420   setOperationErrorCodeAbort(4114);
1421   return 0;
1422 }//NdbTransaction::getNdbIndexOperation()
1423 
1424 /*****************************************************************************
1425 NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
1426 
1427 Return Value    Return a pointer to a NdbIndexOperation object if getNdbIndexOperation was succesful.
1428                 Return NULL: In all other case.
1429 Parameters:     tableId : Id of the database table beeing deleted.
1430 Remark:         Get an operation from NdbIndexOperation object idlelist and get the NdbTransaction
1431                 object who was fetch by startTransaction pointing to this  operation
1432   	        getOperation will set the theTableId in the NdbIndexOperation object, synchronous.
1433 *****************************************************************************/
1434 NdbIndexOperation*
getNdbIndexOperation(const NdbIndexImpl * anIndex,const NdbTableImpl * aTable,NdbOperation * aNextOp)1435 NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
1436 				    const NdbTableImpl * aTable,
1437                                     NdbOperation* aNextOp)
1438 {
1439   NdbIndexOperation* tOp;
1440 
1441   tOp = theNdb->getIndexOperation();
1442   if (tOp == NULL)
1443     goto getNdbOp_error1;
1444   if (aNextOp == NULL) {
1445     if (theLastOpInList != NULL) {
1446        theLastOpInList->next(tOp);
1447        theLastOpInList = tOp;
1448     } else {
1449        theLastOpInList = tOp;
1450        theFirstOpInList = tOp;
1451     }//if
1452     tOp->next(NULL);
1453   } else {
1454     // add before the given op
1455     if (theFirstOpInList == aNextOp) {
1456       theFirstOpInList = tOp;
1457     } else {
1458       NdbOperation* aLoopOp = theFirstOpInList;
1459       while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1460         aLoopOp = aLoopOp->next();
1461       assert(aLoopOp != NULL);
1462       aLoopOp->next(tOp);
1463     }
1464     tOp->next(aNextOp);
1465   }
1466   if (tOp->indxInit(anIndex, aTable, this)!= -1) {
1467     return tOp;
1468   } else {
1469     theNdb->releaseOperation(tOp);
1470   }//if
1471   return NULL;
1472 
1473  getNdbOp_error1:
1474   setOperationErrorCodeAbort(4000);
1475   return NULL;
1476 }//NdbTransaction::getNdbIndexOperation()
1477 
1478 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index)1479 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
1480 {
1481   if (index)
1482   {
1483     const NdbDictionary::Table *table=
1484       theNdb->theDictionary->getTable(index->getTable());
1485 
1486     if (table)
1487       return getNdbIndexOperation(index, table);
1488 
1489     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1490     return NULL;
1491   }
1492   setOperationErrorCodeAbort(4271);
1493   return NULL;
1494 }
1495 
1496 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1497 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
1498 				    const NdbDictionary::Table * table)
1499 {
1500   if (index && table)
1501     return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
1502 				& NdbTableImpl::getImpl(*table));
1503 
1504   setOperationErrorCodeAbort(4271);
1505   return NULL;
1506 }//NdbTransaction::getNdbIndexOperation()
1507 
1508 
1509 /*******************************************************************************
1510 int  receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
1511 
1512 Return Value:  Return 0 : receiveDIHNDBTAMPER was successful.
1513                Return -1: In all other case.
1514 Parameters:    aSignal: The signal object pointer.
1515 Remark:        Sets theRestartGCI in the NDB object.
1516 *******************************************************************************/
1517 int
receiveDIHNDBTAMPER(NdbApiSignal * aSignal)1518 NdbTransaction::receiveDIHNDBTAMPER(NdbApiSignal* aSignal)
1519 {
1520   if (theStatus != Connecting) {
1521     return -1;
1522   } else {
1523     theNdb->RestartGCI((Uint32)aSignal->readData(2));
1524     theStatus = Connected;
1525   }//if
1526   return 0;
1527 }//NdbTransaction::receiveDIHNDBTAMPER()
1528 
1529 /*******************************************************************************
1530 int  receiveTCSEIZECONF(NdbApiSignal* aSignal);
1531 
1532 Return Value:  Return 0 : receiveTCSEIZECONF was successful.
1533                Return -1: In all other case.
1534 Parameters:    aSignal: The signal object pointer.
1535 Remark:        Sets TC Connect pointer at reception of TCSEIZECONF.
1536 *******************************************************************************/
1537 int
receiveTCSEIZECONF(NdbApiSignal * aSignal)1538 NdbTransaction::receiveTCSEIZECONF(NdbApiSignal* aSignal)
1539 {
1540   if (theStatus != Connecting)
1541   {
1542     return -1;
1543   } else
1544   {
1545     theTCConPtr = (Uint32)aSignal->readData(2);
1546     theStatus = Connected;
1547   }
1548   return 0;
1549 }//NdbTransaction::receiveTCSEIZECONF()
1550 
1551 /*******************************************************************************
1552 int  receiveTCSEIZEREF(NdbApiSignal* aSignal);
1553 
1554 Return Value:  Return 0 : receiveTCSEIZEREF was successful.
1555                Return -1: In all other case.
1556 Parameters:    aSignal: The signal object pointer.
1557 Remark:        Sets TC Connect pointer.
1558 *******************************************************************************/
1559 int
receiveTCSEIZEREF(NdbApiSignal * aSignal)1560 NdbTransaction::receiveTCSEIZEREF(NdbApiSignal* aSignal)
1561 {
1562   DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
1563   if (theStatus != Connecting)
1564   {
1565     DBUG_RETURN(-1);
1566   } else
1567   {
1568     theStatus = ConnectFailure;
1569     theNdb->theError.code = aSignal->readData(2);
1570     DBUG_PRINT("info",("error code %d, %s",
1571 		       theNdb->getNdbError().code,
1572 		       theNdb->getNdbError().message));
1573     DBUG_RETURN(0);
1574   }
1575 }//NdbTransaction::receiveTCSEIZEREF()
1576 
1577 /*******************************************************************************
1578 int  receiveTCRELEASECONF(NdbApiSignal* aSignal);
1579 
1580 Return Value:  Return 0 : receiveTCRELEASECONF was successful.
1581                Return -1: In all other case.
1582 Parameters:    aSignal: The signal object pointer.
1583 Remark:         DisConnect TC Connect pointer to NDBAPI.
1584 *******************************************************************************/
1585 int
receiveTCRELEASECONF(NdbApiSignal * aSignal)1586 NdbTransaction::receiveTCRELEASECONF(NdbApiSignal* aSignal)
1587 {
1588   if (theStatus != DisConnecting)
1589   {
1590     return -1;
1591   } else
1592   {
1593     theStatus = NotConnected;
1594   }
1595   return 0;
1596 }//NdbTransaction::receiveTCRELEASECONF()
1597 
1598 /*******************************************************************************
1599 int  receiveTCRELEASEREF(NdbApiSignal* aSignal);
1600 
1601 Return Value:  Return 0 : receiveTCRELEASEREF was successful.
1602                Return -1: In all other case.
1603 Parameters:    aSignal: The signal object pointer.
1604 Remark:        DisConnect TC Connect pointer to NDBAPI Failure.
1605 *******************************************************************************/
1606 int
receiveTCRELEASEREF(NdbApiSignal * aSignal)1607 NdbTransaction::receiveTCRELEASEREF(NdbApiSignal* aSignal)
1608 {
1609   if (theStatus != DisConnecting) {
1610     return -1;
1611   } else {
1612     theStatus = ConnectFailure;
1613     theNdb->theError.code = aSignal->readData(2);
1614     return 0;
1615   }//if
1616 }//NdbTransaction::receiveTCRELEASEREF()
1617 
1618 /******************************************************************************
1619 int  receiveTC_COMMITCONF(NdbApiSignal* aSignal);
1620 
1621 Return Value:  Return 0 : receiveTC_COMMITCONF was successful.
1622                Return -1: In all other case.
1623 Parameters:    aSignal: The signal object pointer.
1624 Remark:
1625 ******************************************************************************/
1626 int
receiveTC_COMMITCONF(const TcCommitConf * commitConf)1627 NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf)
1628 {
1629   if(checkState_TransId(&commitConf->transId1)){
1630     theCommitStatus = Committed;
1631     theCompletionStatus = CompletedSuccess;
1632     theGlobalCheckpointId = commitConf->gci;
1633     // theGlobalCheckpointId == 0 if NoOp transaction
1634     if (theGlobalCheckpointId)
1635       *p_latest_trans_gci = theGlobalCheckpointId;
1636     return 0;
1637   } else {
1638 #ifdef NDB_NO_DROPPED_SIGNAL
1639     abort();
1640 #endif
1641   }
1642   return -1;
1643 }//NdbTransaction::receiveTC_COMMITCONF()
1644 
1645 /******************************************************************************
1646 int  receiveTC_COMMITREF(NdbApiSignal* aSignal);
1647 
1648 Return Value:  Return 0 : receiveTC_COMMITREF was successful.
1649                Return -1: In all other case.
1650 Parameters:    aSignal: The signal object pointer.
1651 Remark:
1652 ******************************************************************************/
1653 int
receiveTC_COMMITREF(NdbApiSignal * aSignal)1654 NdbTransaction::receiveTC_COMMITREF(NdbApiSignal* aSignal)
1655 {
1656   const TcCommitRef * ref = CAST_CONSTPTR(TcCommitRef, aSignal->getDataPtr());
1657   if(checkState_TransId(&ref->transId1)){
1658     setOperationErrorCodeAbort(ref->errorCode);
1659     theCommitStatus = Aborted;
1660     theCompletionStatus = CompletedFailure;
1661     theReturnStatus = ReturnFailure;
1662     return 0;
1663   } else {
1664 #ifdef NDB_NO_DROPPED_SIGNAL
1665     abort();
1666 #endif
1667   }
1668 
1669   return -1;
1670 }//NdbTransaction::receiveTC_COMMITREF()
1671 
1672 /******************************************************************************
1673 int  receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
1674 
1675 Return Value:  Return 0 : receiveTCROLLBACKCONF was successful.
1676                Return -1: In all other case.
1677 Parameters:    aSignal: The signal object pointer.
1678 Remark:
1679 ******************************************************************************/
1680 int
receiveTCROLLBACKCONF(NdbApiSignal * aSignal)1681 NdbTransaction::receiveTCROLLBACKCONF(NdbApiSignal* aSignal)
1682 {
1683   if(checkState_TransId(aSignal->getDataPtr() + 1)){
1684     theCommitStatus = Aborted;
1685     theCompletionStatus = CompletedSuccess;
1686     return 0;
1687   } else {
1688 #ifdef NDB_NO_DROPPED_SIGNAL
1689     abort();
1690 #endif
1691   }
1692 
1693   return -1;
1694 }//NdbTransaction::receiveTCROLLBACKCONF()
1695 
1696 /*******************************************************************************
1697 int  receiveTCROLLBACKREF(NdbApiSignal* aSignal);
1698 
1699 Return Value:  Return 0 : receiveTCROLLBACKREF was successful.
1700                Return -1: In all other case.
1701 Parameters:    aSignal: The signal object pointer.
1702 Remark:
1703 *******************************************************************************/
1704 int
receiveTCROLLBACKREF(NdbApiSignal * aSignal)1705 NdbTransaction::receiveTCROLLBACKREF(NdbApiSignal* aSignal)
1706 {
1707   if(checkState_TransId(aSignal->getDataPtr() + 1)){
1708     setOperationErrorCodeAbort(aSignal->readData(4));
1709     theCommitStatus = Aborted;
1710     theCompletionStatus = CompletedFailure;
1711     theReturnStatus = ReturnFailure;
1712     return 0;
1713   } else {
1714 #ifdef NDB_NO_DROPPED_SIGNAL
1715     abort();
1716 #endif
1717   }
1718 
1719   return -1;
1720 }//NdbTransaction::receiveTCROLLBACKREF()
1721 
1722 /*****************************************************************************
1723 int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
1724 
1725 Return Value:   Return 0 : send was succesful.
1726                 Return -1: In all other case.
1727 Parameters:     aSignal: the signal object that contains the
1728                 TCROLLBACKREP signal from TC.
1729 Remark:         Handles the reception of the ROLLBACKREP signal.
1730 *****************************************************************************/
1731 int
receiveTCROLLBACKREP(NdbApiSignal * aSignal)1732 NdbTransaction::receiveTCROLLBACKREP( NdbApiSignal* aSignal)
1733 {
1734   DBUG_ENTER("NdbTransaction::receiveTCROLLBACKREP");
1735 
1736   /****************************************************************************
1737 Check that we are expecting signals from this transaction and that it doesn't
1738 belong to a transaction already completed. Simply ignore messages from other
1739 transactions.
1740   ****************************************************************************/
1741   if(checkState_TransId(aSignal->getDataPtr() + 1)){
1742     theError.code = aSignal->readData(4);// Override any previous errors
1743     if (aSignal->getLength() == TcRollbackRep::SignalLength)
1744     {
1745       // Signal may contain additional error data
1746       theError.details = (char *) aSignal->readData(5);
1747     }
1748 
1749     /**********************************************************************/
1750     /*	A serious error has occured. This could be due to deadlock or */
1751     /*	lack of resources or simply a programming error in NDB. This  */
1752     /*	transaction will be aborted. Actually it has already been     */
1753     /*	and we only need to report completion and return with the     */
1754     /*	error code to the application.				      */
1755     /**********************************************************************/
1756     theCompletionStatus = CompletedFailure;
1757     theCommitStatus = Aborted;
1758     theReturnStatus = ReturnFailure;
1759     DBUG_RETURN(0);
1760   } else {
1761 #ifdef NDB_NO_DROPPED_SIGNAL
1762     abort();
1763 #endif
1764   }
1765 
1766   DBUG_RETURN(-1);
1767 }//NdbTransaction::receiveTCROLLBACKREP()
1768 
1769 /*******************************************************************************
1770 int  receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
1771 
1772 Return Value:  Return 0 : receiveTCKEYCONF was successful.
1773                Return -1: In all other case.
1774 Parameters:    aSignal: The signal object pointer.
1775 Remark:
1776 *******************************************************************************/
1777 int
receiveTCKEYCONF(const TcKeyConf * keyConf,Uint32 aDataLength)1778 NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
1779 {
1780   NdbReceiver* tOp;
1781   const Uint32 tTemp = keyConf->confInfo;
1782   /***************************************************************************
1783 Check that we are expecting signals from this transaction and that it
1784 doesn't belong to a transaction already completed. Simply ignore messages
1785 from other transactions.
1786   ***************************************************************************/
1787   if(checkState_TransId(&keyConf->transId1)){
1788 
1789     const Uint32 tNoOfOperations = TcKeyConf::getNoOfOperations(tTemp);
1790     const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
1791 
1792     const Uint32* tPtr = (Uint32 *)&keyConf->operations[0];
1793     Uint32 tNoComp = theNoOfOpCompleted;
1794     for (Uint32 i = 0; i < tNoOfOperations ; i++) {
1795       tOp = theNdb->void2rec(theNdb->int2void(*tPtr++));
1796       const Uint32 tAttrInfoLen = *tPtr++;
1797       if (tOp && tOp->checkMagicNumber()) {
1798 	Uint32 done = tOp->execTCOPCONF(tAttrInfoLen);
1799 	if(tAttrInfoLen > TcKeyConf::DirtyReadBit){
1800 	  Uint32 node = tAttrInfoLen & (~TcKeyConf::DirtyReadBit);
1801 	  NdbNodeBitmask::set(m_db_nodes, node);
1802 	  if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done)
1803 	  {
1804 	    done = 1;
1805 	    tOp->setErrorCode(4119);
1806 	    theCompletionStatus = CompletedFailure;
1807 	    theReturnStatus = NdbTransaction::ReturnFailure;
1808 	  }
1809 	}
1810 	tNoComp += done;
1811       } else {
1812  	return -1;
1813       }//if
1814     }//for
1815     Uint32 tNoSent = theNoOfOpSent;
1816     theNoOfOpCompleted = tNoComp;
1817     Uint32 tGCI    = keyConf->gci;
1818     if (tCommitFlag == 1) {
1819       theCommitStatus = Committed;
1820       theGlobalCheckpointId = tGCI;
1821       if (tGCI) // Read(dirty) only transaction doesnt get GCI
1822       {
1823 	*p_latest_trans_gci = tGCI;
1824       }
1825     } else if ((tNoComp >= tNoSent) &&
1826                (theLastExecOpInList->theCommitIndicator == 1)){
1827 
1828 
1829 /**********************************************************************/
1830 // We sent the transaction with Commit flag set and received a CONF with
1831 // no Commit flag set. This is clearly an anomaly.
1832 /**********************************************************************/
1833       theError.code = 4011;
1834       theCompletionStatus = CompletedFailure;
1835       theReturnStatus = NdbTransaction::ReturnFailure;
1836       theCommitStatus = Aborted;
1837       return 0;
1838     }//if
1839     if (tNoComp >= tNoSent) {
1840       return 0;	// No more operations to wait for
1841     }//if
1842      // Not completed the reception yet.
1843   } else {
1844 #ifdef NDB_NO_DROPPED_SIGNAL
1845     abort();
1846 #endif
1847   }
1848 
1849   return -1;
1850 }//NdbTransaction::receiveTCKEYCONF()
1851 
1852 /*****************************************************************************
1853 int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
1854 
1855 Return Value:   Return 0 : receive was completed.
1856                 Return -1: In all other case.
1857 Parameters:     aSignal: the signal object that contains the
1858                 TCKEY_FAILCONF signal from TC.
1859 Remark:         Handles the reception of the TCKEY_FAILCONF signal.
1860 *****************************************************************************/
1861 int
receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)1862 NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
1863 {
1864   NdbOperation*	tOp;
1865   /*
1866     Check that we are expecting signals from this transaction and that it
1867     doesn't belong  to a transaction already completed. Simply ignore
1868     messages from other transactions.
1869   */
1870   if(checkState_TransId(&failConf->transId1)){
1871     /*
1872       A node failure of the TC node occured. The transaction has
1873       been committed.
1874     */
1875     theCommitStatus = Committed;
1876     tOp = theFirstExecOpInList;
1877     while (tOp != NULL) {
1878       /*
1879        * Check if the transaction expected read values...
1880        * If it did some of them might have gotten lost even if we succeeded
1881        * in committing the transaction.
1882        */
1883       switch(tOp->theOperationType){
1884       case NdbOperation::UpdateRequest:
1885       case NdbOperation::InsertRequest:
1886       case NdbOperation::DeleteRequest:
1887       case NdbOperation::WriteRequest:
1888 	tOp = tOp->next();
1889 	break;
1890       case NdbOperation::ReadRequest:
1891       case NdbOperation::ReadExclusive:
1892       case NdbOperation::OpenScanRequest:
1893       case NdbOperation::OpenRangeScanRequest:
1894 	theCompletionStatus = CompletedFailure;
1895 	theReturnStatus = NdbTransaction::ReturnFailure;
1896 	setOperationErrorCodeAbort(4115);
1897 	tOp = NULL;
1898 	break;
1899       case NdbOperation::NotDefined:
1900       case NdbOperation::NotDefined2:
1901 	assert(false);
1902 	break;
1903       }//if
1904     }//while
1905     theReleaseOnClose = true;
1906     return 0;
1907   } else {
1908 #ifdef VM_TRACE
1909     ndbout_c("Recevied TCKEY_FAILCONF wo/ operation");
1910 #endif
1911   }
1912   return -1;
1913 }//NdbTransaction::receiveTCKEY_FAILCONF()
1914 
1915 /*************************************************************************
1916 int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
1917 
1918 Return Value:   Return 0 : receive was completed.
1919                 Return -1: In all other case.
1920 Parameters:     aSignal: the signal object that contains the
1921                 TCKEY_FAILREF signal from TC.
1922 Remark:         Handles the reception of the TCKEY_FAILREF signal.
1923 **************************************************************************/
1924 int
receiveTCKEY_FAILREF(NdbApiSignal * aSignal)1925 NdbTransaction::receiveTCKEY_FAILREF(NdbApiSignal* aSignal)
1926 {
1927   /*
1928     Check that we are expecting signals from this transaction and
1929     that it doesn't belong to a transaction already
1930     completed. Simply ignore messages from other transactions.
1931   */
1932   if(checkState_TransId(aSignal->getDataPtr()+1)){
1933     /*
1934       We received an indication of that this transaction was aborted due to a
1935       node failure.
1936     */
1937     if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
1938       /*
1939 	We were in the process of sending a rollback anyways. We will
1940 	report it as a success.
1941       */
1942       theCompletionStatus = NdbTransaction::CompletedSuccess;
1943     } else {
1944       theReturnStatus = NdbTransaction::ReturnFailure;
1945       theCompletionStatus = NdbTransaction::CompletedFailure;
1946       theError.code = 4031;
1947     }//if
1948     theReleaseOnClose = true;
1949     theCommitStatus = NdbTransaction::Aborted;
1950     return 0;
1951   } else {
1952 #ifdef VM_TRACE
1953     ndbout_c("Recevied TCKEY_FAILREF wo/ operation");
1954 #endif
1955   }
1956   return -1;
1957 }//NdbTransaction::receiveTCKEY_FAILREF()
1958 
1959 /******************************************************************************
1960 int  receiveTCINDXCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
1961 
1962 Return Value:  Return 0 : receiveTCINDXCONF was successful.
1963                Return -1: In all other case.
1964 Parameters:    aSignal: The signal object pointer.
1965 Remark:
1966 ******************************************************************************/
1967 int
receiveTCINDXCONF(const TcIndxConf * indxConf,Uint32 aDataLength)1968 NdbTransaction::receiveTCINDXCONF(const TcIndxConf * indxConf,
1969 				 Uint32 aDataLength)
1970 {
1971   if(checkState_TransId(&indxConf->transId1)){
1972     const Uint32 tTemp = indxConf->confInfo;
1973     const Uint32 tNoOfOperations = TcIndxConf::getNoOfOperations(tTemp);
1974     const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
1975 
1976     const Uint32* tPtr = (Uint32 *)&indxConf->operations[0];
1977     Uint32 tNoComp = theNoOfOpCompleted;
1978     for (Uint32 i = 0; i < tNoOfOperations ; i++) {
1979       NdbReceiver* tOp = theNdb->void2rec(theNdb->int2void(*tPtr));
1980       tPtr++;
1981       const Uint32 tAttrInfoLen = *tPtr;
1982       tPtr++;
1983       if (tOp && tOp->checkMagicNumber()) {
1984 	tNoComp += tOp->execTCOPCONF(tAttrInfoLen);
1985       } else {
1986 	return -1;
1987       }//if
1988     }//for
1989     Uint32 tNoSent = theNoOfOpSent;
1990     Uint32 tGCI    = indxConf->gci;
1991     theNoOfOpCompleted = tNoComp;
1992     if (tCommitFlag == 1) {
1993       theCommitStatus = Committed;
1994       theGlobalCheckpointId = tGCI;
1995       if (tGCI) // Read(dirty) only transaction doesnt get GCI
1996       {
1997 	*p_latest_trans_gci = tGCI;
1998       }
1999     } else if ((tNoComp >= tNoSent) &&
2000                (theLastExecOpInList->theCommitIndicator == 1)){
2001 
2002       /**********************************************************************/
2003       // We sent the transaction with Commit flag set and received a CONF with
2004       // no Commit flag set. This is clearly an anomaly.
2005       /**********************************************************************/
2006       theError.code = 4011;
2007       theCompletionStatus = NdbTransaction::CompletedFailure;
2008       theCommitStatus = NdbTransaction::Aborted;
2009       theReturnStatus = NdbTransaction::ReturnFailure;
2010       return 0;
2011     }//if
2012     if (tNoComp >= tNoSent) {
2013       return 0;	// No more operations to wait for
2014     }//if
2015      // Not completed the reception yet.
2016   } else {
2017 #ifdef NDB_NO_DROPPED_SIGNAL
2018     abort();
2019 #endif
2020   }
2021 
2022   return -1;
2023 }//NdbTransaction::receiveTCINDXCONF()
2024 
2025 /*******************************************************************************
2026 int OpCompletedFailure();
2027 
2028 Return Value:  Return 0 : OpCompleteSuccess was successful.
2029                Return -1: In all other case.
2030 Parameters:    aErrorCode: The error code.
2031 Remark:        An operation was completed with failure.
2032 *******************************************************************************/
2033 int
OpCompleteFailure(NdbOperation * op)2034 NdbTransaction::OpCompleteFailure(NdbOperation* op)
2035 {
2036   Uint32 tNoComp = theNoOfOpCompleted;
2037   Uint32 tNoSent = theNoOfOpSent;
2038 
2039   tNoComp++;
2040   theNoOfOpCompleted = tNoComp;
2041 
2042   return (tNoComp == tNoSent) ? 0 : -1;
2043 }//NdbTransaction::OpCompleteFailure()
2044 
2045 /******************************************************************************
2046 int OpCompleteSuccess();
2047 
2048 Return Value:  Return 0 : OpCompleteSuccess was successful.
2049                Return -1: In all other case.
2050 Remark:        An operation was completed with success.
2051 *******************************************************************************/
2052 int
OpCompleteSuccess()2053 NdbTransaction::OpCompleteSuccess()
2054 {
2055   Uint32 tNoComp = theNoOfOpCompleted;
2056   Uint32 tNoSent = theNoOfOpSent;
2057   tNoComp++;
2058   theNoOfOpCompleted = tNoComp;
2059   if (tNoComp == tNoSent) { // Last operation completed
2060     return 0;
2061   } else if (tNoComp < tNoSent) {
2062     return -1;	// Continue waiting for more signals
2063   } else {
2064     setOperationErrorCodeAbort(4113);	// Too many operations,
2065                                         // stop waiting for more
2066     theCompletionStatus = NdbTransaction::CompletedFailure;
2067     theReturnStatus = NdbTransaction::ReturnFailure;
2068     return 0;
2069   }//if
2070 }//NdbTransaction::OpCompleteSuccess()
2071 
2072 /******************************************************************************
2073  int            getGCI();
2074 
2075 Remark:		Get global checkpoint identity of the transaction
2076 *******************************************************************************/
2077 int
getGCI()2078 NdbTransaction::getGCI()
2079 {
2080   if (theCommitStatus == NdbTransaction::Committed) {
2081     return theGlobalCheckpointId;
2082   }//if
2083   return 0;
2084 }//NdbTransaction::getGCI()
2085 
2086 /*******************************************************************************
2087 Uint64 getTransactionId(void);
2088 
2089 Remark:        Get the transaction identity.
2090 *******************************************************************************/
2091 Uint64
getTransactionId()2092 NdbTransaction::getTransactionId()
2093 {
2094   return theTransactionId;
2095 }//NdbTransaction::getTransactionId()
2096 
2097 NdbTransaction::CommitStatusType
commitStatus()2098 NdbTransaction::commitStatus()
2099 {
2100   return theCommitStatus;
2101 }//NdbTransaction::commitStatus()
2102 
2103 int
getNdbErrorLine()2104 NdbTransaction::getNdbErrorLine()
2105 {
2106   return theErrorLine;
2107 }
2108 
2109 NdbOperation*
getNdbErrorOperation()2110 NdbTransaction::getNdbErrorOperation()
2111 {
2112   return theErrorOperation;
2113 }//NdbTransaction::getNdbErrorOperation()
2114 
2115 const NdbOperation *
getNextCompletedOperation(const NdbOperation * current) const2116 NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
2117   if(current == 0)
2118     return theCompletedFirstOp;
2119   return current->theNext;
2120 }
2121 
2122 #ifdef VM_TRACE
2123 #define CASE(x) case x: ndbout << " " << #x; break
2124 void
printState()2125 NdbTransaction::printState()
2126 {
2127   ndbout << "con=" << hex << this << dec;
2128   ndbout << " node=" << getConnectedNodeId();
2129   switch (theStatus) {
2130   CASE(NotConnected);
2131   CASE(Connecting);
2132   CASE(Connected);
2133   CASE(DisConnecting);
2134   CASE(ConnectFailure);
2135   default: ndbout << (Uint32) theStatus;
2136   }
2137   switch (theListState) {
2138   CASE(NotInList);
2139   CASE(InPreparedList);
2140   CASE(InSendList);
2141   CASE(InCompletedList);
2142   default: ndbout << (Uint32) theListState;
2143   }
2144   switch (theSendStatus) {
2145   CASE(NotInit);
2146   CASE(InitState);
2147   CASE(sendOperations);
2148   CASE(sendCompleted);
2149   CASE(sendCOMMITstate);
2150   CASE(sendABORT);
2151   CASE(sendABORTfail);
2152   CASE(sendTC_ROLLBACK);
2153   CASE(sendTC_COMMIT);
2154   CASE(sendTC_OP);
2155   default: ndbout << (Uint32) theSendStatus;
2156   }
2157   switch (theCommitStatus) {
2158   CASE(NotStarted);
2159   CASE(Started);
2160   CASE(Committed);
2161   CASE(Aborted);
2162   CASE(NeedAbort);
2163   default: ndbout << (Uint32) theCommitStatus;
2164   }
2165   switch (theCompletionStatus) {
2166   CASE(NotCompleted);
2167   CASE(CompletedSuccess);
2168   CASE(CompletedFailure);
2169   CASE(DefinitionFailure);
2170   default: ndbout << (Uint32) theCompletionStatus;
2171   }
2172   ndbout << endl;
2173 }
2174 #undef CASE
2175 #endif
2176 
2177 int
report_node_failure(Uint32 id)2178 NdbTransaction::report_node_failure(Uint32 id){
2179   NdbNodeBitmask::set(m_failed_db_nodes, id);
2180   if(!NdbNodeBitmask::get(m_db_nodes, id))
2181   {
2182     return 0;
2183   }
2184 
2185   /**
2186    *   Arrived
2187    *   TCKEYCONF   TRANSIDAI
2188    * 1)   -           -
2189    * 2)   -           X
2190    * 3)   X           -
2191    * 4)   X           X
2192    */
2193   NdbOperation* tmp = theFirstExecOpInList;
2194   const Uint32 len = TcKeyConf::DirtyReadBit | id;
2195   Uint32 tNoComp = theNoOfOpCompleted;
2196   Uint32 tNoSent = theNoOfOpSent;
2197   Uint32 count = 0;
2198   while(tmp != 0)
2199   {
2200     if(tmp->theReceiver.m_expected_result_length == len &&
2201        tmp->theReceiver.m_received_result_length == 0)
2202     {
2203       count++;
2204       tmp->theError.code = 4119;
2205     }
2206     tmp = tmp->next();
2207   }
2208   tNoComp += count;
2209   theNoOfOpCompleted = tNoComp;
2210   if(count)
2211   {
2212     theReturnStatus = NdbTransaction::ReturnFailure;
2213     if(tNoComp == tNoSent)
2214     {
2215       theError.code = 4119;
2216       theCompletionStatus = NdbTransaction::CompletedFailure;
2217       return 1;
2218     }
2219   }
2220   return 0;
2221 }
2222