1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <NdbOut.hpp>
27 #include "API.hpp"
28 
29 #include <AttributeHeader.hpp>
30 #include <signaldata/TcKeyConf.hpp>
31 #include <signaldata/TcIndx.hpp>
32 #include <signaldata/TcCommit.hpp>
33 #include <signaldata/TcKeyFailConf.hpp>
34 #include <signaldata/TcHbRep.hpp>
35 #include <signaldata/TcRollbackRep.hpp>
36 
37 /*****************************************************************************
38 NdbTransaction( Ndb* aNdb );
39 
40 Return Value:  None
41 Parameters:    aNdb: Pointers to the Ndb object
42 Remark:        Creates a connection object.
43 *****************************************************************************/
NdbTransaction(Ndb * aNdb)44 NdbTransaction::NdbTransaction( Ndb* aNdb ) :
45   theSendStatus(NotInit),
46   theCallbackFunction(NULL),
47   theCallbackObject(NULL),
48   theTransArrayIndex(0),
49   theStartTransTime(0),
50   theErrorLine(0),
51   theErrorOperation(NULL),
52   theNdb(aNdb),
53   theNext(NULL),
54   theFirstOpInList(NULL),
55   theLastOpInList(NULL),
56   theFirstExecOpInList(NULL),
57   theLastExecOpInList(NULL),
58   theCompletedFirstOp(NULL),
59   theCompletedLastOp(NULL),
60   theNoOfOpSent(0),
61   theNoOfOpCompleted(0),
62   theMyRef(0),
63   theTCConPtr(0),
64   theTransactionId(0),
65   theGlobalCheckpointId(0),
66   p_latest_trans_gci(0),
67   theStatus(NotConnected),
68   theCompletionStatus(NotCompleted),
69   theCommitStatus(NotStarted),
70   theMagicNumber(0xFE11DC),
71   theTransactionIsStarted(false),
72   theDBnode(0),
73   theReleaseOnClose(false),
74   // Composite query operations
75   m_firstQuery(NULL),
76   m_firstExecQuery(NULL),
77   m_firstActiveQuery(NULL),
78   // Scan operations
79   m_waitForReply(true),
80   m_theFirstScanOperation(NULL),
81   m_theLastScanOperation(NULL),
82   m_firstExecutedScanOp(NULL),
83   // Scan operations
84   theScanningOp(NULL),
85   m_scanningQuery(NULL),
86   theBuddyConPtr(0xFFFFFFFF),
87   theBlobFlag(false),
88   thePendingBlobOps(0),
89   maxPendingBlobReadBytes(~Uint32(0)),
90   maxPendingBlobWriteBytes(~Uint32(0)),
91   pendingBlobReadBytes(0),
92   pendingBlobWriteBytes(0),
93   m_theFirstLockHandle(NULL),
94   m_theLastLockHandle(NULL),
95   m_tcRef(numberToRef(DBTC, 0))
96 {
97   theListState = NotInList;
98   theError.code = 0;
99   //theId = NdbObjectIdMap::InvalidId;
100   theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
101 
102 #define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz)
103 
104   CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
105   CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
106 }//NdbTransaction::NdbTransaction()
107 
108 /*****************************************************************************
109 ~NdbTransaction();
110 
111 Remark:        Deletes the connection object.
112 *****************************************************************************/
~NdbTransaction()113 NdbTransaction::~NdbTransaction()
114 {
115   DBUG_ENTER("NdbTransaction::~NdbTransaction");
116   theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
117   DBUG_VOID_RETURN;
118 }//NdbTransaction::~NdbTransaction()
119 
120 /*****************************************************************************
121 void init();
122 
123 Remark:         Initialise connection object for new transaction.
124 *****************************************************************************/
125 int
init()126 NdbTransaction::init()
127 {
128   theListState            = NotInList;
129   theInUseState           = true;
130   theTransactionIsStarted = false;
131   theNext		  = NULL;
132 
133   theFirstOpInList	  = NULL;
134   theLastOpInList	  = NULL;
135 
136   theScanningOp           = NULL;
137   m_scanningQuery         = NULL;
138 
139   theFirstExecOpInList	  = NULL;
140   theLastExecOpInList	  = NULL;
141 
142   theCompletedFirstOp	  = NULL;
143   theCompletedLastOp	  = NULL;
144 
145   theGlobalCheckpointId   = 0;
146   p_latest_trans_gci      =
147     theNdb->theImpl->m_ndb_cluster_connection.get_latest_trans_gci();
148   theCommitStatus         = Started;
149   theCompletionStatus     = NotCompleted;
150 
151   theError.code		  = 0;
152   theErrorLine		  = 0;
153   theErrorOperation	  = NULL;
154 
155   theReleaseOnClose       = false;
156   theSimpleState          = true;
157   theSendStatus           = InitState;
158   theMagicNumber          = 0x37412619;
159 
160   // Query operations
161   m_firstQuery            = NULL;
162   m_firstExecQuery        = NULL;
163   m_firstActiveQuery      = NULL;
164 
165   // Scan operations
166   m_waitForReply          = true;
167   m_theFirstScanOperation = NULL;
168   m_theLastScanOperation  = NULL;
169   m_firstExecutedScanOp   = 0;
170   theBuddyConPtr          = 0xFFFFFFFF;
171   //
172   theBlobFlag = false;
173   thePendingBlobOps = 0;
174   m_theFirstLockHandle    = NULL;
175   m_theLastLockHandle     = NULL;
176   pendingBlobReadBytes = 0;
177   pendingBlobWriteBytes = 0;
178   if (theId == NdbObjectIdMap::InvalidId)
179   {
180     theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
181     if (theId == NdbObjectIdMap::InvalidId)
182     {
183       theError.code = 4000;
184       return -1;
185     }
186   }
187   return 0;
188 
189 }//NdbTransaction::init()
190 
191 /*****************************************************************************
192 setOperationErrorCode(int error);
193 
194 Remark:        Sets an error code on the connection object from an
195                operation object.
196 *****************************************************************************/
197 void
setOperationErrorCode(int error)198 NdbTransaction::setOperationErrorCode(int error)
199 {
200   DBUG_ENTER("NdbTransaction::setOperationErrorCode");
201   setErrorCode(error);
202   DBUG_VOID_RETURN;
203 }
204 
205 /*****************************************************************************
206 setOperationErrorCodeAbort(int error);
207 
208 Remark:        Sets an error code on the connection object from an
209                operation object.
210 *****************************************************************************/
211 void
setOperationErrorCodeAbort(int error,int abortOption)212 NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
213 {
214   DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
215   if (theTransactionIsStarted == false) {
216     theCommitStatus = Aborted;
217   } else if ((theCommitStatus != Committed) &&
218              (theCommitStatus != Aborted)) {
219     theCommitStatus = NeedAbort;
220   }//if
221   setErrorCode(error);
222   DBUG_VOID_RETURN;
223 }
224 
225 /*****************************************************************************
226 setErrorCode(int anErrorCode);
227 
228 Remark:        Sets an error indication on the connection object.
229 *****************************************************************************/
230 void
setErrorCode(int error)231 NdbTransaction::setErrorCode(int error)
232 {
233   DBUG_ENTER("NdbTransaction::setErrorCode");
234   DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
235 
236   if (theError.code == 0)
237     theError.code = error;
238 
239   DBUG_VOID_RETURN;
240 }//NdbTransaction::setErrorCode()
241 
242 int
restart()243 NdbTransaction::restart(){
244   DBUG_ENTER("NdbTransaction::restart");
245   if(theCompletionStatus == CompletedSuccess){
246     releaseCompletedOperations();
247     releaseCompletedQueries();
248 
249     theTransactionId = theNdb->allocate_transaction_id();
250 
251     theCommitStatus = Started;
252     theCompletionStatus = NotCompleted;
253     theTransactionIsStarted = false;
254     DBUG_RETURN(0);
255   }
256   DBUG_PRINT("error",("theCompletionStatus != CompletedSuccess"));
257   DBUG_RETURN(-1);
258 }
259 
260 /*****************************************************************************
261 void handleExecuteCompletion(void);
262 
263 Remark:        Handle time-out on a transaction object.
264 *****************************************************************************/
265 void
handleExecuteCompletion()266 NdbTransaction::handleExecuteCompletion()
267 {
268   /***************************************************************************
269    *	  Move the NdbOperation objects from the list of executing
270    *      operations to list of completed
271    **************************************************************************/
272   NdbOperation* tFirstExecOp = theFirstExecOpInList;
273   NdbOperation* tLastExecOp = theLastExecOpInList;
274   if (tLastExecOp != NULL) {
275     tLastExecOp->next(theCompletedFirstOp);
276     theCompletedFirstOp = tFirstExecOp;
277     if (theCompletedLastOp == NULL)
278       theCompletedLastOp = tLastExecOp;
279     theFirstExecOpInList = NULL;
280     theLastExecOpInList = NULL;
281   }//if
282 
283   theSendStatus = InitState;
284   return;
285 }//NdbTransaction::handleExecuteCompletion()
286 
287 /*****************************************************************************
288 int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
289 
290 Return Value:  Return 0 : execute was successful.
291                Return -1: In all other case.
292 Parameters :   aTypeOfExec: Type of execute.
293 Remark:        Initialise connection object for new transaction.
294 *****************************************************************************/
295 int
execute(ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)296 NdbTransaction::execute(ExecType aTypeOfExec,
297 			NdbOperation::AbortOption abortOption,
298 			int forceSend)
299 {
300   NdbError existingTransError = theError;
301   NdbError firstTransError;
302   DBUG_ENTER("NdbTransaction::execute");
303   DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
304 		       aTypeOfExec, abortOption));
305 
306   if (! theBlobFlag)
307     DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
308 
309   /*
310    * execute prepared ops in batches, as requested by blobs
311    * - blob error does not terminate execution
312    * - blob error sets error on operation
313    * - if error on operation skip blob calls
314    *
315    * In the call to preExecute(), each operation involving blobs can
316    * add (and execute) extra operations before (reads) and after
317    * (writes) the operation on the main row.
318    * In the call to postExecute(), each blob can add extra read and
319    * write operations to be executed immediately
320    * It is assumed that all operations added in preExecute() are
321    * defined 'before' operations added in postExecute().
322    * To facilitate this, the transaction's list of operations is
323    * pre-emptively split when a Blob operation is encountered.
324    * preExecute can add operations before and after the operation being
325    * processed, and if no batch execute is required, the list is rejoined.
326    * If batch execute is required, then execute() is performed, and then
327    * the postExecute() actions (which can add operations) are called before
328    * the list is rejoined.  See NdbBlob::preExecute() and
329    * NdbBlob::postExecute() for more info.
330    */
331 
332   NdbOperation* tPrepOp;
333 
334   if (abortOption != NdbOperation::DefaultAbortOption)
335   {
336     DBUG_PRINT("info", ("Forcing operations to take execute() abortOption %d",
337                         abortOption));
338     /* For Blobs, we have to execute with DefaultAbortOption
339      * If the user supplied a non default AbortOption to execute()
340      * then we need to make sure that all of the operations in their
341      * batch are set to use the supplied AbortOption so that the
342      * expected behaviour is obtained when executing below
343      */
344     tPrepOp= theFirstOpInList;
345     while(tPrepOp != NULL)
346     {
347       DBUG_PRINT("info", ("Changing abortOption from %d",
348                           tPrepOp->m_abortOption));
349       tPrepOp->m_abortOption= abortOption;
350       tPrepOp= tPrepOp->next();
351     }
352   }
353 
354 
355   ExecType tExecType;
356   NdbOperation* tCompletedFirstOp = NULL;
357   NdbOperation* tCompletedLastOp = NULL;
358 
359   int ret = 0;
360   do {
361     NdbOperation* firstSavedOp= NULL;
362     NdbOperation* lastSavedOp= NULL;
363 
364     tExecType = aTypeOfExec;
365     tPrepOp = theFirstOpInList;
366     while (tPrepOp != NULL) {
367       if (tPrepOp->theError.code == 0) {
368         bool batch = false;
369         NdbBlob* tBlob = tPrepOp->theBlobList;
370         if (tBlob !=NULL) {
371           /* We split the operation list just after this
372            * operation, in case it adds extra ops
373            */
374           firstSavedOp = tPrepOp->next(); // Could be NULL
375           lastSavedOp = theLastOpInList;
376           DBUG_PRINT("info", ("Splitting ops list between %p and %p",
377                               firstSavedOp, lastSavedOp));
378           tPrepOp->next(NULL);
379           theLastOpInList= tPrepOp;
380         }
381         while (tBlob != NULL) {
382           if (tBlob->preExecute(tExecType, batch) == -1)
383 	  {
384             ret = -1;
385 	    if (firstTransError.code==0)
386 	      firstTransError= theError;
387 	  }
388           tBlob = tBlob->theNext;
389         }
390         if (batch) {
391           // blob asked to execute all up to lastOpInBatch now
392           tExecType = NoCommit;
393           break;
394         }
395         else {
396           /* No batching yet - rejoin the current and
397            * saved operation lists
398            */
399           DBUG_PRINT("info", ("Rejoining ops list after preExecute between %p and %p",
400                               theLastOpInList,
401                               firstSavedOp));
402           if (firstSavedOp != NULL && lastSavedOp != NULL) {
403             if (theFirstOpInList == NULL)
404               theFirstOpInList = firstSavedOp;
405             else
406               theLastOpInList->next(firstSavedOp);
407             theLastOpInList = lastSavedOp;
408           }
409           firstSavedOp= lastSavedOp= NULL;
410         }
411       }
412       tPrepOp = tPrepOp->next();
413     }
414 
415     if (tExecType == Commit) {
416       NdbOperation* tOp = theCompletedFirstOp;
417       while (tOp != NULL) {
418         if (tOp->theError.code == 0) {
419           NdbBlob* tBlob = tOp->theBlobList;
420           while (tBlob != NULL) {
421             if (tBlob->preCommit() == -1)
422 	    {
423 	      ret = -1;
424 	      if (firstTransError.code==0)
425 		firstTransError= theError;
426 	    }
427             tBlob = tBlob->theNext;
428           }
429         }
430         tOp = tOp->next();
431       }
432     }
433 
434     // completed ops are in unspecified order
435     if (theCompletedFirstOp != NULL) {
436       if (tCompletedFirstOp == NULL) {
437         tCompletedFirstOp = theCompletedFirstOp;
438         tCompletedLastOp = theCompletedLastOp;
439       } else {
440         tCompletedLastOp->next(theCompletedFirstOp);
441         tCompletedLastOp = theCompletedLastOp;
442       }
443       theCompletedFirstOp = NULL;
444       theCompletedLastOp = NULL;
445     }
446 
447     if (executeNoBlobs(tExecType,
448 		       NdbOperation::DefaultAbortOption,
449 		       forceSend) == -1)
450     {
451       /**
452        * We abort the execute here. But we still need to put the split-off
453        * operation list back into the transaction object, or we will get a
454        * memory leak.
455        */
456       if (firstSavedOp != NULL && lastSavedOp != NULL) {
457         DBUG_PRINT("info", ("Rejoining ops list after postExecute between "
458                             "%p and %p", theLastOpInList, firstSavedOp));
459         if (theFirstOpInList == NULL)
460           theFirstOpInList = firstSavedOp;
461         else
462           theLastOpInList->next(firstSavedOp);
463         theLastOpInList = lastSavedOp;
464       }
465       if (tCompletedFirstOp != NULL) {
466         tCompletedLastOp->next(theCompletedFirstOp);
467         theCompletedFirstOp = tCompletedFirstOp;
468         if (theCompletedLastOp == NULL)
469           theCompletedLastOp = tCompletedLastOp;
470       }
471 
472       /* executeNoBlobs will have set transaction error */
473       DBUG_RETURN(-1);
474     }
475 
476     /* Capture any trans error left by the execute() in case it gets trampled */
477     if (firstTransError.code==0)
478       firstTransError= theError;
479 
480 #ifdef ndb_api_crash_on_complex_blob_abort
481     assert(theFirstOpInList == NULL && theLastOpInList == NULL);
482 #else
483     theFirstOpInList = theLastOpInList = NULL;
484 #endif
485 
486     {
487       NdbOperation* tOp = theCompletedFirstOp;
488       while (tOp != NULL) {
489         if (tOp->theError.code == 0) {
490           NdbBlob* tBlob = tOp->theBlobList;
491           while (tBlob != NULL) {
492             // may add new operations if batch
493             if (tBlob->postExecute(tExecType) == -1)
494 	    {
495               ret = -1;
496 	      if (firstTransError.code==0)
497 		firstTransError= theError;
498 	    }
499             tBlob = tBlob->theNext;
500           }
501         }
502         tOp = tOp->next();
503       }
504     }
505 
506     // Restore any saved prepared ops if we batched
507     if (firstSavedOp != NULL && lastSavedOp != NULL) {
508       DBUG_PRINT("info", ("Rejoining ops list after postExecute between %p and %p",
509                           theLastOpInList,
510                           firstSavedOp));
511       if (theFirstOpInList == NULL)
512         theFirstOpInList = firstSavedOp;
513       else
514         theLastOpInList->next(firstSavedOp);
515       theLastOpInList = lastSavedOp;
516     }
517     assert(theFirstOpInList == NULL || tExecType == NoCommit);
518   } while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
519 
520   if (tCompletedFirstOp != NULL) {
521     tCompletedLastOp->next(theCompletedFirstOp);
522     theCompletedFirstOp = tCompletedFirstOp;
523     if (theCompletedLastOp == NULL)
524       theCompletedLastOp = tCompletedLastOp;
525   }
526 #if ndb_api_count_completed_ops_after_blob_execute
527   { NdbOperation* tOp; unsigned n = 0;
528     for (tOp = theCompletedFirstOp; tOp != NULL; tOp = tOp->next()) n++;
529     ndbout << "completed ops: " << n << endl;
530   }
531 #endif
532 
533   /* Sometimes the original error is trampled by 'Trans already aborted',
534    * detect this case and attempt to restore the original error
535    */
536   if (theError.code == 4350) // Trans already aborted
537   {
538     DBUG_PRINT("info", ("Trans already aborted, existingTransError.code %u, "
539                         "firstTransError.code %u",
540                         existingTransError.code,
541                         firstTransError.code));
542     if (existingTransError.code != 0)
543     {
544       theError = existingTransError;
545     }
546     else if (firstTransError.code != 0)
547     {
548       theError = firstTransError;
549     }
550   }
551 
552   /* Generally return the first error which we encountered as
553    * the Trans error.  Caller can traverse the op list to
554    * get the full picture
555    */
556   if (firstTransError.code != 0)
557   {
558     DBUG_PRINT("info", ("Setting error to first error.  firstTransError.code = %u, "
559                         "theError.code = %u",
560                         firstTransError.code,
561                         theError.code));
562     theError = firstTransError;
563   }
564 
565   DBUG_RETURN(ret);
566 }
567 
568 int
executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,NdbOperation::AbortOption abortOption,int forceSend)569 NdbTransaction::executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,
570 			       NdbOperation::AbortOption abortOption,
571 			       int forceSend)
572 {
573   DBUG_ENTER("NdbTransaction::executeNoBlobs");
574   DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
575 		       aTypeOfExec, abortOption));
576 
577 //------------------------------------------------------------------------
578 // We will start by preparing all operations in the transaction defined
579 // since last execute or since beginning. If this works ok we will continue
580 // by calling the poll with wait method. This method will return when
581 // the NDB kernel has completed its task or when 10 seconds have passed.
582 // The NdbTransactionCallBack-method will receive the return code of the
583 // transaction. The normal methods of reading error codes still apply.
584 //------------------------------------------------------------------------
585   Ndb* tNdb = theNdb;
586 
587   Uint32 timeout = theNdb->theImpl->get_waitfor_timeout();
588   m_waitForReply = false;
589   executeAsynchPrepare(aTypeOfExec, NULL, NULL, abortOption);
590   if (m_waitForReply){
591     while (1) {
592       int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
593       if (unlikely(noOfComp == 0)) {
594         /*
595          * Just for fun, this is only one of two places where
596          * we could hit this error... It's quite possible we
597          * hit it in Ndbif.cpp in Ndb::check_send_timeout()
598          *
599          * We behave rather similarly in both places.
600          * Hitting this is certainly a bug though...
601          */
602         g_eventLogger->error("WARNING: Timeout in executeNoBlobs() waiting for "
603                              "response from NDB data nodes. This should NEVER "
604                              "occur. You have likely hit a NDB Bug. Please "
605                              "file a bug.");
606         DBUG_PRINT("error",("This timeout should never occure, execute()"));
607         g_eventLogger->error("Forcibly trying to rollback txn (%p"
608                              ") to try to clean up data node resources.",
609                              this);
610         executeNoBlobs(NdbTransaction::Rollback);
611         theError.code = 4012;
612         theError.status= NdbError::PermanentError;
613         theError.classification= NdbError::TimeoutExpired;
614         setOperationErrorCodeAbort(4012); // ndbd timeout
615         DBUG_RETURN(-1);
616       }//if
617 
618       /*
619        * Check that the completed transactions include this one.  There
620        * could be another thread running asynchronously.  Even in pure
621        * async case rollback is done synchronously.
622        */
623       if (theListState != NotInList)
624         continue;
625 #ifdef VM_TRACE
626       unsigned anyway = 0;
627       for (unsigned i = 0; i < theNdb->theNoOfPreparedTransactions; i++)
628         anyway += theNdb->thePreparedTransactionsArray[i] == this;
629       for (unsigned i = 0; i < theNdb->theNoOfSentTransactions; i++)
630         anyway += theNdb->theSentTransactionsArray[i] == this;
631       for (unsigned i = 0; i < theNdb->theNoOfCompletedTransactions; i++)
632         anyway += theNdb->theCompletedTransactionsArray[i] == this;
633       if (anyway) {
634         theNdb->printState("execute %lx", (long)this);
635         abort();
636       }
637 #endif
638       if (theReturnStatus == ReturnFailure) {
639         DBUG_RETURN(-1);
640       }//if
641       break;
642     }
643   }
644   thePendingBlobOps = 0;
645   pendingBlobReadBytes = 0;
646   pendingBlobWriteBytes = 0;
647   DBUG_RETURN(0);
648 }//NdbTransaction::executeNoBlobs()
649 
650 /**
651  * Get the first query in the current transaction that has a lookup operation
652  * as its root.
653  */
getFirstLookupQuery(NdbQueryImpl * firstQuery)654 static NdbQueryImpl* getFirstLookupQuery(NdbQueryImpl* firstQuery)
655 {
656   NdbQueryImpl* current = firstQuery;
657   while (current != NULL && current->getQueryDef().isScanQuery()) {
658     current = current->getNext();
659   }
660   return current;
661 }
662 
663 /**
664  * Get the last query in the current transaction that has a lookup operation
665  * as its root.
666  */
getLastLookupQuery(NdbQueryImpl * firstQuery)667 static NdbQueryImpl* getLastLookupQuery(NdbQueryImpl* firstQuery)
668 {
669   NdbQueryImpl* current = firstQuery;
670   NdbQueryImpl* last = NULL;
671   while (current != NULL) {
672     if (!current->getQueryDef().isScanQuery()) {
673       last = current;
674     }
675     current = current->getNext();
676   }
677   return last;
678 }
679 
680 /*****************************************************************************
681 void executeAsynchPrepare(ExecType           aTypeOfExec,
682                           NdbAsynchCallback  callBack,
683                           void*              anyObject,
684                           CommitType         aTypeOfCommit);
685 
686 Return Value:  No return value
687 Parameters :   aTypeOfExec:   Type of execute.
688                anyObject:     An object provided in the callback method
689                callBack:      The callback method
690                aTypeOfCommit: What to do when read/updated/deleted records
691                               are missing or inserted records already exist.
692 
693 Remark:        Prepare a part of a transaction in an asynchronous manner.
694 *****************************************************************************/
695 void
executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption)696 NdbTransaction::executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,
697                                      NdbAsynchCallback  aCallback,
698                                      void*              anyObject,
699                                      NdbOperation::AbortOption abortOption)
700 {
701   DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
702   DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: 0x%lx, anyObject: Ox%lx",
703 		       aTypeOfExec, (long) aCallback, (long) anyObject));
704 
705   /**
706    * Reset error.code on execute
707    */
708 #ifndef DBUG_OFF
709   if (theError.code != 0)
710     DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
711 #endif
712   {
713     switch (aTypeOfExec)
714     {
715     case NdbTransaction::Commit:
716       theNdb->theImpl->incClientStat(Ndb::TransCommitCount, 1);
717       break;
718     case NdbTransaction::Rollback:
719       theNdb->theImpl->incClientStat(Ndb::TransAbortCount, 1);
720       break;
721     default:
722       break;
723     }
724   }
725   /**
726    * for timeout (4012) we want sendROLLBACK to behave differently.
727    * Else, normal behaviour of reset errcode
728    */
729   if (theError.code != 4012)
730     theError.code = 0;
731 
732   /***************************************************************************
733    * Eager garbage collect queries which has completed execution
734    * w/ all its results made available to client.
735    * TODO: Add a member 'doEagerRelease' to check below.
736    **************************************************************************/
737   if (false) {
738     releaseCompletedQueries();
739   }
740 
741   NdbScanOperation* tcOp = m_theFirstScanOperation;
742   if (tcOp != 0){
743     // Execute any cursor operations
744     while (tcOp != NULL) {
745       int tReturnCode;
746       tReturnCode = tcOp->executeCursor(theDBnode);
747       if (tReturnCode == -1) {
748         DBUG_VOID_RETURN;
749       }//if
750       tcOp->postExecuteRelease(); // Release unneeded resources
751                                   // outside TP mutex
752       tcOp = (NdbScanOperation*)tcOp->next();
753     } // while
754     m_theLastScanOperation->next(m_firstExecutedScanOp);
755     m_firstExecutedScanOp = m_theFirstScanOperation;
756     // Discard cursor operations, since these are also
757     // in the complete operations list we do not need
758     // to release them.
759     m_theFirstScanOperation = m_theLastScanOperation = NULL;
760   }
761 
762   bool tTransactionIsStarted = theTransactionIsStarted;
763   NdbOperation*	tLastOp = theLastOpInList;
764   Ndb* tNdb = theNdb;
765   CommitStatusType tCommitStatus = theCommitStatus;
766   Uint32 tnoOfPreparedTransactions = tNdb->theNoOfPreparedTransactions;
767 
768   theReturnStatus     = ReturnSuccess;
769   theCallbackFunction = aCallback;
770   theCallbackObject   = anyObject;
771   m_waitForReply = true;
772   tNdb->thePreparedTransactionsArray[tnoOfPreparedTransactions] = this;
773   theTransArrayIndex = tnoOfPreparedTransactions;
774   theListState = InPreparedList;
775   tNdb->theNoOfPreparedTransactions = tnoOfPreparedTransactions + 1;
776 
777   theNoOfOpSent		= 0;
778   theNoOfOpCompleted	= 0;
779   NdbNodeBitmask::clear(m_db_nodes);
780   NdbNodeBitmask::clear(m_failed_db_nodes);
781 
782   if ((tCommitStatus != Started) ||
783       (aTypeOfExec == Rollback)) {
784 /*****************************************************************************
785  *	Rollback have been ordered on a started transaction. Call rollback.
786  *      Could also be state problem or previous problem which leads to the
787  *      same action.
788  ****************************************************************************/
789     if (aTypeOfExec == Rollback) {
790       if (theTransactionIsStarted == false || theSimpleState) {
791 	theCommitStatus = Aborted;
792 	theSendStatus = sendCompleted;
793       } else {
794 	theSendStatus = sendABORT;
795       }
796     } else {
797       theSendStatus = sendABORTfail;
798     }//if
799     if (theCommitStatus == Aborted){
800       DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
801       setErrorCode(4350);
802     }
803     DBUG_VOID_RETURN;
804   }//if
805 
806   NdbQueryImpl* const lastLookupQuery = getLastLookupQuery(m_firstQuery);
807 
808   if (tTransactionIsStarted == true) {
809     if (tLastOp != NULL) {
810       if (aTypeOfExec == Commit) {
811 /*****************************************************************************
812  *	Set commit indicator on last operation when commit has been ordered
813  *      and also a number of operations.
814 ******************************************************************************/
815         tLastOp->theCommitIndicator = 1;
816       }//if
817     } else if (lastLookupQuery != NULL) {
818       if (aTypeOfExec == Commit) {
819         lastLookupQuery->setCommitIndicator();
820       }
821     } else if (m_firstQuery == NULL) {
822       if (aTypeOfExec == Commit && !theSimpleState) {
823 	/**********************************************************************
824 	 *   A Transaction have been started and no more operations exist.
825 	 *   We will use the commit method.
826 	 *********************************************************************/
827         theSendStatus = sendCOMMITstate;
828 	DBUG_VOID_RETURN;
829       } else {
830 	/**********************************************************************
831 	 * We need to put it into the array of completed transactions to
832 	 * ensure that we report the completion in a proper way.
833 	 * We cannot do this here since that would endanger the completed
834 	 * transaction array since that is also updated from the receiver
835 	 * thread and thus we need to do it under mutex lock and thus we
836 	 * set the sendStatus to ensure that the send method will
837 	 * put it into the completed array.
838 	 **********************************************************************/
839         theSendStatus = sendCompleted;
840 	DBUG_VOID_RETURN; // No Commit with no operations is OK
841       }//if
842     }//if
843   } else if (tTransactionIsStarted == false) {
844     NdbOperation* tFirstOp = theFirstOpInList;
845 
846     /*
847      * Lookups that are roots of queries are sent before non-linked lookups.
848      * If both types are present, then the start indicator should be set
849      * on a query root lookup, and the commit indicator on a non-linked
850      * lookup.
851      */
852     if (lastLookupQuery != NULL) {
853       getFirstLookupQuery(m_firstQuery)->setStartIndicator();
854     } else if (tFirstOp != NULL) {
855       tFirstOp->setStartIndicator();
856     }
857 
858     if (tFirstOp != NULL) {
859       if (aTypeOfExec == Commit) {
860         tLastOp->theCommitIndicator = 1;
861       }//if
862     } else if (lastLookupQuery != NULL) {
863       if (aTypeOfExec == Commit) {
864         lastLookupQuery->setCommitIndicator();
865       }//if
866     } else if (m_firstQuery == NULL) {
867       /***********************************************************************
868        *    No operations are defined and we have not started yet.
869        *    Simply return OK. Set commit status if Commit.
870        ***********************************************************************/
871       if (aTypeOfExec == Commit) {
872         theCommitStatus = Committed;
873       }//if
874       /***********************************************************************
875        * We need to put it into the array of completed transactions to
876        * ensure that we report the completion in a proper way. We
877        * cannot do this here since that would endanger the completed
878        * transaction array since that is also updated from the
879        * receiver thread and thus we need to do it under mutex lock
880        * and thus we set the sendStatus to ensure that the send method
881        * will put it into the completed array.
882        ***********************************************************************/
883       theSendStatus = sendCompleted;
884       DBUG_VOID_RETURN;
885     }//if
886   }
887 
888   theCompletionStatus = NotCompleted;
889 
890   // Prepare sending of all pending NdbQuery's
891   if (m_firstQuery) {
892     NdbQueryImpl* query = m_firstQuery;
893     NdbQueryImpl* last = NULL;
894     while (query!=NULL) {
895       const int tReturnCode = query->prepareSend();
896       if (unlikely(tReturnCode != 0)) {
897         theSendStatus = sendABORTfail;
898         DBUG_VOID_RETURN;
899       }//if
900       last  = query;
901       query = query->getNext();
902     }
903     assert (m_firstExecQuery==NULL);
904     last->setNext(m_firstExecQuery);
905     m_firstExecQuery = m_firstQuery;
906     m_firstQuery = NULL;
907   }
908 
909   // Prepare sending of all pending (non-scan) NdbOperations's
910   NdbOperation* tOp = theFirstOpInList;
911   Uint32 pkOpCount = 0;
912   Uint32 ukOpCount = 0;
913   while (tOp) {
914     int tReturnCode;
915     NdbOperation* tNextOp = tOp->next();
916 
917     /* Count operation */
918     if (tOp->theTCREQ->theVerId_signalNumber == GSN_TCINDXREQ)
919       ukOpCount++;
920     else
921       pkOpCount++;
922 
923     if (tOp->Status() == NdbOperation::UseNdbRecord)
924       tReturnCode = tOp->prepareSendNdbRecord(abortOption);
925     else
926       tReturnCode= tOp->prepareSend(theTCConPtr, theTransactionId, abortOption);
927 
928     if (tReturnCode == -1) {
929       theSendStatus = sendABORTfail;
930       DBUG_VOID_RETURN;
931     }//if
932 
933     /*************************************************************************
934      * Now that we have successfully prepared the send of this operation we
935      * move it to the list of executing operations and remove it from the
936      * list of defined operations.
937      ************************************************************************/
938     tOp = tNextOp;
939   }
940 
941   theNdb->theImpl->incClientStat(Ndb::PkOpCount, pkOpCount);
942   theNdb->theImpl->incClientStat(Ndb::UkOpCount, ukOpCount);
943 
944   NdbOperation* tLastOpInList = theLastOpInList;
945   NdbOperation* tFirstOpInList = theFirstOpInList;
946 
947   theFirstOpInList = NULL;
948   theLastOpInList = NULL;
949   theFirstExecOpInList = tFirstOpInList;
950   theLastExecOpInList = tLastOpInList;
951 
952   theCompletionStatus = CompletedSuccess;
953   theSendStatus = sendOperations;
954   DBUG_VOID_RETURN;
955 }//NdbTransaction::executeAsynchPrepare()
956 
957 void
executeAsynch(ExecType aTypeOfExec,NdbAsynchCallback aCallback,void * anyObject,NdbOperation::AbortOption abortOption,int forceSend)958 NdbTransaction::executeAsynch(ExecType aTypeOfExec,
959                               NdbAsynchCallback aCallback,
960                               void* anyObject,
961                               NdbOperation::AbortOption abortOption,
962                               int forceSend)
963 {
964   executeAsynchPrepare(aTypeOfExec, aCallback, anyObject, abortOption);
965   theNdb->sendPreparedTransactions(forceSend);
966 }
967 
close()968 void NdbTransaction::close()
969 {
970   theNdb->closeTransaction(this);
971 }
972 
refresh()973 int NdbTransaction::refresh()
974 {
975   for(NdbIndexScanOperation* scan_op = m_firstExecutedScanOp;
976       scan_op != 0; scan_op = (NdbIndexScanOperation *) scan_op->theNext)
977   {
978     NdbTransaction* scan_trans = scan_op->theNdbCon;
979     if (scan_trans)
980     {
981       scan_trans->sendTC_HBREP();
982     }
983   }
984   return sendTC_HBREP();
985 }
986 
987 /*****************************************************************************
988 int sendTC_HBREP();
989 
990 Return Value:  No return value.
991 Parameters :   None.
992 Remark:        Order NDB to refresh the timeout counter of the transaction.
993 ******************************************************************************/
994 int
sendTC_HBREP()995 NdbTransaction::sendTC_HBREP()		// Send a TC_HBREP signal;
996 {
997   NdbApiSignal* tSignal;
998   Ndb* tNdb = theNdb;
999   Uint32 tTransId1, tTransId2;
1000 
1001   tSignal = tNdb->getSignal();
1002   if (tSignal == NULL) {
1003     return -1;
1004   }
1005 
1006   if (tSignal->setSignal(GSN_TC_HBREP, refToBlock(m_tcRef)) == -1) {
1007     return -1;
1008   }
1009 
1010   TcHbRep * const tcHbRep = CAST_PTR(TcHbRep, tSignal->getDataPtrSend());
1011 
1012   tcHbRep->apiConnectPtr = theTCConPtr;
1013 
1014   tTransId1 = (Uint32) theTransactionId;
1015   tTransId2 = (Uint32) (theTransactionId >> 32);
1016   tcHbRep->transId1      = tTransId1;
1017   tcHbRep->transId2      = tTransId2;
1018 
1019   tNdb->theImpl->lock();
1020   const int res = tNdb->theImpl->sendSignal(tSignal,theDBnode);
1021   tNdb->theImpl->unlock();
1022   tNdb->releaseSignal(tSignal);
1023 
1024   if (res == -1){
1025     return -1;
1026   }
1027 
1028   return 0;
1029 }//NdbTransaction::sendTC_HBREP()
1030 
1031 /*****************************************************************************
1032 int doSend();
1033 
1034 Return Value:  Return 0 : send was successful.
1035                Return -1: In all other case.
1036 Remark:        Send all operations and queries belonging to this connection.
1037                The caller of this method has the responsibility to remove the
1038                object from the prepared transactions array on the Ndb-object.
1039 *****************************************************************************/
1040 int
doSend()1041 NdbTransaction::doSend()
1042 {
1043   DBUG_ENTER("NdbTransaction::doSend");
1044   /*
1045   This method assumes that at least one operation or query have been defined.
1046   This is ensured by the caller of this routine (=execute).
1047   */
1048 
1049   switch(theSendStatus){
1050   case sendOperations: {
1051     assert (m_firstExecQuery!=NULL || theFirstExecOpInList!=NULL);
1052 
1053     const NdbQueryImpl* const lastLookupQuery
1054       = getLastLookupQuery(m_firstExecQuery);
1055     if (m_firstExecQuery!=NULL) {
1056       NdbQueryImpl* query = m_firstExecQuery;
1057       NdbQueryImpl* last  = NULL;
1058       while (query!=NULL) {
1059         const bool lastFlag =
1060           query == lastLookupQuery && theFirstExecOpInList == NULL;
1061         const int tReturnCode = query->doSend(theDBnode, lastFlag);
1062         if (tReturnCode == -1) {
1063           goto fail;
1064         }
1065         last = query;
1066         query = query->getNext();
1067       } // while
1068 
1069       // Append to list of active queries
1070       last->setNext(m_firstActiveQuery);
1071       m_firstActiveQuery = m_firstExecQuery;
1072       m_firstExecQuery = NULL;
1073     }
1074 
1075     NdbOperation * tOp = theFirstExecOpInList;
1076     while (tOp != NULL) {
1077       NdbOperation* tNext = tOp->next();
1078       const Uint32 lastFlag = ((tNext == NULL) ? 1 : 0);
1079       const int tReturnCode = tOp->doSend(theDBnode, lastFlag);
1080       if (tReturnCode == -1) {
1081         goto fail;
1082       }//if
1083       tOp = tNext;
1084     }
1085 
1086     if (theFirstExecOpInList || lastLookupQuery != NULL) {
1087       theSendStatus = sendTC_OP;
1088       theTransactionIsStarted = true;
1089       theNdb->insert_sent_list(this);      // Lookup: completes with KEYCONF/REF
1090     } else {
1091       theSendStatus = sendCompleted;
1092       theNdb->insert_completed_list(this); // Scans query completes after send
1093     }
1094     DBUG_RETURN(0);
1095   }//case
1096   case sendABORT:
1097   case sendABORTfail:{
1098   /***********************************************************************
1099    * Rollback have been ordered on a not started transaction.
1100    * Simply return OK and set abort status.
1101    ***********************************************************************/
1102     if (theSendStatus == sendABORTfail) {
1103       theReturnStatus = ReturnFailure;
1104     }//if
1105     if (sendROLLBACK() == 0) {
1106       DBUG_RETURN(0);
1107     }//if
1108     break;
1109   }//case
1110   case sendCOMMITstate:
1111     if (sendCOMMIT() == 0) {
1112       DBUG_RETURN(0);
1113     }//if
1114     break;
1115   case sendCompleted:
1116     theNdb->insert_completed_list(this);
1117     DBUG_RETURN(0);
1118   default:
1119     ndbout << "Inconsistent theSendStatus = "
1120 	   << (Uint32) theSendStatus << endl;
1121     abort();
1122     break;
1123   }//switch
1124 
1125   theReleaseOnClose = true;
1126   theTransactionIsStarted = false;
1127   theCommitStatus = Aborted;
1128 fail:
1129   setOperationErrorCodeAbort(4002);
1130   DBUG_RETURN(-1);
1131 }//NdbTransaction::doSend()
1132 
1133 /**************************************************************************
1134 int sendROLLBACK();
1135 
1136 Return Value:  Return -1 if send unsuccessful.
1137 Parameters :   None.
1138 Remark:        Order NDB to rollback the transaction.
1139 **************************************************************************/
1140 int
sendROLLBACK()1141 NdbTransaction::sendROLLBACK()      // Send a TCROLLBACKREQ signal;
1142 {
1143   Ndb* tNdb = theNdb;
1144   if ((theTransactionIsStarted == true) &&
1145       (theCommitStatus != Committed) &&
1146       (theCommitStatus != Aborted)) {
1147 /**************************************************************************
1148  *	The user did not perform any rollback but simply closed the
1149  *      transaction. We must rollback Ndb since Ndb have been contacted.
1150  *************************************************************************/
1151     NdbApiSignal tSignal(tNdb->theMyRef);
1152     Uint32 tTransId1, tTransId2;
1153     NdbImpl * impl = theNdb->theImpl;
1154     int	  tReturnCode;
1155 
1156     tTransId1 = (Uint32) theTransactionId;
1157     tTransId2 = (Uint32) (theTransactionId >> 32);
1158     tSignal.setSignal(GSN_TCROLLBACKREQ, refToBlock(m_tcRef));
1159     tSignal.setData(theTCConPtr, 1);
1160     tSignal.setData(tTransId1, 2);
1161     tSignal.setData(tTransId2, 3);
1162     if(theError.code == 4012)
1163     {
1164       g_eventLogger->error("Sending TCROLLBACKREQ with Bad flag");
1165       tSignal.setLength(tSignal.getLength() + 1); // + flags
1166       tSignal.setData(0x1, 4); // potentially bad data
1167     }
1168     tReturnCode = impl->sendSignal(&tSignal,theDBnode);
1169     if (tReturnCode != -1) {
1170       theSendStatus = sendTC_ROLLBACK;
1171       tNdb->insert_sent_list(this);
1172       return 0;
1173     }//if
1174    /*********************************************************************
1175     * It was not possible to abort the transaction towards the NDB kernel
1176     * and thus we put it into the array of completed transactions that
1177     * are ready for reporting to the application.
1178     *********************************************************************/
1179     return -1;
1180   } else {
1181     /*
1182      It is not necessary to abort the transaction towards the NDB kernel and
1183      thus we put it into the array of completed transactions that are ready
1184      for reporting to the application.
1185      */
1186     theSendStatus = sendCompleted;
1187     tNdb->insert_completed_list(this);
1188     return 0;
1189     ;
1190   }//if
1191 }//NdbTransaction::sendROLLBACK()
1192 
1193 /***************************************************************************
1194 int sendCOMMIT();
1195 
1196 Return Value:  Return 0 : send was successful.
1197                Return -1: In all other case.
1198 Parameters :   None.
1199 Remark:        Order NDB to commit the transaction.
1200 ***************************************************************************/
1201 int
sendCOMMIT()1202 NdbTransaction::sendCOMMIT()    // Send a TC_COMMITREQ signal;
1203 {
1204   NdbApiSignal tSignal(theNdb->theMyRef);
1205   Uint32 tTransId1, tTransId2;
1206   NdbImpl * impl = theNdb->theImpl;
1207   int	  tReturnCode;
1208 
1209   tTransId1 = (Uint32) theTransactionId;
1210   tTransId2 = (Uint32) (theTransactionId >> 32);
1211   tSignal.setSignal(GSN_TC_COMMITREQ, refToBlock(m_tcRef));
1212   tSignal.setData(theTCConPtr, 1);
1213   tSignal.setData(tTransId1, 2);
1214   tSignal.setData(tTransId2, 3);
1215 
1216   tReturnCode = impl->sendSignal(&tSignal,theDBnode);
1217   if (tReturnCode != -1) {
1218     theSendStatus = sendTC_COMMIT;
1219     theNdb->insert_sent_list(this);
1220     return 0;
1221   } else {
1222     return -1;
1223   }//if
1224 }//NdbTransaction::sendCOMMIT()
1225 
1226 /******************************************************************************
1227 void release();
1228 
1229 Remark:         Release all operations.
1230 ******************************************************************************/
1231 void
release()1232 NdbTransaction::release(){
1233   releaseOperations();
1234   releaseLockHandles();
1235   if ( (theTransactionIsStarted == true) &&
1236        ((theCommitStatus != Committed) &&
1237 	(theCommitStatus != Aborted))) {
1238     /************************************************************************
1239      *	The user did not perform any rollback but simply closed the
1240      *      transaction. We must rollback Ndb since Ndb have been contacted.
1241      ************************************************************************/
1242     if (!theSimpleState)
1243     {
1244       execute(Rollback);
1245     }
1246   }//if
1247   theMagicNumber = 0xFE11DC;
1248   theInUseState = false;
1249 #ifdef VM_TRACE
1250   if (theListState != NotInList) {
1251     theNdb->printState("release %lx", (long)this);
1252     abort();
1253   }
1254 #endif
1255 }//NdbTransaction::release()
1256 
1257 void
releaseOps(NdbOperation * tOp)1258 NdbTransaction::releaseOps(NdbOperation* tOp){
1259   while (tOp != NULL) {
1260     NdbOperation* tmp = tOp;
1261     tOp->release();
1262     tOp = tOp->next();
1263     theNdb->releaseOperation(tmp);
1264   }//while
1265 }
1266 
1267 /******************************************************************************
1268 void releaseOperations();
1269 
1270 Remark:         Release all operations.
1271 ******************************************************************************/
1272 void
releaseOperations()1273 NdbTransaction::releaseOperations()
1274 {
1275   // Release any open scans
1276   releaseScanOperations(m_theFirstScanOperation);
1277   releaseScanOperations(m_firstExecutedScanOp);
1278 
1279   releaseQueries(m_firstQuery);
1280   releaseQueries(m_firstExecQuery);
1281   releaseQueries(m_firstActiveQuery);
1282   releaseOps(theCompletedFirstOp);
1283   releaseOps(theFirstOpInList);
1284   releaseOps(theFirstExecOpInList);
1285 
1286   theCompletedFirstOp = NULL;
1287   theCompletedLastOp = NULL;
1288   theFirstOpInList = NULL;
1289   theFirstExecOpInList = NULL;
1290   theLastOpInList = NULL;
1291   theLastExecOpInList = NULL;
1292   theScanningOp = NULL;
1293   m_scanningQuery = NULL;
1294   m_theFirstScanOperation = NULL;
1295   m_theLastScanOperation = NULL;
1296   m_firstExecutedScanOp = NULL;
1297   m_firstQuery = NULL;
1298   m_firstExecQuery = NULL;
1299   m_firstActiveQuery = NULL;
1300 
1301 }//NdbTransaction::releaseOperations()
1302 
1303 void
releaseCompletedOperations()1304 NdbTransaction::releaseCompletedOperations()
1305 {
1306   releaseOps(theCompletedFirstOp);
1307   theCompletedFirstOp = NULL;
1308   theCompletedLastOp = NULL;
1309 }//NdbTransaction::releaseCompletedOperations()
1310 
1311 
1312 void
releaseCompletedQueries()1313 NdbTransaction::releaseCompletedQueries()
1314 {
1315   /**
1316    * Find & release all active queries which as completed.
1317    */
1318   NdbQueryImpl* prev  = NULL;
1319   NdbQueryImpl* query = m_firstActiveQuery;
1320   while (query != NULL) {
1321     NdbQueryImpl* next = query->getNext();
1322 
1323     if (query->hasCompleted()) {
1324       // Unlink from completed-query list
1325       if (prev)
1326         prev->setNext(next);
1327       else
1328         m_firstActiveQuery = next;
1329 
1330       query->release();
1331     } else {
1332       prev = query;
1333     }
1334     query = next;
1335   } // while
1336 }//NdbTransaction::releaseCompletedQueries()
1337 
1338 
1339 /******************************************************************************
1340 void releaseQueries();
1341 
1342 Remark:         Release all queries
1343 ******************************************************************************/
1344 void
releaseQueries(NdbQueryImpl * query)1345 NdbTransaction::releaseQueries(NdbQueryImpl* query)
1346 {
1347   while (query != NULL) {
1348     NdbQueryImpl* next = query->getNext();
1349     query->release();
1350     query = next;
1351   }
1352 }//NdbTransaction::releaseQueries
1353 
1354 /******************************************************************************
1355 void releaseScanOperations();
1356 
1357 Remark:         Release all cursor operations.
1358                 (NdbScanOperation and NdbIndexOperation)
1359 ******************************************************************************/
1360 void
releaseScanOperations(NdbIndexScanOperation * cursorOp)1361 NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
1362 {
1363   while(cursorOp != 0){
1364     NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
1365     cursorOp->release();
1366     theNdb->releaseScanOperation(cursorOp);
1367     cursorOp = next;
1368   }
1369 }//NdbTransaction::releaseScanOperations()
1370 
1371 bool
releaseScanOperation(NdbIndexScanOperation ** listhead,NdbIndexScanOperation ** listtail,NdbIndexScanOperation * op)1372 NdbTransaction::releaseScanOperation(NdbIndexScanOperation** listhead,
1373 				     NdbIndexScanOperation** listtail,
1374 				     NdbIndexScanOperation* op)
1375 {
1376   if (* listhead == op)
1377   {
1378     * listhead = (NdbIndexScanOperation*)op->theNext;
1379     if (listtail && *listtail == op)
1380     {
1381       assert(* listhead == 0);
1382       * listtail = 0;
1383     }
1384 
1385   }
1386   else
1387   {
1388     NdbIndexScanOperation* tmp = * listhead;
1389     while (tmp != NULL)
1390     {
1391       if (tmp->theNext == op)
1392       {
1393 	tmp->theNext = (NdbIndexScanOperation*)op->theNext;
1394 	if (listtail && *listtail == op)
1395 	{
1396 	  assert(op->theNext == 0);
1397 	  *listtail = tmp;
1398 	}
1399 	break;
1400       }
1401       tmp = (NdbIndexScanOperation*)tmp->theNext;
1402     }
1403     if (tmp == NULL)
1404       op = NULL;
1405   }
1406 
1407   if (op != NULL)
1408   {
1409     op->release();
1410     theNdb->releaseScanOperation(op);
1411     return true;
1412   }
1413 
1414   return false;
1415 }
1416 
1417 void
releaseLockHandles()1418 NdbTransaction::releaseLockHandles()
1419 {
1420   NdbLockHandle* lh = m_theFirstLockHandle;
1421 
1422   while (lh)
1423   {
1424     NdbLockHandle* next = lh->next();
1425     lh->next(NULL);
1426 
1427     theNdb->releaseLockHandle(lh);
1428     lh = next;
1429   }
1430 
1431   m_theFirstLockHandle = NULL;
1432   m_theLastLockHandle = NULL;
1433 }
1434 
1435 /*****************************************************************************
1436 NdbOperation* getNdbOperation(const char* aTableName);
1437 
1438 Return Value    Return a pointer to a NdbOperation object if getNdbOperation
1439                 was succesful.
1440                 Return NULL : In all other case.
1441 Parameters:     aTableName : Name of the database table.
1442 Remark:         Get an operation from NdbOperation idlelist and get the
1443                 NdbTransaction object
1444 		who was fetch by startTransaction pointing to this  operation
1445 		getOperation will set the theTableId in the NdbOperation object.
1446                 synchronous
1447 ******************************************************************************/
1448 NdbOperation*
getNdbOperation(const char * aTableName)1449 NdbTransaction::getNdbOperation(const char* aTableName)
1450 {
1451   if (theCommitStatus == Started){
1452     NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1453     if (table != 0){
1454       return getNdbOperation(table);
1455     } else {
1456       setErrorCode(theNdb->theDictionary->getNdbError().code);
1457       return NULL;
1458     }//if
1459   }
1460 
1461   setOperationErrorCodeAbort(4114);
1462 
1463   return NULL;
1464 }//NdbTransaction::getNdbOperation()
1465 
1466 /*****************************************************************************
1467 NdbOperation* getNdbOperation(const NdbTableImpl* tab, NdbOperation* aNextOp,
1468                               bool useRec)
1469 
1470 Return Value    Return a pointer to a NdbOperation object if getNdbOperation
1471                 was succesful.
1472                 Return NULL: In all other case.
1473 Parameters:     tableId : Id of the database table beeing deleted.
1474 Remark:         Get an operation from NdbOperation object idlelist and
1475                 get the NdbTransaction object who was fetch by
1476                 startTransaction pointing to this operation
1477   	        getOperation will set the theTableId in the NdbOperation
1478                 object, synchronous.
1479 *****************************************************************************/
1480 NdbOperation*
getNdbOperation(const NdbTableImpl * tab,NdbOperation * aNextOp,bool useRec)1481 NdbTransaction::getNdbOperation(const NdbTableImpl * tab,
1482                                 NdbOperation* aNextOp,
1483                                 bool useRec)
1484 {
1485   NdbOperation* tOp;
1486 
1487   if (theScanningOp != NULL || m_scanningQuery != NULL){
1488     setErrorCode(4607);
1489     return NULL;
1490   }
1491 
1492   tOp = theNdb->getOperation();
1493   if (tOp == NULL)
1494     goto getNdbOp_error1;
1495   if (aNextOp == NULL) {
1496     if (theLastOpInList != NULL) {
1497        theLastOpInList->next(tOp);
1498        theLastOpInList = tOp;
1499     } else {
1500        theLastOpInList = tOp;
1501        theFirstOpInList = tOp;
1502     }//if
1503     tOp->next(NULL);
1504   } else {
1505     // add before the given op
1506     if (theFirstOpInList == aNextOp) {
1507       theFirstOpInList = tOp;
1508     } else {
1509       NdbOperation* aLoopOp = theFirstOpInList;
1510       while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1511         aLoopOp = aLoopOp->next();
1512       assert(aLoopOp != NULL);
1513       aLoopOp->next(tOp);
1514     }
1515     tOp->next(aNextOp);
1516   }
1517   if (tOp->init(tab, this, useRec) != -1) {
1518     return tOp;
1519   } else {
1520     theNdb->releaseOperation(tOp);
1521   }//if
1522   return NULL;
1523 
1524  getNdbOp_error1:
1525   setOperationErrorCodeAbort(4000);
1526   return NULL;
1527 }//NdbTransaction::getNdbOperation()
1528 
getNdbOperation(const NdbDictionary::Table * table)1529 NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
1530 {
1531   if (table)
1532     return getNdbOperation(& NdbTableImpl::getImpl(*table));
1533   else
1534     return NULL;
1535 }//NdbTransaction::getNdbOperation()
1536 
1537 
1538 // NdbScanOperation
1539 /*****************************************************************************
1540 NdbScanOperation* getNdbScanOperation(const char* aTableName);
1541 
1542 Return Value    Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1543                 Return NULL : In all other case.
1544 Parameters:     aTableName : Name of the database table.
1545 Remark:         Get an operation from NdbScanOperation idlelist and get the NdbTransaction object
1546 		who was fetch by startTransaction pointing to this  operation
1547 		getOperation will set the theTableId in the NdbOperation object.synchronous
1548 ******************************************************************************/
1549 NdbScanOperation*
getNdbScanOperation(const char * aTableName)1550 NdbTransaction::getNdbScanOperation(const char* aTableName)
1551 {
1552   if (theCommitStatus == Started){
1553     NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
1554     if (tab != 0){
1555       return getNdbScanOperation(tab);
1556     } else {
1557       setOperationErrorCodeAbort(theNdb->theDictionary->m_error.code);
1558       return NULL;
1559     }//if
1560   }
1561 
1562   setOperationErrorCodeAbort(4114);
1563   return NULL;
1564 }//NdbTransaction::getNdbScanOperation()
1565 
1566 /*****************************************************************************
1567 NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
1568 
1569 Return Value    Return a pointer to a NdbIndexScanOperation object if getNdbIndexScanOperation was succesful.
1570                 Return NULL : In all other case.
1571 Parameters:     anIndexName : Name of the index to use.
1572                 aTableName : Name of the database table.
1573 Remark:         Get an operation from NdbIndexScanOperation idlelist and get the NdbTransaction object
1574 		who was fetch by startTransaction pointing to this  operation
1575 		getOperation will set the theTableId in the NdbIndexScanOperation object.synchronous
1576 ******************************************************************************/
1577 NdbIndexScanOperation*
getNdbIndexScanOperation(const char * anIndexName,const char * aTableName)1578 NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
1579 					const char* aTableName)
1580 {
1581   NdbIndexImpl* index =
1582     theNdb->theDictionary->getIndex(anIndexName, aTableName);
1583   if (index == 0)
1584   {
1585     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1586     return 0;
1587   }
1588   NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1589   if (table == 0)
1590   {
1591     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1592     return 0;
1593   }
1594 
1595   return getNdbIndexScanOperation(index, table);
1596 }
1597 
1598 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbIndexImpl * index,const NdbTableImpl * table)1599 NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
1600 					const NdbTableImpl* table)
1601 {
1602   if (theCommitStatus == Started){
1603     const NdbTableImpl * indexTable = index->getIndexTable();
1604     if (indexTable != 0){
1605       NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
1606       if(tOp)
1607       {
1608 	tOp->m_currentTable = table;
1609         // Mark that this really is an NdbIndexScanOperation
1610         tOp->m_type = NdbOperation::OrderedIndexScan;
1611       }
1612       return tOp;
1613     } else {
1614       setOperationErrorCodeAbort(4271);
1615       return NULL;
1616     }//if
1617   }
1618 
1619   setOperationErrorCodeAbort(4114);
1620   return NULL;
1621 }//NdbTransaction::getNdbIndexScanOperation()
1622 
1623 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index)1624 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
1625 {
1626   if (index)
1627   {
1628     /* This fetches the underlying table being indexed. */
1629     const NdbDictionary::Table *table=
1630       theNdb->theDictionary->getTable(index->getTable());
1631 
1632     if (table)
1633       return getNdbIndexScanOperation(index, table);
1634 
1635     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1636     return NULL;
1637   }
1638   setOperationErrorCodeAbort(4271);
1639   return NULL;
1640 }
1641 
1642 NdbIndexScanOperation*
getNdbIndexScanOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1643 NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
1644 					const NdbDictionary::Table * table)
1645 {
1646   if (index && table)
1647     return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
1648 				    & NdbTableImpl::getImpl(*table));
1649   setOperationErrorCodeAbort(4271);
1650   return NULL;
1651 }//NdbTransaction::getNdbIndexScanOperation()
1652 
1653 /*****************************************************************************
1654 NdbScanOperation* getNdbScanOperation(int aTableId);
1655 
1656 Return Value    Return a pointer to a NdbScanOperation object if getNdbScanOperation was succesful.
1657                 Return NULL: In all other case.
1658 Parameters:     tableId : Id of the database table beeing deleted.
1659 Remark:         Get an operation from NdbScanOperation object idlelist and get the NdbTransaction
1660                 object who was fetch by startTransaction pointing to this  operation
1661   	        getOperation will set the theTableId in the NdbScanOperation object, synchronous.
1662 *****************************************************************************/
1663 NdbIndexScanOperation*
getNdbScanOperation(const NdbTableImpl * tab)1664 NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
1665 {
1666   NdbIndexScanOperation* tOp;
1667 
1668   tOp = theNdb->getScanOperation();
1669   if (tOp == NULL)
1670     goto getNdbOp_error1;
1671 
1672   if (tOp->init(tab, this) != -1) {
1673     define_scan_op(tOp);
1674     // Mark that this NdbIndexScanOperation is used as NdbScanOperation
1675     tOp->m_type = NdbOperation::TableScan;
1676     return tOp;
1677   } else {
1678     theNdb->releaseScanOperation(tOp);
1679   }//if
1680   return NULL;
1681 
1682 getNdbOp_error1:
1683   setOperationErrorCodeAbort(4000);
1684   return NULL;
1685 }//NdbTransaction::getNdbScanOperation()
1686 
1687 void
remove_list(NdbOperation * & list,NdbOperation * op)1688 NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
1689   NdbOperation* tmp= list;
1690   if(tmp == op)
1691     list = op->next();
1692   else {
1693     while(tmp && tmp->next() != op) tmp = tmp->next();
1694     if(tmp)
1695       tmp->next(op->next());
1696   }
1697   op->next(NULL);
1698 }
1699 
1700 void
define_scan_op(NdbIndexScanOperation * tOp)1701 NdbTransaction::define_scan_op(NdbIndexScanOperation * tOp){
1702   // Link scan operation into list of cursor operations
1703   if (m_theLastScanOperation == NULL)
1704     m_theFirstScanOperation = m_theLastScanOperation = tOp;
1705   else {
1706     m_theLastScanOperation->next(tOp);
1707     m_theLastScanOperation = tOp;
1708   }
1709   tOp->next(NULL);
1710 }
1711 
1712 NdbScanOperation*
getNdbScanOperation(const NdbDictionary::Table * table)1713 NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
1714 {
1715   if (table)
1716     return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
1717   else
1718     return NULL;
1719 }//NdbTransaction::getNdbScanOperation()
1720 
1721 
1722 // IndexOperation
1723 /*****************************************************************************
1724 NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
1725 					const char* aTableName);
1726 
1727 Return Value    Return a pointer to an NdbIndexOperation object if
1728                 getNdbIndexOperation was succesful.
1729                 Return NULL : In all other case.
1730 Parameters:     aTableName : Name of the database table.
1731 Remark:         Get an operation from NdbIndexOperation idlelist and get the NdbTransaction object
1732 		who was fetch by startTransaction pointing to this operation
1733 		getOperation will set the theTableId in the NdbIndexOperation object.synchronous
1734 ******************************************************************************/
1735 NdbIndexOperation*
getNdbIndexOperation(const char * anIndexName,const char * aTableName)1736 NdbTransaction::getNdbIndexOperation(const char* anIndexName,
1737                                     const char* aTableName)
1738 {
1739   if (theCommitStatus == Started) {
1740     NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
1741     NdbIndexImpl * index;
1742 
1743     if (table == 0)
1744     {
1745       setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1746       return NULL;
1747     }
1748 
1749     if (table->m_frm.get_data())
1750     {
1751       // This unique index is defined from SQL level
1752       static const char* uniqueSuffix= "$unique";
1753       BaseString uniqueIndexName(anIndexName);
1754       uniqueIndexName.append(uniqueSuffix);
1755       index = theNdb->theDictionary->getIndex(uniqueIndexName.c_str(),
1756 					      aTableName);
1757     }
1758     else
1759       index = theNdb->theDictionary->getIndex(anIndexName,
1760 					      aTableName);
1761     if(table != 0 && index != 0){
1762       return getNdbIndexOperation(index, table);
1763     }
1764 
1765     if(index == 0){
1766       setOperationErrorCodeAbort(4243);
1767       return NULL;
1768     }
1769 
1770     setOperationErrorCodeAbort(4243);
1771     return NULL;
1772   }
1773 
1774   setOperationErrorCodeAbort(4114);
1775   return 0;
1776 }//NdbTransaction::getNdbIndexOperation()
1777 
1778 /*****************************************************************************
1779 NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
1780 
1781 Return Value    Return a pointer to a NdbIndexOperation object if getNdbIndexOperation was succesful.
1782                 Return NULL: In all other case.
1783 Parameters:     tableId : Id of the database table beeing deleted.
1784 Remark:         Get an operation from NdbIndexOperation object idlelist and get the NdbTransaction
1785                 object who was fetch by startTransaction pointing to this  operation
1786   	        getOperation will set the theTableId in the NdbIndexOperation object, synchronous.
1787 *****************************************************************************/
1788 NdbIndexOperation*
getNdbIndexOperation(const NdbIndexImpl * anIndex,const NdbTableImpl * aTable,NdbOperation * aNextOp,bool useRec)1789 NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
1790                                      const NdbTableImpl * aTable,
1791                                      NdbOperation* aNextOp,
1792                                      bool useRec)
1793 {
1794   NdbIndexOperation* tOp;
1795 
1796   tOp = theNdb->getIndexOperation();
1797   if (tOp == NULL)
1798     goto getNdbOp_error1;
1799   if (aNextOp == NULL) {
1800     if (theLastOpInList != NULL) {
1801        theLastOpInList->next(tOp);
1802        theLastOpInList = tOp;
1803     } else {
1804        theLastOpInList = tOp;
1805        theFirstOpInList = tOp;
1806     }//if
1807     tOp->next(NULL);
1808   } else {
1809     // add before the given op
1810     if (theFirstOpInList == aNextOp) {
1811       theFirstOpInList = tOp;
1812     } else {
1813       NdbOperation* aLoopOp = theFirstOpInList;
1814       while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1815         aLoopOp = aLoopOp->next();
1816       assert(aLoopOp != NULL);
1817       aLoopOp->next(tOp);
1818     }
1819     tOp->next(aNextOp);
1820   }
1821   if (tOp->indxInit(anIndex, aTable, this, useRec)!= -1) {
1822     return tOp;
1823   } else {
1824     theNdb->releaseOperation(tOp);
1825   }//if
1826   return NULL;
1827 
1828  getNdbOp_error1:
1829   setOperationErrorCodeAbort(4000);
1830   return NULL;
1831 }//NdbTransaction::getNdbIndexOperation()
1832 
1833 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index)1834 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
1835 {
1836   if (index)
1837   {
1838     const NdbDictionary::Table *table=
1839       theNdb->theDictionary->getTable(index->getTable());
1840 
1841     if (table)
1842       return getNdbIndexOperation(index, table);
1843 
1844     setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1845     return NULL;
1846   }
1847   setOperationErrorCodeAbort(4271);
1848   return NULL;
1849 }
1850 
1851 NdbIndexOperation*
getNdbIndexOperation(const NdbDictionary::Index * index,const NdbDictionary::Table * table)1852 NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
1853 				    const NdbDictionary::Table * table)
1854 {
1855   if (index && table)
1856     return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
1857 				& NdbTableImpl::getImpl(*table));
1858 
1859   setOperationErrorCodeAbort(4271);
1860   return NULL;
1861 }//NdbTransaction::getNdbIndexOperation()
1862 
1863 
1864 /*******************************************************************************
1865 int  receiveTCSEIZECONF(NdbApiSignal* aSignal);
1866 
1867 Return Value:  Return 0 : receiveTCSEIZECONF was successful.
1868                Return -1: In all other case.
1869 Parameters:    aSignal: The signal object pointer.
1870 Remark:        Sets TC Connect pointer at reception of TCSEIZECONF.
1871 *******************************************************************************/
1872 int
receiveTCSEIZECONF(const NdbApiSignal * aSignal)1873 NdbTransaction::receiveTCSEIZECONF(const NdbApiSignal* aSignal)
1874 {
1875   if (theStatus != Connecting)
1876   {
1877     return -1;
1878   } else
1879   {
1880     theTCConPtr = (Uint32)aSignal->readData(2);
1881     if (aSignal->getLength() >= 3)
1882     {
1883       m_tcRef = aSignal->readData(3);
1884     }
1885     else
1886     {
1887       m_tcRef = numberToRef(DBTC, theDBnode);
1888     }
1889 
1890     assert(m_tcRef == aSignal->theSendersBlockRef);
1891 
1892     theStatus = Connected;
1893   }
1894   return 0;
1895 }//NdbTransaction::receiveTCSEIZECONF()
1896 
1897 /*******************************************************************************
1898 int  receiveTCSEIZEREF(NdbApiSignal* aSignal);
1899 
1900 Return Value:  Return 0 : receiveTCSEIZEREF was successful.
1901                Return -1: In all other case.
1902 Parameters:    aSignal: The signal object pointer.
1903 Remark:        Sets TC Connect pointer.
1904 *******************************************************************************/
1905 int
receiveTCSEIZEREF(const NdbApiSignal * aSignal)1906 NdbTransaction::receiveTCSEIZEREF(const NdbApiSignal* aSignal)
1907 {
1908   DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
1909   if (theStatus != Connecting)
1910   {
1911     DBUG_RETURN(-1);
1912   } else
1913   {
1914     theStatus = ConnectFailure;
1915     theNdb->theError.code = aSignal->readData(2);
1916     DBUG_PRINT("info",("error code %d, %s",
1917 		       theNdb->getNdbError().code,
1918 		       theNdb->getNdbError().message));
1919     DBUG_RETURN(0);
1920   }
1921 }//NdbTransaction::receiveTCSEIZEREF()
1922 
1923 /*******************************************************************************
1924 int  receiveTCRELEASECONF(NdbApiSignal* aSignal);
1925 
1926 Return Value:  Return 0 : receiveTCRELEASECONF was successful.
1927                Return -1: In all other case.
1928 Parameters:    aSignal: The signal object pointer.
1929 Remark:         DisConnect TC Connect pointer to NDBAPI.
1930 *******************************************************************************/
1931 int
receiveTCRELEASECONF(const NdbApiSignal * aSignal)1932 NdbTransaction::receiveTCRELEASECONF(const NdbApiSignal* aSignal)
1933 {
1934   if (theStatus != DisConnecting)
1935   {
1936     return -1;
1937   } else
1938   {
1939     theStatus = NotConnected;
1940   }
1941   return 0;
1942 }//NdbTransaction::receiveTCRELEASECONF()
1943 
1944 /*******************************************************************************
1945 int  receiveTCRELEASEREF(NdbApiSignal* aSignal);
1946 
1947 Return Value:  Return 0 : receiveTCRELEASEREF was successful.
1948                Return -1: In all other case.
1949 Parameters:    aSignal: The signal object pointer.
1950 Remark:        DisConnect TC Connect pointer to NDBAPI Failure.
1951 *******************************************************************************/
1952 int
receiveTCRELEASEREF(const NdbApiSignal * aSignal)1953 NdbTransaction::receiveTCRELEASEREF(const NdbApiSignal* aSignal)
1954 {
1955   if (theStatus != DisConnecting) {
1956     return -1;
1957   } else {
1958     theStatus = ConnectFailure;
1959     theNdb->theError.code = aSignal->readData(2);
1960     return 0;
1961   }//if
1962 }//NdbTransaction::receiveTCRELEASEREF()
1963 
1964 /******************************************************************************
1965 int  receiveTC_COMMITCONF(NdbApiSignal* aSignal);
1966 
1967 Return Value:  Return 0 : receiveTC_COMMITCONF was successful.
1968                Return -1: In all other case.
1969 Parameters:    aSignal: The signal object pointer.
1970 Remark:
1971 ******************************************************************************/
1972 int
receiveTC_COMMITCONF(const TcCommitConf * commitConf,Uint32 len)1973 NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf,
1974                                      Uint32 len)
1975 {
1976   if(checkState_TransId(&commitConf->transId1)){
1977     theCommitStatus = Committed;
1978     theCompletionStatus = CompletedSuccess;
1979     Uint32 tGCI_hi = commitConf->gci_hi;
1980     Uint32 tGCI_lo = commitConf->gci_lo;
1981     if (unlikely(len < TcCommitConf::SignalLength))
1982     {
1983       tGCI_lo = 0;
1984     }
1985     Uint64 tGCI = Uint64(tGCI_lo) | (Uint64(tGCI_hi) << 32);
1986     theGlobalCheckpointId = tGCI;
1987     // theGlobalCheckpointId == 0 if NoOp transaction
1988     if (tGCI)
1989       *p_latest_trans_gci = tGCI;
1990     return 0;
1991   } else {
1992 #ifdef NDB_NO_DROPPED_SIGNAL
1993     abort();
1994 #endif
1995   }
1996   return -1;
1997 }//NdbTransaction::receiveTC_COMMITCONF()
1998 
1999 /******************************************************************************
2000 int  receiveTC_COMMITREF(NdbApiSignal* aSignal);
2001 
2002 Return Value:  Return 0 : receiveTC_COMMITREF was successful.
2003                Return -1: In all other case.
2004 Parameters:    aSignal: The signal object pointer.
2005 Remark:
2006 ******************************************************************************/
2007 int
receiveTC_COMMITREF(const NdbApiSignal * aSignal)2008 NdbTransaction::receiveTC_COMMITREF(const NdbApiSignal* aSignal)
2009 {
2010   const TcCommitRef * ref = CAST_CONSTPTR(TcCommitRef, aSignal->getDataPtr());
2011   if(checkState_TransId(&ref->transId1)){
2012     setOperationErrorCodeAbort(ref->errorCode);
2013     theCommitStatus = Aborted;
2014     theCompletionStatus = CompletedFailure;
2015     theReturnStatus = ReturnFailure;
2016     return 0;
2017   } else {
2018 #ifdef NDB_NO_DROPPED_SIGNAL
2019     abort();
2020 #endif
2021   }
2022 
2023   return -1;
2024 }//NdbTransaction::receiveTC_COMMITREF()
2025 
2026 /******************************************************************************
2027 int  receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
2028 
2029 Return Value:  Return 0 : receiveTCROLLBACKCONF was successful.
2030                Return -1: In all other case.
2031 Parameters:    aSignal: The signal object pointer.
2032 Remark:
2033 ******************************************************************************/
2034 int
receiveTCROLLBACKCONF(const NdbApiSignal * aSignal)2035 NdbTransaction::receiveTCROLLBACKCONF(const NdbApiSignal* aSignal)
2036 {
2037   if(checkState_TransId(aSignal->getDataPtr() + 1)){
2038     theCommitStatus = Aborted;
2039     theCompletionStatus = CompletedSuccess;
2040     return 0;
2041   } else {
2042 #ifdef NDB_NO_DROPPED_SIGNAL
2043     abort();
2044 #endif
2045   }
2046 
2047   return -1;
2048 }//NdbTransaction::receiveTCROLLBACKCONF()
2049 
2050 /*******************************************************************************
2051 int  receiveTCROLLBACKREF(NdbApiSignal* aSignal);
2052 
2053 Return Value:  Return 0 : receiveTCROLLBACKREF was successful.
2054                Return -1: In all other case.
2055 Parameters:    aSignal: The signal object pointer.
2056 Remark:
2057 *******************************************************************************/
2058 int
receiveTCROLLBACKREF(const NdbApiSignal * aSignal)2059 NdbTransaction::receiveTCROLLBACKREF(const NdbApiSignal* aSignal)
2060 {
2061   if(checkState_TransId(aSignal->getDataPtr() + 1)){
2062     setOperationErrorCodeAbort(aSignal->readData(4));
2063     theCommitStatus = Aborted;
2064     theCompletionStatus = CompletedFailure;
2065     theReturnStatus = ReturnFailure;
2066     return 0;
2067   } else {
2068 #ifdef NDB_NO_DROPPED_SIGNAL
2069     abort();
2070 #endif
2071   }
2072 
2073   return -1;
2074 }//NdbTransaction::receiveTCROLLBACKREF()
2075 
2076 /*****************************************************************************
2077 int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
2078 
2079 Return Value:   Return 0 : send was succesful.
2080                 Return -1: In all other case.
2081 Parameters:     aSignal: the signal object that contains the
2082                 TCROLLBACKREP signal from TC.
2083 Remark:         Handles the reception of the ROLLBACKREP signal.
2084 *****************************************************************************/
2085 int
receiveTCROLLBACKREP(const NdbApiSignal * aSignal)2086 NdbTransaction::receiveTCROLLBACKREP( const NdbApiSignal* aSignal)
2087 {
2088   DBUG_ENTER("NdbTransaction::receiveTCROLLBACKREP");
2089 
2090   /****************************************************************************
2091 Check that we are expecting signals from this transaction and that it doesn't
2092 belong to a transaction already completed. Simply ignore messages from other
2093 transactions.
2094   ****************************************************************************/
2095   if(checkState_TransId(aSignal->getDataPtr() + 1)){
2096     theError.code = aSignal->readData(4);// Override any previous errors
2097     if (aSignal->getLength() == TcRollbackRep::SignalLength)
2098     {
2099       // Signal may contain additional error data
2100       theError.details = (char *) aSignal->readData(5);
2101     }
2102 
2103     /**********************************************************************/
2104     /*	A serious error has occured. This could be due to deadlock or */
2105     /*	lack of resources or simply a programming error in NDB. This  */
2106     /*	transaction will be aborted. Actually it has already been     */
2107     /*	and we only need to report completion and return with the     */
2108     /*	error code to the application.				      */
2109     /**********************************************************************/
2110     theCompletionStatus = CompletedFailure;
2111     theCommitStatus = Aborted;
2112     theReturnStatus = ReturnFailure;
2113     DBUG_RETURN(0);
2114   } else {
2115 #ifdef NDB_NO_DROPPED_SIGNAL
2116     abort();
2117 #endif
2118   }
2119 
2120   DBUG_RETURN(-1);
2121 }//NdbTransaction::receiveTCROLLBACKREP()
2122 
2123 /*******************************************************************************
2124 int  receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
2125 
2126 Return Value:  Return 0 : receiveTCKEYCONF was successful.
2127                Return -1: In all other case.
2128 Parameters:    aSignal: The signal object pointer.
2129 Remark:
2130 *******************************************************************************/
2131 int
receiveTCKEYCONF(const TcKeyConf * keyConf,Uint32 aDataLength)2132 NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
2133 {
2134   const Uint32 tTemp = keyConf->confInfo;
2135   /***************************************************************************
2136 Check that we are expecting signals from this transaction and that it
2137 doesn't belong to a transaction already completed. Simply ignore messages
2138 from other transactions.
2139   ***************************************************************************/
2140   if(checkState_TransId(&keyConf->transId1)){
2141 
2142     const Uint32 tNoOfOperations = TcKeyConf::getNoOfOperations(tTemp);
2143     const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
2144 
2145     const Uint32* tPtr = (Uint32 *)&keyConf->operations[0];
2146     Uint32 tNoComp = theNoOfOpCompleted;
2147     for (Uint32 i = 0; i < tNoOfOperations ; i++) {
2148       NdbReceiver* const tReceiver =
2149         theNdb->void2rec(theNdb->int2void(*tPtr++));
2150       const Uint32 tAttrInfoLen = *tPtr++;
2151       if(tReceiver && tReceiver->checkMagicNumber()){
2152         Uint32 done;
2153         if(tReceiver->getType()==NdbReceiver::NDB_QUERY_OPERATION){
2154           /* This signal is part of a linked operation.*/
2155           done = ((NdbQueryOperationImpl*)(tReceiver->m_owner))
2156             ->getQuery().execTCKEYCONF();
2157         }else{
2158           done = tReceiver->execTCOPCONF(tAttrInfoLen);
2159         }
2160 	if(tAttrInfoLen > TcKeyConf::DirtyReadBit){
2161 	  Uint32 node = tAttrInfoLen & (~TcKeyConf::DirtyReadBit);
2162           NdbNodeBitmask::set(m_db_nodes, node);
2163           if(NdbNodeBitmask::get(m_failed_db_nodes, node) && !done)
2164 	  {
2165             done = 1;
2166             // 4119 = "Simple/dirty read failed due to node failure"
2167             tReceiver->setErrorCode(4119);
2168             theCompletionStatus = CompletedFailure;
2169             theReturnStatus = NdbTransaction::ReturnFailure;
2170 	  }
2171 	}
2172 	tNoComp += done;
2173       } else { // if(tReceiver && tReceiver->checkMagicNumber())
2174  	return -1;
2175       }//if
2176     }//for
2177     theNoOfOpCompleted = tNoComp;
2178     const Uint32 tNoSent = theNoOfOpSent;
2179     const Uint32 tGCI_hi = keyConf->gci_hi;
2180     Uint32       tGCI_lo = * tPtr; // After op(s)
2181     if (unlikely(aDataLength < TcKeyConf::StaticLength+1 + 2*tNoOfOperations))
2182     {
2183       tGCI_lo = 0;
2184     }
2185     const Uint64 tGCI = Uint64(tGCI_lo) | (Uint64(tGCI_hi) << 32);
2186     if (tCommitFlag == 1)
2187     {
2188       theCommitStatus = Committed;
2189       theGlobalCheckpointId = tGCI;
2190       if (tGCI) // Read(dirty) only transaction doesnt get GCI
2191       {
2192 	*p_latest_trans_gci = tGCI;
2193       }
2194     }
2195     else if (theLastExecOpInList &&
2196              theLastExecOpInList->theCommitIndicator == 1)
2197     {
2198       /**
2199        * We're waiting for a commit reply...
2200        */
2201       return -1;
2202     }//if
2203     if (tNoComp >= tNoSent)
2204     {
2205       return 0;	// No more operations to wait for
2206     }//if
2207      // Not completed the reception yet.
2208   } else {
2209 #ifdef NDB_NO_DROPPED_SIGNAL
2210     abort();
2211 #endif
2212   }
2213 
2214   return -1;
2215 }//NdbTransaction::receiveTCKEYCONF()
2216 
2217 /*****************************************************************************
2218 int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
2219 
2220 Return Value:   Return 0 : receive was completed.
2221                 Return -1: In all other case.
2222 Parameters:     aSignal: the signal object that contains the
2223                 TCKEY_FAILCONF signal from TC.
2224 Remark:         Handles the reception of the TCKEY_FAILCONF signal.
2225 *****************************************************************************/
2226 int
receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)2227 NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
2228 {
2229   NdbOperation*	tOp;
2230   /*
2231     Check that we are expecting signals from this transaction and that it
2232     doesn't belong  to a transaction already completed. Simply ignore
2233     messages from other transactions.
2234   */
2235   if(checkState_TransId(&failConf->transId1)){
2236     /*
2237       A node failure of the TC node occured. The transaction has
2238       been committed.
2239     */
2240     theCommitStatus = Committed;
2241     tOp = theFirstExecOpInList;
2242     while (tOp != NULL) {
2243       /*
2244        * Check if the transaction expected read values...
2245        * If it did some of them might have gotten lost even if we succeeded
2246        * in committing the transaction.
2247        */
2248       switch(tOp->theOperationType){
2249       case NdbOperation::UpdateRequest:
2250       case NdbOperation::InsertRequest:
2251       case NdbOperation::DeleteRequest:
2252       case NdbOperation::WriteRequest:
2253       case NdbOperation::UnlockRequest:
2254       case NdbOperation::RefreshRequest:
2255 	tOp = tOp->next();
2256 	break;
2257       case NdbOperation::ReadRequest:
2258       case NdbOperation::ReadExclusive:
2259       case NdbOperation::OpenScanRequest:
2260       case NdbOperation::OpenRangeScanRequest:
2261 	theCompletionStatus = CompletedFailure;
2262 	theReturnStatus = NdbTransaction::ReturnFailure;
2263 	setOperationErrorCodeAbort(4115);
2264 	tOp = NULL;
2265 	break;
2266       case NdbOperation::NotDefined:
2267       case NdbOperation::NotDefined2:
2268 	assert(false);
2269 	break;
2270       }//if
2271     }//while
2272     theReleaseOnClose = true;
2273     return 0;
2274   } else {
2275 #ifdef VM_TRACE
2276     ndbout_c("Recevied TCKEY_FAILCONF wo/ operation");
2277 #endif
2278   }
2279   return -1;
2280 }//NdbTransaction::receiveTCKEY_FAILCONF()
2281 
2282 /*************************************************************************
2283 int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
2284 
2285 Return Value:   Return 0 : receive was completed.
2286                 Return -1: In all other case.
2287 Parameters:     aSignal: the signal object that contains the
2288                 TCKEY_FAILREF signal from TC.
2289 Remark:         Handles the reception of the TCKEY_FAILREF signal.
2290 **************************************************************************/
2291 int
receiveTCKEY_FAILREF(const NdbApiSignal * aSignal)2292 NdbTransaction::receiveTCKEY_FAILREF(const NdbApiSignal* aSignal)
2293 {
2294   /*
2295     Check that we are expecting signals from this transaction and
2296     that it doesn't belong to a transaction already
2297     completed. Simply ignore messages from other transactions.
2298   */
2299   if(checkState_TransId(aSignal->getDataPtr()+1)){
2300     /*
2301       We received an indication of that this transaction was aborted due to a
2302       node failure.
2303     */
2304     if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
2305       /*
2306 	We were in the process of sending a rollback anyways. We will
2307 	report it as a success.
2308       */
2309       theCompletionStatus = NdbTransaction::CompletedSuccess;
2310     } else {
2311       theReturnStatus = NdbTransaction::ReturnFailure;
2312       theCompletionStatus = NdbTransaction::CompletedFailure;
2313       theError.code = 4031;
2314     }//if
2315     theReleaseOnClose = true;
2316     theCommitStatus = NdbTransaction::Aborted;
2317     return 0;
2318   } else {
2319 #ifdef VM_TRACE
2320     ndbout_c("Recevied TCKEY_FAILREF wo/ operation");
2321 #endif
2322   }
2323   return -1;
2324 }//NdbTransaction::receiveTCKEY_FAILREF()
2325 
2326 /*******************************************************************************
2327 int OpCompletedFailure();
2328 
2329 Return Value:  Return 0 : OpCompleteSuccess was successful.
2330                Return -1: In all other case.
2331 Remark:        An operation was completed with failure.
2332 *******************************************************************************/
2333 int
OpCompleteFailure()2334 NdbTransaction::OpCompleteFailure()
2335 {
2336   Uint32 tNoComp = theNoOfOpCompleted;
2337   Uint32 tNoSent = theNoOfOpSent;
2338 
2339   tNoComp++;
2340   theNoOfOpCompleted = tNoComp;
2341 
2342   return (tNoComp == tNoSent) ? 0 : -1;
2343 }//NdbTransaction::OpCompleteFailure()
2344 
2345 /******************************************************************************
2346 int OpCompleteSuccess();
2347 
2348 Return Value:  Return 0 : OpCompleteSuccess was successful.
2349                Return -1: In all other case.
2350 Remark:        An operation was completed with success.
2351 *******************************************************************************/
2352 int
OpCompleteSuccess()2353 NdbTransaction::OpCompleteSuccess()
2354 {
2355   Uint32 tNoComp = theNoOfOpCompleted;
2356   Uint32 tNoSent = theNoOfOpSent;
2357   tNoComp++;
2358   theNoOfOpCompleted = tNoComp;
2359 #ifdef JW_TEST
2360   ndbout << "NdbTransaction::OpCompleteSuccess() tNoComp=" << tNoComp
2361 	 << " tNoSent=" << tNoSent << endl;
2362 #endif
2363   if (tNoComp == tNoSent) { // Last operation completed
2364     return 0;
2365   } else if (tNoComp < tNoSent) {
2366     return -1;	// Continue waiting for more signals
2367   } else {
2368     setOperationErrorCodeAbort(4113);	// Too many operations,
2369                                         // stop waiting for more
2370     theCompletionStatus = NdbTransaction::CompletedFailure;
2371     theReturnStatus = NdbTransaction::ReturnFailure;
2372     return 0;
2373   }//if
2374 }//NdbTransaction::OpCompleteSuccess()
2375 
2376 /******************************************************************************
2377  int            getGCI();
2378 
2379 Remark:		Get global checkpoint identity of the transaction
2380 *******************************************************************************/
2381 int
getGCI()2382 NdbTransaction::getGCI()
2383 {
2384   Uint64 val;
2385   if (getGCI(&val) == 0)
2386   {
2387     return (int)(val >> 32);
2388   }
2389   return -1;
2390 }
2391 
2392 int
getGCI(Uint64 * val)2393 NdbTransaction::getGCI(Uint64 * val)
2394 {
2395   if (theCommitStatus == NdbTransaction::Committed)
2396   {
2397     if (val)
2398     {
2399       * val = theGlobalCheckpointId;
2400     }
2401     return 0;
2402   }
2403   return -1;
2404 }
2405 
2406 /*******************************************************************************
2407 Uint64 getTransactionId(void);
2408 
2409 Remark:        Get the transaction identity.
2410 *******************************************************************************/
2411 Uint64
getTransactionId()2412 NdbTransaction::getTransactionId()
2413 {
2414   return theTransactionId;
2415 }//NdbTransaction::getTransactionId()
2416 
2417 NdbTransaction::CommitStatusType
commitStatus()2418 NdbTransaction::commitStatus()
2419 {
2420   return theCommitStatus;
2421 }//NdbTransaction::commitStatus()
2422 
2423 int
getNdbErrorLine()2424 NdbTransaction::getNdbErrorLine()
2425 {
2426   return theErrorLine;
2427 }
2428 
2429 NdbOperation*
getNdbErrorOperation()2430 NdbTransaction::getNdbErrorOperation()
2431 {
2432   return theErrorOperation;
2433 }//NdbTransaction::getNdbErrorOperation()
2434 
2435 
2436 const NdbOperation*
getNdbErrorOperation() const2437 NdbTransaction::getNdbErrorOperation() const
2438 {
2439   return theErrorOperation;
2440 }//NdbTransaction::getNdbErrorOperation()
2441 
2442 
2443 const NdbOperation *
getNextCompletedOperation(const NdbOperation * current) const2444 NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
2445   if(current == 0)
2446     return theCompletedFirstOp;
2447   return current->theNext;
2448 }
2449 
2450 NdbOperation *
setupRecordOp(NdbOperation::OperationType type,NdbOperation::LockMode lock_mode,NdbOperation::AbortOption default_ao,const NdbRecord * key_record,const char * key_row,const NdbRecord * attribute_record,const char * attribute_row,const unsigned char * mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions,const NdbLockHandle * lh)2451 NdbTransaction::setupRecordOp(NdbOperation::OperationType type,
2452                               NdbOperation::LockMode lock_mode,
2453                               NdbOperation::AbortOption default_ao,
2454                               const NdbRecord *key_record,
2455                               const char *key_row,
2456                               const NdbRecord *attribute_record,
2457                               const char *attribute_row,
2458                               const unsigned char *mask,
2459                               const NdbOperation::OperationOptions *opts,
2460                               Uint32 sizeOfOptions,
2461                               const NdbLockHandle* lh)
2462 {
2463   NdbOperation *op;
2464 
2465   /* Check that we've got a base table record for the attribute record */
2466   if (attribute_record->flags & NdbRecord::RecIsIndex)
2467   {
2468     /* Result or attribute record must be a base
2469        table ndbrecord, not an index ndbrecord */
2470     setOperationErrorCodeAbort(4340);
2471     return NULL;
2472   }
2473   /*
2474     We are actually passing the table object for the index here, not the table
2475     object of the underlying table. But we only need it to keep the existing
2476     NdbOperation code happy, it is not actually used for NdbRecord operation.
2477     We will eliminate the need for passing table and index completely when
2478     implementing WL#3707.
2479   */
2480   if (key_record->flags & NdbRecord::RecIsIndex)
2481   {
2482     op= getNdbIndexOperation(key_record->table->m_index,
2483                              attribute_record->table, NULL, true);
2484   }
2485   else
2486   {
2487     if (key_record->tableId != attribute_record->tableId)
2488     {
2489       setOperationErrorCodeAbort(4287);
2490       return NULL;
2491     }
2492     op= getNdbOperation(attribute_record->table, NULL, true);
2493   }
2494   if(!op)
2495     return NULL;
2496 
2497   op->theStatus= NdbOperation::UseNdbRecord;
2498   op->theOperationType= type;
2499   op->theErrorLine++;
2500   op->theLockMode= lock_mode;
2501   op->m_key_record= key_record;
2502   op->m_key_row= key_row;
2503   op->m_attribute_record= attribute_record;
2504   op->m_attribute_row= attribute_row;
2505   op->m_abortOption=default_ao;
2506   op->theLockHandle = const_cast<NdbLockHandle*>(lh);
2507 
2508   AttributeMask readMask;
2509   attribute_record->copyMask(readMask.rep.data, mask);
2510 
2511   /*
2512    * Handle options
2513    */
2514   if (opts != NULL)
2515   {
2516     /* Delegate to static method in NdbOperation */
2517     Uint32 result = NdbOperation::handleOperationOptions (type,
2518                                                           opts,
2519                                                           sizeOfOptions,
2520                                                           op);
2521     if (result !=0)
2522     {
2523       setOperationErrorCodeAbort(result);
2524       return NULL;
2525     }
2526   }
2527 
2528   /* Handle delete + blobs */
2529   if (type == NdbOperation::DeleteRequest &&
2530       (attribute_record->flags & NdbRecord::RecTableHasBlob))
2531   {
2532     /* Need to link in all the Blob handles for delete
2533      * If there is a pre-read, check that no Blobs have
2534      * been asked for
2535      */
2536     if (op->getBlobHandlesNdbRecordDelete(this,
2537                                           (attribute_row != NULL),
2538                                           readMask.rep.data) == -1)
2539       return NULL;
2540   }
2541   else if (unlikely((attribute_record->flags & NdbRecord::RecHasBlob) &&
2542                     (type != NdbOperation::UnlockRequest)))
2543   {
2544     /* Create blob handles for non-delete, non-unlock operations */
2545     if (op->getBlobHandlesNdbRecord(this, readMask.rep.data) == -1)
2546       return NULL;
2547   }
2548 
2549   /*
2550    * Now prepare the signals to be sent...
2551    *
2552    */
2553   int returnCode=op->buildSignalsNdbRecord(theTCConPtr, theTransactionId,
2554                                            readMask.rep.data);
2555 
2556   if (returnCode)
2557   {
2558     // buildSignalsNdbRecord should have set the error status
2559     // So we can return NULL
2560     return NULL;
2561   }
2562 
2563   return op;
2564 }
2565 
2566 
2567 
2568 const NdbOperation *
readTuple(const NdbRecord * key_rec,const char * key_row,const NdbRecord * result_rec,char * result_row,NdbOperation::LockMode lock_mode,const unsigned char * result_mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2569 NdbTransaction::readTuple(const NdbRecord *key_rec, const char *key_row,
2570                           const NdbRecord *result_rec, char *result_row,
2571                           NdbOperation::LockMode lock_mode,
2572                           const unsigned char *result_mask,
2573                           const NdbOperation::OperationOptions *opts,
2574                           Uint32 sizeOfOptions)
2575 {
2576   /* Check that the NdbRecord specifies the full primary key. */
2577   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2578   {
2579     setOperationErrorCodeAbort(4292);
2580     return NULL;
2581   }
2582 
2583   /* It appears that unique index operations do no support readCommitted. */
2584   if (key_rec->flags & NdbRecord::RecIsIndex &&
2585       lock_mode == NdbOperation::LM_CommittedRead)
2586     lock_mode= NdbOperation::LM_Read;
2587 
2588   NdbOperation::OperationType opType=
2589     (lock_mode == NdbOperation::LM_Exclusive ?
2590        NdbOperation::ReadExclusive : NdbOperation::ReadRequest);
2591   NdbOperation *op= setupRecordOp(opType, lock_mode,
2592                                   NdbOperation::AO_IgnoreError,
2593                                   key_rec, key_row,
2594                                   result_rec, result_row, result_mask,
2595                                   opts,
2596                                   sizeOfOptions);
2597   if (!op)
2598     return NULL;
2599 
2600   if (op->theLockMode == NdbOperation::LM_CommittedRead)
2601   {
2602     op->theDirtyIndicator= 1;
2603     op->theSimpleIndicator= 1;
2604   }
2605   else
2606   {
2607     if (op->theLockMode == NdbOperation::LM_SimpleRead)
2608     {
2609       op->theSimpleIndicator = 1;
2610     }
2611 
2612 
2613     theSimpleState= 0;
2614   }
2615 
2616   /* Setup the record/row for receiving the results. */
2617   op->theReceiver.getValues(result_rec, result_row);
2618 
2619   return op;
2620 }
2621 
2622 const NdbOperation *
insertTuple(const NdbRecord * key_rec,const char * key_row,const NdbRecord * attr_rec,const char * attr_row,const unsigned char * mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2623 NdbTransaction::insertTuple(const NdbRecord *key_rec, const char *key_row,
2624                             const NdbRecord *attr_rec, const char *attr_row,
2625                             const unsigned char *mask,
2626                             const NdbOperation::OperationOptions *opts,
2627                             Uint32 sizeOfOptions)
2628 {
2629   /* Check that the NdbRecord specifies the full primary key. */
2630   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2631   {
2632     setOperationErrorCodeAbort(4292);
2633     return NULL;
2634   }
2635 
2636   NdbOperation *op= setupRecordOp(NdbOperation::InsertRequest,
2637                                   NdbOperation::LM_Exclusive,
2638                                   NdbOperation::AbortOnError,
2639                                   key_rec, key_row,
2640                                   attr_rec, attr_row, mask,
2641                                   opts,
2642                                   sizeOfOptions);
2643   if (!op)
2644     return NULL;
2645 
2646   theSimpleState= 0;
2647 
2648   return op;
2649 }
2650 
2651 const NdbOperation *
insertTuple(const NdbRecord * combined_rec,const char * combined_row,const unsigned char * mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2652 NdbTransaction::insertTuple(const NdbRecord *combined_rec, const char *combined_row,
2653                             const unsigned char *mask,
2654                             const NdbOperation::OperationOptions *opts,
2655                             Uint32 sizeOfOptions)
2656 {
2657   return insertTuple(combined_rec, combined_row,
2658                      combined_rec, combined_row,
2659                      mask,
2660                      opts,
2661                      sizeOfOptions);
2662 }
2663 
2664 const NdbOperation *
updateTuple(const NdbRecord * key_rec,const char * key_row,const NdbRecord * attr_rec,const char * attr_row,const unsigned char * mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2665 NdbTransaction::updateTuple(const NdbRecord *key_rec, const char *key_row,
2666                             const NdbRecord *attr_rec, const char *attr_row,
2667                             const unsigned char *mask,
2668                             const NdbOperation::OperationOptions *opts,
2669                             Uint32 sizeOfOptions)
2670 {
2671   /* Check that the NdbRecord specifies the full primary key. */
2672   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2673   {
2674     setOperationErrorCodeAbort(4292);
2675     return NULL;
2676   }
2677 
2678   NdbOperation *op= setupRecordOp(NdbOperation::UpdateRequest,
2679                                   NdbOperation::LM_Exclusive,
2680                                   NdbOperation::AbortOnError,
2681                                   key_rec, key_row,
2682                                   attr_rec, attr_row, mask,
2683                                   opts,
2684                                   sizeOfOptions);
2685   if(!op)
2686     return op;
2687 
2688   theSimpleState= 0;
2689 
2690   return op;
2691 }
2692 
2693 const NdbOperation *
deleteTuple(const NdbRecord * key_rec,const char * key_row,const NdbRecord * result_rec,char * result_row,const unsigned char * result_mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2694 NdbTransaction::deleteTuple(const NdbRecord *key_rec,
2695                             const char *key_row,
2696                             const NdbRecord *result_rec,
2697                             char *result_row,
2698                             const unsigned char *result_mask,
2699                             const NdbOperation::OperationOptions* opts,
2700                             Uint32 sizeOfOptions)
2701 {
2702   /* Check that the key NdbRecord specifies the full primary key. */
2703   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2704   {
2705     setOperationErrorCodeAbort(4292);
2706     return NULL;
2707   }
2708 
2709   NdbOperation *op= setupRecordOp(NdbOperation::DeleteRequest,
2710                                   NdbOperation::LM_Exclusive,
2711                                   NdbOperation::AbortOnError,
2712                                   key_rec, key_row,
2713                                   result_rec, result_row, result_mask,
2714                                   opts,
2715                                   sizeOfOptions);
2716   if(!op)
2717     return op;
2718 
2719   theSimpleState= 0;
2720 
2721   if (result_row != NULL) // readBeforeDelete
2722   {
2723     /* Setup the record/row for receiving the results. */
2724     op->theReceiver.getValues(result_rec, result_row);
2725   }
2726 
2727   return op;
2728 }
2729 
2730 const NdbOperation *
writeTuple(const NdbRecord * key_rec,const char * key_row,const NdbRecord * attr_rec,const char * attr_row,const unsigned char * mask,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2731 NdbTransaction::writeTuple(const NdbRecord *key_rec, const char *key_row,
2732                            const NdbRecord *attr_rec, const char *attr_row,
2733                            const unsigned char *mask,
2734                            const NdbOperation::OperationOptions *opts,
2735                            Uint32 sizeOfOptions)
2736 {
2737   /* Check that the NdbRecord specifies the full primary key. */
2738   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2739   {
2740     setOperationErrorCodeAbort(4292);
2741     return NULL;
2742   }
2743 
2744   NdbOperation *op= setupRecordOp(NdbOperation::WriteRequest,
2745                                   NdbOperation::LM_Exclusive,
2746                                   NdbOperation::AbortOnError,
2747                                   key_rec, key_row,
2748                                   attr_rec, attr_row, mask,
2749                                   opts,
2750                                   sizeOfOptions);
2751   if(!op)
2752     return op;
2753 
2754   theSimpleState= 0;
2755 
2756   return op;
2757 }
2758 
2759 const NdbOperation *
refreshTuple(const NdbRecord * key_rec,const char * key_row,const NdbOperation::OperationOptions * opts,Uint32 sizeOfOptions)2760 NdbTransaction::refreshTuple(const NdbRecord *key_rec, const char *key_row,
2761                              const NdbOperation::OperationOptions *opts,
2762                              Uint32 sizeOfOptions)
2763 {
2764   /* Check TC node version lockless */
2765   {
2766     Uint32 tcVer = theNdb->theImpl->getNodeInfo(theDBnode).m_info.m_version;
2767     if (unlikely(! ndb_refresh_tuple(tcVer)))
2768     {
2769       /* Function not implemented yet */
2770       setOperationErrorCodeAbort(4003);
2771       return NULL;
2772     }
2773   }
2774 
2775   /* Check that the NdbRecord specifies the full primary key. */
2776   if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2777   {
2778     setOperationErrorCodeAbort(4292);
2779     return NULL;
2780   }
2781 
2782   Uint8 keymask[NDB_MAX_ATTRIBUTES_IN_TABLE/8];
2783   bzero(keymask, sizeof(keymask));
2784   for (Uint32 i = 0; i<key_rec->key_index_length; i++)
2785   {
2786     Uint32 id = key_rec->columns[key_rec->key_indexes[i]].attrId;
2787     keymask[(id / 8)] |= (1 << (id & 7));
2788   }
2789 
2790   NdbOperation *op= setupRecordOp(NdbOperation::RefreshRequest,
2791                                   NdbOperation::LM_Exclusive,
2792                                   NdbOperation::AbortOnError,
2793                                   key_rec, key_row,
2794                                   key_rec, key_row,
2795                                   keymask /* mask */,
2796                                   opts,
2797                                   sizeOfOptions);
2798   if(!op)
2799     return op;
2800 
2801   theSimpleState= 0;
2802 
2803   return op;
2804 }
2805 
2806 NdbScanOperation *
scanTable(const NdbRecord * result_record,NdbOperation::LockMode lock_mode,const unsigned char * result_mask,const NdbScanOperation::ScanOptions * options,Uint32 sizeOfOptions)2807 NdbTransaction::scanTable(const NdbRecord *result_record,
2808                           NdbOperation::LockMode lock_mode,
2809                           const unsigned char *result_mask,
2810                           const NdbScanOperation::ScanOptions *options,
2811                           Uint32 sizeOfOptions)
2812 {
2813   DBUG_ENTER("NdbTransaction::scanTable");
2814   DBUG_PRINT("info", ("Options=%p(0x%x)", options,
2815                       (options ? (unsigned)(options->optionsPresent) : 0)));
2816   /*
2817     Normal scan operations are created as NdbIndexScanOperations.
2818     The reason for this is that they can then share a pool of allocated
2819     objects.
2820   */
2821   NdbIndexScanOperation *op_idx=
2822     getNdbScanOperation(result_record->table);
2823 
2824   if (op_idx == NULL)
2825   {
2826     /* Memory allocation error */
2827     setOperationErrorCodeAbort(4000);
2828     DBUG_RETURN(NULL);
2829   }
2830 
2831   op_idx->m_scanUsingOldApi= false;
2832 
2833   /* The real work is done in NdbScanOperation */
2834   if (op_idx->scanTableImpl(result_record,
2835                             lock_mode,
2836                             result_mask,
2837                             options,
2838                             sizeOfOptions) == 0)
2839   {
2840     DBUG_RETURN(op_idx);
2841   }
2842 
2843   releaseScanOperation(&m_theFirstScanOperation, &m_theLastScanOperation,
2844                        op_idx);
2845   DBUG_RETURN(NULL);
2846 }
2847 
2848 
2849 
2850 NdbIndexScanOperation *
scanIndex(const NdbRecord * key_record,const NdbRecord * result_record,NdbOperation::LockMode lock_mode,const unsigned char * result_mask,const NdbIndexScanOperation::IndexBound * bound,const NdbScanOperation::ScanOptions * options,Uint32 sizeOfOptions)2851 NdbTransaction::scanIndex(const NdbRecord *key_record,
2852                           const NdbRecord *result_record,
2853                                 NdbOperation::LockMode lock_mode,
2854                           const unsigned char *result_mask,
2855                           const NdbIndexScanOperation::IndexBound *bound,
2856                           const NdbScanOperation::ScanOptions *options,
2857                           Uint32 sizeOfOptions)
2858 {
2859   /*
2860     Normal scan operations are created as NdbIndexScanOperations.
2861     The reason for this is that they can then share a pool of allocated
2862     objects.
2863   */
2864   NdbIndexScanOperation *op= getNdbScanOperation(key_record->table);
2865   if (op==NULL)
2866   {
2867     /* Memory allocation error */
2868     setOperationErrorCodeAbort(4000);
2869     return NULL;
2870   }
2871 
2872   op->m_scanUsingOldApi= false;
2873 
2874   /* Defer the rest of the work to NdbIndexScanOperation */
2875   if (op->scanIndexImpl(key_record,
2876                         result_record,
2877                         lock_mode,
2878                         result_mask,
2879                         bound,
2880                         options,
2881                         sizeOfOptions) != 0)
2882   {
2883     releaseScanOperation(&m_theFirstScanOperation, &m_theLastScanOperation, op);
2884     return NULL;
2885   }
2886 
2887   return op;
2888 } // ::scanIndex();
2889 
2890 Uint32
getMaxPendingBlobReadBytes() const2891 NdbTransaction::getMaxPendingBlobReadBytes() const
2892 {
2893   /* 0 == max */
2894   return (maxPendingBlobReadBytes ==
2895           (~Uint32(0)) ? 0 : maxPendingBlobReadBytes);
2896 };
2897 
2898 Uint32
getMaxPendingBlobWriteBytes() const2899 NdbTransaction::getMaxPendingBlobWriteBytes() const
2900 {
2901   /* 0 == max */
2902   return (maxPendingBlobWriteBytes ==
2903           (~Uint32(0)) ? 0 : maxPendingBlobWriteBytes);
2904 };
2905 
2906 void
setMaxPendingBlobReadBytes(Uint32 bytes)2907 NdbTransaction::setMaxPendingBlobReadBytes(Uint32 bytes)
2908 {
2909   /* 0 == max */
2910   maxPendingBlobReadBytes = (bytes?bytes : (~ Uint32(0)));
2911 }
2912 
2913 void
setMaxPendingBlobWriteBytes(Uint32 bytes)2914 NdbTransaction::setMaxPendingBlobWriteBytes(Uint32 bytes)
2915 {
2916   /* 0 == max */
2917   maxPendingBlobWriteBytes = (bytes?bytes : (~ Uint32(0)));
2918 }
2919 
2920 #ifdef VM_TRACE
2921 #define CASE(x) case x: ndbout << " " << #x; break
2922 void
printState()2923 NdbTransaction::printState()
2924 {
2925   ndbout << "con=" << hex << this << dec;
2926   ndbout << " node=" << getConnectedNodeId();
2927   switch (theStatus) {
2928   CASE(NotConnected);
2929   CASE(Connecting);
2930   CASE(Connected);
2931   CASE(DisConnecting);
2932   CASE(ConnectFailure);
2933   default: ndbout << (Uint32) theStatus;
2934   }
2935   switch (theListState) {
2936   CASE(NotInList);
2937   CASE(InPreparedList);
2938   CASE(InSendList);
2939   CASE(InCompletedList);
2940   default: ndbout << (Uint32) theListState;
2941   }
2942   switch (theSendStatus) {
2943   CASE(NotInit);
2944   CASE(InitState);
2945   CASE(sendOperations);
2946   CASE(sendCompleted);
2947   CASE(sendCOMMITstate);
2948   CASE(sendABORT);
2949   CASE(sendABORTfail);
2950   CASE(sendTC_ROLLBACK);
2951   CASE(sendTC_COMMIT);
2952   CASE(sendTC_OP);
2953   default: ndbout << (Uint32) theSendStatus;
2954   }
2955   switch (theCommitStatus) {
2956   CASE(NotStarted);
2957   CASE(Started);
2958   CASE(Committed);
2959   CASE(Aborted);
2960   CASE(NeedAbort);
2961   default: ndbout << (Uint32) theCommitStatus;
2962   }
2963   switch (theCompletionStatus) {
2964   CASE(NotCompleted);
2965   CASE(CompletedSuccess);
2966   CASE(CompletedFailure);
2967   CASE(DefinitionFailure);
2968   default: ndbout << (Uint32) theCompletionStatus;
2969   }
2970   ndbout << endl;
2971 }
2972 #undef CASE
2973 #endif
2974 
2975 int
report_node_failure(Uint32 id)2976 NdbTransaction::report_node_failure(Uint32 id){
2977   NdbNodeBitmask::set(m_failed_db_nodes, id);
2978   if(!NdbNodeBitmask::get(m_db_nodes, id))
2979   {
2980     return 0;
2981   }
2982 
2983   /**
2984    *   Arrived
2985    *   TCKEYCONF   TRANSIDAI
2986    * 1)   -           -
2987    * 2)   -           X
2988    * 3)   X           -
2989    * 4)   X           X
2990    */
2991   NdbOperation* tmp = theFirstExecOpInList;
2992   const Uint32 len = TcKeyConf::DirtyReadBit | id;
2993   Uint32 tNoComp = theNoOfOpCompleted;
2994   Uint32 tNoSent = theNoOfOpSent;
2995   Uint32 count = 0;
2996   while(tmp != 0)
2997   {
2998     if(tmp->theReceiver.m_expected_result_length == len &&
2999        tmp->theReceiver.m_received_result_length == 0)
3000     {
3001       count++;
3002       tmp->theError.code = 4119;
3003     }
3004     tmp = tmp->next();
3005   }
3006 
3007   /**
3008    * TODO, only abort ones really needing abort
3009    */
3010   NdbQueryImpl* qtmp = m_firstActiveQuery;
3011   while (qtmp != 0)
3012   {
3013     if (qtmp->getQueryDef().isScanQuery() == false)
3014     {
3015       count++;
3016       qtmp->setErrorCode(4119);
3017     }
3018     qtmp = qtmp->getNext();
3019   }
3020 
3021   tNoComp += count;
3022   theNoOfOpCompleted = tNoComp;
3023   if(count)
3024   {
3025     theReturnStatus = NdbTransaction::ReturnFailure;
3026     if(tNoComp == tNoSent)
3027     {
3028       theError.code = 4119;
3029       theCompletionStatus = NdbTransaction::CompletedFailure;
3030       return 1;
3031     }
3032   }
3033   return 0;
3034 }
3035 
3036 NdbQuery*
createQuery(const NdbQueryDef * def,const NdbQueryParamValue paramValues[],NdbOperation::LockMode lock_mode)3037 NdbTransaction::createQuery(const NdbQueryDef* def,
3038                             const NdbQueryParamValue paramValues[],
3039                             NdbOperation::LockMode lock_mode)
3040 {
3041   NdbQueryImpl* query = NdbQueryImpl::buildQuery(*this, def->getImpl());
3042   if (unlikely(query == NULL)) {
3043     return NULL; // Error code for transaction is already set.
3044   }
3045 
3046   const int error = query->assignParameters(paramValues);
3047   if (unlikely(error)) {
3048     // Error code for transaction is already set.
3049     query->release();
3050     return NULL;
3051   }
3052 
3053   query->setNext(m_firstQuery);
3054   m_firstQuery = query;
3055 
3056   return &query->getInterface();
3057 }
3058 
3059 NdbLockHandle*
getLockHandle()3060 NdbTransaction::getLockHandle()
3061 {
3062   NdbLockHandle* lh;
3063 
3064   /* Get a LockHandle object from the Ndb pool and
3065    * link it into our transaction
3066    */
3067   lh = theNdb->getLockHandle();
3068 
3069   if (lh)
3070   {
3071     lh->thePrev = m_theLastLockHandle;
3072     if (m_theLastLockHandle == NULL)
3073     {
3074       m_theFirstLockHandle = lh;
3075       m_theLastLockHandle = lh;
3076     }
3077     else
3078     {
3079       lh->next(NULL);
3080       m_theLastLockHandle->next(lh);
3081       m_theLastLockHandle = lh;
3082     }
3083   }
3084 
3085   return lh;
3086 }
3087 
3088 const NdbOperation*
unlock(const NdbLockHandle * lockHandle,NdbOperation::AbortOption ao)3089 NdbTransaction::unlock(const NdbLockHandle* lockHandle,
3090                        NdbOperation::AbortOption ao)
3091 {
3092   switch(lockHandle->m_state)
3093   {
3094   case NdbLockHandle::FREE:
3095     /* LockHandle already released */
3096     setErrorCode(4551);
3097     return NULL;
3098   case NdbLockHandle::PREPARED:
3099     if (likely(lockHandle->isLockRefValid()))
3100     {
3101       /* Looks ok */
3102       break;
3103     }
3104     /* Fall through */
3105   case NdbLockHandle::ALLOCATED:
3106     /* NdbLockHandle original operation not executed successfully */
3107     setErrorCode(4553);
3108     return NULL;
3109   default:
3110     abort();
3111     return NULL;
3112   }
3113 
3114   if (m_theFirstLockHandle == NULL)
3115   {
3116     /* NdbLockHandle does not belong to transaction */
3117     setErrorCode(4552);
3118     return NULL;
3119   }
3120 
3121 #ifdef VM_TRACE
3122   /* Check that this transaction 'owns' this lockhandle */
3123   {
3124     NdbLockHandle* tmp = m_theLastLockHandle;
3125     while (tmp && (tmp != lockHandle))
3126     {
3127       tmp = tmp->thePrev;
3128     }
3129 
3130     if (tmp != lockHandle)
3131     {
3132       /* NdbLockHandle does not belong to transaction */
3133       setErrorCode(4552);
3134       return NULL;
3135     }
3136   }
3137 #endif
3138 
3139   assert(theSimpleState == 0);
3140 
3141   /* Use the first work of the Lock reference as the unlock
3142    * operation's partition id
3143    * The other two words form the key.
3144    */
3145   NdbOperation::OperationOptions opts;
3146 
3147   opts.optionsPresent = NdbOperation::OperationOptions::OO_PARTITION_ID;
3148   opts.partitionId = lockHandle->getDistKey();
3149 
3150   if (ao != NdbOperation::DefaultAbortOption)
3151   {
3152     /* User supplied a preference, pass it on */
3153     opts.optionsPresent |= NdbOperation::OperationOptions::OO_ABORTOPTION;
3154     opts.abortOption = ao;
3155   }
3156 
3157   NdbOperation* unlockOp = setupRecordOp(NdbOperation::UnlockRequest,
3158                                          NdbOperation::LM_CommittedRead,
3159                                          NdbOperation::AbortOnError, // Default
3160                                          lockHandle->m_table->m_ndbrecord,
3161                                          NULL, // key_row
3162                                          lockHandle->m_table->m_ndbrecord,
3163                                          NULL,             // attr_row
3164                                          NULL,             // mask
3165                                          &opts,            // opts,
3166                                          sizeof(opts),     // sizeOfOptions
3167                                          lockHandle);
3168 
3169   return unlockOp;
3170 }
3171 
3172 int
releaseLockHandle(const NdbLockHandle * lockHandle)3173 NdbTransaction::releaseLockHandle(const NdbLockHandle* lockHandle)
3174 {
3175   NdbLockHandle* prev = lockHandle->thePrev;
3176   NdbLockHandle* next = lockHandle->theNext;
3177 
3178   switch(lockHandle->m_state)
3179   {
3180   case NdbLockHandle::FREE:
3181     /* NdbLockHandle already released */
3182     setErrorCode(4551);
3183     return -1;
3184   case NdbLockHandle::PREPARED:
3185     if (! lockHandle->isLockRefValid())
3186     {
3187       /* It's not safe to release the lockHandle after it's
3188        * defined and before the operation's executed.
3189        * The lockhandle memory is needed to receive the
3190        * Lock Reference during execution
3191        */
3192       /* Cannot releaseLockHandle until operation executed */
3193       setErrorCode(4550);
3194       return -1;
3195     }
3196     /* Fall through */
3197   case NdbLockHandle::ALLOCATED:
3198     /* Ok to release */
3199     break;
3200   default:
3201     /* Bad state */
3202     abort();
3203     return -1;
3204   }
3205 
3206 #ifdef VM_TRACE
3207   /* Check lockhandle is known to this transaction */
3208   NdbLockHandle* tmp = m_theFirstLockHandle;
3209   while (tmp &&
3210          (tmp != lockHandle))
3211   {
3212     tmp = tmp->next();
3213   }
3214 
3215   if (tmp != lockHandle)
3216   {
3217     abort();
3218     return -1;
3219   }
3220 #endif
3221 
3222   /* Repair list around lock handle */
3223   if (prev)
3224     prev->next(next);
3225 
3226   if (next)
3227     next->thePrev = prev;
3228 
3229   /* Repair list head and tail ptrs */
3230   if (lockHandle == m_theFirstLockHandle)
3231   {
3232     m_theFirstLockHandle = next;
3233   }
3234   if (lockHandle == m_theLastLockHandle)
3235   {
3236     m_theLastLockHandle = prev;
3237   }
3238 
3239   /* Now return it to the Ndb's freelist */
3240   NdbLockHandle* lh = const_cast<NdbLockHandle*>(lockHandle);
3241 
3242   lh->thePrev = NULL;
3243   lh->theNext = NULL;
3244 
3245   theNdb->releaseLockHandle(lh);
3246 
3247   return 0;
3248 }
3249