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