MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
testNdbApi.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <NDBT.hpp>
19 #include <NDBT_Test.hpp>
20 #include <HugoTransactions.hpp>
21 #include <UtilTransactions.hpp>
22 #include <NdbRestarter.hpp>
23 #include <NdbRestarts.hpp>
24 #include <Vector.hpp>
25 #include <random.h>
26 #include <NdbTick.h>
27 #include <my_sys.h>
28 
29 #define MAX_NDB_OBJECTS 32678
30 
31 #define CHECK(b) if (!(b)) { \
32  ndbout << "ERR: failed on line " << __LINE__ << endl; \
33  return -1; }
34 
35 #define CHECKE(b) if (!(b)) { \
36  errors++; \
37  ndbout << "ERR: "<< step->getName() \
38  << " failed on line " << __LINE__ << endl; \
39  result = NDBT_FAILED; \
40  continue; }
41 
42 static const char* ApiFailTestRun = "ApiFailTestRun";
43 static const char* ApiFailTestComplete = "ApiFailTestComplete";
44 static const char* ApiFailTestsRunning = "ApiFailTestsRunning";
45 static const char* ApiFailNumberPkSteps = "ApiFailNumberPkSteps";
46 static const int MAX_STEPS = 10;
47 static Ndb_cluster_connection* otherConnection = NULL;
48 static Ndb* stepNdbs[MAX_STEPS];
49 
50 
51 int runTestMaxNdb(NDBT_Context* ctx, NDBT_Step* step){
52  Uint32 loops = ctx->getNumLoops();
53  Uint32 l = 0;
54  int oldi = 0;
55  int result = NDBT_OK;
56 
57  while (l < loops && result == NDBT_OK){
58  ndbout_c("loop %d", l + 1);
59  int errors = 0;
60 
61  Vector<Ndb*> ndbVector;
62  int i = 0;
63  int init = 0;
64  do {
65 
66  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
67  if (pNdb == NULL){
68  ndbout << "pNdb == NULL" << endl;
69  errors++;
70  continue;
71 
72  }
73  i++;
74 
75  ndbVector.push_back(pNdb);
76 
77  if (pNdb->init()){
78  ERR(pNdb->getNdbError());
79  errors++;
80  continue;
81  }
82 
83  init++;
84 
85  } while (errors == 0);
86 
87  ndbout << i << " ndb objects created" << endl;
88 
89  if (l > 0 && i != oldi && init != MAX_NDB_OBJECTS){
90  ndbout << l << ": not as manyNdb objects created" << endl
91  << i << " != " << oldi << endl;
92  result = NDBT_FAILED;
93  }
94 
95  oldi = i;
96 
97 
98  for(size_t j = 0; j < ndbVector.size(); j++){
99  delete ndbVector[j];
100  if(((j+1) % 250) == 0){
101  ndbout << "Deleted " << (Uint64) j << " ndb objects " << endl;
102  }
103  }
104  ndbVector.clear();
105 
106  l++;
107  }
108 
109  return result;
110 }
111 
112 int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){
113  Uint32 loops = ctx->getNumLoops();
114  Uint32 l = 0;
115  int oldi = 0;
116  int result = NDBT_OK;
117 
118  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
119  if (pNdb == NULL){
120  ndbout << "pNdb == NULL" << endl;
121  return NDBT_FAILED;
122  }
123  if (pNdb->init(2048)){
124  ERR(pNdb->getNdbError());
125  delete pNdb;
126  return NDBT_FAILED;
127  }
128 
129  const NdbDictionary::Table* pTab = ctx->getTab();
130  if (pTab == 0) abort();
131 
132  while (l < loops && result == NDBT_OK){
133  int errors = 0;
134  int maxErrors = 5;
135 
136  Vector<NdbConnection*> conVector;
137 
138 
139  int i = 0;
140  do {
141 
142  NdbConnection* pCon;
143 
144  int type = i%2;
145  switch (type){
146  case 0:
147  pCon = pNdb->startTransaction();
148  break;
149  case 1:
150  {
151  BaseString key;
152  key.appfmt("DATA-%d", i);
153  ndbout_c("%s", key.c_str());
154  pCon = pNdb->startTransaction(pTab,
155  key.c_str(),
156  key.length());
157  }
158  break;
159  default:
160  abort();
161  }
162 
163  if (pCon == NULL){
164  ERR(pNdb->getNdbError());
165  errors++;
166  continue;
167  }
168 
169  conVector.push_back(pCon);
170 
171  i++;
172  } while (errors < maxErrors);
173 
174  ndbout << i << " connections created" << endl;
175 
176  if (l > 0 && i != oldi){
177  ndbout << l << ": not as many transactions created" << endl
178  << i << " != " << oldi << endl;
179  result = NDBT_FAILED;
180  }
181 
182  oldi = i;
183 
184 
185  for(size_t j = 0; j < conVector.size(); j++){
186  pNdb->closeTransaction(conVector[j]);
187  }
188  conVector.clear();
189  l++;
190 
191  }
192 
193  // BONUS Test closeTransaction with null trans
194  pNdb->closeTransaction(NULL);
195 
196  delete pNdb;
197 
198 
199  return result;
200 }
201 
202 int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){
203  Uint32 l = 1;
204  int result = NDBT_OK;
205  int maxOpsLimit = 1;
206  const NdbDictionary::Table* pTab = ctx->getTab();
207 
208  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
209  if (pNdb == NULL){
210  ndbout << "pNdb == NULL" << endl;
211  return NDBT_FAILED;
212  }
213  if (pNdb->init(2048)){
214  ERR(pNdb->getNdbError());
215  delete pNdb;
216  return NDBT_FAILED;
217  }
218 
219  HugoOperations hugoOps(*pTab);
220 
221  bool endTest = false;
222  while (!endTest && result == NDBT_OK){
223  int errors = 0;
224  int maxErrors = 5;
225 
226  maxOpsLimit = l*1000;
227 
228  if (hugoOps.startTransaction(pNdb) != NDBT_OK){
229  delete pNdb;
230  return NDBT_FAILED;
231  }
232 
233  int i = 0;
234  while (errors < maxErrors){
235 
236  if(hugoOps.pkReadRecord(pNdb,1, 1) != NDBT_OK){
237  errors++;
238  continue;
239  }
240 
241  i++;
242 
243  if (i >= maxOpsLimit){
244  errors = maxErrors;
245  }
246 
247  }
248 
249  ndbout << i << " operations used" << endl;
250 
251  int execResult = hugoOps.execute_Commit(pNdb);
252  switch(execResult){
253  case NDBT_OK:
254  break;
255  case 233: // Out of operation records in transaction coordinator
256  // OK - end test
257  endTest = true;
258  break;
259  default:
260  result = NDBT_FAILED;
261  break;
262  }
263 
264  hugoOps.closeTransaction(pNdb);
265 
266  l++;
267 
268  }
269 
270  delete pNdb;
271 
272  return result;
273 }
274 
275 int runTestGetValue(NDBT_Context* ctx, NDBT_Step* step){
276 
277  int result = NDBT_OK;
278  const NdbDictionary::Table* pTab = ctx->getTab();
279 
280  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
281  if (pNdb == NULL){
282  ndbout << "pNdb == NULL" << endl;
283  return NDBT_FAILED;
284  }
285  if (pNdb->init(2048)){
286  ERR(pNdb->getNdbError());
287  delete pNdb;
288  return NDBT_FAILED;
289  }
290 
291  HugoOperations hugoOps(*pTab);
292 
293  for (int m = 1; m < 100; m++){
294  int errors = 0;
295  int maxErrors = 5;
296 
297  NdbConnection* pCon = pNdb->startTransaction();
298  if (pCon == NULL){
299  delete pNdb;
300  return NDBT_FAILED;
301  }
302 
303  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
304  if (pOp == NULL){
305  pNdb->closeTransaction(pCon);
306  delete pNdb;
307  return NDBT_FAILED;
308  }
309 
310  if (pOp->readTuple() != 0){
311  pNdb->closeTransaction(pCon);
312  delete pNdb;
313  return NDBT_FAILED;
314  }
315 
316  for(int a = 0; a<pTab->getNoOfColumns(); a++){
317  if (pTab->getColumn(a)->getPrimaryKey() == true){
318  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
319  ERR(pCon->getNdbError());
320  pNdb->closeTransaction(pCon);
321  delete pNdb;
322  return NDBT_FAILED;
323  }
324  }
325  }
326 
327  int i = 0;
328  int maxLimit = 1000*m;
329  do {
330 
331  if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
332  const NdbError err = pCon->getNdbError();
333  ERR(err);
334  if (err.code == 0)
335  result = NDBT_FAILED;
336  errors++;
337  continue;
338  }
339 
340  i++;
341 
342  } while (errors < maxErrors && i < maxLimit);
343 
344  ndbout << i << " getValues called" << endl;
345 
346 
347  if (pCon->execute(Commit) != 0){
348  const NdbError err = pCon->getNdbError();
349  switch(err.code){
350  case 880: // TUP - Read too much
351  case 823: // TUP - Too much AI
352  case 4257: // NDBAPI - Too much AI
353  case 4002: // NDBAPI - send problem
354  // OK errors
355  ERR(pCon->getNdbError());
356  break;
357  default:
358  ERR(pCon->getNdbError());
359  ndbout << "Illegal error" << endl;
360  result= NDBT_FAILED;
361  break;
362  }
363  }
364 
365  pNdb->closeTransaction(pCon);
366 
367  }// m
368 
369 
370  delete pNdb;
371 
372  return result;
373 }
374 
375 int runTestEqual(NDBT_Context* ctx, NDBT_Step* step){
376  Uint32 loops = ctx->getNumLoops();
377  Uint32 l = 0;
378  int result = NDBT_OK;
379  const NdbDictionary::Table* pTab = ctx->getTab();
380 
381  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
382  if (pNdb == NULL){
383  ndbout << "pNdb == NULL" << endl;
384  return NDBT_FAILED;
385  }
386  if (pNdb->init(2048)){
387  ERR(pNdb->getNdbError());
388  delete pNdb;
389  return NDBT_FAILED;
390  }
391 
392  HugoOperations hugoOps(*pTab);
393 
394  while (l < loops){
395  for(int m = 1; m < 10; m++){
396  int errors = 0;
397  int maxErrors = 5;
398 
399  NdbConnection* pCon = pNdb->startTransaction();
400  if (pCon == NULL){
401  ndbout << "Could not start transaction" << endl;
402  delete pNdb;
403  return NDBT_FAILED;
404  }
405 
406  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
407  if (pOp == NULL){
408  ERR(pCon->getNdbError());
409  pNdb->closeTransaction(pCon);
410  delete pNdb;
411  return NDBT_FAILED;
412  }
413 
414  if (pOp->readTuple() != 0){
415  ERR(pCon->getNdbError());
416  pNdb->closeTransaction(pCon);
417  delete pNdb;
418  return NDBT_FAILED;
419  }
420 
421  int i = 0;
422  int maxLimit = 1000*m;
423  do {
424 
425  if ((l%2)!=0){
426  // Forward
427  for(int a = 0; a<pTab->getNoOfColumns(); a++){
428  if (pTab->getColumn(a)->getPrimaryKey() == true){
429  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
430  const NdbError err = pCon->getNdbError();
431  ERR(err);
432  if (err.code == 0)
433  result = NDBT_FAILED;
434  errors++;
435  }
436  }
437  }
438  } else {
439  // Backward
440  for(int a = pTab->getNoOfColumns()-1; a>=0; a--){
441  if (pTab->getColumn(a)->getPrimaryKey() == true){
442  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
443  const NdbError err = pCon->getNdbError();
444  ERR(err);
445  if (err.code == 0)
446  result = NDBT_FAILED;
447  errors++;
448  }
449  }
450  }
451  }
452 
453  i++;
454 
455  } while (errors < maxErrors && i < maxLimit);
456 
457  if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
458  const NdbError err = pCon->getNdbError();
459  ERR(pCon->getNdbError());
460  pNdb->closeTransaction(pCon);
461  delete pNdb;
462  if (err.code == 4225) {
463  return NDBT_OK;
464  } else {
465  return NDBT_FAILED;
466  }//if
467  }
468 
469  ndbout << i << " equal called" << endl;
470 
471 
472  int check = pCon->execute(Commit);
473  if (check != 0){
474  ERR(pCon->getNdbError());
475  }
476 
477  pNdb->closeTransaction(pCon);
478 
479  }// m
480  l++;
481 
482  }// l
483 
484  delete pNdb;
485  return result;
486 }
487 
488 int runTestDeleteNdb(NDBT_Context* ctx, NDBT_Step* step){
489  Uint32 loops = ctx->getNumLoops();
490  Uint32 l = 0;
491  int result = NDBT_OK;
492  NdbRestarts restarts;
493  Vector<Ndb*> ndbVector;
494  const NdbDictionary::Table* pTab = ctx->getTab();
495  HugoTransactions hugoTrans(*pTab);
496  int records = ctx->getNumRecords();
497 
498  while (l < loops && result == NDBT_OK){
499 
500  // Create 5 ndb objects
501  for( int i = 0; i < 5; i++){
502  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
503  if (pNdb == NULL){
504  ndbout << "pNdb == NULL" << endl;
505  result = NDBT_FAILED;
506  goto end_test;
507  }
508  ndbVector.push_back(pNdb);
509 
510  if (pNdb->init()){
511  ERR(pNdb->getNdbError());
512  result = NDBT_FAILED;
513  goto end_test;
514  }
515  if (pNdb->waitUntilReady() != 0){
516  ERR(pNdb->getNdbError());
517  result = NDBT_FAILED;
518  goto end_test;
519  }
520  if (hugoTrans.pkReadRecords(pNdb, records) != 0){
521  result = NDBT_FAILED;
522  goto end_test;
523  }
524  }
525 
526  if ((l % 2) == 0){
527  // Restart random node
528  ndbout << "Restart random node " << endl;
529  if(restarts.executeRestart(ctx, "RestartRandomNodeAbort", 120) != 0){
530  g_err << "Failed to executeRestart(RestartRandomNode)"<<endl;
531  result = NDBT_FAILED;
532  goto end_test;
533  }
534  } else {
535  // Restart all nodes
536  ndbout << "Restart all nodes " << endl;
537  if(restarts.executeRestart(ctx, "RestartAllNodesAbort", 120) != 0){
538  g_err << "Failed to executeRestart(RestartAllNodes)"<<endl;
539  result = NDBT_FAILED;
540  goto end_test;
541  }
542  }
543 
544  // Delete the ndb objects
545  for(size_t j = 0; j < ndbVector.size(); j++)
546  delete ndbVector[j];
547  ndbVector.clear();
548  l++;
549  }
550 
551 
552  end_test:
553 
554  for(size_t i = 0; i < ndbVector.size(); i++)
555  delete ndbVector[i];
556  ndbVector.clear();
557 
558  return result;
559 }
560 
561 
562 int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
563  int records = ctx->getNumRecords();
564 
565  UtilTransactions utilTrans(*ctx->getTab());
566  if (utilTrans.clearTable2(GETNDB(step), records) != 0){
567  return NDBT_FAILED;
568  }
569  return NDBT_OK;
570 }
571 int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
572 
573  int records = ctx->getNumRecords();
574  HugoTransactions hugoTrans(*ctx->getTab());
575  if (hugoTrans.loadTable(GETNDB(step), records) != 0){
576  return NDBT_FAILED;
577  }
578  return NDBT_OK;
579 }
580 
581 int runTestWaitUntilReady(NDBT_Context* ctx, NDBT_Step* step){
582 
583  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
584 
585  // Forget about calling pNdb->init();
586 
587  if (pNdb->waitUntilReady() == 0){
588  ndbout << "waitUntilReady returned OK" << endl;
589  delete pNdb;
590  return NDBT_FAILED;
591  }
592  const NdbError err = pNdb->getNdbError();
593  delete pNdb;
594 
595  ERR(err);
596  if (err.code != 4256)
597  return NDBT_FAILED;
598 
599  return NDBT_OK;
600 }
601 
602 int runGetNdbOperationNoTab(NDBT_Context* ctx, NDBT_Step* step){
603 
604  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
605  if (pNdb == NULL){
606  ndbout << "pNdb == NULL" << endl;
607  return NDBT_FAILED;
608  }
609  if (pNdb->init()){
610  ERR(pNdb->getNdbError());
611  delete pNdb;
612  return NDBT_FAILED;
613  }
614 
615  NdbConnection* pCon = pNdb->startTransaction();
616  if (pCon == NULL){
617  delete pNdb;
618  return NDBT_FAILED;
619  }
620 
621  // Call getNdbOperation on an unknown table
622  NdbOperation* pOp = pCon->getNdbOperation("HUPP76");
623  if (pOp == NULL){
624  NdbError err = pCon->getNdbError();
625  ERR(err);
626  if (err.code == 0){
627  pNdb->closeTransaction(pCon);
628  delete pNdb;
629  return NDBT_FAILED;
630  }
631  }
632 
633  pNdb->closeTransaction(pCon);
634 
635  delete pNdb;
636 
637  return NDBT_OK;
638 }
639 
640 int runBadColNameHandling(NDBT_Context* ctx, NDBT_Step* step){
641  int result = NDBT_OK;
642  const NdbDictionary::Table* pTab = ctx->getTab();
643 
644 
645  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
646  if (pNdb == NULL){
647  ndbout << "pNdb == NULL" << endl;
648  return NDBT_FAILED;
649  }
650  if (pNdb->init()){
651  ERR(pNdb->getNdbError());
652  delete pNdb;
653  return NDBT_FAILED;
654  }
655 
656  const int CASES= 5;
657  int i;
658 
659  for (i= 0; i < CASES; i++)
660  {
661  ndbout << "Case " << i << endl;
662  NdbConnection* pCon = pNdb->startTransaction();
663  if (pCon == NULL){
664  pNdb->closeTransaction(pCon);
665  delete pNdb;
666  return NDBT_FAILED;
667  }
668 
669  /* Cases 0-3 use PK ops, 4 + use scans */
670  NdbOperation* pOp = (i < 4 ? pCon->getNdbOperation(pTab->getName()):
671  pCon->getNdbScanOperation(pTab->getName()));
672  if (pOp == NULL){
673  ERR(pCon->getNdbError());
674  pNdb->closeTransaction(pCon);
675  delete pNdb;
676  return NDBT_FAILED;
677  }
678 
679  bool failed= false;
680  int expectedError= 0;
681  HugoOperations hugoOps(*pTab);
682 
683  switch(i) {
684  case 0:
685  if (pOp->readTuple() != 0){
686  ERR(pCon->getNdbError());
687  pNdb->closeTransaction(pCon);
688  delete pNdb;
689  return NDBT_FAILED;
690  }
691 
692  // getValue should fail, we check that we get correct errors
693  // in expected places.
694  expectedError= 4004;
695  failed= (pOp->getValue("MOST_IMPROBABLE2") == NULL);
696  break;
697 
698  case 1:
699  if (pOp->readTuple() != 0){
700  ERR(pCon->getNdbError());
701  pNdb->closeTransaction(pCon);
702  delete pNdb;
703  return NDBT_FAILED;
704  }
705 
706  // equal should fail, we check that we get correct errors
707  // in expected places.
708  expectedError= 4004;
709  failed= (pOp->equal("MOST_IMPROBABLE2", 0) != 0);
710  break;
711 
712  case 2:
713  if (pOp->writeTuple() != 0){
714  ERR(pCon->getNdbError());
715  pNdb->closeTransaction(pCon);
716  delete pNdb;
717  return NDBT_FAILED;
718  }
719 
720  // set equality on pk columns
721  for(int a = 0; a<pTab->getNoOfColumns(); a++){
722  if (pTab->getColumn(a)->getPrimaryKey() == true){
723  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
724  const NdbError err = pCon->getNdbError();
725  ERR(err);
726  pNdb->closeTransaction(pCon);
727  delete pNdb;
728  return NDBT_FAILED;
729  }
730  }
731  }
732 
733  // setValue should fail, we check that we get correct errors
734  // in expected places.
735  expectedError= 4004;
736  failed= (pOp->setValue("MOST_IMPROBABLE2", 0) != 0);
737  break;
738 
739  case 3:
740  if (pOp->readTuple() != 0){
741  ERR(pCon->getNdbError());
742  pNdb->closeTransaction(pCon);
743  delete pNdb;
744  return NDBT_FAILED;
745  }
746 
747  // getBlobHandle should fail, we check that we get correct errors
748  // in expected places.
749  expectedError= 4004;
750  failed= (pOp->getBlobHandle("MOST_IMPROBABLE2") == NULL);
751  break;
752 
753  case 4:
754  {
755  NdbScanOperation* sop= (NdbScanOperation*) pOp;
756  if (sop->readTuples() != 0){
757  ERR(pCon->getNdbError());
758  pNdb->closeTransaction(pCon);
759  delete pNdb;
760  return NDBT_FAILED;
761  }
762 
763  // getBlobHandle should fail, we check that we get correct errors
764  // in expected places.
765  expectedError= 4004;
766  ndbout << "About to call getBlobHandle" << endl;
767  failed= (sop->getBlobHandle("MOST_IMPROBABLE2") == NULL);
768 
769  sop->close();
770  break;
771  }
772 
773  default:
774  break;
775  }
776 
777  if (failed)
778  {
779  const NdbError opErr= pOp->getNdbError();
780  const NdbError transErr = pCon->getNdbError();
781  ERR(opErr);
782  ERR(transErr);
783  if (opErr.code != transErr.code) {
784  ndbout << "Error reporting mismatch, expected "
785  << expectedError << endl;
786  result = NDBT_FAILED;
787  }
788  if (opErr.code != expectedError){
789  ndbout << "No or bad error detected, expected "
790  << expectedError << endl;
791  result = NDBT_FAILED;
792  }
793  } else {
794  ndbout << "Case " << i << " did not fail" << endl;
795  result = NDBT_FAILED;
796  }
797 
798  pNdb->closeTransaction(pCon);
799 
800  if (result == NDBT_FAILED)
801  break;
802  } // for
803 
804  delete pNdb;
805 
806  return result;
807 }
808 
809 int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
810  int result = NDBT_OK;
811  const NdbDictionary::Table* pTab = ctx->getTab();
812 
813 
814  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
815  if (pNdb == NULL){
816  ndbout << "pNdb == NULL" << endl;
817  return NDBT_FAILED;
818  }
819  if (pNdb->init()){
820  ERR(pNdb->getNdbError());
821  delete pNdb;
822  return NDBT_FAILED;
823  }
824 
825  NdbConnection* pCon = pNdb->startTransaction();
826  if (pCon == NULL){
827  pNdb->closeTransaction(pCon);
828  delete pNdb;
829  return NDBT_FAILED;
830  }
831 
832  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
833  if (pOp == NULL){
834  ERR(pCon->getNdbError());
835  pNdb->closeTransaction(pCon);
836  delete pNdb;
837  return NDBT_FAILED;
838  }
839 
840  // Forget about calling pOp->insertTuple();
841 
842  // Call getValue should not work
843  if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
844  const NdbError err = pCon->getNdbError();
845  ERR(err);
846  if (err.code == 0){
847  ndbout << "hupp" << endl;
848  result = NDBT_FAILED;
849  }
850  } else {
851  ndbout << "hupp2" << endl;
852  result = NDBT_FAILED;
853  }
854 
855  pNdb->closeTransaction(pCon);
856  delete pNdb;
857 
858  return result;
859 }
860 
861 int runGetValueInUpdate(NDBT_Context* ctx, NDBT_Step* step){
862  const NdbDictionary::Table* pTab = ctx->getTab();
863 
864  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
865  if (pNdb == NULL){
866  ndbout << "pNdb == NULL" << endl;
867  return NDBT_FAILED;
868  }
869  if (pNdb->init()){
870  ERR(pNdb->getNdbError());
871  delete pNdb;
872  return NDBT_FAILED;
873  }
874 
875  NdbConnection* pCon = pNdb->startTransaction();
876  if (pCon == NULL){
877  pNdb->closeTransaction(pCon);
878  delete pNdb;
879  return NDBT_FAILED;
880  }
881 
882  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
883  if (pOp == NULL){
884  ERR(pCon->getNdbError());
885  pNdb->closeTransaction(pCon);
886  delete pNdb;
887  return NDBT_FAILED;
888  }
889 
890  if (pOp->updateTuple() != 0){
891  pNdb->closeTransaction(pCon);
892  delete pNdb;
893  return NDBT_FAILED;
894  }
895 
896  // Call getValue should not work
897  if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
898  // It didn't work
899  const NdbError err = pCon->getNdbError();
900  ERR(err);
901  if (err.code == 0){
902  pNdb->closeTransaction(pCon);
903  delete pNdb;
904  return NDBT_FAILED;
905  }
906  } else {
907  // It worked, not good!
908  pNdb->closeTransaction(pCon);
909  delete pNdb;
910  return NDBT_FAILED;
911  }
912 
913  int check = pCon->execute(Commit);
914  if (check != 0){
915  ERR(pCon->getNdbError());
916  }
917 
918  pNdb->closeTransaction(pCon);
919  delete pNdb;
920 
921  return NDBT_OK;
922 }
923 
924 int runUpdateWithoutValues(NDBT_Context* ctx, NDBT_Step* step){
925  int result = NDBT_OK;
926  const NdbDictionary::Table* pTab = ctx->getTab();
927 
928  HugoOperations hugoOps(*pTab);
929 
930  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
931  if (pNdb == NULL){
932  ndbout << "pNdb == NULL" << endl;
933  return NDBT_FAILED;
934  }
935  if (pNdb->init()){
936  ERR(pNdb->getNdbError());
937  delete pNdb;
938  return NDBT_FAILED;
939  }
940 
941  NdbConnection* pCon = pNdb->startTransaction();
942  if (pCon == NULL){
943  pNdb->closeTransaction(pCon);
944  delete pNdb;
945  return NDBT_FAILED;
946  }
947 
948  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
949  if (pOp == NULL){
950  ERR(pCon->getNdbError());
951  pNdb->closeTransaction(pCon);
952  delete pNdb;
953  return NDBT_FAILED;
954  }
955 
956  if (pOp->updateTuple() != 0){
957  pNdb->closeTransaction(pCon);
958  ERR(pOp->getNdbError());
959  delete pNdb;
960  return NDBT_FAILED;
961  }
962 
963  for(int a = 0; a<pTab->getNoOfColumns(); a++){
964  if (pTab->getColumn(a)->getPrimaryKey() == true){
965  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
966  ERR(pCon->getNdbError());
967  pNdb->closeTransaction(pCon);
968  delete pNdb;
969  return NDBT_FAILED;
970  }
971  }
972  }
973 
974  // Dont' call any setValues
975 
976  // Execute should work
977  int check = pCon->execute(Commit);
978  if (check == 0){
979  ndbout << "execute worked" << endl;
980  } else {
981  ERR(pCon->getNdbError());
982  result = NDBT_FAILED;
983  }
984 
985  pNdb->closeTransaction(pCon);
986  delete pNdb;
987 
988  return result;
989 }
990 
991 int runUpdateWithoutKeys(NDBT_Context* ctx, NDBT_Step* step){
992  int result = NDBT_OK;
993  const NdbDictionary::Table* pTab = ctx->getTab();
994 
995 
996  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
997  if (pNdb == NULL){
998  ndbout << "pNdb == NULL" << endl;
999  return NDBT_FAILED;
1000  }
1001  if (pNdb->init()){
1002  ERR(pNdb->getNdbError());
1003  delete pNdb;
1004  return NDBT_FAILED;
1005  }
1006 
1007  NdbConnection* pCon = pNdb->startTransaction();
1008  if (pCon == NULL){
1009  pNdb->closeTransaction(pCon);
1010  delete pNdb;
1011  return NDBT_FAILED;
1012  }
1013 
1014  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1015  if (pOp == NULL){
1016  ERR(pCon->getNdbError());
1017  pNdb->closeTransaction(pCon);
1018  delete pNdb;
1019  return NDBT_FAILED;
1020  }
1021 
1022  if (pOp->updateTuple() != 0){
1023  pNdb->closeTransaction(pCon);
1024  ERR(pOp->getNdbError());
1025  delete pNdb;
1026  return NDBT_FAILED;
1027  }
1028 
1029  // Dont' call any equal or setValues
1030 
1031  // Execute should not work
1032  int check = pCon->execute(Commit);
1033  if (check == 0){
1034  ndbout << "execute worked" << endl;
1035  result = NDBT_FAILED;
1036  } else {
1037  ERR(pCon->getNdbError());
1038  }
1039 
1040  pNdb->closeTransaction(pCon);
1041  delete pNdb;
1042 
1043  return result;
1044 }
1045 
1046 
1047 int runReadWithoutGetValue(NDBT_Context* ctx, NDBT_Step* step){
1048  int result = NDBT_OK;
1049  const NdbDictionary::Table* pTab = ctx->getTab();
1050 
1051  HugoOperations hugoOps(*pTab);
1052 
1053  Ndb* pNdb = GETNDB(step);
1054  Uint32 lm;
1055 
1056  for(Uint32 cm= 0; cm < 2; cm++)
1057  {
1058  for(lm= 0; lm <= NdbOperation::LM_CommittedRead; lm++)
1059  {
1060  NdbConnection* pCon = pNdb->startTransaction();
1061  if (pCon == NULL){
1062  pNdb->closeTransaction(pCon);
1063  return NDBT_FAILED;
1064  }
1065 
1066  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1067  if (pOp == NULL){
1068  ERR(pCon->getNdbError());
1069  pNdb->closeTransaction(pCon);
1070  return NDBT_FAILED;
1071  }
1072 
1073  if (pOp->readTuple((NdbOperation::LockMode)lm) != 0){
1074  pNdb->closeTransaction(pCon);
1075  ERR(pOp->getNdbError());
1076  return NDBT_FAILED;
1077  }
1078 
1079  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1080  if (pTab->getColumn(a)->getPrimaryKey() == true){
1081  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
1082  ERR(pCon->getNdbError());
1083  pNdb->closeTransaction(pCon);
1084  return NDBT_FAILED;
1085  }
1086  }
1087  }
1088 
1089  // Dont' call any getValues
1090 
1091  // Execute should work
1092  int check = pCon->execute(cm == 0 ? NoCommit : Commit);
1093  if (check == 0){
1094  ndbout << "execute worked" << endl;
1095  } else {
1096  ERR(pCon->getNdbError());
1097  result = NDBT_FAILED;
1098  }
1099 
1100  pNdb->closeTransaction(pCon);
1101  }
1102  }
1103 
1107  for(lm= 0; lm <= NdbOperation::LM_CommittedRead; lm++)
1108  {
1109  NdbConnection* pCon = pNdb->startTransaction();
1110  if (pCon == NULL){
1111  pNdb->closeTransaction(pCon);
1112  return NDBT_FAILED;
1113  }
1114 
1115  NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1116  if (pOp == NULL){
1117  ERR(pCon->getNdbError());
1118  pNdb->closeTransaction(pCon);
1119  return NDBT_FAILED;
1120  }
1121 
1122  if ((pOp->readTuples((NdbOperation::LockMode)lm)) != 0){
1123  pNdb->closeTransaction(pCon);
1124  ERR(pOp->getNdbError());
1125  return NDBT_FAILED;
1126  }
1127 
1128 
1129  // Dont' call any getValues
1130 
1131  // Execute should work
1132  int check = pCon->execute(NoCommit);
1133  if (check == 0){
1134  ndbout << "execute worked" << endl;
1135  } else {
1136  ERR(pCon->getNdbError());
1137  result = NDBT_FAILED;
1138  }
1139 
1140  int res;
1141  while((res = pOp->nextResult()) == 0);
1142  pNdb->closeTransaction(pCon);
1143 
1144  if(res != 1)
1145  result = NDBT_FAILED;
1146  }
1147 
1148  return result;
1149 }
1150 
1151 
1152 int runCheckGetNdbErrorOperation(NDBT_Context* ctx, NDBT_Step* step){
1153  int result = NDBT_OK;
1154  const NdbDictionary::Table* pTab = ctx->getTab();
1155 
1156  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1157  if (pNdb == NULL){
1158  ndbout << "pNdb == NULL" << endl;
1159  return NDBT_FAILED;
1160  }
1161  if (pNdb->init(2048)){
1162  ERR(pNdb->getNdbError());
1163  delete pNdb;
1164  return NDBT_FAILED;
1165  }
1166 
1167  HugoOperations hugoOps(*pTab);
1168 
1169 
1170  NdbConnection* pCon = pNdb->startTransaction();
1171  if (pCon == NULL){
1172  ndbout << "Could not start transaction" << endl;
1173  delete pNdb;
1174  return NDBT_FAILED;
1175  }
1176 
1177  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1178  if (pOp == NULL){
1179  ERR(pCon->getNdbError());
1180  pNdb->closeTransaction(pCon);
1181  delete pNdb;
1182  return NDBT_FAILED;
1183  }
1184 
1185  // Dont call readTuple here
1186  // That's the error!
1187 
1188  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1189  if (pTab->getColumn(a)->getPrimaryKey() == true){
1190  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
1191  // An error has occured, check that
1192  // it's possible to get the NdbErrorOperation
1193  const NdbError err = pCon->getNdbError();
1194  ERR(err);
1195  if (err.code == 0)
1196  result = NDBT_FAILED;
1197 
1198  NdbOperation* pOp2 = pCon->getNdbErrorOperation();
1199  if (pOp2 == NULL)
1200  result = NDBT_FAILED;
1201  else {
1202  const NdbError err2 = pOp2->getNdbError();
1203  ERR(err2);
1204  if (err.code == 0)
1205  result = NDBT_FAILED;
1206  }
1207  }
1208  }
1209  }
1210 
1211  pNdb->closeTransaction(pCon);
1212 
1213  delete pNdb;
1214  return result;
1215 }
1216 
1217 #define C2(x) { int _x= (x); if(_x == 0){ ndbout << "line: " << __LINE__ << endl; return NDBT_FAILED;} }
1218 
1219 int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){
1220  int result = NDBT_OK;
1221  const NdbDictionary::Table* pTab = ctx->getTab();
1222 
1223  HugoOperations hugoOps(*pTab);
1224 
1225  Ndb* pNdb = GETNDB(step);
1226  C2(hugoOps.startTransaction(pNdb) == 0);
1227  C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1228  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1229  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1230  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1231  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1232  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1233  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1234  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1235  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1236  C2(hugoOps.execute_Commit(pNdb) == 0);
1237  C2(hugoOps.closeTransaction(pNdb) == 0);
1238 
1239  C2(hugoOps.startTransaction(pNdb) == 0);
1240  C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1241  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1242  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1243  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1244  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1245  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1246  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1247  C2(hugoOps.execute_Commit(pNdb) == 0);
1248  C2(hugoOps.closeTransaction(pNdb) == 0);
1249 
1250  C2(hugoOps.startTransaction(pNdb) == 0);
1251  C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1252  C2(hugoOps.execute_Commit(pNdb) == 0);
1253  C2(hugoOps.closeTransaction(pNdb) == 0);
1254 
1255  C2(hugoOps.startTransaction(pNdb) == 0);
1256  C2(hugoOps.pkReadRecord(pNdb, 0, 1, NdbOperation::LM_Exclusive) == 0);
1257  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1258  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1259  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1260  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1261  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1262  C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1263  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1264  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1265  C2(hugoOps.execute_Commit(pNdb) == 0);
1266  C2(hugoOps.closeTransaction(pNdb) == 0);
1267 
1268  Ndb ndb2(&ctx->m_cluster_connection, "TEST_DB");
1269  C2(ndb2.init() == 0);
1270  C2(ndb2.waitUntilReady() == 0);
1271  HugoOperations hugoOps2(*pTab);
1272 
1273  C2(hugoOps.startTransaction(pNdb) == 0);
1274  C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1275  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1276  C2(hugoOps2.startTransaction(&ndb2) == 0);
1277  C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1278  C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1279  C2(hugoOps.execute_Commit(pNdb) == 0);
1280  C2(hugoOps2.wait_async(&ndb2) == 0);
1281  C2(hugoOps.closeTransaction(pNdb) == 0);
1282  C2(hugoOps2.closeTransaction(&ndb2) == 0);
1283 
1284  C2(hugoOps.startTransaction(pNdb) == 0);
1285  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1286  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1287  C2(hugoOps2.startTransaction(&ndb2) == 0);
1288  C2(hugoOps2.pkWriteRecord(&ndb2, 0, 1) == 0);
1289  C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1290  C2(hugoOps.execute_Commit(pNdb) == 0);
1291  C2(hugoOps2.wait_async(&ndb2) == 0);
1292  C2(hugoOps2.execute_Commit(pNdb) == 0);
1293  C2(hugoOps.closeTransaction(pNdb) == 0);
1294  C2(hugoOps2.closeTransaction(&ndb2) == 0);
1295 
1296  C2(hugoOps.startTransaction(pNdb) == 0);
1297  C2(hugoOps.pkUpdateRecord(pNdb, 0, 1) == 0);
1298  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1299  C2(hugoOps2.startTransaction(&ndb2) == 0);
1300  C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1301  C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1302  C2(hugoOps.execute_Commit(pNdb) == 0);
1303  C2(hugoOps2.wait_async(&ndb2) == 0);
1304  C2(hugoOps.closeTransaction(pNdb) == 0);
1305  C2(hugoOps2.closeTransaction(&ndb2) == 0);
1306 
1307  C2(hugoOps.startTransaction(pNdb) == 0);
1308  C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1309  C2(hugoOps.execute_NoCommit(pNdb) == 0);
1310  C2(hugoOps2.startTransaction(&ndb2) == 0);
1311  C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1312  C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1313  C2(hugoOps.execute_Commit(pNdb) == 0);
1314  C2(hugoOps2.wait_async(&ndb2) != 0);
1315  C2(hugoOps.closeTransaction(pNdb) == 0);
1316  C2(hugoOps2.closeTransaction(&ndb2) == 0);
1317 
1318  return result;
1319 }
1320 
1321 int runBug_WritePartialIgnoreError(NDBT_Context* ctx, NDBT_Step* step){
1322  int result = NDBT_OK;
1323  const NdbDictionary::Table* pTab = ctx->getTab();
1324 
1325  HugoOperations hugoOps(*pTab);
1326 
1327  Ndb* pNdb = GETNDB(step);
1328  C2(hugoOps.startTransaction(pNdb) == 0);
1329  C2(hugoOps.pkWritePartialRecord(pNdb, 0, 1) == 0);
1330  C2(hugoOps.execute_Commit(pNdb, AO_IgnoreError) == 839);
1331  C2(hugoOps.closeTransaction(pNdb) == 0);
1332 
1333  return result;
1334 }
1335 
1336 int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){
1337  int result = NDBT_OK;
1338  const Uint32 max= 5;
1339  const NdbDictionary::Table* pTab = ctx->getTab();
1340 
1341  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1342  if (pNdb == NULL){
1343  ndbout << "pNdb == NULL" << endl;
1344  return NDBT_FAILED;
1345  }
1346  if (pNdb->init(max)){
1347  ERR(pNdb->getNdbError());
1348  delete pNdb;
1349  return NDBT_FAILED;
1350  }
1351 
1352  NdbConnection* pCon = pNdb->startTransaction();
1353  if (pCon == NULL){
1354  pNdb->closeTransaction(pCon);
1355  delete pNdb;
1356  return NDBT_FAILED;
1357  }
1358 
1359  Uint32 i;
1361  for(i = 0; i<10*max; i++)
1362  {
1363  NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1364  if (pOp == NULL){
1365  ERR(pCon->getNdbError());
1366  pNdb->closeTransaction(pCon);
1367  delete pNdb;
1368  return NDBT_FAILED;
1369  }
1370 
1371  if (pOp->readTuples() != 0){
1372  pNdb->closeTransaction(pCon);
1373  ERR(pOp->getNdbError());
1374  delete pNdb;
1375  return NDBT_FAILED;
1376  }
1377  scans.push_back(pOp);
1378  }
1379 
1380  // Dont' call any equal or setValues
1381 
1382  // Execute should not work
1383  int check = pCon->execute(NoCommit);
1384  if (check == 0){
1385  ndbout << "execute worked" << endl;
1386  } else {
1387  ERR(pCon->getNdbError());
1388  }
1389 
1390  for(i= 0; i<scans.size(); i++)
1391  {
1392  NdbScanOperation* pOp= scans[i];
1393  while((check= pOp->nextResult()) == 0);
1394  if(check != 1)
1395  {
1396  ERR(pOp->getNdbError());
1397  pNdb->closeTransaction(pCon);
1398  delete pNdb;
1399  return NDBT_FAILED;
1400  }
1401  }
1402 
1403  pNdb->closeTransaction(pCon);
1404 
1406  for(i= 0; i<10*max; i++)
1407  {
1408  pCon= pNdb->startTransaction();
1409  if(pCon)
1410  cons.push_back(pCon);
1411  else
1412  break;
1413  }
1414 
1415  for(i= 0; i<cons.size(); i++)
1416  {
1417  cons[i]->close();
1418  }
1419 
1420  if(cons.size() != max)
1421  {
1422  result= NDBT_FAILED;
1423  }
1424 
1425  delete pNdb;
1426 
1427  return result;
1428 }
1429 
1430 char pkIdxName[255];
1431 
1432 int createPkIndex(NDBT_Context* ctx, NDBT_Step* step){
1433  bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
1434 
1435  const NdbDictionary::Table* pTab = ctx->getTab();
1436  Ndb* pNdb = GETNDB(step);
1437 
1438  bool logged = ctx->getProperty("LoggedIndexes", 1);
1439 
1440  // Create index
1441  BaseString::snprintf(pkIdxName, 255, "IDC_PK_%s", pTab->getName());
1442  if (orderedIndex)
1443  ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index "
1444  << pkIdxName << " (";
1445  else
1446  ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "unique index "
1447  << pkIdxName << " (";
1448 
1449  NdbDictionary::Index pIdx(pkIdxName);
1450  pIdx.setTable(pTab->getName());
1451  if (orderedIndex)
1452  pIdx.setType(NdbDictionary::Index::OrderedIndex);
1453  else
1455  for (int c = 0; c< pTab->getNoOfColumns(); c++){
1456  const NdbDictionary::Column * col = pTab->getColumn(c);
1457  if(col->getPrimaryKey()){
1458  pIdx.addIndexColumn(col->getName());
1459  ndbout << col->getName() <<" ";
1460  }
1461  }
1462 
1463  pIdx.setStoredIndex(logged);
1464  ndbout << ") ";
1465  if (pNdb->getDictionary()->createIndex(pIdx) != 0){
1466  ndbout << "FAILED!" << endl;
1467  const NdbError err = pNdb->getDictionary()->getNdbError();
1468  ERR(err);
1469  return NDBT_FAILED;
1470  }
1471 
1472  ndbout << "OK!" << endl;
1473  return NDBT_OK;
1474 }
1475 
1476 int createPkIndex_Drop(NDBT_Context* ctx, NDBT_Step* step){
1477  const NdbDictionary::Table* pTab = ctx->getTab();
1478  Ndb* pNdb = GETNDB(step);
1479 
1480  // Drop index
1481  ndbout << "Dropping index " << pkIdxName << " ";
1482  if (pNdb->getDictionary()->dropIndex(pkIdxName,
1483  pTab->getName()) != 0){
1484  ndbout << "FAILED!" << endl;
1485  ERR(pNdb->getDictionary()->getNdbError());
1486  return NDBT_FAILED;
1487  } else {
1488  ndbout << "OK!" << endl;
1489  }
1490 
1491  return NDBT_OK;
1492 }
1493 
1494 static
1495 int
1496 op_row(NdbTransaction* pTrans, HugoOperations& hugoOps,
1497  const NdbDictionary::Table* pTab, int op, int row)
1498 {
1499  NdbOperation * pOp = 0;
1500  switch(op){
1501  case 0:
1502  case 1:
1503  case 2:
1504  case 3:
1505  case 4:
1506  case 5:
1507  case 12:
1508  pOp = pTrans->getNdbOperation(pTab->getName());
1509  break;
1510  case 9:
1511  return 0;
1512  case 6:
1513  case 7:
1514  case 8:
1515  case 10:
1516  case 11:
1517  pOp = pTrans->getNdbIndexOperation(pkIdxName, pTab->getName());
1518  default:
1519  break;
1520  }
1521 
1522  switch(op){
1523  case 0:
1524  case 6:
1525  pOp->readTuple();
1526  break;
1527  case 1:
1528  case 7:
1529  pOp->committedRead();
1530  break;
1531  case 2:
1532  case 8:
1533  pOp->readTupleExclusive();
1534  break;
1535  case 3:
1536  case 9:
1537  pOp->insertTuple();
1538  break;
1539  case 4:
1540  case 10:
1541  pOp->updateTuple();
1542  break;
1543  case 5:
1544  case 11:
1545  pOp->deleteTuple();
1546  break;
1547  case 12:
1548  CHECK(!pOp->simpleRead());
1549  break;
1550  default:
1551  abort();
1552  }
1553 
1554  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1555  if (pTab->getColumn(a)->getPrimaryKey() == true){
1556  if(hugoOps.equalForAttr(pOp, a, row) != 0){
1557  return NDBT_FAILED;
1558  }
1559  }
1560  }
1561 
1562  switch(op){
1563  case 0:
1564  case 1:
1565  case 2:
1566  case 6:
1567  case 7:
1568  case 8:
1569  case 12:
1570  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1571  CHECK(pOp->getValue(a));
1572  }
1573  break;
1574  case 3:
1575  case 4:
1576  case 10:
1577  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1578  if (pTab->getColumn(a)->getPrimaryKey() == false){
1579  if(hugoOps.setValueForAttr(pOp, a, row, 2) != 0){
1580  return NDBT_FAILED;
1581  }
1582  }
1583  }
1584  break;
1585  case 5:
1586  case 11:
1587  pOp->deleteTuple();
1588  break;
1589  case 9:
1590  default:
1591  abort();
1592  }
1593 
1594  return NDBT_OK;
1595 }
1596 
1597 static void print(int op)
1598 {
1599  const char * str = 0;
1600  switch(op){
1601  case 0: str = "pk read-sh"; break;
1602  case 1: str = "pk read-nl"; break;
1603  case 2: str = "pk read-ex"; break;
1604  case 3: str = "pk insert "; break;
1605  case 4: str = "pk update "; break;
1606  case 5: str = "pk delete "; break;
1607  case 6: str = "uk read-sh"; break;
1608  case 7: str = "uk read-nl"; break;
1609  case 8: str = "uk read-ex"; break;
1610  case 9: str = "noop "; break;
1611  case 10: str = "uk update "; break;
1612  case 11: str = "uk delete "; break;
1613  case 12: str = "pk read-si"; break;
1614 
1615  default:
1616  abort();
1617  }
1618  printf("%s ", str);
1619 }
1620 
1621 int
1622 runTestIgnoreError(NDBT_Context* ctx, NDBT_Step* step)
1623 {
1624  Uint32 loops = ctx->getNumRecords();
1625  const NdbDictionary::Table* pTab = ctx->getTab();
1626 
1627  HugoOperations hugoOps(*pTab);
1628  HugoTransactions hugoTrans(*pTab);
1629 
1630  Ndb* pNdb = GETNDB(step);
1631 
1632  struct {
1633  ExecType et;
1634  AbortOption ao;
1635  } tests[] = {
1636  { Commit, AbortOnError },
1637  { Commit, AO_IgnoreError },
1638  { NoCommit, AbortOnError },
1639  { NoCommit, AO_IgnoreError },
1640  };
1641 
1642  printf("case: <op1> <op2> c/nc ao/ie\n");
1643  Uint32 tno = 0;
1644  for (Uint32 op1 = 0; op1 < 13; op1++)
1645  {
1646  // NOTE : I get a node crash if the following loop starts from 0!
1647  for (Uint32 op2 = op1; op2 < 13; op2++)
1648  {
1649  int ret;
1650  NdbTransaction* pTrans = 0;
1651 
1652  for (Uint32 i = 0; i<4; i++, tno++)
1653  {
1654  if (loops != 1000 && loops != tno)
1655  continue;
1656  ExecType et = tests[i].et;
1657  AbortOption ao = tests[i].ao;
1658 
1659  printf("%.3d : ", tno);
1660  print(op1);
1661  print(op2);
1662  switch(et){
1663  case Commit: printf("c "); break;
1664  case NoCommit: printf("nc "); break;
1665  default: printf("bad exectype : %d\n", et); return NDBT_FAILED;
1666  }
1667  switch(ao){
1668  case AbortOnError: printf("aoe "); break;
1669  case AO_IgnoreError: printf("ie "); break;
1670  default: printf("bad abortoption : %d\n", ao); return NDBT_FAILED;
1671  }
1672  printf(": ");
1673 
1674 
1675  hugoTrans.loadTable(pNdb, 1);
1676  CHECK(pTrans = pNdb->startTransaction());
1677  CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
1678  ret = pTrans->execute(et, ao);
1679  pTrans->close();
1680  printf("%d ", ret);
1681  hugoTrans.clearTable(pNdb);
1682 
1683  hugoTrans.loadTable(pNdb, 1);
1684  CHECK(pTrans = pNdb->startTransaction());
1685  CHECK(!op_row(pTrans, hugoOps, pTab, op1, 1));
1686  ret = pTrans->execute(et, ao);
1687  pTrans->close();
1688  printf("%d ", ret);
1689  hugoTrans.clearTable(pNdb);
1690 
1691  hugoTrans.loadTable(pNdb, 1);
1692  CHECK(pTrans = pNdb->startTransaction());
1693  CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
1694  CHECK(!op_row(pTrans, hugoOps, pTab, op2, 1));
1695  ret = pTrans->execute(et, ao);
1696  pTrans->close();
1697  printf("%d\n", ret);
1698  hugoTrans.clearTable(pNdb);
1699 
1700  hugoTrans.clearTable(pNdb);
1701  }
1702  }
1703  }
1704  return NDBT_OK;
1705 }
1706 
1707 static
1708 Uint32
1709 do_cnt(Ndb_cluster_connection* con)
1710 {
1711  Uint32 cnt = 0;
1712  const Ndb* p = 0;
1713  con->lock_ndb_objects();
1714  while ((p = con->get_next_ndb_object(p)) != 0) cnt++;
1715  con->unlock_ndb_objects();
1716  return cnt;
1717 }
1718 
1719 int runCheckNdbObjectList(NDBT_Context* ctx, NDBT_Step* step)
1720 {
1721  Ndb_cluster_connection* con = &ctx->m_cluster_connection;
1722 
1723  Uint32 cnt1 = do_cnt(con);
1724  Vector<Ndb*> objs;
1725  for (Uint32 i = 0; i<100; i++)
1726  {
1727  Uint32 add = 1 + (rand() % 5);
1728  for (Uint32 j = 0; j<add; j++)
1729  {
1730  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1731  if (pNdb == NULL){
1732  ndbout << "pNdb == NULL" << endl;
1733  return NDBT_FAILED;
1734  }
1735  objs.push_back(pNdb);
1736  }
1737  if (do_cnt(con) != (cnt1 + objs.size()))
1738  return NDBT_FAILED;
1739  }
1740 
1741  for (Uint32 i = 0; i<100 && objs.size(); i++)
1742  {
1743  Uint32 sub = 1 + rand() % objs.size();
1744  for (Uint32 j = 0; j<sub && objs.size(); j++)
1745  {
1746  Uint32 idx = rand() % objs.size();
1747  delete objs[idx];
1748  objs.erase(idx);
1749  }
1750  if (do_cnt(con) != (cnt1 + objs.size()))
1751  return NDBT_FAILED;
1752  }
1753 
1754  for (Uint32 i = 0; i<objs.size(); i++)
1755  delete objs[i];
1756 
1757  return (cnt1 == do_cnt(con)) ? NDBT_OK : NDBT_FAILED;
1758 }
1759 
1760 static void
1761 testExecuteAsynchCallback(int res, NdbTransaction *con, void *data_ptr)
1762 {
1763  int *res_ptr= (int *)data_ptr;
1764 
1765  *res_ptr= res;
1766 }
1767 
1768 int runTestExecuteAsynch(NDBT_Context* ctx, NDBT_Step* step){
1769  /* Test that NdbTransaction::executeAsynch() works (BUG#27495). */
1770  int result = NDBT_OK;
1771  const NdbDictionary::Table* pTab = ctx->getTab();
1772 
1773  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1774  if (pNdb == NULL){
1775  ndbout << "pNdb == NULL" << endl;
1776  return NDBT_FAILED;
1777  }
1778  if (pNdb->init(2048)){
1779  ERR(pNdb->getNdbError());
1780  delete pNdb;
1781  return NDBT_FAILED;
1782  }
1783 
1784  NdbConnection* pCon = pNdb->startTransaction();
1785  if (pCon == NULL){
1786  ERR(pNdb->getNdbError());
1787  delete pNdb;
1788  return NDBT_FAILED;
1789  }
1790 
1791  NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1792  if (pOp == NULL){
1793  ERR(pOp->getNdbError());
1794  pNdb->closeTransaction(pCon);
1795  delete pNdb;
1796  return NDBT_FAILED;
1797  }
1798 
1799  if (pOp->readTuples() != 0){
1800  ERR(pOp->getNdbError());
1801  pNdb->closeTransaction(pCon);
1802  delete pNdb;
1803  return NDBT_FAILED;
1804  }
1805 
1806  if (pOp->getValue(NdbDictionary::Column::FRAGMENT) == 0){
1807  ERR(pOp->getNdbError());
1808  pNdb->closeTransaction(pCon);
1809  delete pNdb;
1810  return NDBT_FAILED;
1811  }
1812  int res= 42;
1813  pCon->executeAsynch(NoCommit, testExecuteAsynchCallback, &res);
1814  while(pNdb->pollNdb(100000) == 0)
1815  ;
1816  if (res != 0){
1817  ERR(pCon->getNdbError());
1818  ndbout << "Error returned from execute: " << res << endl;
1819  result= NDBT_FAILED;
1820  }
1821 
1822  pNdb->closeTransaction(pCon);
1823 
1824  delete pNdb;
1825 
1826  return result;
1827 }
1828 
1829 template class Vector<NdbScanOperation*>;
1830 
1831 int
1832 runBug28443(NDBT_Context* ctx, NDBT_Step* step)
1833 {
1834  int result = NDBT_OK;
1835  int records = ctx->getNumRecords();
1836 
1837  NdbRestarter restarter;
1838 
1839  restarter.insertErrorInAllNodes(9003);
1840 
1841  for (int i = 0; i<ctx->getNumLoops(); i++)
1842  {
1843  HugoTransactions hugoTrans(*ctx->getTab());
1844  if (hugoTrans.loadTable(GETNDB(step), records, 2048) != 0)
1845  {
1846  result = NDBT_FAILED;
1847  goto done;
1848  }
1849  if (runClearTable(ctx, step) != 0)
1850  {
1851  result = NDBT_FAILED;
1852  goto done;
1853  }
1854  }
1855 
1856 done:
1857  restarter.insertErrorInAllNodes(9003);
1858 
1859  return result;
1860 }
1861 
1862 int
1863 runBug37158(NDBT_Context* ctx, NDBT_Step* step)
1864 {
1865  int result = NDBT_OK;
1866  Ndb* pNdb = GETNDB(step);
1867 
1868  for (int i = 0; i<ctx->getNumLoops(); i++)
1869  {
1870  HugoOperations hugoOps(*ctx->getTab());
1871  hugoOps.startTransaction(pNdb);
1872  if (hugoOps.pkWriteRecord(pNdb, 0) != 0)
1873  {
1874  result = NDBT_FAILED;
1875  goto done;
1876  }
1877 
1878 
1879  if (hugoOps.pkWritePartialRecord(pNdb, 1) != 0)
1880  {
1881  result = NDBT_FAILED;
1882  goto done;
1883  }
1884 
1885  if (hugoOps.pkWriteRecord(pNdb, 2) != 0)
1886  {
1887  result = NDBT_FAILED;
1888  goto done;
1889  }
1890 
1891  if (hugoOps.pkUpdateRecord(pNdb, 0) != 0)
1892  {
1893  result = NDBT_FAILED;
1894  goto done;
1895  }
1896 
1897  if (hugoOps.execute_Commit(pNdb, AO_IgnoreError) == 4011)
1898  {
1899  result = NDBT_FAILED;
1900  goto done;
1901  }
1902  hugoOps.closeTransaction(pNdb);
1903 
1904  if (runClearTable(ctx, step) != 0)
1905  {
1906  result = NDBT_FAILED;
1907  goto done;
1908  }
1909  }
1910 
1911 done:
1912 
1913  return result;
1914 }
1915 
1916 int
1917 simpleReadAbortOnError(NDBT_Context* ctx, NDBT_Step* step)
1918 {
1919  /* Simple read has some error handling issues
1920  * Setting the operation to be AbortOnError can expose these
1921  */
1922  Ndb* pNdb = GETNDB(step);
1923  const NdbDictionary::Table* pTab= ctx->getTab();
1924  HugoOperations hugoOps(*pTab);
1925  NdbRestarter restarter;
1926 
1927  hugoOps.startTransaction(pNdb);
1928  CHECK(!hugoOps.pkWriteRecord(pNdb,0));
1929  CHECK(!hugoOps.execute_Commit(pNdb, AbortOnError));
1930 
1931  NdbTransaction* trans;
1932 
1933  CHECK(trans= pNdb->startTransaction());
1934 
1935  /* Insert error 5047 which causes next LQHKEYREQ to fail due
1936  * to 'transporter overload'
1937  * Error insert is self-clearing
1938  */
1939  restarter.insertErrorInAllNodes(5047);
1940 
1941  /* Create SimpleRead on row 0, which exists (though we'll get
1942  * 'transporter overload for this'
1943  */
1944  NdbOperation* op;
1945  CHECK(op= trans->getNdbOperation(pTab));
1946 
1947  CHECK(!op->simpleRead());
1948 
1949  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1950  if (pTab->getColumn(a)->getPrimaryKey() == true){
1951  if(hugoOps.equalForAttr(op, a, 0) != 0){
1952  restarter.insertErrorInAllNodes(0);
1953  return NDBT_FAILED;
1954  }
1955  }
1956  }
1957  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1958  CHECK(op->getValue(a));
1959  }
1960 
1961  CHECK(!op->setAbortOption(NdbOperation::AbortOnError));
1962 
1963  /* Create normal read on row 0 which will succeed */
1964  NdbOperation* op2;
1965  CHECK(op2= trans->getNdbOperation(pTab));
1966 
1967  CHECK(!op2->readTuple());
1968 
1969  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1970  if (pTab->getColumn(a)->getPrimaryKey() == true){
1971  if(hugoOps.equalForAttr(op2, a, 0) != 0){
1972  restarter.insertErrorInAllNodes(0);
1973  return NDBT_FAILED;
1974  }
1975  }
1976  }
1977  for(int a = 0; a<pTab->getNoOfColumns(); a++){
1978  CHECK(op2->getValue(a));
1979  }
1980 
1981  CHECK(!op2->setAbortOption(NdbOperation::AbortOnError));
1982 
1983 
1984  CHECK(trans->execute(NoCommit) == -1);
1985 
1986  CHECK(trans->getNdbError().code == 1218); // Transporter Overload
1987 
1988  restarter.insertErrorInAllNodes(0);
1989 
1990  return NDBT_OK;
1991 
1992 }
1993 
1994 
1995 int
1996 testNdbRecordPkAmbiguity(NDBT_Context* ctx, NDBT_Step* step)
1997 {
1998  /* NdbRecord Insert and Write can take 2 record and row ptrs
1999  * In all cases, the AttrInfo sent to TC for PK columns
2000  * should be the same as the KeyInfo sent to TC to avoid
2001  * inconsistency
2002  * Approach :
2003  * 1) Use Insert/Write to insert tuple with different
2004  * values for pks in attr row
2005  * 2) Read back all data, including PKs
2006  * 3) Verify all values.
2007  */
2008  Ndb* pNdb = GETNDB(step);
2009  const NdbDictionary::Table* pTab= ctx->getTab();
2010  const NdbRecord* tabRec= pTab->getDefaultRecord();
2011  const Uint32 sizeOfTabRec= NdbDictionary::getRecordRowLength(tabRec);
2012  char keyRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2013  char attrRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2014  bzero(keyRowBuf, sizeof(keyRowBuf));
2015  bzero(attrRowBuf, sizeof(attrRowBuf));
2016 
2017  HugoCalculator calc(*pTab);
2018 
2019  const int numRecords= 100;
2020 
2021  for (int optype=0; optype < 2; optype++)
2022  {
2023  /* First, let's calculate the correct Hugo values for this row */
2024 
2025  for (int record=0; record < numRecords; record++)
2026  {
2027  int updates= 0;
2028  for (int col=0; col<pTab->getNoOfColumns(); col++)
2029  {
2030  char* valPtr= NdbDictionary::getValuePtr(tabRec,
2031  keyRowBuf,
2032  col);
2033  CHECK(valPtr != NULL);
2034 
2035  int len= pTab->getColumn(col)->getSizeInBytes();
2036  Uint32 real_len;
2037  bool isNull= (calc.calcValue(record, col, updates, valPtr,
2038  len, &real_len) == NULL);
2039  if (pTab->getColumn(col)->getNullable())
2040  {
2041  NdbDictionary::setNull(tabRec,
2042  keyRowBuf,
2043  col,
2044  isNull);
2045  }
2046  }
2047 
2048  /* Now copy the values to the Attr record */
2049  memcpy(attrRowBuf, keyRowBuf, sizeOfTabRec);
2050 
2051  Uint32 mippleAttempts= 3;
2052 
2053  while (memcmp(keyRowBuf, attrRowBuf, sizeOfTabRec) == 0)
2054  {
2055  /* Now doctor the PK values in the Attr record */
2056  for (int col=0; col<pTab->getNoOfColumns(); col++)
2057  {
2058  if (pTab->getColumn(col)->getPrimaryKey())
2059  {
2060  char* valPtr= NdbDictionary::getValuePtr(tabRec,
2061  attrRowBuf,
2062  col);
2063  CHECK(valPtr != NULL);
2064 
2065  int len= pTab->getColumn(col)->getSizeInBytes();
2066  Uint32 real_len;
2067  /* We use the PK value for some other record */
2068  int badRecord= record + (rand() % 1000);
2069  bool isNull= (calc.calcValue(badRecord, col, updates, valPtr,
2070  len, &real_len) == NULL);
2071  CHECK(! isNull);
2072  }
2073  }
2074 
2075  /* Can try to get variance only a limited number of times */
2076  CHECK(mippleAttempts-- != 0);
2077  }
2078 
2079  /* Ok, now have key and attr records with different values for
2080  * PK cols, let's try to insert
2081  */
2082  NdbTransaction* trans=pNdb->startTransaction();
2083  CHECK(trans != 0);
2084 
2085  const NdbOperation* op= NULL;
2086  if (optype == 0)
2087  {
2088  // ndbout << "Using insertTuple" << endl;
2089  op= trans->insertTuple(tabRec,
2090  keyRowBuf,
2091  tabRec,
2092  attrRowBuf);
2093  }
2094  else
2095  {
2096  // ndbout << "Using writeTuple" << endl;
2097  op= trans->writeTuple(tabRec,
2098  keyRowBuf,
2099  tabRec,
2100  attrRowBuf);
2101  }
2102  CHECK(op != 0);
2103 
2104  CHECK(trans->execute(Commit) == 0);
2105  trans->close();
2106 
2107  /* Now read back */
2108  memset(attrRowBuf, 0, sizeOfTabRec);
2109 
2110  Uint32 pkVal= 0;
2111  memcpy(&pkVal, NdbDictionary::getValuePtr(tabRec,
2112  keyRowBuf,
2113  0),
2114  sizeof(pkVal));
2115 
2116  trans= pNdb->startTransaction();
2117  op= trans->readTuple(tabRec,
2118  keyRowBuf,
2119  tabRec,
2120  attrRowBuf);
2121  CHECK(op != 0);
2122  CHECK(trans->execute(Commit) == 0);
2123  CHECK(trans->getNdbError().code == 0);
2124  trans->close();
2125 
2126  /* Verify the values read back */
2127  for (int col=0; col<pTab->getNoOfColumns(); col++)
2128  {
2129  const char* valPtr= NdbDictionary::getValuePtr(tabRec,
2130  attrRowBuf,
2131  col);
2132  CHECK(valPtr != NULL);
2133 
2134  char calcBuff[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2135  int len= pTab->getColumn(col)->getSizeInBytes();
2136  Uint32 real_len;
2137  bool isNull= (calc.calcValue(record, col, updates, calcBuff,
2138  len, &real_len) == NULL);
2139  bool colIsNullable= pTab->getColumn(col)->getNullable();
2140  if (isNull)
2141  {
2142  CHECK(colIsNullable);
2143  if (!NdbDictionary::isNull(tabRec,
2144  attrRowBuf,
2145  col))
2146  {
2147  ndbout << "Error, col " << col
2148  << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
2149  << ") should be Null, but is not" << endl;
2150  return NDBT_FAILED;
2151  }
2152  }
2153  else
2154  {
2155  if (colIsNullable)
2156  {
2157  if (NdbDictionary::isNull(tabRec,
2158  attrRowBuf,
2159  col))
2160  {
2161  ndbout << "Error, col " << col
2162  << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
2163  << ") should be non-Null but is null" << endl;
2164  return NDBT_FAILED;
2165  };
2166  }
2167 
2168  /* Compare actual data read back */
2169  if( memcmp(calcBuff, valPtr, real_len) != 0 )
2170  {
2171  ndbout << "Error, col " << col
2172  << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
2173  << ") should be equal, but isn't for record "
2174  << record << endl;
2175  ndbout << "Expected :";
2176  for (Uint32 i=0; i < real_len; i++)
2177  {
2178  ndbout_c("%x ", calcBuff[i]);
2179  }
2180  ndbout << endl << "Received :";
2181  for (Uint32 i=0; i < real_len; i++)
2182  {
2183  ndbout_c("%x ", valPtr[i]);
2184  }
2185  ndbout << endl;
2186 
2187  return NDBT_FAILED;
2188  }
2189  }
2190  }
2191 
2192  /* Now delete the tuple */
2193  trans= pNdb->startTransaction();
2194  op= trans->deleteTuple(tabRec,
2195  keyRowBuf,
2196  tabRec);
2197  CHECK(op != 0);
2198  CHECK(trans->execute(Commit) == 0);
2199 
2200  trans->close();
2201  }
2202  }
2203 
2204  return NDBT_OK;
2205 
2206 }
2207 
2208 int
2209 testNdbRecordPKUpdate(NDBT_Context* ctx, NDBT_Step* step)
2210 {
2211  /* In general, we should be able to update primary key
2212  * values. We cannot *change* them, but for cases where
2213  * a collation maps several discrete values to a single
2214  * normalised value, it should be possible to modify
2215  * the discrete value of the key, as the normalised
2216  * key value is unchanged.
2217  * Rather than testing with such a collation here, we
2218  * cop out and test for errors with a 'null' change.
2219  */
2220  Ndb* pNdb = GETNDB(step);
2221  const NdbDictionary::Table* pTab= ctx->getTab();
2222  const NdbRecord* tabRec= pTab->getDefaultRecord();
2223  char rowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2224  char badKeyRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2225 
2226  HugoCalculator calc(*pTab);
2227 
2228  const int numRecords= 100;
2229 
2230  /* First, let's calculate the correct Hugo values for this row */
2231  for (int record=0; record < numRecords; record++)
2232  {
2233  int updates= 0;
2234  for (int col=0; col<pTab->getNoOfColumns(); col++)
2235  {
2236  char* valPtr= NdbDictionary::getValuePtr(tabRec,
2237  rowBuf,
2238  col);
2239  CHECK(valPtr != NULL);
2240 
2241  int len= pTab->getColumn(col)->getSizeInBytes();
2242  Uint32 real_len;
2243  bool isNull= (calc.calcValue(record, col, updates, valPtr,
2244  len, &real_len) == NULL);
2245  if (pTab->getColumn(col)->getNullable())
2246  {
2247  NdbDictionary::setNull(tabRec,
2248  rowBuf,
2249  col,
2250  isNull);
2251  }
2252  }
2253 
2254  /* Create similar row, but with different id col (different
2255  * PK from p.o.v. of PK column update
2256  */
2257  memcpy(badKeyRowBuf, rowBuf, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2258  for (int col=0; col<pTab->getNoOfColumns(); col++)
2259  {
2260  if (calc.isIdCol(col))
2261  {
2262  char* valPtr= NdbDictionary::getValuePtr(tabRec,
2263  badKeyRowBuf,
2264  col);
2265  Uint32 badId= record+333;
2266  memcpy(valPtr, &badId, sizeof(badId));
2267  }
2268  }
2269 
2270  NdbTransaction* trans=pNdb->startTransaction();
2271  CHECK(trans != 0);
2272 
2273  const NdbOperation* op= trans->insertTuple(tabRec,
2274  rowBuf);
2275  CHECK(op != 0);
2276 
2277  CHECK(trans->execute(Commit) == 0);
2278  trans->close();
2279 
2280  /* Now update the PK columns */
2281  trans= pNdb->startTransaction();
2282  op= trans->updateTuple(tabRec,
2283  rowBuf,
2284  tabRec,
2285  rowBuf);
2286  CHECK(op != 0);
2287  CHECK(trans->execute(Commit) == 0);
2288  CHECK(trans->getNdbError().code == 0);
2289  trans->close();
2290 
2291  /* Now update PK with scan takeover op */
2292  trans= pNdb->startTransaction();
2293 
2294  NdbScanOperation* scanOp=trans->scanTable(tabRec,
2296  CHECK(scanOp != 0);
2297 
2298  CHECK(trans->execute(NoCommit) == 0);
2299 
2300  /* Now update PK with lock takeover op */
2301  const char* rowPtr;
2302  CHECK(scanOp->nextResult(&rowPtr, true, true) == 0);
2303 
2304  op= scanOp->updateCurrentTuple(trans,
2305  tabRec,
2306  rowBuf);
2307  CHECK(op != NULL);
2308 
2309  CHECK(trans->execute(Commit) == 0);
2310 
2311  trans->close();
2312 
2313  /* Now attempt bad PK update with lock takeover op
2314  * This is interesting as NDBAPI normally takes the
2315  * value of PK columns in an update from the key
2316  * row - so it's not possible to pass a 'different'
2317  * value (except when collations are used).
2318  * Scan Takeover update takes the PK values from the
2319  * attribute record and so different values can
2320  * be supplied.
2321  * Here we check that different values result in the
2322  * kernel complaining.
2323  */
2324  trans= pNdb->startTransaction();
2325 
2326  scanOp=trans->scanTable(tabRec,
2328  CHECK(scanOp != 0);
2329 
2330  CHECK(trans->execute(NoCommit) == 0);
2331 
2332  /* Now update PK with lock takeover op */
2333  CHECK(scanOp->nextResult(&rowPtr, true, true) == 0);
2334 
2335  op= scanOp->updateCurrentTuple(trans,
2336  tabRec,
2337  badKeyRowBuf);
2338  CHECK(op != NULL);
2339 
2340  CHECK(trans->execute(Commit) == -1);
2341  CHECK(trans->getNdbError().code == 897);
2342 
2343  trans->close();
2344 
2345  /* Now delete the tuple */
2346  trans= pNdb->startTransaction();
2347  op= trans->deleteTuple(tabRec,
2348  rowBuf,
2349  tabRec);
2350  CHECK(op != 0);
2351  CHECK(trans->execute(Commit) == 0);
2352 
2353  trans->close();
2354  }
2355 
2356  return NDBT_OK;
2357 
2358 }
2359 
2360 static
2361 BaseString getKeyVal(int record, bool upper)
2362 {
2363  /* Create VARCHAR format key with upper or
2364  * lower case leading char
2365  */
2366  BaseString keyData;
2367  char c= 'a' + (record % ('z' - 'a'));
2368 
2369  keyData.appfmt("%cblahblah%d", c, record);
2370 
2371  if (upper)
2372  keyData.ndb_toupper();
2373 
2374  BaseString varCharKey;
2375  varCharKey.appfmt("%c%s", keyData.length(), keyData.c_str());
2376 
2377  return varCharKey;
2378 }
2379 
2380 int
2381 testNdbRecordCICharPKUpdate(NDBT_Context* ctx, NDBT_Step* step)
2382 {
2383  /* Test a change to a CHAR primary key with a case insensitive
2384  * collation.
2385  */
2386  Ndb* pNdb = GETNDB(step);
2387  const NdbDictionary::Table* pTab= ctx->getTab();
2388 
2389  /* Run as a 'T1' testcase - do nothing for other tables */
2390  if (strcmp(pTab->getName(), "T1") != 0)
2391  return NDBT_OK;
2392 
2393  CHARSET_INFO* charset= NULL;
2394  const char* csname="latin1_general_ci";
2395  charset= get_charset_by_name(csname, MYF(0));
2396 
2397  if (charset == NULL)
2398  {
2399  ndbout << "Couldn't get charset " << csname << endl;
2400  return NDBT_FAILED;
2401  }
2402 
2403  /* Create table with required schema */
2405  tab.setName("TAB_CICHARPKUPD");
2406 
2408  pk.setName("PK");
2410  pk.setLength(20);
2411  pk.setNullable(false);
2412  pk.setPrimaryKey(true);
2413  pk.setCharset(charset);
2414  tab.addColumn(pk);
2415 
2416  NdbDictionary::Column data;
2417  data.setName("DATA");
2419  data.setNullable(false);
2420  data.setPrimaryKey(false);
2421  tab.addColumn(data);
2422 
2423  pNdb->getDictionary()->dropTable(tab.getName());
2424  if(pNdb->getDictionary()->createTable(tab) != 0)
2425  {
2426  ndbout << "Create table failed with error : "
2427  << pNdb->getDictionary()->getNdbError().code
2428  << pNdb->getDictionary()->getNdbError().message
2429  << endl;
2430  return NDBT_FAILED;
2431  }
2432 
2433  ndbout << (NDBT_Table&)tab << endl;
2434 
2435  pTab= pNdb->getDictionary()->getTable(tab.getName());
2436 
2437  const NdbRecord* tabRec= pTab->getDefaultRecord();
2438  const Uint32 rowLen= NDB_MAX_TUPLE_SIZE_IN_WORDS << 2;
2439  char ucRowBuf[ rowLen ];
2440  char lcRowBuf[ rowLen ];
2441  char readBuf[ rowLen ];
2442  char* ucPkPtr= NdbDictionary::getValuePtr(tabRec,
2443  ucRowBuf,
2444  0);
2445  Uint32* ucDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2446  ucRowBuf,
2447  1);
2448  char* lcPkPtr= NdbDictionary::getValuePtr(tabRec,
2449  lcRowBuf,
2450  0);
2451  Uint32* lcDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2452  lcRowBuf,
2453  1);
2454 
2455  char* readPkPtr= NdbDictionary::getValuePtr(tabRec,
2456  readBuf,
2457  0);
2458  Uint32* readDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2459  readBuf,
2460  1);
2461 
2462 
2463  const int numRecords= 100;
2464  BaseString upperKey;
2465  BaseString lowerKey;
2466 
2467  for (int record=0; record < numRecords; record++)
2468  {
2469  upperKey.assign(getKeyVal(record, true).c_str());
2470  lowerKey.assign(getKeyVal(record, false).c_str());
2471 
2472  memcpy(ucPkPtr, upperKey.c_str(), upperKey.length());
2473  memcpy(lcPkPtr, lowerKey.c_str(), lowerKey.length());
2474  memcpy(ucDataPtr, &record, sizeof(record));
2475  memcpy(lcDataPtr, &record, sizeof(record));
2476 
2477  /* Insert with upper case */
2478  NdbTransaction* trans=pNdb->startTransaction();
2479  CHECK(trans != 0);
2480 
2481  const NdbOperation* op= trans->insertTuple(tabRec,
2482  ucRowBuf);
2483  CHECK(op != 0);
2484 
2485  int rc= trans->execute(Commit);
2486  if (rc != 0)
2487  ndbout << "Error " << trans->getNdbError().message << endl;
2488  CHECK(rc == 0);
2489  trans->close();
2490 
2491  /* Read with upper case */
2492  trans=pNdb->startTransaction();
2493  CHECK(trans != 0);
2494  op= trans->readTuple(tabRec,
2495  ucRowBuf,
2496  tabRec,
2497  readBuf);
2498  CHECK(op != 0);
2499  CHECK(trans->execute(Commit) == 0);
2500  trans->close();
2501 
2502  /* Check key and data read */
2503  CHECK(memcmp(ucPkPtr, readPkPtr, ucPkPtr[0]) == 0);
2504  CHECK(memcmp(ucDataPtr, readDataPtr, sizeof(int)) == 0);
2505 
2506  memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2507 
2508  /* Read with lower case */
2509  trans=pNdb->startTransaction();
2510  CHECK(trans != 0);
2511  op= trans->readTuple(tabRec,
2512  lcRowBuf,
2513  tabRec,
2514  readBuf);
2515  CHECK(op != 0);
2516  CHECK(trans->execute(Commit) == 0);
2517  trans->close();
2518 
2519  /* Check key and data read */
2520  CHECK(memcmp(ucPkPtr, readPkPtr, ucPkPtr[0]) == 0);
2521  CHECK(memcmp(ucDataPtr, readDataPtr, sizeof(int)) == 0);
2522 
2523  memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2524 
2525  /* Now update just the PK column to lower case */
2526  trans= pNdb->startTransaction();
2527  unsigned char mask[1];
2528  mask[0]= 1;
2529  op= trans->updateTuple(tabRec,
2530  lcRowBuf,
2531  tabRec,
2532  lcRowBuf,
2533  mask);
2534  CHECK(op != 0);
2535  CHECK(trans->execute(Commit) == 0);
2536  CHECK(trans->getNdbError().code == 0);
2537  trans->close();
2538 
2539  /* Now check that we can read with the upper case key */
2540  memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2541 
2542  trans=pNdb->startTransaction();
2543  CHECK(trans != 0);
2544  op= trans->readTuple(tabRec,
2545  ucRowBuf,
2546  tabRec,
2547  readBuf);
2548  CHECK(op != 0);
2549  CHECK(trans->execute(Commit) == 0);
2550  trans->close();
2551 
2552  /* Check key and data read */
2553  CHECK(memcmp(lcPkPtr, readPkPtr, lcPkPtr[0]) == 0);
2554  CHECK(memcmp(lcDataPtr, readDataPtr, sizeof(int)) == 0);
2555 
2556  /* Now check that we can read with the lower case key */
2557  memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2558 
2559  trans=pNdb->startTransaction();
2560  CHECK(trans != 0);
2561  op= trans->readTuple(tabRec,
2562  lcRowBuf,
2563  tabRec,
2564  readBuf);
2565  CHECK(op != 0);
2566  CHECK(trans->execute(Commit) == 0);
2567  trans->close();
2568 
2569  /* Check key and data read */
2570  CHECK(memcmp(lcPkPtr, readPkPtr, lcPkPtr[0]) == 0);
2571  CHECK(memcmp(lcDataPtr, readDataPtr, sizeof(int)) == 0);
2572 
2573 
2574  /* Now delete the tuple */
2575  trans= pNdb->startTransaction();
2576  op= trans->deleteTuple(tabRec,
2577  ucRowBuf,
2578  tabRec);
2579  CHECK(op != 0);
2580  CHECK(trans->execute(Commit) == 0);
2581 
2582  trans->close();
2583  }
2584 
2585  pNdb->getDictionary()->dropTable(tab.getName());
2586 
2587  return NDBT_OK;
2588 
2589 }
2590 
2591 int
2592 testNdbRecordRowLength(NDBT_Context* ctx, NDBT_Step* step)
2593 {
2594  /* Bug#43891 ignored null bits at the end of an row
2595  * when calculating the row length, leading to various
2596  * problems
2597  */
2598  Ndb* pNdb = GETNDB(step);
2599  const NdbDictionary::Table* pTab= ctx->getTab();
2600  int numCols= pTab->getNoOfColumns();
2601  const NdbRecord* defaultRecord= pTab->getDefaultRecord();
2602 
2603  /* Create an NdbRecord structure with all the Null
2604  * bits at the end - to test that they are included
2605  * correctly in row length calculations.
2606  */
2607  NdbDictionary::RecordSpecification rsArray[ NDB_MAX_ATTRIBUTES_IN_TABLE ];
2608 
2609  bool hasNullable= false;
2610  Uint32 highestUsed= 9000;
2611  for (int attrId=0; attrId< numCols; attrId++)
2612  {
2613  NdbDictionary::RecordSpecification& rs= rsArray[attrId];
2614 
2615  rs.column= pTab->getColumn(attrId);
2616  CHECK(NdbDictionary::getOffset(defaultRecord,
2617  attrId,
2618  rs.offset));
2619  CHECK(NdbDictionary::getNullBitOffset(defaultRecord,
2620  attrId,
2621  rs.nullbit_byte_offset,
2622  rs.nullbit_bit_in_byte));
2623  if (rs.column->getNullable())
2624  {
2625  /* Shift null bit(s) to bytes beyond the end of the record */
2626  hasNullable= true;
2627  rs.nullbit_byte_offset= highestUsed++;
2628  rs.nullbit_bit_in_byte= 0;
2629  }
2630  }
2631 
2632  if (hasNullable)
2633  {
2634  printf("Testing");
2635  const NdbRecord* myRecord= pNdb->getDictionary()->createRecord(pTab,
2636  rsArray,
2637  numCols,
2639  CHECK(myRecord != 0);
2640  Uint32 rowLength= NdbDictionary::getRecordRowLength(myRecord);
2641  if (rowLength != highestUsed)
2642  {
2643  ndbout << "Failure, expected row length " << highestUsed
2644  << " got row length " << rowLength
2645  << endl;
2646  return NDBT_FAILED;
2647  }
2648  }
2649 
2650  return NDBT_OK;
2651 }
2652 
2653 int
2654 runBug44015(NDBT_Context* ctx, NDBT_Step* step)
2655 {
2656  /* testNdbApi -n WeirdAssertFail
2657  * Generates phrase "here2" on 6.3 which is
2658  * output by DbtupExecQuery::handleReadReq()
2659  * detecting that the record's tuple checksum
2660  * is incorrect.
2661  * Later can generate assertion failure in
2662  * prepare_read
2663  * ndbassert(src_len >= (dynstart - src_data));
2664  * resulting in node failure
2665  */
2666  Ndb* pNdb = GETNDB(step);
2667  const NdbDictionary::Table* pTab= ctx->getTab();
2668 
2669  int numIterations= 100;
2670  int numRecords= 1024;
2671 
2672  NdbTransaction* trans;
2673  HugoOperations hugoOps(*pTab);
2674 
2675  for (int iter=0; iter < numIterations; iter++)
2676  {
2677  ndbout << "Iter : " << iter << endl;
2678  CHECK((trans= pNdb->startTransaction()) != 0);
2679 
2680  CHECK(hugoOps.setTransaction(trans) == 0);
2681 
2682  CHECK(hugoOps.pkInsertRecord(pNdb,
2683  0,
2684  numRecords) == 0);
2685 
2686  /* Now execute the transaction */
2687  if ((trans->execute(NdbTransaction::NoCommit) != 0))
2688  {
2689  ndbout << "Execute failed, error is "
2690  << trans->getNdbError().code << " "
2691  << trans->getNdbError().message << endl;
2692  CHECK(0);
2693  }
2694 
2695  CHECK(trans->getNdbError().code == 0);
2696 
2697  /* Now delete the records in the same transaction
2698  * Need to do this manually as Hugo doesn't support it
2699  */
2700  CHECK(hugoOps.pkDeleteRecord(pNdb,
2701  0,
2702  numRecords) == 0);
2703 
2704  CHECK(trans->execute(NdbTransaction::NoCommit) == 0);
2705  CHECK(trans->getNdbError().code == 0);
2706 
2707  /* Now abort the transaction by closing it */
2708  trans->close();
2709 
2710  /* Force Hugo Transaction back to NULL */
2711  hugoOps.setTransaction(NULL, true);
2712  }
2713 
2714  ctx->stopTest();
2715 
2716  return NDBT_OK;
2717 }
2718 
2719 int runScanReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
2720  int result = NDBT_OK;
2721  int i = 0;
2722  int scan_flags = NdbScanOperation::SF_TupScan;
2725  ctx->getProperty("ReadLockMode", (Uint32)NdbOperation::LM_CommittedRead);
2726 
2727  HugoTransactions hugoTrans(*ctx->getTab());
2728  while (ctx->isTestStopped() == false) {
2729  g_info << i << ": ";
2730  if (hugoTrans.scanReadRecords(GETNDB(step), 0, 0, 0,
2731  lm, scan_flags) != 0){
2732  return NDBT_FAILED;
2733  }
2734  i++;
2735  }
2736  return result;
2737 }
2738 
2739 int
2740 runBug44065_org(NDBT_Context* ctx, NDBT_Step* step)
2741 {
2742  /* testNdbApi -n WeirdAssertFail2
2743  * Results in assertion failure in DbtupCommit::execTUP_DEALLOCREQ()
2744  * ndbassert(ptr->m_header_bits & Tuple_header::FREE);
2745  * Results in node failure
2746  */
2747  Ndb* pNdb = GETNDB(step);
2748  const NdbDictionary::Table* pTab= ctx->getTab();
2749 
2750  int numOuterIterations= 50;
2751  int numInnerIterations= 20;
2752  int numRecords= 200;
2753 
2754  NdbTransaction* trans;
2755 
2756  for (int outerIter=0; outerIter < numOuterIterations; outerIter++)
2757  {
2758  HugoOperations hugoOps(*pTab);
2759 
2760  int offset= (outerIter * numRecords);
2761  ndbout << "Outer Iter : " << outerIter
2762  << " " << offset << "-" << (offset + numRecords - 1) << endl;
2763 
2764  {
2765  HugoTransactions trans(*pTab);
2766  CHECK(trans.loadTableStartFrom(pNdb, offset, numRecords) == 0);
2767  }
2768 
2769  for (int iter=0; iter < numInnerIterations; iter++)
2770  {
2771  //ndbout << "Inner Iter : " << iter << endl;
2772  CHECK((trans= pNdb->startTransaction()) != 0);
2773 
2774  CHECK(hugoOps.setTransaction(trans) == 0);
2775 
2776  /* Delete the records */
2777  CHECK(hugoOps.pkDeleteRecord(pNdb,
2778  offset,
2779  numRecords) == 0);
2780 
2781  /* Re-insert them */
2782  CHECK(hugoOps.pkInsertRecord(pNdb,
2783  offset,
2784  numRecords) == 0);
2785 
2786  /* Now execute the transaction, with IgnoreError */
2787  if ((trans->execute(NdbTransaction::NoCommit,
2789  {
2790  NdbError err = trans->getNdbError();
2791  ndbout << "Execute failed, error is "
2792  << err.code << " " << endl;
2795  NdbSleep_MilliSleep(50);
2796  }
2797 
2798  /* Now abort the transaction by closing it without committing */
2799  trans->close();
2800 
2801  /* Force Hugo Transaction back to NULL */
2802  hugoOps.setTransaction(NULL, true);
2803  }
2804  }
2805 
2806  ctx->stopTest();
2807 
2808  return NDBT_OK;
2809 }
2810 
2811 static volatile int aValue = 0;
2812 
2813 void
2814 a_callback(int, NdbTransaction*, void*)
2815 {
2816  ndbout_c("callback received!");
2817  aValue = 1;
2818 }
2819 
2820 int
2821 runBug44065(NDBT_Context* ctx, NDBT_Step* step)
2822 {
2823  /* testNdbApi -n WeirdAssertFail2
2824  * Results in assertion failure in DbtupCommit::execTUP_DEALLOCREQ()
2825  * ndbassert(ptr->m_header_bits & Tuple_header::FREE);
2826  * Results in node failure
2827  */
2828  int rowno = 0;
2829  aValue = 0;
2830  Ndb* pNdb = GETNDB(step);
2831  Ndb * pNdb2 = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
2832  pNdb2->init();
2833  pNdb2->waitUntilReady();
2834 
2835  const NdbDictionary::Table* pTab= ctx->getTab();
2836 
2837  HugoOperations hugoOps1(*pTab);
2838  CHECK(hugoOps1.startTransaction(pNdb) == 0);
2839  CHECK(hugoOps1.pkInsertRecord(pNdb, rowno) == 0);
2840  CHECK(hugoOps1.execute_NoCommit(pNdb) == 0);
2841 
2842  {
2843  HugoOperations hugoOps2(*pTab);
2844  CHECK(hugoOps2.startTransaction(pNdb2) == 0);
2845 
2846  CHECK(hugoOps2.pkDeleteRecord(pNdb2, rowno) == 0);
2847  CHECK(hugoOps2.pkInsertRecord(pNdb2, rowno) == 0);
2848 
2849  NdbTransaction* trans = hugoOps2.getTransaction();
2850  aValue = 0;
2851 
2852  trans->executeAsynch(NdbTransaction::NoCommit, a_callback, 0);
2853  pNdb2->sendPreparedTransactions(1);
2854  CHECK(hugoOps1.execute_Commit(pNdb) == 0);
2855  ndbout_c("waiting for callback");
2856  while (aValue == 0)
2857  {
2858  pNdb2->pollNdb();
2859  NdbSleep_MilliSleep(100);
2860  }
2861  CHECK(hugoOps2.execute_Rollback(pNdb2) == 0);
2862  }
2863 
2864  delete pNdb2; // need to delete hugoOps2 before pNdb2
2865  ctx->stopTest();
2866 
2867  return NDBT_OK;
2868 }
2869 
2870 int testApiFailReqImpl(NDBT_Context* ctx, NDBT_Step* step)
2871 {
2872  /* Setup a separate connection for running PK updates
2873  * with that will be disconnected without affecting
2874  * the test framework
2875  */
2876  if (otherConnection != NULL)
2877  {
2878  ndbout << "Connection not null" << endl;
2879  return NDBT_FAILED;
2880  }
2881 
2882  char connectString[256];
2883  ctx->m_cluster_connection.get_connectstring(connectString,
2884  sizeof(connectString));
2885 
2886  otherConnection= new Ndb_cluster_connection(connectString);
2887 
2888  if (otherConnection == NULL)
2889  {
2890  ndbout << "Connection is null" << endl;
2891  return NDBT_FAILED;
2892  }
2893 
2894  int rc= otherConnection->connect();
2895 
2896  if (rc!= 0)
2897  {
2898  ndbout << "Connect failed with rc " << rc << endl;
2899  return NDBT_FAILED;
2900  }
2901 
2902  /* Check that all nodes are alive - if one has failed
2903  * then probably we exposed bad API_FAILREQ handling
2904  */
2905  if (otherConnection->wait_until_ready(10,10) != 0)
2906  {
2907  ndbout << "Cluster connection was not ready" << endl;
2908  return NDBT_FAILED;
2909  }
2910 
2911  for (int i=0; i < MAX_STEPS; i++)
2912  {
2913  /* We must create the Ndb objects here as we
2914  * are still single threaded
2915  */
2916  stepNdbs[i]= new Ndb(otherConnection,
2917  "TEST_DB");
2918  stepNdbs[i]->init();
2919  int rc= stepNdbs[i]->waitUntilReady(10);
2920 
2921  if (rc != 0)
2922  {
2923  ndbout << "Ndb " << i << " was not ready" << endl;
2924  return NDBT_FAILED;
2925  }
2926 
2927  }
2928 
2929  /* Now signal the 'worker' threads to start sending Pk
2930  * reads
2931  */
2932  ctx->setProperty(ApiFailTestRun, 1);
2933 
2934  /* Wait until all of them are running before proceeding */
2935  ctx->getPropertyWait(ApiFailTestsRunning,
2936  ctx->getProperty(ApiFailNumberPkSteps));
2937 
2938  if (ctx->isTestStopped())
2939  {
2940  return NDBT_OK;
2941  }
2942 
2943  /* Clear the test-run flag so that they'll wait after
2944  * they hit an error
2945  */
2946  ctx->setProperty(ApiFailTestRun, (Uint32)0);
2947 
2948  /* Wait a little */
2949  sleep(1);
2950 
2951  /* Active more stringent checking of behaviour after
2952  * API_FAILREQ
2953  */
2954  NdbRestarter restarter;
2955 
2956  /* Activate 8078 - TCs will abort() if they get a TCKEYREQ
2957  * from the failed API after an API_FAILREQ message
2958  */
2959  ndbout << "Activating 8078" << endl;
2960  restarter.insertErrorInAllNodes(8078);
2961 
2962  /* Wait a little longer */
2963  sleep(1);
2964 
2965  /* Now cause our connection to disconnect
2966  * This results in TC receiving an API_FAILREQ
2967  * If there's an issue with API_FAILREQ 'cleanly'
2968  * stopping further signals, there should be
2969  * an assertion failure in TC
2970  */
2971  int otherNodeId = otherConnection->node_id();
2972 
2973  ndbout << "Forcing disconnect of node "
2974  << otherNodeId << endl;
2975 
2976  /* All dump 900 <nodeId> */
2977  int args[2]= {900, otherNodeId};
2978 
2979  restarter.dumpStateAllNodes( args, 2 );
2980 
2981 
2982  /* Now wait for all workers to finish
2983  * (Running worker count to get down to zero
2984  */
2985  ctx->getPropertyWait(ApiFailTestsRunning, (Uint32)0);
2986 
2987  if (ctx->isTestStopped())
2988  {
2989  return NDBT_OK;
2990  }
2991 
2992  /* Clean up error insert */
2993  restarter.insertErrorInAllNodes(0);
2994 
2995  /* Clean up allocated resources */
2996  for (int i= 0; i < MAX_STEPS; i++)
2997  {
2998  delete stepNdbs[i];
2999  stepNdbs[i]= NULL;
3000  }
3001 
3002  delete otherConnection;
3003  otherConnection= NULL;
3004 
3005  return NDBT_OK;
3006 }
3007 
3008 
3009 int testApiFailReq(NDBT_Context* ctx, NDBT_Step* step)
3010 {
3011  /* Perform a number of iterations, connecting,
3012  * sending lots of PK updates, inserting error
3013  * and then causing node failure
3014  */
3015  Uint32 iterations = 10;
3016  int rc = NDBT_OK;
3017 
3018  while (iterations --)
3019  {
3020  rc= testApiFailReqImpl(ctx, step);
3021 
3022  if (rc == NDBT_FAILED)
3023  {
3024  break;
3025  }
3026  } // while(iterations --)
3027 
3028  /* Avoid PkRead worker threads getting stuck */
3029  ctx->setProperty(ApiFailTestComplete, (Uint32) 1);
3030 
3031  return rc;
3032 }
3033 
3034 int runBulkPkReads(NDBT_Context* ctx, NDBT_Step* step)
3035 {
3036  /* Run batched Pk reads */
3037 
3038  while(true)
3039  {
3040  /* Wait to be signalled to start running */
3041  while ((ctx->getProperty(ApiFailTestRun) == 0) &&
3042  (ctx->getProperty(ApiFailTestComplete) == 0) &&
3043  !ctx->isTestStopped())
3044  {
3045  ctx->wait_timeout(500); /* 500 millis */
3046  }
3047 
3048  if (ctx->isTestStopped() ||
3049  (ctx->getProperty(ApiFailTestComplete) != 0))
3050  {
3051  /* Asked to stop by main test thread */
3052  return NDBT_OK;
3053  }
3054  /* Indicate that we're underway */
3055  ctx->incProperty(ApiFailTestsRunning);
3056 
3057  Ndb* otherNdb = stepNdbs[step->getStepNo()];
3058  HugoOperations hugoOps(*ctx->getTab());
3059  Uint32 numRecords = ctx->getNumRecords();
3060  Uint32 batchSize = (1000 < numRecords)? 1000 : numRecords;
3061 
3062  ndbout << "Step number " << step->getStepNo()
3063  << " reading batches of " << batchSize
3064  << " rows " << endl;
3065 
3066  while(true)
3067  {
3068  if (hugoOps.startTransaction(otherNdb) != 0)
3069  {
3070  if (otherNdb->getNdbError().code == 4009)
3071  {
3072  /* Api disconnect sometimes manifests as Cluster failure
3073  * from API's point of view as it cannot seize() a
3074  * transaction from any Ndbd node
3075  * We treat this the same way as the later error cases
3076  */
3077  break;
3078  }
3079 
3080  ndbout << "Failed to start transaction. Error : "
3081  << otherNdb->getNdbError().message << endl;
3082  return NDBT_FAILED;
3083  }
3084 
3085  for (Uint32 op = 0; op < batchSize; op++)
3086  {
3087  if (hugoOps.pkReadRecord(otherNdb,
3088  op) != 0)
3089  {
3090  ndbout << "Failed to define read of record number " << op << endl;
3091  ndbout << "Error : " << hugoOps.getTransaction()->getNdbError().message
3092  << endl;
3093  return NDBT_FAILED;
3094  }
3095  }
3096 
3097  if (hugoOps.execute_Commit(otherNdb) != 0)
3098  {
3099  NdbError err = hugoOps.getTransaction()->getNdbError();
3100  ndbout << "Execute failed with Error : "
3101  << err.message
3102  << endl;
3103 
3104  hugoOps.closeTransaction(otherNdb);
3105 
3106  if ((err.code == 4002) || // send failed
3107  (err.code == 4010) || // Node failure
3108  (err.code == 4025) || // Node failure
3109  (err.code == 1218)) // Send buffer overload (reading larger tables)
3110  {
3111  /* Expected scenario due to injected Api disconnect
3112  * If there was a node failure due to assertion failure
3113  * then we'll detect it when we try to setup a new
3114  * connection
3115  */
3116  break;
3117  }
3118  return NDBT_FAILED;
3119  }
3120 
3121  hugoOps.closeTransaction(otherNdb);
3122  }
3123 
3124  /* Signal that we've finished running this iteration */
3125  ctx->decProperty(ApiFailTestsRunning);
3126  }
3127 
3128  return NDBT_OK;
3129 }
3130 
3131 int runReadColumnDuplicates(NDBT_Context* ctx, NDBT_Step* step){
3132 
3133  int result = NDBT_OK;
3134  const NdbDictionary::Table* pTab = ctx->getTab();
3135  HugoCalculator hc(*pTab);
3136  Uint32 numRecords = ctx->getNumRecords();
3137 
3138  Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
3139  if (pNdb == NULL){
3140  ndbout << "pNdb == NULL" << endl;
3141  return NDBT_FAILED;
3142  }
3143  if (pNdb->init()){
3144  ERR(pNdb->getNdbError());
3145  delete pNdb;
3146  return NDBT_FAILED;
3147  }
3148 
3149  HugoOperations hugoOps(*pTab);
3150 
3151  for (int m = 1; m < 100; m++){
3152  Uint32 record = (100 - m) % numRecords;
3153  NdbConnection* pCon = pNdb->startTransaction();
3154  if (pCon == NULL){
3155  delete pNdb;
3156  return NDBT_FAILED;
3157  }
3158 
3159  NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
3160  if (pOp == NULL){
3161  pNdb->closeTransaction(pCon);
3162  delete pNdb;
3163  return NDBT_FAILED;
3164  }
3165 
3166  if (pOp->readTuple() != 0){
3167  pNdb->closeTransaction(pCon);
3168  delete pNdb;
3169  return NDBT_FAILED;
3170  }
3171 
3172  int numCols= pTab->getNoOfColumns();
3173 
3174  for(int a = 0; a < numCols; a++){
3175  if (pTab->getColumn(a)->getPrimaryKey() == true){
3176  if(hugoOps.equalForAttr(pOp, a, record) != 0){
3177  ERR(pCon->getNdbError());
3178  pNdb->closeTransaction(pCon);
3179  delete pNdb;
3180  return NDBT_FAILED;
3181  }
3182  }
3183  }
3184 
3185  int dupColNum = m % numCols;
3186  int numReads = m + 1;
3187 
3188  NdbRecAttr* first = NULL;
3189  ndbout << "Reading record "
3190  << record << " Column "
3191  << dupColNum << " " << numReads
3192  << " times" << endl;
3193  while (numReads--)
3194  {
3195  NdbRecAttr* recAttr = pOp->getValue(dupColNum);
3196  if (recAttr == NULL) {
3197  const NdbError err = pCon->getNdbError();
3198  ERR(err);
3199  result = NDBT_FAILED;
3200  pNdb->closeTransaction(pCon);
3201  break;
3202  }
3203  first = (first == NULL) ? recAttr : first;
3204  };
3205 
3206  if (result == NDBT_FAILED)
3207  break;
3208 
3209  if (pCon->execute(Commit) != 0){
3210  const NdbError err = pCon->getNdbError();
3211  ERR(err);
3212  result = NDBT_FAILED;
3213  pNdb->closeTransaction(pCon);
3214  break;
3215  }
3216 
3217  if (pCon->getNdbError().code != 0)
3218  {
3219  NdbError err = pCon->getNdbError();
3220  if (err.code == 880)
3221  {
3222  /* Tried to read too much error - this column
3223  * is probably too large.
3224  * Skip to next iteration
3225  */
3226  ndbout << "Reading too much in one op, skipping..." << endl;
3227  pNdb->closeTransaction(pCon);
3228  continue;
3229  }
3230  ndbout << "Error at execute time : " << err.code
3231  << ":" << err.message << endl;
3232  pNdb->closeTransaction(pCon);
3233  result = NDBT_FAILED;
3234  break;
3235  }
3236 
3237  /* Let's check the results */
3238 
3239 
3240  const NdbRecAttr* curr = first;
3241 
3242  for (int c= 0; c < (m+1); c++)
3243  {
3244  if (hc.verifyRecAttr(record,
3245  0,
3246  curr))
3247  {
3248  ndbout << "Mismatch on record "
3249  << record << " column "
3250  << dupColNum << " read number "
3251  << c+1 << endl;
3252  result = NDBT_FAILED;
3253  break;
3254  }
3255 
3256  ndbout << "/";
3257 
3258  curr = curr->next();
3259  }
3260 
3261  ndbout << endl;
3262 
3263  pNdb->closeTransaction(pCon);
3264 
3265  if (result == NDBT_FAILED)
3266  break;
3267 
3268  if (curr != NULL)
3269  {
3270  ndbout << "Error - extra RecAttr(s) found" << endl;
3271  result = NDBT_FAILED;
3272  break;
3273  }
3274 
3275  }// m
3276 
3277  delete pNdb;
3278 
3279  return result;
3280 }
3281 
3283 {
3284  NdbTransaction* pTrans;
3285 public:
3286  TransGuard(NdbTransaction * p) : pTrans(p) {}
3287  ~TransGuard() { if (pTrans) pTrans->close(); pTrans = 0; }
3288 };
3289 
3290 int
3291 runBug51775(NDBT_Context* ctx, NDBT_Step* step)
3292 {
3293  Ndb* pNdb = GETNDB(step);
3294 
3295  NdbTransaction * pTrans1 = pNdb->startTransaction();
3296  if (pTrans1 == NULL)
3297  {
3298  ERR(pNdb->getNdbError());
3299  return NDBT_FAILED;
3300  }
3301  TransGuard g1(pTrans1);
3302 
3303  NdbTransaction * pTrans2 = pNdb->startTransaction();
3304  if (pTrans2 == NULL)
3305  {
3306  pTrans1->close();
3307  ERR(pNdb->getNdbError());
3308  return NDBT_FAILED;
3309  }
3310 
3311  TransGuard g2(pTrans2);
3312 
3313  {
3314  NdbOperation * pOp = pTrans1->getNdbOperation(ctx->getTab()->getName());
3315  if (pOp == NULL)
3316  {
3317  ERR(pOp->getNdbError());
3318  return NDBT_FAILED;
3319  }
3320 
3321  if (pOp->insertTuple() != 0)
3322  {
3323  ERR(pOp->getNdbError());
3324  return NDBT_FAILED;
3325  }
3326 
3327  HugoOperations hugoOps(* ctx->getTab());
3328  hugoOps.setValues(pOp, 0, 0);
3329  }
3330 
3331  {
3332  NdbOperation * pOp = pTrans2->getNdbOperation(ctx->getTab()->getName());
3333  if (pOp == NULL)
3334  {
3335  ERR(pOp->getNdbError());
3336  return NDBT_FAILED;
3337  }
3338 
3339  if (pOp->readTuple() != 0)
3340  {
3341  ERR(pOp->getNdbError());
3342  return NDBT_FAILED;
3343  }
3344 
3345  HugoOperations hugoOps(* ctx->getTab());
3346  hugoOps.equalForRow(pOp, 0);
3347  pOp->getValue(NdbDictionary::Column::FRAGMENT);
3348  }
3349 
3350 
3351  pTrans1->execute(NoCommit); // We now have un uncommitted insert
3352 
3356  pTrans2->executeAsynch(NoCommit, 0, 0);
3357  int res = pNdb->pollNdb(1, 1000);
3358  ndbout_c("res: %u", res);
3359 
3360  NdbSleep_SecSleep(10);
3361  ndbout_c("pollNdb()");
3362  while (pNdb->pollNdb() + res == 0);
3363 
3364  return NDBT_OK;
3365 }
3366 
3367 int testFragmentedApiFailImpl(NDBT_Context* ctx, NDBT_Step* step)
3368 {
3369  /* Setup a separate connection for running scan operations
3370  * with that will be disconnected without affecting
3371  * the test framework
3372  */
3373  if (otherConnection != NULL)
3374  {
3375  ndbout << "FragApiFail : Connection not null" << endl;
3376  return NDBT_FAILED;
3377  }
3378 
3379  char connectString[256];
3380  ctx->m_cluster_connection.get_connectstring(connectString,
3381  sizeof(connectString));
3382 
3383  otherConnection= new Ndb_cluster_connection(connectString);
3384 
3385  if (otherConnection == NULL)
3386  {
3387  ndbout << "FragApiFail : Connection is null" << endl;
3388  return NDBT_FAILED;
3389  }
3390 
3391  int rc= otherConnection->connect();
3392 
3393  if (rc!= 0)
3394  {
3395  ndbout << "FragApiFail : Connect failed with rc " << rc << endl;
3396  return NDBT_FAILED;
3397  }
3398 
3399  /* Check that all nodes are alive - if one has failed
3400  * then probably we exposed bad API_FAILREQ handling
3401  */
3402  if (otherConnection->wait_until_ready(10,10) != 0)
3403  {
3404  ndbout << "FragApiFail : Cluster connection was not ready" << endl;
3405  return NDBT_FAILED;
3406  }
3407 
3408  for (int i=0; i < MAX_STEPS; i++)
3409  {
3410  /* We must create the Ndb objects here as we
3411  * are still single threaded
3412  */
3413  stepNdbs[i]= new Ndb(otherConnection,
3414  "TEST_DB");
3415  stepNdbs[i]->init();
3416  int rc= stepNdbs[i]->waitUntilReady(10);
3417 
3418  if (rc != 0)
3419  {
3420  ndbout << "FragApiFail : Ndb " << i << " was not ready" << endl;
3421  return NDBT_FAILED;
3422  }
3423 
3424  }
3425 
3426  /* Now signal the 'worker' threads to start sending Pk
3427  * reads
3428  */
3429  ctx->setProperty(ApiFailTestRun, 1);
3430 
3431  /* Wait until all of them are running before proceeding */
3432  ctx->getPropertyWait(ApiFailTestsRunning,
3433  ctx->getProperty(ApiFailNumberPkSteps));
3434 
3435  if (ctx->isTestStopped())
3436  {
3437  return NDBT_OK;
3438  }
3439 
3440  /* Clear the test-run flag so that they'll wait after
3441  * they hit an error
3442  */
3443  ctx->setProperty(ApiFailTestRun, (Uint32)0);
3444 
3445  /* Wait a little */
3446  sleep(1);
3447 
3448  /* Now cause our connection to disconnect
3449  * This results in NDBD running API failure
3450  * code and cleaning up any in-assembly fragmented
3451  * signals
3452  */
3453  int otherNodeId = otherConnection->node_id();
3454 
3455  ndbout << "FragApiFail : Forcing disconnect of node "
3456  << otherNodeId << endl;
3457 
3458  /* All dump 900 <nodeId> */
3459  int args[2]= {900, otherNodeId};
3460 
3461  NdbRestarter restarter;
3462  restarter.dumpStateAllNodes( args, 2 );
3463 
3464  /* Now wait for all workers to finish
3465  * (Running worker count to get down to zero
3466  */
3467  ctx->getPropertyWait(ApiFailTestsRunning, (Uint32)0);
3468 
3469  if (ctx->isTestStopped())
3470  {
3471  return NDBT_OK;
3472  }
3473 
3474  /* Clean up allocated resources */
3475  for (int i= 0; i < MAX_STEPS; i++)
3476  {
3477  delete stepNdbs[i];
3478  stepNdbs[i]= NULL;
3479  }
3480 
3481  delete otherConnection;
3482  otherConnection= NULL;
3483 
3484  return NDBT_OK;
3485 }
3486 
3487 int testFragmentedApiFail(NDBT_Context* ctx, NDBT_Step* step)
3488 {
3489  /* Perform a number of iterations, connecting,
3490  * sending lots of PK updates, inserting error
3491  * and then causing node failure
3492  */
3493  Uint32 iterations = 10;
3494  int rc = NDBT_OK;
3495 
3496  while (iterations --)
3497  {
3498  rc= testFragmentedApiFailImpl(ctx, step);
3499 
3500  if (rc == NDBT_FAILED)
3501  {
3502  break;
3503  }
3504  } // while(iterations --)
3505 
3506  /* Avoid scan worker threads getting stuck */
3507  ctx->setProperty(ApiFailTestComplete, (Uint32) 1);
3508 
3509  return rc;
3510 }
3511 
3512 int runFragmentedScanOtherApi(NDBT_Context* ctx, NDBT_Step* step)
3513 {
3514  /* We run a loop sending large scan requests that will be
3515  * fragmented.
3516  * The requests are so large that they actually fail on
3517  * arrival at TUP as there is too much ATTRINFO
3518  * That doesn't affect this testcase though, as it is
3519  * testing TC cleanup of fragmented signals from a
3520  * failed API
3521  */
3522  /* SEND > ((2 * MAX_SEND_MESSAGE_BYTESIZE) + SOME EXTRA)
3523  * This way we get at least 3 fragments
3524  * However, as this is generally > 64kB, it's too much AttrInfo for
3525  * a ScanTabReq, so the 'success' case returns error 874
3526  */
3527  const Uint32 PROG_WORDS= 16500;
3528 
3529  /* Use heap rather than stack as stack is too small in
3530  * STEP thread
3531  */
3532  Uint32* buff= new Uint32[ PROG_WORDS + 10 ]; // 10 extra for final 'return' etc.
3533  Uint32 stepNo = step->getStepNo();
3534 
3535  while(true)
3536  {
3537  /* Wait to be signalled to start running */
3538  while ((ctx->getProperty(ApiFailTestRun) == 0) &&
3539  (ctx->getProperty(ApiFailTestComplete) == 0) &&
3540  !ctx->isTestStopped())
3541  {
3542  ctx->wait_timeout(500); /* 500 millis */
3543  }
3544 
3545  if (ctx->isTestStopped() ||
3546  (ctx->getProperty(ApiFailTestComplete) != 0))
3547  {
3548  ndbout << stepNo << ": Test stopped, exiting thread" << endl;
3549  /* Asked to stop by main test thread */
3550  delete[] buff;
3551  return NDBT_OK;
3552  }
3553  /* Indicate that we're underway */
3554  ctx->incProperty(ApiFailTestsRunning);
3555 
3556  Ndb* otherNdb = stepNdbs[stepNo];
3557 
3558  while (true)
3559  {
3560  /* Start a transaction */
3561  NdbTransaction* trans= otherNdb->startTransaction();
3562  if (!trans)
3563  {
3564  ndbout << stepNo << ": Failed to start transaction from Ndb object"
3565  << " Error : "
3566  << otherNdb->getNdbError().code << " "
3567  << otherNdb->getNdbError().message << endl;
3568 
3569  /* During this test, if we attempt to get a transaction
3570  * when the API is disconnected, we can get error 4009
3571  * (Cluster failure). We treat this similarly to the
3572  * "Node failure caused abort of transaction" case
3573  */
3574  if (otherNdb->getNdbError().code == 4009)
3575  {
3576  break;
3577  }
3578  delete[] buff;
3579  return NDBT_FAILED;
3580  }
3581 
3582  NdbScanOperation* scan= trans->getNdbScanOperation(ctx->getTab());
3583 
3584  CHECK(scan != NULL);
3585 
3586  CHECK(0 == scan->readTuples());
3587 
3588  /* Create a large program, to give a large SCANTABREQ */
3589  NdbInterpretedCode prog(ctx->getTab(),
3590  buff, PROG_WORDS + 10);
3591 
3592  for (Uint32 w=0; w < PROG_WORDS; w++)
3593  CHECK(0 == prog.load_const_null(1));
3594 
3595  CHECK(0 == prog.interpret_exit_ok());
3596  CHECK(0 == prog.finalise());
3597 
3598  CHECK(0 == scan->setInterpretedCode(&prog));
3599 
3600  CHECK(0 == trans->execute(NdbTransaction::NoCommit));
3601 
3602  Uint32 execError= trans->getNdbError().code;
3603 
3604  /* Can get success (0), or 874 for too much AttrInfo, depending
3605  * on timing
3606  */
3607  if ((execError != 0) &&
3608  (execError != 874) &&
3609  (execError != 4002))
3610  {
3611  ndbout_c("%u incorrect error code: %u", __LINE__, execError);
3612  ERR(trans->getNdbError());
3613  trans->close();
3614  delete[] buff;
3615  return NDBT_FAILED;
3616  }
3617 
3618  /* nextResult will always fail */
3619  CHECK(-1 == scan->nextResult());
3620 
3621  NdbError scanError= scan->getNdbError();
3622 
3623  /* 'Success case' is 874 for too much AttrInfo */
3624  if (scanError.code != 874)
3625  {
3626  /* When disconnected, we get
3627  * 4028 : 'Node failure caused abort of transaction'
3628  */
3629  if (scanError.classification == NdbError::NodeRecoveryError)
3630  {
3631  ndbout << stepNo << ": Scan failed due to node failure/disconnect" << endl;
3632  trans->close();
3633  break;
3634  }
3635  else
3636  {
3637  ndbout_c("%u incorrect error code: %u", __LINE__, execError);
3638  ERR(scan->getNdbError());
3639  trans->close();
3640  delete[] buff;
3641  return NDBT_FAILED;
3642  }
3643  }
3644 
3645  scan->close();
3646 
3647  trans->close();
3648  } // while (true)
3649 
3650  /* Node failure case - as expected */
3651  ndbout << stepNo << ": Scan thread finished iteration" << endl;
3652 
3653  /* Signal that we've finished running this iteration */
3654  ctx->decProperty(ApiFailTestsRunning);
3655  }
3656 
3657  delete[] buff;
3658  return NDBT_OK;
3659 }
3660 
3661 void outputLockMode(NdbOperation::LockMode lm)
3662 {
3663  switch(lm)
3664  {
3666  ndbout << "LM_Exclusive";
3667  break;
3668  case NdbOperation::LM_Read:
3669  ndbout << "LM_Read";
3670  break;
3672  ndbout << "LM_SimpleRead";
3673  break;
3674  case NdbOperation::LM_CommittedRead:
3675  ndbout << "LM_CommittedRead";
3676  break;
3677  }
3678 }
3679 
3680 NdbOperation::LockMode chooseLockMode(bool onlyRealLocks = false)
3681 {
3682  Uint32 choice;
3683 
3684  if (onlyRealLocks)
3685  {
3686  choice = rand() % 2;
3687  }
3688  else
3689  {
3690  choice = rand() % 4;
3691  }
3692 
3694 
3695  switch(choice)
3696  {
3697  case 0:
3699  break;
3700  case 1:
3701  lm = NdbOperation::LM_Read;
3702  break;
3703  case 2:
3705  break;
3706  case 3:
3707  default:
3709  break;
3710  }
3711 
3712  outputLockMode(lm);
3713  ndbout << endl;
3714 
3715  return lm;
3716 }
3717 
3718 NdbOperation::LockMode chooseConflictingLockMode(NdbOperation::LockMode lm)
3719 {
3721 
3722  switch (lm)
3723  {
3725  conflicting = (((rand() % 2) == 0) ?
3728 
3729  break;
3730  case NdbOperation::LM_Read:
3731  conflicting = NdbOperation::LM_Exclusive;
3732  break;
3733  default:
3734  abort(); // SimpleRead + CommittedRead can't conflict reliably
3735  }
3736 
3737  ndbout << "conflicting with ";
3738  outputLockMode(lm);
3739  ndbout << " using ";
3740  outputLockMode(conflicting);
3741  ndbout << endl;
3742  return conflicting;
3743 }
3744 
3745 #define CHECKN(c, o, e) { if (!(c)) { \
3746  ndbout << "Failed on line " << __LINE__ << endl; \
3747  ndbout << (o)->getNdbError() << endl; \
3748  return e; } }
3749 
3750 NdbOperation* defineReadAllColsOp(HugoOperations* hugoOps,
3751  NdbTransaction* trans,
3752  const NdbDictionary::Table* pTab,
3754  Uint32 rowNum)
3755 {
3756  NdbOperation* op = trans->getNdbOperation(pTab);
3757  CHECKN(op != NULL, trans, NULL);
3758 
3759  CHECKN(op->readTuple(lm) == 0, op, NULL);
3760 
3761  hugoOps->equalForRow(op, rowNum);
3762 
3763  for(int c = 0; c < pTab->getNoOfColumns(); c++)
3764  {
3765  if(!pTab->getColumn(c)->getPrimaryKey())
3766  {
3767  CHECKN(op->getValue(pTab->getColumn(c)->getName()) != NULL, op, NULL);
3768  }
3769  }
3770 
3771  return op;
3772 }
3773 
3774 bool checkReadRc(HugoOperations* hugoOps,
3775  Ndb* ndb,
3776  const NdbDictionary::Table* pTab,
3778  Uint32 rowNum,
3779  int expectedRc)
3780 {
3781  NdbTransaction* trans = ndb->startTransaction();
3782  CHECKN(trans != NULL, ndb, false);
3783 
3784  NdbOperation* readOp = defineReadAllColsOp(hugoOps,
3785  trans,
3786  pTab,
3787  lm,
3788  rowNum);
3789  CHECKN(readOp != NULL, trans, false);
3790 
3791  int execRc = trans->execute(Commit);
3792 
3793  if (expectedRc)
3794  {
3795  /* Here we assume that the error is on the transaction
3796  * which may not be the case for some errors
3797  */
3798  if (trans->getNdbError().code != expectedRc)
3799  {
3800  ndbout << "Expected " << expectedRc << " at " << __LINE__ << endl;
3801  ndbout << "Got " << trans->getNdbError() << endl;
3802  return false;
3803  }
3804  }
3805  else
3806  {
3807  CHECKN(execRc == 0, trans, false);
3808  CHECKN(readOp->getNdbError().code == 0, readOp, false);
3809  }
3810 
3811  trans->close();
3812 
3813  return true;
3814 }
3815 
3816 bool checkReadDeadlocks(HugoOperations* hugoOps,
3817  Ndb* ndb,
3818  const NdbDictionary::Table* pTab,
3820  Uint32 rowNum)
3821 {
3822  return checkReadRc(hugoOps, ndb, pTab, lm, rowNum, 266);
3823 }
3824 
3825 bool checkReadSucceeds(HugoOperations* hugoOps,
3826  Ndb* ndb,
3827  const NdbDictionary::Table* pTab,
3829  Uint32 rowNum)
3830 {
3831  return checkReadRc(hugoOps, ndb, pTab, lm, rowNum, 0);
3832 }
3833 
3834 int runTestUnlockBasic(NDBT_Context* ctx, NDBT_Step* step)
3835 {
3836  /* Basic tests that we can lock and unlock rows
3837  * using the unlock mechanism
3838  * Some minor side-validation that the API rejects
3839  * readLockInfo for non Exclusive / Shared lock modes
3840  * and that double-release of the lockhandle is caught
3841  */
3842  const NdbDictionary::Table* pTab = ctx->getTab();
3843 
3844  HugoOperations hugoOps(*pTab);
3845 
3846  const Uint32 iterations = 200;
3847 
3848  for (Uint32 iter = 0; iter < iterations; iter++)
3849  {
3850  Uint32 rowNum = iter % ctx->getNumRecords();
3851 
3852  NdbTransaction* trans = GETNDB(step)->startTransaction();
3853  CHECKN(trans != NULL, GETNDB(step), NDBT_FAILED);
3854 
3855  ndbout << "First transaction operation using ";
3856  NdbOperation::LockMode lm = chooseLockMode();
3857 
3858  NdbOperation* op = defineReadAllColsOp(&hugoOps,
3859  trans,
3860  pTab,
3861  lm,
3862  rowNum);
3863  CHECKN(op != NULL, trans, NDBT_FAILED);
3864 
3865  if (op->getLockHandle() == NULL)
3866  {
3867  if ((lm == NdbOperation::LM_CommittedRead) ||
3869  {
3870  if (op->getNdbError().code == 4549)
3871  {
3872  /* As expected, go to next iteration */
3873  ndbout << "Definition error as expected, moving to next" << endl;
3874  trans->close();
3875  continue;
3876  }
3877  ndbout << "Expected 4549, got :" << endl;
3878  }
3879  ndbout << op->getNdbError() << endl;
3880  ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
3881  return NDBT_FAILED;
3882  }
3883 
3884  CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
3885 
3886  const NdbLockHandle* lh = op->getLockHandle();
3887  CHECKN(lh != NULL, op, NDBT_FAILED);
3888 
3889  /* Ok, let's use another transaction to try and get a
3890  * lock on the row (exclusive or shared)
3891  */
3892  NdbTransaction* trans2 = GETNDB(step)->startTransaction();
3893  CHECKN(trans2 != NULL, GETNDB(step), NDBT_FAILED);
3894 
3895 
3896  ndbout << "Second transaction operation using ";
3897  NdbOperation::LockMode lm2 = chooseLockMode();
3898 
3899  NdbOperation* op2 = defineReadAllColsOp(&hugoOps,
3900  trans2,
3901  pTab,
3902  lm2,
3903  rowNum);
3904  CHECKN(op2 != NULL, trans2, NDBT_FAILED);
3905 
3906  /* Execute can succeed if both lock modes are LM read
3907  * otherwise we'll deadlock (266)
3908  */
3909  bool expectOk = ((lm2 == NdbOperation::LM_CommittedRead) ||
3910  ((lm == NdbOperation::LM_Read) &&
3911  ((lm2 == NdbOperation::LM_Read) ||
3912  (lm2 == NdbOperation::LM_SimpleRead))));
3913 
3914  /* Exclusive read locks primary only, and SimpleRead locks
3915  * Primary or Backup, so SimpleRead may or may not succeed
3916  */
3917  bool unknownCase = ((lm == NdbOperation::LM_Exclusive) &&
3918  (lm2 == NdbOperation::LM_SimpleRead));
3919 
3920  if (trans2->execute(NoCommit) != 0)
3921  {
3922  if (expectOk ||
3923  (trans2->getNdbError().code != 266))
3924  {
3925  ndbout << trans2->getNdbError() << endl;
3926  ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
3927  return NDBT_FAILED;
3928  }
3929  }
3930  else
3931  {
3932  if (!expectOk && !unknownCase)
3933  {
3934  ndbout << "Expected deadlock but had success!" << endl;
3935  return NDBT_FAILED;
3936  }
3937  }
3938  trans2->close();
3939 
3940  /* Now let's try to create an unlockRow operation, and
3941  * execute it
3942  */
3943  const NdbOperation* unlockOp = trans->unlock(lh);
3944 
3945  CHECKN(unlockOp != NULL, trans, NDBT_FAILED);
3946 
3947  CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
3948 
3949  /* Now let's try to get an exclusive lock on the row from
3950  * another transaction which can only be possible if the
3951  * original lock has been removed.
3952  */
3953  CHECK(checkReadSucceeds(&hugoOps,
3954  GETNDB(step),
3955  pTab,
3957  rowNum));
3958  ndbout << "Third transaction operation using LM_Exclusive succeeded" << endl;
3959 
3960  Uint32 choice = rand() % 3;
3961  switch(choice)
3962  {
3963  case 0:
3964  ndbout << "Closing transaction" << endl;
3965  trans->close();
3966  break;
3967  case 1:
3968  ndbout << "Releasing handle and closing transaction" << endl;
3969  CHECKN(trans->releaseLockHandle(lh) == 0, trans, NDBT_FAILED);
3970  trans->close();
3971  break;
3972  case 2:
3973  ndbout << "Attempting to release the handle twice" << endl;
3974  CHECKN(trans->releaseLockHandle(lh) == 0, trans, NDBT_FAILED);
3975 
3976  if ((trans->releaseLockHandle(lh) != -1) ||
3977  (trans->getNdbError().code != 4551))
3978  {
3979  ndbout << "Expected 4551, but got no error " << endl;
3980  ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
3981  return NDBT_FAILED;
3982  }
3983 
3984  trans->close();
3985  break;
3986  default:
3987  abort();
3988  break;
3989  }
3990  } // for (Uint32 iter
3991 
3992  return NDBT_OK;
3993 }
3994 
3995 int runTestUnlockRepeat(NDBT_Context* ctx, NDBT_Step* step)
3996 {
3997  /* Transaction A locks 2 rows
3998  * It repeatedly unlocks and re-locks one row, but leaves
3999  * the other locked
4000  * Transaction B verifies that it can only lock the unlocked
4001  * row when it is unlocked, and can never lock the row which
4002  * is never unlocked!
4003  */
4004 
4005  const NdbDictionary::Table* pTab = ctx->getTab();
4006 
4007  HugoOperations hugoOps(*pTab);
4008 
4009  const Uint32 outerLoops = 2;
4010  const Uint32 iterations = 10;
4011 
4012  Ndb* ndb = GETNDB(step);
4013 
4014  /* Transaction A will take a lock on otherRowNum and hold it
4015  * throughout.
4016  * RowNum will be locked and unlocked each iteration
4017  */
4018  Uint32 otherRowNum = ctx->getNumRecords() - 1;
4019 
4020  for (Uint32 outerLoop = 0; outerLoop < outerLoops; outerLoop ++)
4021  {
4022  NdbTransaction* transA = ndb->startTransaction();
4023  CHECKN(transA != NULL, ndb, NDBT_FAILED);
4024 
4025  NdbOperation::LockMode lockAOtherMode;
4026  ndbout << "TransA : Try to lock otherRowNum in mode ";
4027 
4028  switch (outerLoop % 2) {
4029  case 0:
4030  ndbout << "LM_Exclusive" << endl;
4031  lockAOtherMode = NdbOperation::LM_Exclusive;
4032  break;
4033  default:
4034  ndbout << "LM_Read" << endl;
4035  lockAOtherMode = NdbOperation::LM_Read;
4036  break;
4037  }
4038 
4039  NdbOperation* lockAOtherRowNum = defineReadAllColsOp(&hugoOps,
4040  transA,
4041  pTab,
4042  lockAOtherMode,
4043  otherRowNum);
4044  CHECKN(lockAOtherRowNum != NULL, transA, NDBT_FAILED);
4045 
4046  CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4047 
4048  ndbout << "TransA : Got initial lock on otherRowNum" << endl;
4049 
4050  for (Uint32 iter = 0; iter < iterations; iter++)
4051  {
4052  Uint32 rowNum = iter % (ctx->getNumRecords() - 1);
4053 
4054  ndbout << " TransA : Try to lock rowNum with mode ";
4055  NdbOperation::LockMode lockAMode = chooseLockMode(true); // Exclusive or LM_Read
4056 
4057  /* Transaction A takes a lock on rowNum */
4058  NdbOperation* lockARowNum = defineReadAllColsOp(&hugoOps,
4059  transA,
4060  pTab,
4061  lockAMode,
4062  rowNum);
4063  CHECKN(lockARowNum != NULL, transA, NDBT_FAILED);
4064 
4065  const NdbLockHandle* lockAHandle = lockARowNum->getLockHandle();
4066  CHECKN(lockAHandle != NULL, lockARowNum, NDBT_FAILED);
4067 
4068  CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4069 
4070  ndbout << " TransA : Got lock on rowNum" << endl;
4071 
4072  /* Now transaction B checks that it cannot get a conflicting lock
4073  * on rowNum
4074  */
4075  ndbout << " TransB : Try to lock rowNum by ";
4076 
4077  CHECK(checkReadDeadlocks(&hugoOps,
4078  ndb,
4079  pTab,
4080  chooseConflictingLockMode(lockAMode),
4081  rowNum));
4082 
4083  ndbout << " TransB : Failed to get lock on rowNum as expected" << endl;
4084 
4085  /* Now transaction A unlocks rowNum */
4086  const NdbOperation* unlockOpA = transA->unlock(lockAHandle);
4087  CHECKN(unlockOpA != NULL, transA, NDBT_FAILED);
4088 
4089  CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4090 
4091  ndbout << " TransA : Unlocked rowNum" << endl;
4092 
4093  /* Now transaction B attempts to gain a lock on RowNum */
4094  NdbTransaction* transB = ndb->startTransaction();
4095  CHECKN(transB != NULL, ndb, NDBT_FAILED);
4096 
4097  ndbout << " TransB : Try to lock rowNum with mode ";
4098  NdbOperation::LockMode lockBMode = chooseLockMode(true);
4099 
4100  NdbOperation* tryLockBRowNum2 = defineReadAllColsOp(&hugoOps,
4101  transB,
4102  pTab,
4103  lockBMode,
4104  rowNum);
4105  CHECKN(tryLockBRowNum2 != NULL, transB, NDBT_FAILED);
4106 
4107  CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4108 
4109  ndbout << " TransB : Got lock on rowNum" << endl;
4110 
4111  ndbout << " TransB : Try to lock other row by ";
4112  NdbOperation::LockMode lockBOtherMode = chooseConflictingLockMode(lockAOtherMode);
4113 
4114  /* Now transaction B attempts to gain a lock on OtherRowNum
4115  * which should fail as transaction A still has it locked
4116  */
4117  NdbOperation* tryLockBOtherRowNum = defineReadAllColsOp(&hugoOps,
4118  transB,
4119  pTab,
4120  lockBOtherMode,
4121  otherRowNum);
4122  CHECKN(tryLockBOtherRowNum != NULL, transB, NDBT_FAILED);
4123 
4124  CHECKN(transB->execute(NoCommit) == -1, transB, NDBT_FAILED);
4125 
4126  if (transB->getNdbError().code != 266)
4127  {
4128  ndbout << "Error was expecting 266, but got " << transB->getNdbError() << endl;
4129  ndbout << "At line " << __LINE__ << endl;
4130  return NDBT_FAILED;
4131  }
4132 
4133  ndbout << " TransB : Failed to get lock on otherRowNum as expected" << endl;
4134 
4135  transB->close();
4136  }
4137 
4138  transA->close();
4139  }
4140 
4141  return NDBT_OK;
4142 }
4143 
4144 
4145 int runTestUnlockMulti(NDBT_Context* ctx, NDBT_Step* step)
4146 {
4147  const NdbDictionary::Table* pTab = ctx->getTab();
4148 
4149  /* Verifies that a single transaction (or multiple
4150  * transactions) taking multiple locks on the same
4151  * row using multiple operations behaves correctly
4152  * as the operations unlock their locks.
4153  *
4154  * Transaction A will lock the row to depth A
4155  * Transaction A may use an exclusive lock as its first lock
4156  * Transaction B will lock the row to depth B
4157  * iff transaction A did not use exclusive locks
4158  *
4159  * Once all locks are in place, the locks placed are
4160  * removed.
4161  * The code checks that the row remains locked until
4162  * all locking operations are unlocked
4163  * The code checks that the row is unlocked when all
4164  * locking operations are unlocked.
4165  *
4166  * Depth A and B and whether A uses exclusive or not
4167  * are varied.
4168  */
4169 
4170  HugoOperations hugoOps(*pTab);
4171 
4172  const Uint32 MinLocks = 3;
4173  const Uint32 MaxLocksPerTrans = 20;
4174  Uint32 rowNum = ctx->getNumRecords() - 1;
4175  Uint32 numLocksInTransA = rand() % MaxLocksPerTrans;
4176  numLocksInTransA = (numLocksInTransA > MinLocks) ?
4177  numLocksInTransA : MinLocks;
4178  bool useExclusiveInA = ((rand() % 2) == 0);
4179 
4180  Uint32 numLocksInTransB = useExclusiveInA ? 0 :
4181  (rand() % MaxLocksPerTrans);
4182 
4183  Uint32 maxLocks = (numLocksInTransA > numLocksInTransB) ?
4184  numLocksInTransA : numLocksInTransB;
4185 
4186  ndbout << "NumLocksInTransA " << numLocksInTransA
4187  << " NumLocksInTransB " << numLocksInTransB
4188  << " useExclusiveInA " << useExclusiveInA
4189  << endl;
4190 
4191  NdbOperation* transAOps[ MaxLocksPerTrans ];
4192  NdbOperation* transBOps[ MaxLocksPerTrans ];
4193 
4194  /* First the lock phase when transA and transB
4195  * claim locks (with LockHandles)
4196  * As this occurs, transC attempts to obtain
4197  * a conflicting lock and fails.
4198  */
4199  Ndb* ndb = GETNDB(step);
4200 
4201  NdbTransaction* transA = ndb->startTransaction();
4202  CHECKN(transA != NULL, ndb, NDBT_FAILED);
4203 
4204  NdbTransaction* transB = ndb->startTransaction();
4205  CHECKN(transB != NULL, ndb, NDBT_FAILED);
4206 
4207  ndbout << "Locking phase" << endl << endl;
4208  for(Uint32 depth=0; depth < maxLocks; depth++)
4209  {
4210  ndbout << "Depth " << depth << endl;
4212  /* TransA */
4213  if (depth < numLocksInTransA)
4214  {
4215  ndbout << " TransA : Locking with mode ";
4216  if ((depth == 0) && useExclusiveInA)
4217  {
4219  ndbout << "LM_Exclusive" << endl;
4220  }
4221  else if (!useExclusiveInA)
4222  {
4223  lmA = NdbOperation::LM_Read;
4224  ndbout << "LM_Read" << endl;
4225  }
4226  else
4227  {
4228  lmA = chooseLockMode(true); // LM_Exclusive or LM_Read;
4229  }
4230 
4231  NdbOperation* lockA = defineReadAllColsOp(&hugoOps,
4232  transA,
4233  pTab,
4234  lmA,
4235  rowNum);
4236  CHECKN(lockA != NULL, transA, NDBT_FAILED);
4237  CHECKN(lockA->getLockHandle() != NULL, lockA, NDBT_FAILED);
4238 
4239  transAOps[ depth ] = lockA;
4240 
4241  CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4242  ndbout << " TransA : Succeeded" << endl;
4243  }
4244 
4245  /* TransB */
4246  if (depth < numLocksInTransB)
4247  {
4248  ndbout << " TransB : Locking with mode LM_Read" << endl;
4249 
4250  NdbOperation* lockB = defineReadAllColsOp(&hugoOps,
4251  transB,
4252  pTab,
4254  rowNum);
4255  CHECKN(lockB != NULL, transB, NDBT_FAILED);
4256  CHECKN(lockB->getLockHandle() != NULL, lockB, NDBT_FAILED);
4257 
4258  transBOps[ depth ] = lockB;
4259 
4260  CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4261  ndbout << " TransB : Succeeded" << endl;
4262  }
4263  }
4264 
4265  ndbout << "Unlocking phase" << endl << endl;
4266 
4267  for(Uint32 depth = 0; depth < maxLocks; depth++)
4268  {
4269  Uint32 level = maxLocks - depth - 1;
4270 
4271  ndbout << "Depth " << level << endl;
4272 
4273  ndbout << " TransC : Trying to lock row with lockmode ";
4275  if (useExclusiveInA)
4276  {
4277  lmC = chooseLockMode(true); // LM_Exclusive or LM_Read;
4278  }
4279  else
4280  {
4281  ndbout << "LM_Exclusive" << endl;
4283  }
4284 
4285  CHECK(checkReadDeadlocks(&hugoOps,
4286  ndb,
4287  pTab,
4288  lmC,
4289  rowNum));
4290 
4291  ndbout << " TransC failed as expected" << endl;
4292 
4293  if (level < numLocksInTransB)
4294  {
4295  const NdbLockHandle* lockHandleB = transBOps[ level ]->getLockHandle();
4296  CHECKN(lockHandleB != NULL, transBOps[ level ], NDBT_FAILED);
4297 
4298  const NdbOperation* unlockB = transB->unlock(lockHandleB);
4299  CHECKN(unlockB != NULL, transB, NDBT_FAILED);
4300 
4301  CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4302  ndbout << " TransB unlock succeeded" << endl;
4303  }
4304 
4305  if (level < numLocksInTransA)
4306  {
4307  const NdbLockHandle* lockHandleA = transAOps[ level ]->getLockHandle();
4308  CHECKN(lockHandleA != NULL, transAOps[ level ], NDBT_FAILED);
4309 
4310  const NdbOperation* unlockA = transA->unlock(lockHandleA);
4311  CHECKN(unlockA != NULL, transA, NDBT_FAILED);
4312 
4313  CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4314  ndbout << " TransA unlock succeeded" << endl;
4315  }
4316  }
4317 
4318 
4319  /* Finally, all are unlocked and transC can successfully
4320  * obtain a conflicting lock
4321  */
4322  CHECK(checkReadSucceeds(&hugoOps,
4323  ndb,
4324  pTab,
4326  rowNum));
4327 
4328  ndbout << "TransC LM_Exclusive lock succeeded" << endl;
4329 
4330  transA->close();
4331  transB->close();
4332 
4333  return NDBT_OK;
4334 }
4335 
4336 
4337 int runTestUnlockScan(NDBT_Context* ctx, NDBT_Step* step)
4338 {
4339  /* Performs a table scan with LM_Read or LM_Exclusive
4340  * and lock takeovers for a number of the rows returned
4341  * Validates that some of the taken-over locks are held
4342  * before unlocking them and validating that they
4343  * are released.
4344  */
4345  const NdbDictionary::Table* pTab = ctx->getTab();
4346 
4347  HugoCalculator calc(*pTab);
4348  HugoOperations hugoOps(*pTab);
4349 
4350  /*
4351  1) Perform scan of the table with LM_Read / LM_Exclusive
4352  2) Takeover some of the rows with read and lockinfo
4353  3) Unlock the rows
4354  4) Check that they are unlocked
4355  */
4356  Ndb* ndb = GETNDB(step);
4357 
4358  const int iterations = 2;
4359 
4360  const int maxNumTakeovers = 15;
4361  NdbOperation* takeoverOps[ maxNumTakeovers ];
4362  Uint32 takeoverColIds[ maxNumTakeovers ];
4363 
4364  int numTakeovers = MIN(maxNumTakeovers, ctx->getNumRecords());
4365  int takeoverMod = ctx->getNumRecords() / numTakeovers;
4366 
4367  ndbout << "numTakeovers is " << numTakeovers
4368  << " takeoverMod is " << takeoverMod << endl;
4369 
4370  for (int iter = 0; iter < iterations; iter++)
4371  {
4372  ndbout << "Scanning table with lock mode : ";
4373  NdbOperation::LockMode lmScan = chooseLockMode(true); // LM_Exclusive or LM_Read
4374 
4375  NdbTransaction* trans = ndb->startTransaction();
4376  CHECKN(trans != NULL, ndb, NDBT_FAILED);
4377 
4378  /* Define scan */
4379  NdbScanOperation* scan = trans->getNdbScanOperation(pTab);
4380  CHECKN(scan != NULL, trans, NDBT_FAILED);
4381 
4382  Uint32 scanFlags = NdbScanOperation::SF_KeyInfo;
4383 
4384  CHECKN(scan->readTuples(lmScan, scanFlags) == 0, scan, NDBT_FAILED);
4385 
4386  NdbRecAttr* idColRecAttr = NULL;
4387 
4388  for(int c = 0; c < pTab->getNoOfColumns(); c++)
4389  {
4390  NdbRecAttr* ra = scan->getValue(pTab->getColumn(c)->getName());
4391  CHECKN(ra != NULL, scan, NDBT_FAILED);
4392  if (calc.isIdCol(c))
4393  {
4394  CHECK(idColRecAttr == NULL);
4395  idColRecAttr = ra;
4396  }
4397  }
4398  CHECK(idColRecAttr != NULL);
4399 
4400  CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4401 
4402  int rowsRead = 0;
4403  int rowsTakenover = 0;
4404  while (scan->nextResult(true) == 0)
4405  {
4406  if ((rowsTakenover < maxNumTakeovers) &&
4407  (0 == (rowsRead % takeoverMod)))
4408  {
4409  /* We're going to take the lock for this row into
4410  * a separate operation
4411  */
4412  Uint32 rowId = idColRecAttr->u_32_value();
4413  ndbout << " Taking over lock on result num " << rowsRead
4414  << " row (" << rowId << ")" << endl;
4415  NdbOperation* readTakeoverOp = scan->lockCurrentTuple();
4416  CHECKN(readTakeoverOp != NULL, scan, NDBT_FAILED);
4417 
4418  CHECKN(readTakeoverOp->getLockHandle() != NULL, readTakeoverOp, NDBT_FAILED);
4419  takeoverOps[ rowsTakenover ] = readTakeoverOp;
4420  takeoverColIds[ rowsTakenover ] = rowId;
4421 
4422  CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4423 
4424  CHECKN(readTakeoverOp->getNdbError().code == 0, readTakeoverOp, NDBT_FAILED);
4425 
4426 // // Uncomment to check that takeover keeps lock.
4427 // if (0 == (rowsTakenover % 7))
4428 // {
4429 // ndbout << " Validating taken-over lock holds on rowid "
4430 // << takeoverColIds[ rowsTakenover ]
4431 // << " by ";
4432 // /* Occasionally validate the lock held by the scan */
4433 // CHECK(checkReadDeadlocks(&hugoOps,
4434 // ndb,
4435 // pTab,
4436 // chooseConflictingLockMode(lmScan),
4437 // takeoverColIds[ rowsTakenover ]));
4438 // }
4439 
4440  rowsTakenover ++;
4441 
4442  }
4443 
4444  rowsRead ++;
4445  }
4446 
4447  scan->close();
4448 
4449  ndbout << "Scan complete : rows read : " << rowsRead
4450  << " rows locked : " << rowsTakenover << endl;
4451 
4452  ndbout << "Now unlocking rows individually" << endl;
4453  for (int lockedRows = 0; lockedRows < rowsTakenover; lockedRows ++)
4454  {
4455  if (0 == (lockedRows % 3))
4456  {
4457  ndbout << " First validating that lock holds on rowid "
4458  << takeoverColIds[ lockedRows ]
4459  << " by ";
4460  /* Occasionally check that the lock held by the scan still holds */
4461  CHECK(checkReadDeadlocks(&hugoOps,
4462  ndb,
4463  pTab,
4464  chooseConflictingLockMode(lmScan),
4465  takeoverColIds[ lockedRows ]));
4466  ndbout << " Lock is held" << endl;
4467  }
4468 
4469  /* Unlock the row */
4470  const NdbLockHandle* lockHandle = takeoverOps[ lockedRows ]->getLockHandle();
4471  CHECKN(lockHandle != NULL, takeoverOps[ lockedRows ], NDBT_FAILED);
4472 
4473  const NdbOperation* unlockOp = trans->unlock(lockHandle);
4474  CHECKN(unlockOp, trans, NDBT_FAILED);
4475 
4476  CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4477 
4478  /* Now check that the row's unlocked */
4479  CHECK(checkReadSucceeds(&hugoOps,
4480  ndb,
4481  pTab,
4483  takeoverColIds[ lockedRows ]));
4484  ndbout << " Row " << takeoverColIds[ lockedRows ]
4485  << " unlocked successfully" << endl;
4486  }
4487 
4488  /* Lastly, verify that scan with LM_Exclusive in separate transaction
4489  * can scan whole table without locking on anything
4490  */
4491  ndbout << "Validating unlocking code with LM_Exclusive table scan" << endl;
4492 
4493  NdbTransaction* otherTrans = ndb->startTransaction();
4494  CHECKN(otherTrans != NULL, ndb, NDBT_FAILED);
4495 
4496  NdbScanOperation* otherScan = otherTrans->getNdbScanOperation(pTab);
4497  CHECKN(otherScan != NULL, otherTrans, NDBT_FAILED);
4498 
4499  CHECKN(otherScan->readTuples(NdbOperation::LM_Exclusive) == 0, otherScan, NDBT_FAILED);
4500 
4501  for(int c = 0; c < pTab->getNoOfColumns(); c++)
4502  {
4503  NdbRecAttr* ra = otherScan->getValue(pTab->getColumn(c)->getName());
4504  CHECKN(ra != NULL, otherScan, NDBT_FAILED);
4505  }
4506 
4507  CHECKN(otherTrans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4508 
4509  int nextRc = 0;
4510  while (0 == (nextRc = otherScan->nextResult(true)))
4511  {};
4512 
4513  if (nextRc != 1)
4514  {
4515  ndbout << "Final scan with lock did not complete successfully" << endl;
4516  ndbout << otherScan->getNdbError() << endl;
4517  ndbout << "at line " << __LINE__ << endl;
4518  return NDBT_FAILED;
4519  }
4520 
4521  otherScan->close();
4522  otherTrans->close();
4523 
4524  ndbout << "All locked rows unlocked" << endl;
4525 
4526  trans->close();
4527  }
4528 
4529  return NDBT_OK;
4530 }
4531 
4532 NDBT_TESTSUITE(testNdbApi);
4533 TESTCASE("MaxNdb",
4534  "Create Ndb objects until no more can be created\n"){
4535  INITIALIZER(runTestMaxNdb);
4536 }
4537 TESTCASE("MaxTransactions",
4538  "Start transactions until no more can be created\n"){
4539  INITIALIZER(runTestMaxTransaction);
4540 }
4541 TESTCASE("MaxOperations",
4542  "Get operations until no more can be created\n"){
4543  INITIALIZER(runLoadTable);
4544  INITIALIZER(runTestMaxOperations);
4545  FINALIZER(runClearTable);
4546 }
4547 TESTCASE("MaxGetValue",
4548  "Call getValue loads of time\n"){
4549  INITIALIZER(runLoadTable);
4550  INITIALIZER(runTestGetValue);
4551  FINALIZER(runClearTable);
4552 }
4553 TESTCASE("MaxEqual",
4554  "Call equal loads of time\n"){
4555  INITIALIZER(runTestEqual);
4556 }
4557 TESTCASE("DeleteNdb",
4558  "Make sure that a deleted Ndb object is properly deleted\n"
4559  "and removed from transporter\n"){
4560  INITIALIZER(runLoadTable);
4561  INITIALIZER(runTestDeleteNdb);
4562  FINALIZER(runClearTable);
4563 }
4564 TESTCASE("WaitUntilReady",
4565  "Make sure you get an error message when calling waitUntilReady\n"
4566  "without an init'ed Ndb\n"){
4567  INITIALIZER(runTestWaitUntilReady);
4568 }
4569 TESTCASE("GetOperationNoTab",
4570  "Call getNdbOperation on a table that does not exist\n"){
4571  INITIALIZER(runGetNdbOperationNoTab);
4572 }
4573 TESTCASE("BadColNameHandling",
4574  "Call methods with an invalid column name and check error handling\n"){
4575  INITIALIZER(runBadColNameHandling);
4576 }
4577 TESTCASE("MissingOperation",
4578  "Missing operation request(insertTuple) should give an error code\n"){
4579  INITIALIZER(runMissingOperation);
4580 }
4581 TESTCASE("GetValueInUpdate",
4582  "Test that it's not possible to perform getValue in an update\n"){
4583  INITIALIZER(runLoadTable);
4584  INITIALIZER(runGetValueInUpdate);
4585  FINALIZER(runClearTable);
4586 }
4587 TESTCASE("UpdateWithoutKeys",
4588  "Test that it's not possible to perform update without setting\n"
4589  "PKs"){
4590  INITIALIZER(runLoadTable);
4591  INITIALIZER(runUpdateWithoutKeys);
4592  FINALIZER(runClearTable);
4593 }
4594 TESTCASE("UpdateWithoutValues",
4595  "Test that it's not possible to perform update without setValues\n"){
4596  INITIALIZER(runLoadTable);
4597  INITIALIZER(runUpdateWithoutValues);
4598  FINALIZER(runClearTable);
4599 }
4600 TESTCASE("NdbErrorOperation",
4601  "Test that NdbErrorOperation is properly set"){
4602  INITIALIZER(runCheckGetNdbErrorOperation);
4603 }
4604 TESTCASE("ReadWithoutGetValue",
4605  "Test that it's possible to perform read wo/ getvalue's\n"){
4606  INITIALIZER(runLoadTable);
4607  INITIALIZER(runReadWithoutGetValue);
4608  FINALIZER(runClearTable);
4609 }
4610 TESTCASE("Bug_11133",
4611  "Test ReadEx-Delete-Write\n"){
4612  INITIALIZER(runBug_11133);
4613  FINALIZER(runClearTable);
4614 }
4615 TESTCASE("Bug_WritePartialIgnoreError",
4616  "Test WritePartialIgnoreError\n"){
4617  INITIALIZER(runBug_WritePartialIgnoreError);
4618  FINALIZER(runClearTable);
4619 }
4620 TESTCASE("Scan_4006",
4621  "Check that getNdbScanOperation does not get 4006\n"){
4622  INITIALIZER(runLoadTable);
4623  INITIALIZER(runScan_4006);
4624  FINALIZER(runClearTable);
4625 }
4626 TESTCASE("IgnoreError", ""){
4627  INITIALIZER(createPkIndex);
4628  STEP(runTestIgnoreError);
4629  FINALIZER(runClearTable);
4630  FINALIZER(createPkIndex_Drop);
4631 }
4632 TESTCASE("CheckNdbObjectList",
4633  ""){
4634  INITIALIZER(runCheckNdbObjectList);
4635 }
4636 TESTCASE("ExecuteAsynch",
4637  "Check that executeAsync() works (BUG#27495)\n"){
4638  INITIALIZER(runTestExecuteAsynch);
4639 }
4640 TESTCASE("Bug28443",
4641  ""){
4642  INITIALIZER(runBug28443);
4643 }
4644 TESTCASE("Bug37158",
4645  ""){
4646  INITIALIZER(runBug37158);
4647 }
4648 TESTCASE("SimpleReadAbortOnError",
4649  "Test behaviour of Simple reads with Abort On Error"){
4650  INITIALIZER(simpleReadAbortOnError);
4651 }
4652 TESTCASE("NdbRecordPKAmbiguity",
4653  "Test behaviour of NdbRecord insert with ambig. pk values"){
4654  INITIALIZER(testNdbRecordPkAmbiguity);
4655 }
4656 TESTCASE("NdbRecordPKUpdate",
4657  "Verify that primary key columns can be updated"){
4658  INITIALIZER(testNdbRecordPKUpdate);
4659 }
4660 TESTCASE("NdbRecordCICharPKUpdate",
4661  "Verify that a case-insensitive char pk column can be updated"){
4662  INITIALIZER(testNdbRecordCICharPKUpdate);
4663 }
4664 TESTCASE("NdbRecordRowLength",
4665  "Verify that the record row length calculation is correct") {
4666  INITIALIZER(testNdbRecordRowLength);
4667 }
4668 TESTCASE("Bug44015",
4669  "Rollback insert followed by delete to get corruption") {
4670  STEP(runBug44015);
4671  STEPS(runScanReadUntilStopped, 10);
4672 }
4673 TESTCASE("Bug44065_org",
4674  "Rollback no-change update on top of existing data") {
4675  INITIALIZER(runBug44065_org);
4676 }
4677 TESTCASE("Bug44065",
4678  "Rollback no-change update on top of existing data") {
4679  INITIALIZER(runBug44065);
4680 }
4681 TESTCASE("ApiFailReqBehaviour",
4682  "Check ApiFailReq cleanly marks Api disconnect") {
4683  // Some flags to enable the various threads to cooperate
4684  TC_PROPERTY(ApiFailTestRun, (Uint32)0);
4685  TC_PROPERTY(ApiFailTestComplete, (Uint32)0);
4686  TC_PROPERTY(ApiFailTestsRunning, (Uint32)0);
4687  TC_PROPERTY(ApiFailNumberPkSteps, (Uint32)5); // Num threads below
4688  INITIALIZER(runLoadTable);
4689  // 5 threads to increase probability of pending
4690  // TCKEYREQ after API_FAILREQ
4691  STEP(runBulkPkReads);
4692  STEP(runBulkPkReads);
4693  STEP(runBulkPkReads);
4694  STEP(runBulkPkReads);
4695  STEP(runBulkPkReads);
4696  STEP(testApiFailReq);
4697  FINALIZER(runClearTable);
4698 }
4699 TESTCASE("ReadColumnDuplicates",
4700  "Check NdbApi behaves ok when reading same column multiple times") {
4701  INITIALIZER(runLoadTable);
4702  STEP(runReadColumnDuplicates);
4703  FINALIZER(runClearTable);
4704 }
4705 TESTCASE("Bug51775", "")
4706 {
4707  INITIALIZER(runBug51775);
4708 }
4709 TESTCASE("FragmentedApiFailure",
4710  "Test in-assembly fragment cleanup code for API failure") {
4711  // We reuse some of the infrastructure from ApiFailReqBehaviour here
4712  TC_PROPERTY(ApiFailTestRun, (Uint32)0);
4713  TC_PROPERTY(ApiFailTestComplete, (Uint32)0);
4714  TC_PROPERTY(ApiFailTestsRunning, (Uint32)0);
4715  TC_PROPERTY(ApiFailNumberPkSteps, (Uint32)5); // Num threads below
4716  // 5 threads to increase probability of fragmented signal being
4717  // in-assembly when disconnect occurs
4718  STEP(runFragmentedScanOtherApi);
4719  STEP(runFragmentedScanOtherApi);
4720  STEP(runFragmentedScanOtherApi);
4721  STEP(runFragmentedScanOtherApi);
4722  STEP(runFragmentedScanOtherApi);
4723  STEP(testFragmentedApiFail);
4724 };
4725 TESTCASE("UnlockBasic",
4726  "Check basic op unlock behaviour") {
4727  INITIALIZER(runLoadTable);
4728  STEP(runTestUnlockBasic);
4729  FINALIZER(runClearTable);
4730 }
4731 TESTCASE("UnlockRepeat",
4732  "Check repeated lock/unlock behaviour") {
4733  INITIALIZER(runLoadTable);
4734  STEP(runTestUnlockRepeat);
4735  FINALIZER(runClearTable);
4736 }
4737 TESTCASE("UnlockMulti",
4738  "Check unlock behaviour with multiple operations") {
4739  INITIALIZER(runLoadTable);
4740  STEP(runTestUnlockMulti);
4741  FINALIZER(runClearTable);
4742 }
4743 TESTCASE("UnlockScan",
4744  "Check unlock behaviour with scan lock-takeover") {
4745  INITIALIZER(runLoadTable);
4746  STEP(runTestUnlockScan);
4747  FINALIZER(runClearTable);
4748 }
4749 NDBT_TESTSUITE_END(testNdbApi);
4750 
4751 int main(int argc, const char** argv){
4752  ndb_init();
4753  NDBT_TESTSUITE_INSTANCE(testNdbApi);
4754  // TABLE("T1");
4755  return testNdbApi.execute(argc, argv);
4756 }
4757 
4758 template class Vector<Ndb*>;
4759 template class Vector<NdbConnection*>;