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