~ubuntu-branches/ubuntu/trusty/mysql-5.6/trusty

« back to all changes in this revision

Viewing changes to storage/ndb/src/ndbapi/NdbTransaction.cpp

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-02-12 11:54:27 UTC
  • Revision ID: package-import@ubuntu.com-20140212115427-oq6tfsqxl1wuwehi
Tags: upstream-5.6.15
ImportĀ upstreamĀ versionĀ 5.6.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
236
NdbTransaction::restart(){
 
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 
 
289
NdbTransaction::execute(ExecType aTypeOfExec, 
 
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, 
 
441
                       NdbOperation::DefaultAbortOption,
 
442
                       forceSend) == -1)
 
443
    {
 
444
      /**
 
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
 
447
       * memory leak.
 
448
       */
 
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;
 
605
        theError.status= NdbError::PermanentError;
 
606
        theError.classification= NdbError::TimeoutExpired;
 
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
 
 
643
/** 
 
644
 * Get the first query in the current transaction that has a lookup operation
 
645
 * as its root.
 
646
 */
 
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
 
 
656
/** 
 
657
 * Get the last query in the current transaction that has a lookup operation
 
658
 * as its root.
 
659
 */
 
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 
 
689
NdbTransaction::executeAsynchPrepare(NdbTransaction::ExecType aTypeOfExec,
 
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
 
 
698
  /**
 
699
   * Reset error.code on execute
 
700
   */
 
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
    {
 
708
    case NdbTransaction::Commit:
 
709
      theNdb->theImpl->incClientStat(Ndb::TransCommitCount, 1);
 
710
      break;
 
711
    case NdbTransaction::Rollback:
 
712
      theNdb->theImpl->incClientStat(Ndb::TransAbortCount, 1);
 
713
      break;
 
714
    default:
 
715
      break;
 
716
    }
 
717
  }
 
718
  /**
 
719
   * for timeout (4012) we want sendROLLBACK to behave differently.
 
720
   * Else, normal behaviour of reset errcode
 
721
   */
 
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
 
951
NdbTransaction::executeAsynch(ExecType aTypeOfExec,
 
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
 
 
961
void NdbTransaction::close()
 
962
{
 
963
  theNdb->closeTransaction(this);
 
964
}
 
965
 
 
966
int NdbTransaction::refresh()
 
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
{
 
1308
  /**
 
1309
   * Find & release all active queries which as completed.
 
1310
   */
 
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,
 
1367
                                     NdbIndexScanOperation* op)
 
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*
 
1474
NdbTransaction::getNdbOperation(const NdbTableImpl * tab,
 
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
 
 
1522
NdbOperation* NdbTransaction::getNdbOperation(const NdbDictionary::Table * table)
 
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
******************************************************************************/
 
1542
NdbScanOperation*
 
1543
NdbTransaction::getNdbScanOperation(const char* aTableName)
 
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
******************************************************************************/
 
1570
NdbIndexScanOperation*
 
1571
NdbTransaction::getNdbIndexScanOperation(const char* anIndexName, 
 
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
 
 
1591
NdbIndexScanOperation*
 
1592
NdbTransaction::getNdbIndexScanOperation(const NdbIndexImpl* index,
 
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
 
 
1616
NdbIndexScanOperation* 
 
1617
NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index)
 
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
 
 
1635
NdbIndexScanOperation* 
 
1636
NdbTransaction::getNdbIndexScanOperation(const NdbDictionary::Index * index,
 
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
*****************************************************************************/
 
1656
NdbIndexScanOperation*
 
1657
NdbTransaction::getNdbScanOperation(const NdbTableImpl * tab)
 
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
 
 
1705
NdbScanOperation* 
 
1706
NdbTransaction::getNdbScanOperation(const NdbDictionary::Table * table)
 
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
******************************************************************************/
 
1728
NdbIndexOperation*
 
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
*****************************************************************************/
 
1781
NdbIndexOperation*
 
1782
NdbTransaction::getNdbIndexOperation(const NdbIndexImpl * anIndex, 
 
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
 
 
1826
NdbIndexOperation* 
 
1827
NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index)
 
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
 
 
1844
NdbIndexOperation* 
 
1845
NdbTransaction::getNdbIndexOperation(const NdbDictionary::Index * index,
 
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
    {  
 
2191
      /**
 
2192
       * We're waiting for a commit reply...
 
2193
       */
 
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){
 
2242
      case NdbOperation::UpdateRequest:
 
2243
      case NdbOperation::InsertRequest:
 
2244
      case NdbOperation::DeleteRequest:
 
2245
      case NdbOperation::WriteRequest:
 
2246
      case NdbOperation::UnlockRequest:
 
2247
      case NdbOperation::RefreshRequest:
 
2248
        tOp = tOp->next();
 
2249
        break;
 
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);
 
2257
        tOp = NULL;
 
2258
        break;
 
2259
      case NdbOperation::NotDefined:
 
2260
      case NdbOperation::NotDefined2:
 
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
 
2375
NdbTransaction::getGCI()
 
2376
{
 
2377
  Uint64 val;
 
2378
  if (getGCI(&val) == 0)
 
2379
  {
 
2380
    return (int)(val >> 32);
 
2381
  }
 
2382
  return -1;
 
2383
}
 
2384
 
 
2385
int
 
2386
NdbTransaction::getGCI(Uint64 * val)
 
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
 
2405
NdbTransaction::getTransactionId()
 
2406
{
 
2407
  return theTransactionId;
 
2408
}//NdbTransaction::getTransactionId()
 
2409
 
 
2410
NdbTransaction::CommitStatusType
 
2411
NdbTransaction::commitStatus()
 
2412
{
 
2413
  return theCommitStatus;
 
2414
}//NdbTransaction::commitStatus()
 
2415
 
 
2416
int 
 
2417
NdbTransaction::getNdbErrorLine()
 
2418
{
 
2419
  return theErrorLine;
 
2420
}
 
2421
 
 
2422
NdbOperation*
 
2423
NdbTransaction::getNdbErrorOperation()
 
2424
{
 
2425
  return theErrorOperation;
 
2426
}//NdbTransaction::getNdbErrorOperation()
 
2427
 
 
2428
 
 
2429
const NdbOperation*
 
2430
NdbTransaction::getNdbErrorOperation() const
 
2431
{
 
2432
  return theErrorOperation;
 
2433
}//NdbTransaction::getNdbErrorOperation()
 
2434
 
 
2435
 
 
2436
const NdbOperation * 
 
2437
NdbTransaction::getNextCompletedOperation(const NdbOperation * current) const {
 
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
 
 
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,
 
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,
 
2630
                                  NdbOperation::LM_Exclusive, 
 
2631
                                  NdbOperation::AbortOnError, 
 
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,
 
2672
                                  NdbOperation::LM_Exclusive, 
 
2673
                                  NdbOperation::AbortOnError, 
 
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,
 
2703
                                  NdbOperation::LM_Exclusive, 
 
2704
                                  NdbOperation::AbortOnError, 
 
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,
 
2738
                                  NdbOperation::LM_Exclusive, 
 
2739
                                  NdbOperation::AbortOnError, 
 
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,
 
2784
                                  NdbOperation::LM_Exclusive,
 
2785
                                  NdbOperation::AbortOnError,
 
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
 
 
2799
NdbScanOperation *
 
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)
 
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
 
 
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)
 
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
  
 
2976
  /**
 
2977
   *   Arrived
 
2978
   *   TCKEYCONF   TRANSIDAI
 
2979
   * 1)   -           -
 
2980
   * 2)   -           X
 
2981
   * 3)   X           -
 
2982
   * 4)   X           X
 
2983
   */
 
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
 
 
3000
  /**
 
3001
   * TODO, only abort ones really needing abort
 
3002
   */
 
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*
 
3030
NdbTransaction::createQuery(const NdbQueryDef* def,
 
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
 
 
3052
NdbLockHandle*
 
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,
 
3083
                       NdbOperation::AbortOption ao)
 
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
   */
 
3138
  NdbOperation::OperationOptions opts;
 
3139
 
 
3140
  opts.optionsPresent = NdbOperation::OperationOptions::OO_PARTITION_ID;
 
3141
  opts.partitionId = lockHandle->getDistKey();
 
3142
 
 
3143
  if (ao != NdbOperation::DefaultAbortOption)
 
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,
 
3151
                                         NdbOperation::LM_CommittedRead,
 
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
}