2
Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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.
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.
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
18
#include <ndb_global.h>
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>
30
/*****************************************************************************
31
NdbTransaction( Ndb* aNdb );
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),
44
theErrorOperation(NULL),
47
theFirstOpInList(NULL),
48
theLastOpInList(NULL),
49
theFirstExecOpInList(NULL),
50
theLastExecOpInList(NULL),
51
theCompletedFirstOp(NULL),
52
theCompletedLastOp(NULL),
54
theNoOfOpCompleted(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),
66
theReleaseOnClose(false),
67
// Composite query operations
69
m_firstExecQuery(NULL),
70
m_firstActiveQuery(NULL),
73
m_theFirstScanOperation(NULL),
74
m_theLastScanOperation(NULL),
75
m_firstExecutedScanOp(NULL),
78
m_scanningQuery(NULL),
79
theBuddyConPtr(0xFFFFFFFF),
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))
90
theListState = NotInList;
92
//theId = NdbObjectIdMap::InvalidId;
93
theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
95
#define CHECK_SZ(mask, sz) assert((sizeof(mask)/sizeof(mask[0])) == sz)
97
CHECK_SZ(m_db_nodes, NdbNodeBitmask::Size);
98
CHECK_SZ(m_failed_db_nodes, NdbNodeBitmask::Size);
99
}//NdbTransaction::NdbTransaction()
101
/*****************************************************************************
104
Remark: Deletes the connection object.
105
*****************************************************************************/
106
NdbTransaction::~NdbTransaction()
108
DBUG_ENTER("NdbTransaction::~NdbTransaction");
109
theNdb->theImpl->theNdbObjectIdMap.unmap(theId, this);
111
}//NdbTransaction::~NdbTransaction()
113
/*****************************************************************************
116
Remark: Initialise connection object for new transaction.
117
*****************************************************************************/
119
NdbTransaction::init()
121
theListState = NotInList;
122
theInUseState = true;
123
theTransactionIsStarted = false;
126
theFirstOpInList = NULL;
127
theLastOpInList = NULL;
129
theScanningOp = NULL;
130
m_scanningQuery = NULL;
132
theFirstExecOpInList = NULL;
133
theLastExecOpInList = NULL;
135
theCompletedFirstOp = NULL;
136
theCompletedLastOp = NULL;
138
theGlobalCheckpointId = 0;
140
theNdb->theImpl->m_ndb_cluster_connection.get_latest_trans_gci();
141
theCommitStatus = Started;
142
theCompletionStatus = NotCompleted;
146
theErrorOperation = NULL;
148
theReleaseOnClose = false;
149
theSimpleState = true;
150
theSendStatus = InitState;
151
theMagicNumber = 0x37412619;
155
m_firstExecQuery = NULL;
156
m_firstActiveQuery = NULL;
159
m_waitForReply = true;
160
m_theFirstScanOperation = NULL;
161
m_theLastScanOperation = NULL;
162
m_firstExecutedScanOp = 0;
163
theBuddyConPtr = 0xFFFFFFFF;
166
thePendingBlobOps = 0;
167
m_theFirstLockHandle = NULL;
168
m_theLastLockHandle = NULL;
169
pendingBlobReadBytes = 0;
170
pendingBlobWriteBytes = 0;
171
if (theId == NdbObjectIdMap::InvalidId)
173
theId = theNdb->theImpl->theNdbObjectIdMap.map(this);
174
if (theId == NdbObjectIdMap::InvalidId)
176
theError.code = 4000;
182
}//NdbTransaction::init()
184
/*****************************************************************************
185
setOperationErrorCode(int error);
187
Remark: Sets an error code on the connection object from an
189
*****************************************************************************/
191
NdbTransaction::setOperationErrorCode(int error)
193
DBUG_ENTER("NdbTransaction::setOperationErrorCode");
198
/*****************************************************************************
199
setOperationErrorCodeAbort(int error);
201
Remark: Sets an error code on the connection object from an
203
*****************************************************************************/
205
NdbTransaction::setOperationErrorCodeAbort(int error, int abortOption)
207
DBUG_ENTER("NdbTransaction::setOperationErrorCodeAbort");
208
if (theTransactionIsStarted == false) {
209
theCommitStatus = Aborted;
210
} else if ((theCommitStatus != Committed) &&
211
(theCommitStatus != Aborted)) {
212
theCommitStatus = NeedAbort;
218
/*****************************************************************************
219
setErrorCode(int anErrorCode);
221
Remark: Sets an error indication on the connection object.
222
*****************************************************************************/
224
NdbTransaction::setErrorCode(int error)
226
DBUG_ENTER("NdbTransaction::setErrorCode");
227
DBUG_PRINT("enter", ("error: %d, theError.code: %d", error, theError.code));
229
if (theError.code == 0)
230
theError.code = error;
233
}//NdbTransaction::setErrorCode()
236
NdbTransaction::restart(){
237
DBUG_ENTER("NdbTransaction::restart");
238
if(theCompletionStatus == CompletedSuccess){
239
releaseCompletedOperations();
240
releaseCompletedQueries();
242
theTransactionId = theNdb->allocate_transaction_id();
244
theCommitStatus = Started;
245
theCompletionStatus = NotCompleted;
246
theTransactionIsStarted = false;
249
DBUG_PRINT("error",("theCompletionStatus != CompletedSuccess"));
253
/*****************************************************************************
254
void handleExecuteCompletion(void);
256
Remark: Handle time-out on a transaction object.
257
*****************************************************************************/
259
NdbTransaction::handleExecuteCompletion()
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;
276
theSendStatus = InitState;
278
}//NdbTransaction::handleExecuteCompletion()
280
/*****************************************************************************
281
int execute(ExecType aTypeOfExec, CommitType aTypeOfCommit, int forceSend);
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
*****************************************************************************/
289
NdbTransaction::execute(ExecType aTypeOfExec,
290
NdbOperation::AbortOption abortOption,
293
NdbError existingTransError = theError;
294
NdbError firstTransError;
295
DBUG_ENTER("NdbTransaction::execute");
296
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
297
aTypeOfExec, abortOption));
300
DBUG_RETURN(executeNoBlobs(aTypeOfExec, abortOption, forceSend));
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
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.
325
NdbOperation* tPrepOp;
327
if (abortOption != NdbOperation::DefaultAbortOption)
329
DBUG_PRINT("info", ("Forcing operations to take execute() abortOption %d",
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
337
tPrepOp= theFirstOpInList;
338
while(tPrepOp != NULL)
340
DBUG_PRINT("info", ("Changing abortOption from %d",
341
tPrepOp->m_abortOption));
342
tPrepOp->m_abortOption= abortOption;
343
tPrepOp= tPrepOp->next();
349
NdbOperation* tCompletedFirstOp = NULL;
350
NdbOperation* tCompletedLastOp = NULL;
354
NdbOperation* firstSavedOp= NULL;
355
NdbOperation* lastSavedOp= NULL;
357
tExecType = aTypeOfExec;
358
tPrepOp = theFirstOpInList;
359
while (tPrepOp != NULL) {
360
if (tPrepOp->theError.code == 0) {
362
NdbBlob* tBlob = tPrepOp->theBlobList;
364
/* We split the operation list just after this
365
* operation, in case it adds extra ops
367
firstSavedOp = tPrepOp->next(); // Could be NULL
368
lastSavedOp = theLastOpInList;
369
DBUG_PRINT("info", ("Splitting ops list between %p and %p",
370
firstSavedOp, lastSavedOp));
372
theLastOpInList= tPrepOp;
374
while (tBlob != NULL) {
375
if (tBlob->preExecute(tExecType, batch) == -1)
378
if (firstTransError.code==0)
379
firstTransError= theError;
381
tBlob = tBlob->theNext;
384
// blob asked to execute all up to lastOpInBatch now
385
tExecType = NoCommit;
389
/* No batching yet - rejoin the current and
390
* saved operation lists
392
DBUG_PRINT("info", ("Rejoining ops list after preExecute between %p and %p",
395
if (firstSavedOp != NULL && lastSavedOp != NULL) {
396
if (theFirstOpInList == NULL)
397
theFirstOpInList = firstSavedOp;
399
theLastOpInList->next(firstSavedOp);
400
theLastOpInList = lastSavedOp;
402
firstSavedOp= lastSavedOp= NULL;
405
tPrepOp = tPrepOp->next();
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)
417
if (firstTransError.code==0)
418
firstTransError= theError;
420
tBlob = tBlob->theNext;
427
// completed ops are in unspecified order
428
if (theCompletedFirstOp != NULL) {
429
if (tCompletedFirstOp == NULL) {
430
tCompletedFirstOp = theCompletedFirstOp;
431
tCompletedLastOp = theCompletedLastOp;
433
tCompletedLastOp->next(theCompletedFirstOp);
434
tCompletedLastOp = theCompletedLastOp;
436
theCompletedFirstOp = NULL;
437
theCompletedLastOp = NULL;
440
if (executeNoBlobs(tExecType,
441
NdbOperation::DefaultAbortOption,
445
* We abort the execute here. But we still need to put the split-off
446
* operation list back into the transaction object, or we will get a
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;
455
theLastOpInList->next(firstSavedOp);
456
theLastOpInList = lastSavedOp;
458
if (tCompletedFirstOp != NULL) {
459
tCompletedLastOp->next(theCompletedFirstOp);
460
theCompletedFirstOp = tCompletedFirstOp;
461
if (theCompletedLastOp == NULL)
462
theCompletedLastOp = tCompletedLastOp;
465
/* executeNoBlobs will have set transaction error */
469
/* Capture any trans error left by the execute() in case it gets trampled */
470
if (firstTransError.code==0)
471
firstTransError= theError;
473
#ifdef ndb_api_crash_on_complex_blob_abort
474
assert(theFirstOpInList == NULL && theLastOpInList == NULL);
476
theFirstOpInList = theLastOpInList = NULL;
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)
489
if (firstTransError.code==0)
490
firstTransError= theError;
492
tBlob = tBlob->theNext;
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",
504
if (theFirstOpInList == NULL)
505
theFirstOpInList = firstSavedOp;
507
theLastOpInList->next(firstSavedOp);
508
theLastOpInList = lastSavedOp;
510
assert(theFirstOpInList == NULL || tExecType == NoCommit);
511
} while (theFirstOpInList != NULL || tExecType != aTypeOfExec);
513
if (tCompletedFirstOp != NULL) {
514
tCompletedLastOp->next(theCompletedFirstOp);
515
theCompletedFirstOp = tCompletedFirstOp;
516
if (theCompletedLastOp == NULL)
517
theCompletedLastOp = tCompletedLastOp;
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;
526
/* Sometimes the original error is trampled by 'Trans already aborted',
527
* detect this case and attempt to restore the original error
529
if (theError.code == 4350) // Trans already aborted
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)
537
theError = existingTransError;
539
else if (firstTransError.code != 0)
541
theError = firstTransError;
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
549
if (firstTransError.code != 0)
551
DBUG_PRINT("info", ("Setting error to first error. firstTransError.code = %u, "
552
"theError.code = %u",
553
firstTransError.code,
555
theError = firstTransError;
562
NdbTransaction::executeNoBlobs(NdbTransaction::ExecType aTypeOfExec,
563
NdbOperation::AbortOption abortOption,
566
DBUG_ENTER("NdbTransaction::executeNoBlobs");
567
DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d",
568
aTypeOfExec, abortOption));
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
//------------------------------------------------------------------------
580
Uint32 timeout = theNdb->theImpl->get_waitfor_timeout();
581
m_waitForReply = false;
582
executeAsynchPrepare(aTypeOfExec, NULL, NULL, abortOption);
585
int noOfComp = tNdb->sendPollNdb(3 * timeout, 1, forceSend);
586
if (unlikely(noOfComp == 0)) {
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()
592
* We behave rather similarly in both places.
593
* Hitting this is certainly a bug though...
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 "
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.",
603
executeNoBlobs(NdbTransaction::Rollback);
604
theError.code = 4012;
605
theError.status= NdbError::PermanentError;
606
theError.classification= NdbError::TimeoutExpired;
607
setOperationErrorCodeAbort(4012); // ndbd timeout
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.
616
if (theListState != NotInList)
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;
627
theNdb->printState("execute %lx", (long)this);
631
if (theReturnStatus == ReturnFailure) {
637
thePendingBlobOps = 0;
638
pendingBlobReadBytes = 0;
639
pendingBlobWriteBytes = 0;
641
}//NdbTransaction::executeNoBlobs()
644
* Get the first query in the current transaction that has a lookup operation
647
static NdbQueryImpl* getFirstLookupQuery(NdbQueryImpl* firstQuery)
649
NdbQueryImpl* current = firstQuery;
650
while (current != NULL && current->getQueryDef().isScanQuery()) {
651
current = current->getNext();
657
* Get the last query in the current transaction that has a lookup operation
660
static NdbQueryImpl* getLastLookupQuery(NdbQueryImpl* firstQuery)
662
NdbQueryImpl* current = firstQuery;
663
NdbQueryImpl* last = NULL;
664
while (current != NULL) {
665
if (!current->getQueryDef().isScanQuery()) {
668
current = current->getNext();
673
/*****************************************************************************
674
void executeAsynchPrepare(ExecType aTypeOfExec,
675
NdbAsynchCallback callBack,
677
CommitType aTypeOfCommit);
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.
686
Remark: Prepare a part of a transaction in an asynchronous manner.
687
*****************************************************************************/
689
NdbTransaction::executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,
690
NdbAsynchCallback aCallback,
692
NdbOperation::AbortOption abortOption)
694
DBUG_ENTER("NdbTransaction::executeAsynchPrepare");
695
DBUG_PRINT("enter", ("aTypeOfExec: %d, aCallback: 0x%lx, anyObject: Ox%lx",
696
aTypeOfExec, (long) aCallback, (long) anyObject));
699
* Reset error.code on execute
702
if (theError.code != 0)
703
DBUG_PRINT("enter", ("Resetting error %d on execute", theError.code));
708
case NdbTransaction::Commit:
709
theNdb->theImpl->incClientStat(Ndb::TransCommitCount, 1);
711
case NdbTransaction::Rollback:
712
theNdb->theImpl->incClientStat(Ndb::TransAbortCount, 1);
719
* for timeout (4012) we want sendROLLBACK to behave differently.
720
* Else, normal behaviour of reset errcode
722
if (theError.code != 4012)
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
**************************************************************************/
731
releaseCompletedQueries();
734
NdbScanOperation* tcOp = m_theFirstScanOperation;
736
// Execute any cursor operations
737
while (tcOp != NULL) {
739
tReturnCode = tcOp->executeCursor(theDBnode);
740
if (tReturnCode == -1) {
743
tcOp->postExecuteRelease(); // Release unneeded resources
745
tcOp = (NdbScanOperation*)tcOp->next();
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
752
m_theFirstScanOperation = m_theLastScanOperation = NULL;
755
bool tTransactionIsStarted = theTransactionIsStarted;
756
NdbOperation* tLastOp = theLastOpInList;
758
CommitStatusType tCommitStatus = theCommitStatus;
759
Uint32 tnoOfPreparedTransactions = tNdb->theNoOfPreparedTransactions;
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;
771
theNoOfOpCompleted = 0;
772
NdbNodeBitmask::clear(m_db_nodes);
773
NdbNodeBitmask::clear(m_failed_db_nodes);
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
781
****************************************************************************/
782
if (aTypeOfExec == Rollback) {
783
if (theTransactionIsStarted == false || theSimpleState) {
784
theCommitStatus = Aborted;
785
theSendStatus = sendCompleted;
787
theSendStatus = sendABORT;
790
theSendStatus = sendABORTfail;
792
if (theCommitStatus == Aborted){
793
DBUG_PRINT("exit", ("theCommitStatus: Aborted"));
799
NdbQueryImpl* const lastLookupQuery = getLastLookupQuery(m_firstQuery);
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;
810
} else if (lastLookupQuery != NULL) {
811
if (aTypeOfExec == Commit) {
812
lastLookupQuery->setCommitIndicator();
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;
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
836
} else if (tTransactionIsStarted == false) {
837
NdbOperation* tFirstOp = theFirstOpInList;
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
845
if (lastLookupQuery != NULL) {
846
getFirstLookupQuery(m_firstQuery)->setStartIndicator();
847
} else if (tFirstOp != NULL) {
848
tFirstOp->setStartIndicator();
851
if (tFirstOp != NULL) {
852
if (aTypeOfExec == Commit) {
853
tLastOp->theCommitIndicator = 1;
855
} else if (lastLookupQuery != NULL) {
856
if (aTypeOfExec == Commit) {
857
lastLookupQuery->setCommitIndicator();
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;
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;
881
theCompletionStatus = NotCompleted;
883
// Prepare sending of all pending NdbQuery's
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;
894
query = query->getNext();
896
assert (m_firstExecQuery==NULL);
897
last->setNext(m_firstExecQuery);
898
m_firstExecQuery = m_firstQuery;
902
// Prepare sending of all pending (non-scan) NdbOperations's
903
NdbOperation* tOp = theFirstOpInList;
904
Uint32 pkOpCount = 0;
905
Uint32 ukOpCount = 0;
908
NdbOperation* tNextOp = tOp->next();
910
/* Count operation */
911
if (tOp->theTCREQ->theVerId_signalNumber == GSN_TCINDXREQ)
916
if (tOp->Status() == NdbOperation::UseNdbRecord)
917
tReturnCode = tOp->prepareSendNdbRecord(abortOption);
919
tReturnCode= tOp->prepareSend(theTCConPtr, theTransactionId, abortOption);
921
if (tReturnCode == -1) {
922
theSendStatus = sendABORTfail;
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
************************************************************************/
934
theNdb->theImpl->incClientStat(Ndb::PkOpCount, pkOpCount);
935
theNdb->theImpl->incClientStat(Ndb::UkOpCount, ukOpCount);
937
NdbOperation* tLastOpInList = theLastOpInList;
938
NdbOperation* tFirstOpInList = theFirstOpInList;
940
theFirstOpInList = NULL;
941
theLastOpInList = NULL;
942
theFirstExecOpInList = tFirstOpInList;
943
theLastExecOpInList = tLastOpInList;
945
theCompletionStatus = CompletedSuccess;
946
theSendStatus = sendOperations;
948
}//NdbTransaction::executeAsynchPrepare()
951
NdbTransaction::executeAsynch(ExecType aTypeOfExec,
952
NdbAsynchCallback aCallback,
954
NdbOperation::AbortOption abortOption,
957
executeAsynchPrepare(aTypeOfExec, aCallback, anyObject, abortOption);
958
theNdb->sendPreparedTransactions(forceSend);
961
void NdbTransaction::close()
963
theNdb->closeTransaction(this);
966
int NdbTransaction::refresh()
968
for(NdbIndexScanOperation* scan_op = m_firstExecutedScanOp;
969
scan_op != 0; scan_op = (NdbIndexScanOperation *) scan_op->theNext)
971
NdbTransaction* scan_trans = scan_op->theNdbCon;
974
scan_trans->sendTC_HBREP();
977
return sendTC_HBREP();
980
/*****************************************************************************
983
Return Value: No return value.
985
Remark: Order NDB to refresh the timeout counter of the transaction.
986
******************************************************************************/
988
NdbTransaction::sendTC_HBREP() // Send a TC_HBREP signal;
990
NdbApiSignal* tSignal;
992
Uint32 tTransId1, tTransId2;
994
tSignal = tNdb->getSignal();
995
if (tSignal == NULL) {
999
if (tSignal->setSignal(GSN_TC_HBREP, refToBlock(m_tcRef)) == -1) {
1003
TcHbRep * const tcHbRep = CAST_PTR(TcHbRep, tSignal->getDataPtrSend());
1005
tcHbRep->apiConnectPtr = theTCConPtr;
1007
tTransId1 = (Uint32) theTransactionId;
1008
tTransId2 = (Uint32) (theTransactionId >> 32);
1009
tcHbRep->transId1 = tTransId1;
1010
tcHbRep->transId2 = tTransId2;
1012
tNdb->theImpl->lock();
1013
const int res = tNdb->theImpl->sendSignal(tSignal,theDBnode);
1014
tNdb->theImpl->unlock();
1015
tNdb->releaseSignal(tSignal);
1022
}//NdbTransaction::sendTC_HBREP()
1024
/*****************************************************************************
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
*****************************************************************************/
1034
NdbTransaction::doSend()
1036
DBUG_ENTER("NdbTransaction::doSend");
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).
1042
switch(theSendStatus){
1043
case sendOperations: {
1044
assert (m_firstExecQuery!=NULL || theFirstExecOpInList!=NULL);
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) {
1059
query = query->getNext();
1062
// Append to list of active queries
1063
last->setNext(m_firstActiveQuery);
1064
m_firstActiveQuery = m_firstExecQuery;
1065
m_firstExecQuery = NULL;
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) {
1079
if (theFirstExecOpInList || lastLookupQuery != NULL) {
1080
theSendStatus = sendTC_OP;
1081
theTransactionIsStarted = true;
1082
theNdb->insert_sent_list(this); // Lookup: completes with KEYCONF/REF
1084
theSendStatus = sendCompleted;
1085
theNdb->insert_completed_list(this); // Scans query completes after send
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;
1098
if (sendROLLBACK() == 0) {
1103
case sendCOMMITstate:
1104
if (sendCOMMIT() == 0) {
1109
theNdb->insert_completed_list(this);
1112
ndbout << "Inconsistent theSendStatus = "
1113
<< (Uint32) theSendStatus << endl;
1118
theReleaseOnClose = true;
1119
theTransactionIsStarted = false;
1120
theCommitStatus = Aborted;
1122
setOperationErrorCodeAbort(4002);
1124
}//NdbTransaction::doSend()
1126
/**************************************************************************
1129
Return Value: Return -1 if send unsuccessful.
1131
Remark: Order NDB to rollback the transaction.
1132
**************************************************************************/
1134
NdbTransaction::sendROLLBACK() // Send a TCROLLBACKREQ signal;
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;
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)
1157
g_eventLogger->error("Sending TCROLLBACKREQ with Bad flag");
1158
tSignal.setLength(tSignal.getLength() + 1); // + flags
1159
tSignal.setData(0x1, 4); // potentially bad data
1161
tReturnCode = impl->sendSignal(&tSignal,theDBnode);
1162
if (tReturnCode != -1) {
1163
theSendStatus = sendTC_ROLLBACK;
1164
tNdb->insert_sent_list(this);
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
*********************************************************************/
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.
1179
theSendStatus = sendCompleted;
1180
tNdb->insert_completed_list(this);
1184
}//NdbTransaction::sendROLLBACK()
1186
/***************************************************************************
1189
Return Value: Return 0 : send was successful.
1190
Return -1: In all other case.
1192
Remark: Order NDB to commit the transaction.
1193
***************************************************************************/
1195
NdbTransaction::sendCOMMIT() // Send a TC_COMMITREQ signal;
1197
NdbApiSignal tSignal(theNdb->theMyRef);
1198
Uint32 tTransId1, tTransId2;
1199
NdbImpl * impl = theNdb->theImpl;
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);
1209
tReturnCode = impl->sendSignal(&tSignal,theDBnode);
1210
if (tReturnCode != -1) {
1211
theSendStatus = sendTC_COMMIT;
1212
theNdb->insert_sent_list(this);
1217
}//NdbTransaction::sendCOMMIT()
1219
/******************************************************************************
1222
Remark: Release all operations.
1223
******************************************************************************/
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)
1240
theMagicNumber = 0xFE11DC;
1241
theInUseState = false;
1243
if (theListState != NotInList) {
1244
theNdb->printState("release %lx", (long)this);
1248
}//NdbTransaction::release()
1251
NdbTransaction::releaseOps(NdbOperation* tOp){
1252
while (tOp != NULL) {
1253
NdbOperation* tmp = tOp;
1256
theNdb->releaseOperation(tmp);
1260
/******************************************************************************
1261
void releaseOperations();
1263
Remark: Release all operations.
1264
******************************************************************************/
1266
NdbTransaction::releaseOperations()
1268
// Release any open scans
1269
releaseScanOperations(m_theFirstScanOperation);
1270
releaseScanOperations(m_firstExecutedScanOp);
1272
releaseQueries(m_firstQuery);
1273
releaseQueries(m_firstExecQuery);
1274
releaseQueries(m_firstActiveQuery);
1275
releaseOps(theCompletedFirstOp);
1276
releaseOps(theFirstOpInList);
1277
releaseOps(theFirstExecOpInList);
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;
1294
}//NdbTransaction::releaseOperations()
1297
NdbTransaction::releaseCompletedOperations()
1299
releaseOps(theCompletedFirstOp);
1300
theCompletedFirstOp = NULL;
1301
theCompletedLastOp = NULL;
1302
}//NdbTransaction::releaseCompletedOperations()
1306
NdbTransaction::releaseCompletedQueries()
1309
* Find & release all active queries which as completed.
1311
NdbQueryImpl* prev = NULL;
1312
NdbQueryImpl* query = m_firstActiveQuery;
1313
while (query != NULL) {
1314
NdbQueryImpl* next = query->getNext();
1316
if (query->hasCompleted()) {
1317
// Unlink from completed-query list
1319
prev->setNext(next);
1321
m_firstActiveQuery = next;
1329
}//NdbTransaction::releaseCompletedQueries()
1332
/******************************************************************************
1333
void releaseQueries();
1335
Remark: Release all queries
1336
******************************************************************************/
1338
NdbTransaction::releaseQueries(NdbQueryImpl* query)
1340
while (query != NULL) {
1341
NdbQueryImpl* next = query->getNext();
1345
}//NdbTransaction::releaseQueries
1347
/******************************************************************************
1348
void releaseScanOperations();
1350
Remark: Release all cursor operations.
1351
(NdbScanOperation and NdbIndexOperation)
1352
******************************************************************************/
1354
NdbTransaction::releaseScanOperations(NdbIndexScanOperation* cursorOp)
1356
while(cursorOp != 0){
1357
NdbIndexScanOperation* next = (NdbIndexScanOperation*)cursorOp->next();
1358
cursorOp->release();
1359
theNdb->releaseScanOperation(cursorOp);
1362
}//NdbTransaction::releaseScanOperations()
1365
NdbTransaction::releaseScanOperation(NdbIndexScanOperation** listhead,
1366
NdbIndexScanOperation** listtail,
1367
NdbIndexScanOperation* op)
1369
if (* listhead == op)
1371
* listhead = (NdbIndexScanOperation*)op->theNext;
1372
if (listtail && *listtail == op)
1374
assert(* listhead == 0);
1381
NdbIndexScanOperation* tmp = * listhead;
1384
if (tmp->theNext == op)
1386
tmp->theNext = (NdbIndexScanOperation*)op->theNext;
1387
if (listtail && *listtail == op)
1389
assert(op->theNext == 0);
1394
tmp = (NdbIndexScanOperation*)tmp->theNext;
1403
theNdb->releaseScanOperation(op);
1411
NdbTransaction::releaseLockHandles()
1413
NdbLockHandle* lh = m_theFirstLockHandle;
1417
NdbLockHandle* next = lh->next();
1420
theNdb->releaseLockHandle(lh);
1424
m_theFirstLockHandle = NULL;
1425
m_theLastLockHandle = NULL;
1428
/*****************************************************************************
1429
NdbOperation* getNdbOperation(const char* aTableName);
1431
Return Value Return a pointer to a NdbOperation object if getNdbOperation
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.
1440
******************************************************************************/
1442
NdbTransaction::getNdbOperation(const char* aTableName)
1444
if (theCommitStatus == Started){
1445
NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1447
return getNdbOperation(table);
1449
setErrorCode(theNdb->theDictionary->getNdbError().code);
1454
setOperationErrorCodeAbort(4114);
1457
}//NdbTransaction::getNdbOperation()
1459
/*****************************************************************************
1460
NdbOperation* getNdbOperation(const NdbTableImpl* tab, NdbOperation* aNextOp,
1463
Return Value Return a pointer to a NdbOperation object if getNdbOperation
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
*****************************************************************************/
1474
NdbTransaction::getNdbOperation(const NdbTableImpl * tab,
1475
NdbOperation* aNextOp,
1480
if (theScanningOp != NULL || m_scanningQuery != NULL){
1485
tOp = theNdb->getOperation();
1487
goto getNdbOp_error1;
1488
if (aNextOp == NULL) {
1489
if (theLastOpInList != NULL) {
1490
theLastOpInList->next(tOp);
1491
theLastOpInList = tOp;
1493
theLastOpInList = tOp;
1494
theFirstOpInList = tOp;
1498
// add before the given op
1499
if (theFirstOpInList == aNextOp) {
1500
theFirstOpInList = tOp;
1502
NdbOperation* aLoopOp = theFirstOpInList;
1503
while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1504
aLoopOp = aLoopOp->next();
1505
assert(aLoopOp != NULL);
1510
if (tOp->init(tab, this, useRec) != -1) {
1513
theNdb->releaseOperation(tOp);
1518
setOperationErrorCodeAbort(4000);
1520
}//NdbTransaction::getNdbOperation()
1522
NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
1525
return getNdbOperation(& NdbTableImpl::getImpl(*table));
1528
}//NdbTransaction::getNdbOperation()
1532
/*****************************************************************************
1533
NdbScanOperation* getNdbScanOperation(const char* aTableName);
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
******************************************************************************/
1543
NdbTransaction::getNdbScanOperation(const char* aTableName)
1545
if (theCommitStatus == Started){
1546
NdbTableImpl* tab = theNdb->theDictionary->getTable(aTableName);
1548
return getNdbScanOperation(tab);
1550
setOperationErrorCodeAbort(theNdb->theDictionary->m_error.code);
1555
setOperationErrorCodeAbort(4114);
1557
}//NdbTransaction::getNdbScanOperation()
1559
/*****************************************************************************
1560
NdbScanOperation* getNdbIndexScanOperation(const char* anIndexName, const char* aTableName);
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
******************************************************************************/
1570
NdbIndexScanOperation*
1571
NdbTransaction::getNdbIndexScanOperation(const char* anIndexName,
1572
const char* aTableName)
1574
NdbIndexImpl* index =
1575
theNdb->theDictionary->getIndex(anIndexName, aTableName);
1578
setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1581
NdbTableImpl* table = theNdb->theDictionary->getTable(aTableName);
1584
setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1588
return getNdbIndexScanOperation(index, table);
1591
NdbIndexScanOperation*
1592
NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
1593
const NdbTableImpl* table)
1595
if (theCommitStatus == Started){
1596
const NdbTableImpl * indexTable = index->getIndexTable();
1597
if (indexTable != 0){
1598
NdbIndexScanOperation* tOp = getNdbScanOperation(indexTable);
1601
tOp->m_currentTable = table;
1602
// Mark that this really is an NdbIndexScanOperation
1603
tOp->m_type = NdbOperation::OrderedIndexScan;
1607
setOperationErrorCodeAbort(4271);
1612
setOperationErrorCodeAbort(4114);
1614
}//NdbTransaction::getNdbIndexScanOperation()
1616
NdbIndexScanOperation*
1617
NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
1621
/* This fetches the underlying table being indexed. */
1622
const NdbDictionary::Table *table=
1623
theNdb->theDictionary->getTable(index->getTable());
1626
return getNdbIndexScanOperation(index, table);
1628
setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1631
setOperationErrorCodeAbort(4271);
1635
NdbIndexScanOperation*
1636
NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
1637
const NdbDictionary::Table * table)
1640
return getNdbIndexScanOperation(& NdbIndexImpl::getImpl(*index),
1641
& NdbTableImpl::getImpl(*table));
1642
setOperationErrorCodeAbort(4271);
1644
}//NdbTransaction::getNdbIndexScanOperation()
1646
/*****************************************************************************
1647
NdbScanOperation* getNdbScanOperation(int aTableId);
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
*****************************************************************************/
1656
NdbIndexScanOperation*
1657
NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
1659
NdbIndexScanOperation* tOp;
1661
tOp = theNdb->getScanOperation();
1663
goto getNdbOp_error1;
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;
1671
theNdb->releaseScanOperation(tOp);
1676
setOperationErrorCodeAbort(4000);
1678
}//NdbTransaction::getNdbScanOperation()
1681
NdbTransaction::remove_list(NdbOperation*& list, NdbOperation* op){
1682
NdbOperation* tmp= list;
1686
while(tmp && tmp->next() != op) tmp = tmp->next();
1688
tmp->next(op->next());
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;
1699
m_theLastScanOperation->next(tOp);
1700
m_theLastScanOperation = tOp;
1706
NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
1709
return getNdbScanOperation(& NdbTableImpl::getImpl(*table));
1712
}//NdbTransaction::getNdbScanOperation()
1716
/*****************************************************************************
1717
NdbIndexOperation* getNdbIndexOperation(const char* anIndexName,
1718
const char* aTableName);
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)
1732
if (theCommitStatus == Started) {
1733
NdbTableImpl * table = theNdb->theDictionary->getTable(aTableName);
1734
NdbIndexImpl * index;
1738
setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1742
if (table->m_frm.get_data())
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(),
1752
index = theNdb->theDictionary->getIndex(anIndexName,
1754
if(table != 0 && index != 0){
1755
return getNdbIndexOperation(index, table);
1759
setOperationErrorCodeAbort(4243);
1763
setOperationErrorCodeAbort(4243);
1767
setOperationErrorCodeAbort(4114);
1769
}//NdbTransaction::getNdbIndexOperation()
1771
/*****************************************************************************
1772
NdbIndexOperation* getNdbIndexOperation(int anIndexId, int aTableId);
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
*****************************************************************************/
1782
NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex,
1783
const NdbTableImpl * aTable,
1784
NdbOperation* aNextOp,
1787
NdbIndexOperation* tOp;
1789
tOp = theNdb->getIndexOperation();
1791
goto getNdbOp_error1;
1792
if (aNextOp == NULL) {
1793
if (theLastOpInList != NULL) {
1794
theLastOpInList->next(tOp);
1795
theLastOpInList = tOp;
1797
theLastOpInList = tOp;
1798
theFirstOpInList = tOp;
1802
// add before the given op
1803
if (theFirstOpInList == aNextOp) {
1804
theFirstOpInList = tOp;
1806
NdbOperation* aLoopOp = theFirstOpInList;
1807
while (aLoopOp != NULL && aLoopOp->next() != aNextOp)
1808
aLoopOp = aLoopOp->next();
1809
assert(aLoopOp != NULL);
1814
if (tOp->indxInit(anIndex, aTable, this, useRec)!= -1) {
1817
theNdb->releaseOperation(tOp);
1822
setOperationErrorCodeAbort(4000);
1824
}//NdbTransaction::getNdbIndexOperation()
1827
NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
1831
const NdbDictionary::Table *table=
1832
theNdb->theDictionary->getTable(index->getTable());
1835
return getNdbIndexOperation(index, table);
1837
setOperationErrorCodeAbort(theNdb->theDictionary->getNdbError().code);
1840
setOperationErrorCodeAbort(4271);
1845
NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
1846
const NdbDictionary::Table * table)
1849
return getNdbIndexOperation(& NdbIndexImpl::getImpl(*index),
1850
& NdbTableImpl::getImpl(*table));
1852
setOperationErrorCodeAbort(4271);
1854
}//NdbTransaction::getNdbIndexOperation()
1857
/*******************************************************************************
1858
int receiveTCSEIZECONF(NdbApiSignal* aSignal);
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
*******************************************************************************/
1866
NdbTransaction::receiveTCSEIZECONF(const NdbApiSignal* aSignal)
1868
if (theStatus != Connecting)
1873
theTCConPtr = (Uint32)aSignal->readData(2);
1874
if (aSignal->getLength() >= 3)
1876
m_tcRef = aSignal->readData(3);
1880
m_tcRef = numberToRef(DBTC, theDBnode);
1883
assert(m_tcRef == aSignal->theSendersBlockRef);
1885
theStatus = Connected;
1888
}//NdbTransaction::receiveTCSEIZECONF()
1890
/*******************************************************************************
1891
int receiveTCSEIZEREF(NdbApiSignal* aSignal);
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
*******************************************************************************/
1899
NdbTransaction::receiveTCSEIZEREF(const NdbApiSignal* aSignal)
1901
DBUG_ENTER("NdbTransaction::receiveTCSEIZEREF");
1902
if (theStatus != Connecting)
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));
1914
}//NdbTransaction::receiveTCSEIZEREF()
1916
/*******************************************************************************
1917
int receiveTCRELEASECONF(NdbApiSignal* aSignal);
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
*******************************************************************************/
1925
NdbTransaction::receiveTCRELEASECONF(const NdbApiSignal* aSignal)
1927
if (theStatus != DisConnecting)
1932
theStatus = NotConnected;
1935
}//NdbTransaction::receiveTCRELEASECONF()
1937
/*******************************************************************************
1938
int receiveTCRELEASEREF(NdbApiSignal* aSignal);
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
*******************************************************************************/
1946
NdbTransaction::receiveTCRELEASEREF(const NdbApiSignal* aSignal)
1948
if (theStatus != DisConnecting) {
1951
theStatus = ConnectFailure;
1952
theNdb->theError.code = aSignal->readData(2);
1955
}//NdbTransaction::receiveTCRELEASEREF()
1957
/******************************************************************************
1958
int receiveTC_COMMITCONF(NdbApiSignal* aSignal);
1960
Return Value: Return 0 : receiveTC_COMMITCONF was successful.
1961
Return -1: In all other case.
1962
Parameters: aSignal: The signal object pointer.
1964
******************************************************************************/
1966
NdbTransaction::receiveTC_COMMITCONF(const TcCommitConf * commitConf,
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))
1978
Uint64 tGCI = Uint64(tGCI_lo) | (Uint64(tGCI_hi) << 32);
1979
theGlobalCheckpointId = tGCI;
1980
// theGlobalCheckpointId == 0 if NoOp transaction
1982
*p_latest_trans_gci = tGCI;
1985
#ifdef NDB_NO_DROPPED_SIGNAL
1990
}//NdbTransaction::receiveTC_COMMITCONF()
1992
/******************************************************************************
1993
int receiveTC_COMMITREF(NdbApiSignal* aSignal);
1995
Return Value: Return 0 : receiveTC_COMMITREF was successful.
1996
Return -1: In all other case.
1997
Parameters: aSignal: The signal object pointer.
1999
******************************************************************************/
2001
NdbTransaction::receiveTC_COMMITREF(const NdbApiSignal* aSignal)
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;
2011
#ifdef NDB_NO_DROPPED_SIGNAL
2017
}//NdbTransaction::receiveTC_COMMITREF()
2019
/******************************************************************************
2020
int receiveTCROLLBACKCONF(NdbApiSignal* aSignal);
2022
Return Value: Return 0 : receiveTCROLLBACKCONF was successful.
2023
Return -1: In all other case.
2024
Parameters: aSignal: The signal object pointer.
2026
******************************************************************************/
2028
NdbTransaction::receiveTCROLLBACKCONF(const NdbApiSignal* aSignal)
2030
if(checkState_TransId(aSignal->getDataPtr() + 1)){
2031
theCommitStatus = Aborted;
2032
theCompletionStatus = CompletedSuccess;
2035
#ifdef NDB_NO_DROPPED_SIGNAL
2041
}//NdbTransaction::receiveTCROLLBACKCONF()
2043
/*******************************************************************************
2044
int receiveTCROLLBACKREF(NdbApiSignal* aSignal);
2046
Return Value: Return 0 : receiveTCROLLBACKREF was successful.
2047
Return -1: In all other case.
2048
Parameters: aSignal: The signal object pointer.
2050
*******************************************************************************/
2052
NdbTransaction::receiveTCROLLBACKREF(const NdbApiSignal* aSignal)
2054
if(checkState_TransId(aSignal->getDataPtr() + 1)){
2055
setOperationErrorCodeAbort(aSignal->readData(4));
2056
theCommitStatus = Aborted;
2057
theCompletionStatus = CompletedFailure;
2058
theReturnStatus = ReturnFailure;
2061
#ifdef NDB_NO_DROPPED_SIGNAL
2067
}//NdbTransaction::receiveTCROLLBACKREF()
2069
/*****************************************************************************
2070
int receiveTCROLLBACKREP( NdbApiSignal* aSignal)
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
*****************************************************************************/
2079
NdbTransaction::receiveTCROLLBACKREP( const NdbApiSignal* aSignal)
2081
DBUG_ENTER("NdbTransaction::receiveTCROLLBACKREP");
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
2087
****************************************************************************/
2088
if(checkState_TransId(aSignal->getDataPtr() + 1)){
2089
theError.code = aSignal->readData(4);// Override any previous errors
2090
if (aSignal->getLength() == TcRollbackRep::SignalLength)
2092
// Signal may contain additional error data
2093
theError.details = (char *) aSignal->readData(5);
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;
2108
#ifdef NDB_NO_DROPPED_SIGNAL
2114
}//NdbTransaction::receiveTCROLLBACKREP()
2116
/*******************************************************************************
2117
int receiveTCKEYCONF(NdbApiSignal* aSignal, Uint32 long_short_ind);
2119
Return Value: Return 0 : receiveTCKEYCONF was successful.
2120
Return -1: In all other case.
2121
Parameters: aSignal: The signal object pointer.
2123
*******************************************************************************/
2125
NdbTransaction::receiveTCKEYCONF(const TcKeyConf * keyConf, Uint32 aDataLength)
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)){
2135
const Uint32 tNoOfOperations = TcKeyConf::getNoOfOperations(tTemp);
2136
const Uint32 tCommitFlag = TcKeyConf::getCommitFlag(tTemp);
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()){
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();
2151
done = tReceiver->execTCOPCONF(tAttrInfoLen);
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)
2159
// 4119 = "Simple/dirty read failed due to node failure"
2160
tReceiver->setErrorCode(4119);
2161
theCompletionStatus = CompletedFailure;
2162
theReturnStatus = NdbTransaction::ReturnFailure;
2166
} else { // if(tReceiver && tReceiver->checkMagicNumber())
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))
2178
const Uint64 tGCI = Uint64(tGCI_lo) | (Uint64(tGCI_hi) << 32);
2179
if (tCommitFlag == 1)
2181
theCommitStatus = Committed;
2182
theGlobalCheckpointId = tGCI;
2183
if (tGCI) // Read(dirty) only transaction doesnt get GCI
2185
*p_latest_trans_gci = tGCI;
2188
else if (theLastExecOpInList &&
2189
theLastExecOpInList->theCommitIndicator == 1)
2192
* We're waiting for a commit reply...
2196
if (tNoComp >= tNoSent)
2198
return 0; // No more operations to wait for
2200
// Not completed the reception yet.
2202
#ifdef NDB_NO_DROPPED_SIGNAL
2208
}//NdbTransaction::receiveTCKEYCONF()
2210
/*****************************************************************************
2211
int receiveTCKEY_FAILCONF( NdbApiSignal* aSignal)
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
*****************************************************************************/
2220
NdbTransaction::receiveTCKEY_FAILCONF(const TcKeyFailConf * failConf)
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.
2228
if(checkState_TransId(&failConf->transId1)){
2230
A node failure of the TC node occured. The transaction has
2233
theCommitStatus = Committed;
2234
tOp = theFirstExecOpInList;
2235
while (tOp != NULL) {
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.
2241
switch(tOp->theOperationType){
2242
case NdbOperation::UpdateRequest:
2243
case NdbOperation::InsertRequest:
2244
case NdbOperation::DeleteRequest:
2245
case NdbOperation::WriteRequest:
2246
case NdbOperation::UnlockRequest:
2247
case NdbOperation::RefreshRequest:
2250
case NdbOperation::ReadRequest:
2251
case NdbOperation::ReadExclusive:
2252
case NdbOperation::OpenScanRequest:
2253
case NdbOperation::OpenRangeScanRequest:
2254
theCompletionStatus = CompletedFailure;
2255
theReturnStatus = NdbTransaction::ReturnFailure;
2256
setOperationErrorCodeAbort(4115);
2259
case NdbOperation::NotDefined:
2260
case NdbOperation::NotDefined2:
2265
theReleaseOnClose = true;
2269
ndbout_c("Recevied TCKEY_FAILCONF wo/ operation");
2273
}//NdbTransaction::receiveTCKEY_FAILCONF()
2275
/*************************************************************************
2276
int receiveTCKEY_FAILREF( NdbApiSignal* aSignal)
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
**************************************************************************/
2285
NdbTransaction::receiveTCKEY_FAILREF(const NdbApiSignal* aSignal)
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.
2292
if(checkState_TransId(aSignal->getDataPtr()+1)){
2294
We received an indication of that this transaction was aborted due to a
2297
if (theSendStatus == NdbTransaction::sendTC_ROLLBACK) {
2299
We were in the process of sending a rollback anyways. We will
2300
report it as a success.
2302
theCompletionStatus = NdbTransaction::CompletedSuccess;
2304
theReturnStatus = NdbTransaction::ReturnFailure;
2305
theCompletionStatus = NdbTransaction::CompletedFailure;
2306
theError.code = 4031;
2308
theReleaseOnClose = true;
2309
theCommitStatus = NdbTransaction::Aborted;
2313
ndbout_c("Recevied TCKEY_FAILREF wo/ operation");
2317
}//NdbTransaction::receiveTCKEY_FAILREF()
2319
/*******************************************************************************
2320
int OpCompletedFailure();
2322
Return Value: Return 0 : OpCompleteSuccess was successful.
2323
Return -1: In all other case.
2324
Remark: An operation was completed with failure.
2325
*******************************************************************************/
2327
NdbTransaction::OpCompleteFailure()
2329
Uint32 tNoComp = theNoOfOpCompleted;
2330
Uint32 tNoSent = theNoOfOpSent;
2333
theNoOfOpCompleted = tNoComp;
2335
return (tNoComp == tNoSent) ? 0 : -1;
2336
}//NdbTransaction::OpCompleteFailure()
2338
/******************************************************************************
2339
int OpCompleteSuccess();
2341
Return Value: Return 0 : OpCompleteSuccess was successful.
2342
Return -1: In all other case.
2343
Remark: An operation was completed with success.
2344
*******************************************************************************/
2346
NdbTransaction::OpCompleteSuccess()
2348
Uint32 tNoComp = theNoOfOpCompleted;
2349
Uint32 tNoSent = theNoOfOpSent;
2351
theNoOfOpCompleted = tNoComp;
2353
ndbout << "NdbTransaction::OpCompleteSuccess() tNoComp=" << tNoComp
2354
<< " tNoSent=" << tNoSent << endl;
2356
if (tNoComp == tNoSent) { // Last operation completed
2358
} else if (tNoComp < tNoSent) {
2359
return -1; // Continue waiting for more signals
2361
setOperationErrorCodeAbort(4113); // Too many operations,
2362
// stop waiting for more
2363
theCompletionStatus = NdbTransaction::CompletedFailure;
2364
theReturnStatus = NdbTransaction::ReturnFailure;
2367
}//NdbTransaction::OpCompleteSuccess()
2369
/******************************************************************************
2372
Remark: Get global checkpoint identity of the transaction
2373
*******************************************************************************/
2375
NdbTransaction::getGCI()
2378
if (getGCI(&val) == 0)
2380
return (int)(val >> 32);
2386
NdbTransaction::getGCI(Uint64 * val)
2388
if (theCommitStatus == NdbTransaction::Committed)
2392
* val = theGlobalCheckpointId;
2399
/*******************************************************************************
2400
Uint64 getTransactionId(void);
2402
Remark: Get the transaction identity.
2403
*******************************************************************************/
2405
NdbTransaction::getTransactionId()
2407
return theTransactionId;
2408
}//NdbTransaction::getTransactionId()
2410
NdbTransaction::CommitStatusType
2411
NdbTransaction::commitStatus()
2413
return theCommitStatus;
2414
}//NdbTransaction::commitStatus()
2417
NdbTransaction::getNdbErrorLine()
2419
return theErrorLine;
2423
NdbTransaction::getNdbErrorOperation()
2425
return theErrorOperation;
2426
}//NdbTransaction::getNdbErrorOperation()
2430
NdbTransaction::getNdbErrorOperation() const
2432
return theErrorOperation;
2433
}//NdbTransaction::getNdbErrorOperation()
2436
const NdbOperation *
2437
NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
2439
return theCompletedFirstOp;
2440
return current->theNext;
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)
2458
/* Check that we've got a base table record for the attribute record */
2459
if (attribute_record->flags & NdbRecord::RecIsIndex)
2461
/* Result or attribute record must be a base
2462
table ndbrecord, not an index ndbrecord */
2463
setOperationErrorCodeAbort(4340);
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.
2473
if (key_record->flags & NdbRecord::RecIsIndex)
2475
op= getNdbIndexOperation(key_record->table->m_index,
2476
attribute_record->table, NULL, true);
2480
if (key_record->tableId != attribute_record->tableId)
2482
setOperationErrorCodeAbort(4287);
2485
op= getNdbOperation(attribute_record->table, NULL, true);
2490
op->theStatus= NdbOperation::UseNdbRecord;
2491
op->theOperationType= type;
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);
2501
AttributeMask readMask;
2502
attribute_record->copyMask(readMask.rep.data, mask);
2509
/* Delegate to static method in NdbOperation */
2510
Uint32 result = NdbOperation::handleOperationOptions (type,
2516
setOperationErrorCodeAbort(result);
2521
/* Handle delete + blobs */
2522
if (type == NdbOperation::DeleteRequest &&
2523
(attribute_record->flags & NdbRecord::RecTableHasBlob))
2525
/* Need to link in all the Blob handles for delete
2526
* If there is a pre-read, check that no Blobs have
2529
if (op->getBlobHandlesNdbRecordDelete(this,
2530
(attribute_row != NULL),
2531
readMask.rep.data) == -1)
2534
else if (unlikely((attribute_record->flags & NdbRecord::RecHasBlob) &&
2535
(type != NdbOperation::UnlockRequest)))
2537
/* Create blob handles for non-delete, non-unlock operations */
2538
if (op->getBlobHandlesNdbRecord(this, readMask.rep.data) == -1)
2543
* Now prepare the signals to be sent...
2546
int returnCode=op->buildSignalsNdbRecord(theTCConPtr, theTransactionId,
2551
// buildSignalsNdbRecord should have set the error status
2552
// So we can return NULL
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)
2569
/* Check that the NdbRecord specifies the full primary key. */
2570
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2572
setOperationErrorCodeAbort(4292);
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;
2581
NdbOperation::OperationType opType=
2582
(lock_mode == NdbOperation::LM_Exclusive ?
2583
NdbOperation::ReadExclusive : NdbOperation::ReadRequest);
2584
NdbOperation *op= setupRecordOp(opType, lock_mode,
2585
NdbOperation::AO_IgnoreError,
2587
result_rec, result_row, result_mask,
2593
if (op->theLockMode == NdbOperation::LM_CommittedRead)
2595
op->theDirtyIndicator= 1;
2596
op->theSimpleIndicator= 1;
2600
if (op->theLockMode == NdbOperation::LM_SimpleRead)
2602
op->theSimpleIndicator = 1;
2609
/* Setup the record/row for receiving the results. */
2610
op->theReceiver.getValues(result_rec, result_row);
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)
2622
/* Check that the NdbRecord specifies the full primary key. */
2623
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2625
setOperationErrorCodeAbort(4292);
2629
NdbOperation *op= setupRecordOp(NdbOperation::InsertRequest,
2630
NdbOperation::LM_Exclusive,
2631
NdbOperation::AbortOnError,
2633
attr_rec, attr_row, mask,
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)
2650
return insertTuple(combined_rec, combined_row,
2651
combined_rec, combined_row,
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)
2664
/* Check that the NdbRecord specifies the full primary key. */
2665
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2667
setOperationErrorCodeAbort(4292);
2671
NdbOperation *op= setupRecordOp(NdbOperation::UpdateRequest,
2672
NdbOperation::LM_Exclusive,
2673
NdbOperation::AbortOnError,
2675
attr_rec, attr_row, mask,
2686
const NdbOperation *
2687
NdbTransaction::deleteTuple(const NdbRecord *key_rec,
2688
const char *key_row,
2689
const NdbRecord *result_rec,
2691
const unsigned char *result_mask,
2692
const NdbOperation::OperationOptions* opts,
2693
Uint32 sizeOfOptions)
2695
/* Check that the key NdbRecord specifies the full primary key. */
2696
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2698
setOperationErrorCodeAbort(4292);
2702
NdbOperation *op= setupRecordOp(NdbOperation::DeleteRequest,
2703
NdbOperation::LM_Exclusive,
2704
NdbOperation::AbortOnError,
2706
result_rec, result_row, result_mask,
2714
if (result_row != NULL) // readBeforeDelete
2716
/* Setup the record/row for receiving the results. */
2717
op->theReceiver.getValues(result_rec, result_row);
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)
2730
/* Check that the NdbRecord specifies the full primary key. */
2731
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2733
setOperationErrorCodeAbort(4292);
2737
NdbOperation *op= setupRecordOp(NdbOperation::WriteRequest,
2738
NdbOperation::LM_Exclusive,
2739
NdbOperation::AbortOnError,
2741
attr_rec, attr_row, mask,
2752
const NdbOperation *
2753
NdbTransaction::refreshTuple(const NdbRecord *key_rec, const char *key_row,
2754
const NdbOperation::OperationOptions *opts,
2755
Uint32 sizeOfOptions)
2757
/* Check TC node version lockless */
2759
Uint32 tcVer = theNdb->theImpl->getNodeInfo(theDBnode).m_info.m_version;
2760
if (unlikely(! ndb_refresh_tuple(tcVer)))
2762
/* Function not implemented yet */
2763
setOperationErrorCodeAbort(4003);
2768
/* Check that the NdbRecord specifies the full primary key. */
2769
if (!(key_rec->flags & NdbRecord::RecHasAllKeys))
2771
setOperationErrorCodeAbort(4292);
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++)
2779
Uint32 id = key_rec->columns[key_rec->key_indexes[i]].attrId;
2780
keymask[(id / 8)] |= (1 << (id & 7));
2783
NdbOperation *op= setupRecordOp(NdbOperation::RefreshRequest,
2784
NdbOperation::LM_Exclusive,
2785
NdbOperation::AbortOnError,
2800
NdbTransaction::scanTable(const NdbRecord *result_record,
2801
NdbOperation::LockMode lock_mode,
2802
const unsigned char *result_mask,
2803
const NdbScanOperation::ScanOptions *options,
2804
Uint32 sizeOfOptions)
2806
DBUG_ENTER("NdbTransaction::scanTable");
2807
DBUG_PRINT("info", ("Options=%p(0x%x)", options,
2808
(options ? (unsigned)(options->optionsPresent) : 0)));
2810
Normal scan operations are created as NdbIndexScanOperations.
2811
The reason for this is that they can then share a pool of allocated
2814
NdbIndexScanOperation *op_idx=
2815
getNdbScanOperation(result_record->table);
2819
/* Memory allocation error */
2820
setOperationErrorCodeAbort(4000);
2824
op_idx->m_scanUsingOldApi= false;
2826
/* The real work is done in NdbScanOperation */
2827
if (op_idx->scanTableImpl(result_record,
2831
sizeOfOptions) == 0)
2833
DBUG_RETURN(op_idx);
2836
releaseScanOperation(&m_theFirstScanOperation, &m_theLastScanOperation,
2843
NdbIndexScanOperation *
2844
NdbTransaction::scanIndex(const NdbRecord *key_record,
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)
2853
Normal scan operations are created as NdbIndexScanOperations.
2854
The reason for this is that they can then share a pool of allocated
2857
NdbIndexScanOperation *op= getNdbScanOperation(key_record->table);
2860
/* Memory allocation error */
2861
setOperationErrorCodeAbort(4000);
2865
op->m_scanUsingOldApi= false;
2867
/* Defer the rest of the work to NdbIndexScanOperation */
2868
if (op->scanIndexImpl(key_record,
2874
sizeOfOptions) != 0)
2876
releaseScanOperation(&m_theFirstScanOperation, &m_theLastScanOperation, op);
2884
NdbTransaction::getMaxPendingBlobReadBytes() const
2887
return (maxPendingBlobReadBytes ==
2888
(~Uint32(0)) ? 0 : maxPendingBlobReadBytes);
2892
NdbTransaction::getMaxPendingBlobWriteBytes() const
2895
return (maxPendingBlobWriteBytes ==
2896
(~Uint32(0)) ? 0 : maxPendingBlobWriteBytes);
2900
NdbTransaction::setMaxPendingBlobReadBytes(Uint32 bytes)
2903
maxPendingBlobReadBytes = (bytes?bytes : (~ Uint32(0)));
2907
NdbTransaction::setMaxPendingBlobWriteBytes(Uint32 bytes)
2910
maxPendingBlobWriteBytes = (bytes?bytes : (~ Uint32(0)));
2914
#define CASE(x) case x: ndbout << " " << #x; break
2916
NdbTransaction::printState()
2918
ndbout << "con=" << hex << this << dec;
2919
ndbout << " node=" << getConnectedNodeId();
2920
switch (theStatus) {
2924
CASE(DisConnecting);
2925
CASE(ConnectFailure);
2926
default: ndbout << (Uint32) theStatus;
2928
switch (theListState) {
2930
CASE(InPreparedList);
2932
CASE(InCompletedList);
2933
default: ndbout << (Uint32) theListState;
2935
switch (theSendStatus) {
2938
CASE(sendOperations);
2939
CASE(sendCompleted);
2940
CASE(sendCOMMITstate);
2942
CASE(sendABORTfail);
2943
CASE(sendTC_ROLLBACK);
2944
CASE(sendTC_COMMIT);
2946
default: ndbout << (Uint32) theSendStatus;
2948
switch (theCommitStatus) {
2954
default: ndbout << (Uint32) theCommitStatus;
2956
switch (theCompletionStatus) {
2958
CASE(CompletedSuccess);
2959
CASE(CompletedFailure);
2960
CASE(DefinitionFailure);
2961
default: ndbout << (Uint32) theCompletionStatus;
2969
NdbTransaction::report_node_failure(Uint32 id){
2970
NdbNodeBitmask::set(m_failed_db_nodes, id);
2971
if(!NdbNodeBitmask::get(m_db_nodes, id))
2978
* TCKEYCONF TRANSIDAI
2984
NdbOperation* tmp = theFirstExecOpInList;
2985
const Uint32 len = TcKeyConf::DirtyReadBit | id;
2986
Uint32 tNoComp = theNoOfOpCompleted;
2987
Uint32 tNoSent = theNoOfOpSent;
2991
if(tmp->theReceiver.m_expected_result_length == len &&
2992
tmp->theReceiver.m_received_result_length == 0)
2995
tmp->theError.code = 4119;
3001
* TODO, only abort ones really needing abort
3003
NdbQueryImpl* qtmp = m_firstActiveQuery;
3006
if (qtmp->getQueryDef().isScanQuery() == false)
3009
qtmp->setErrorCode(4119);
3011
qtmp = qtmp->getNext();
3015
theNoOfOpCompleted = tNoComp;
3018
theReturnStatus = NdbTransaction::ReturnFailure;
3019
if(tNoComp == tNoSent)
3021
theError.code = 4119;
3022
theCompletionStatus = NdbTransaction::CompletedFailure;
3030
NdbTransaction::createQuery(const NdbQueryDef* def,
3031
const NdbQueryParamValue paramValues[],
3032
NdbOperation::LockMode lock_mode)
3034
NdbQueryImpl* query = NdbQueryImpl::buildQuery(*this, def->getImpl());
3035
if (unlikely(query == NULL)) {
3036
return NULL; // Error code for transaction is already set.
3039
const int error = query->assignParameters(paramValues);
3040
if (unlikely(error)) {
3041
// Error code for transaction is already set.
3046
query->setNext(m_firstQuery);
3047
m_firstQuery = query;
3049
return &query->getInterface();
3053
NdbTransaction::getLockHandle()
3057
/* Get a LockHandle object from the Ndb pool and
3058
* link it into our transaction
3060
lh = theNdb->getLockHandle();
3064
lh->thePrev = m_theLastLockHandle;
3065
if (m_theLastLockHandle == NULL)
3067
m_theFirstLockHandle = lh;
3068
m_theLastLockHandle = lh;
3073
m_theLastLockHandle->next(lh);
3074
m_theLastLockHandle = lh;
3082
NdbTransaction::unlock(const NdbLockHandle* lockHandle,
3083
NdbOperation::AbortOption ao)
3085
switch(lockHandle->m_state)
3087
case NdbLockHandle::FREE:
3088
/* LockHandle already released */
3091
case NdbLockHandle::PREPARED:
3092
if (likely(lockHandle->isLockRefValid()))
3098
case NdbLockHandle::ALLOCATED:
3099
/* NdbLockHandle original operation not executed successfully */
3107
if (m_theFirstLockHandle == NULL)
3109
/* NdbLockHandle does not belong to transaction */
3115
/* Check that this transaction 'owns' this lockhandle */
3117
NdbLockHandle* tmp = m_theLastLockHandle;
3118
while (tmp && (tmp != lockHandle))
3123
if (tmp != lockHandle)
3125
/* NdbLockHandle does not belong to transaction */
3132
assert(theSimpleState == 0);
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.
3138
NdbOperation::OperationOptions opts;
3140
opts.optionsPresent = NdbOperation::OperationOptions::OO_PARTITION_ID;
3141
opts.partitionId = lockHandle->getDistKey();
3143
if (ao != NdbOperation::DefaultAbortOption)
3145
/* User supplied a preference, pass it on */
3146
opts.optionsPresent |= NdbOperation::OperationOptions::OO_ABORTOPTION;
3147
opts.abortOption = ao;
3150
NdbOperation* unlockOp = setupRecordOp(NdbOperation::UnlockRequest,
3151
NdbOperation::LM_CommittedRead,
3152
NdbOperation::AbortOnError, // Default
3153
lockHandle->m_table->m_ndbrecord,
3155
lockHandle->m_table->m_ndbrecord,
3159
sizeof(opts), // sizeOfOptions
3166
NdbTransaction::releaseLockHandle(const NdbLockHandle* lockHandle)
3168
NdbLockHandle* prev = lockHandle->thePrev;
3169
NdbLockHandle* next = lockHandle->theNext;
3171
switch(lockHandle->m_state)
3173
case NdbLockHandle::FREE:
3174
/* NdbLockHandle already released */
3177
case NdbLockHandle::PREPARED:
3178
if (! lockHandle->isLockRefValid())
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
3185
/* Cannot releaseLockHandle until operation executed */
3190
case NdbLockHandle::ALLOCATED:
3200
/* Check lockhandle is known to this transaction */
3201
NdbLockHandle* tmp = m_theFirstLockHandle;
3203
(tmp != lockHandle))
3208
if (tmp != lockHandle)
3215
/* Repair list around lock handle */
3220
next->thePrev = prev;
3222
/* Repair list head and tail ptrs */
3223
if (lockHandle == m_theFirstLockHandle)
3225
m_theFirstLockHandle = next;
3227
if (lockHandle == m_theLastLockHandle)
3229
m_theLastLockHandle = prev;
3232
/* Now return it to the Ndb's freelist */
3233
NdbLockHandle* lh = const_cast<NdbLockHandle*>(lockHandle);
3238
theNdb->releaseLockHandle(lh);