1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
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 #include "../../src/ndbapi/SignalSender.hpp"
36 #include <GlobalSignalNumbers.h>
37 
38 #define MAX_NDB_OBJECTS 32678
39 
40 #define CHECK(b) if (!(b)) { \
41   g_err.println("ERR: failed on line %u", __LINE__); \
42   return -1; }
43 
44 static const char* ApiFailTestRun = "ApiFailTestRun";
45 static const char* ApiFailTestComplete = "ApiFailTestComplete";
46 static const char* ApiFailTestsRunning = "ApiFailTestsRunning";
47 static const char* ApiFailNumberPkSteps = "ApiFailNumberPkSteps";
48 static const int MAX_STEPS = 10;
49 static Ndb_cluster_connection* otherConnection = NULL;
50 static Ndb* stepNdbs[MAX_STEPS];
51 
52 
runTestMaxNdb(NDBT_Context * ctx,NDBT_Step * step)53 int runTestMaxNdb(NDBT_Context* ctx, NDBT_Step* step){
54   Uint32 loops = ctx->getNumLoops();
55   Uint32 l = 0;
56   int oldi = 0;
57   int result = NDBT_OK;
58 
59   while (l < loops && result == NDBT_OK){
60     ndbout_c("loop %d", l + 1);
61     int errors = 0;
62 
63     Vector<Ndb*> ndbVector;
64     int i = 0;
65     int init = 0;
66     do {
67 
68       Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
69       if (pNdb == NULL){
70 	ndbout << "pNdb == NULL" << endl;
71 	errors++;
72 	continue;
73 
74       }
75       i++;
76 
77       ndbVector.push_back(pNdb);
78 
79       if (pNdb->init()){
80 	NDB_ERR(pNdb->getNdbError());
81 	errors++;
82 	continue;
83       }
84 
85       init++;
86 
87     } while (errors == 0);
88 
89     ndbout << i << " ndb objects created" << endl;
90 
91     if (l > 0 && i != oldi && init != MAX_NDB_OBJECTS){
92       ndbout << l << ": not as manyNdb objects created" << endl
93 	     << i << " != " << oldi << endl;
94       result =  NDBT_FAILED;
95     }
96 
97     oldi = i;
98 
99 
100     for(unsigned j = 0;  j < ndbVector.size(); j++){
101       delete ndbVector[j];
102       if(((j+1) % 250) == 0){
103 	ndbout << "Deleted " << (Uint64) j << " ndb objects " << endl;
104       }
105     }
106     ndbVector.clear();
107 
108     l++;
109   }
110 
111   return result;
112 }
113 
runTestMaxTransaction(NDBT_Context * ctx,NDBT_Step * step)114 int runTestMaxTransaction(NDBT_Context* ctx, NDBT_Step* step){
115   Uint32 loops = ctx->getNumLoops();
116   Uint32 l = 0;
117   int oldi = 0;
118   int result = NDBT_OK;
119 
120   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
121   if (pNdb == NULL){
122     ndbout << "pNdb == NULL" << endl;
123     return NDBT_FAILED;
124   }
125   if (pNdb->init(2048)){
126     NDB_ERR(pNdb->getNdbError());
127     delete pNdb;
128     return NDBT_FAILED;
129   }
130 
131   const NdbDictionary::Table* pTab = ctx->getTab();
132   if (pTab == 0) abort();
133 
134   while (l < loops && result == NDBT_OK){
135     int errors = 0;
136     int maxErrors = 5;
137 
138     Vector<NdbConnection*> conVector;
139 
140 
141     int i = 0;
142     do {
143 
144       NdbConnection* pCon;
145 
146       int type = i%2;
147       switch (type){
148       case 0:
149 	pCon = pNdb->startTransaction();
150 	break;
151       case 1:
152       {
153 	BaseString key;
154 	key.appfmt("DATA-%d", i);
155 	ndbout_c("%s", key.c_str());
156 	pCon = pNdb->startTransaction(pTab,
157 				      key.c_str(),
158 				      key.length());
159       }
160       break;
161       default:
162 	abort();
163       }
164 
165       if (pCon == NULL){
166 	NDB_ERR(pNdb->getNdbError());
167 	errors++;
168 	continue;
169       }
170 
171       conVector.push_back(pCon);
172 
173       i++;
174     } while (errors < maxErrors);
175 
176     ndbout << i << " connections created" << endl;
177 
178     if (l > 0 && i != oldi){
179       ndbout << l << ": not as many transactions created" << endl
180 	     << i << " != " << oldi << endl;
181       result =  NDBT_FAILED;
182     }
183 
184     oldi = i;
185 
186 
187     for(unsigned j = 0; j < conVector.size(); j++){
188       pNdb->closeTransaction(conVector[j]);
189     }
190     conVector.clear();
191     l++;
192 
193   }
194 
195   // BONUS Test closeTransaction with null trans
196   pNdb->closeTransaction(NULL);
197 
198   delete pNdb;
199 
200 
201   return result;
202 }
203 
runTestMaxOperations(NDBT_Context * ctx,NDBT_Step * step)204 int runTestMaxOperations(NDBT_Context* ctx, NDBT_Step* step){
205   Uint32 l = 1;
206   int result = NDBT_OK;
207   int maxOpsLimit = 1;
208   const NdbDictionary::Table* pTab = ctx->getTab();
209 
210   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
211   if (pNdb == NULL){
212     ndbout << "pNdb == NULL" << endl;
213     return NDBT_FAILED;
214   }
215   if (pNdb->init(2048)){
216     NDB_ERR(pNdb->getNdbError());
217     delete pNdb;
218     return NDBT_FAILED;
219   }
220 
221   HugoOperations hugoOps(*pTab);
222 
223   bool endTest = false;
224   while (!endTest){
225     int errors = 0;
226     const int maxErrors = 5;
227 
228     maxOpsLimit = l*1000;
229 
230     if (hugoOps.startTransaction(pNdb) != NDBT_OK){
231       delete pNdb;
232       return NDBT_FAILED;
233     }
234 
235     int i = 0;
236     do
237     {
238       i++;
239 
240       const int rowNo = (i % 256);
241       if(hugoOps.pkReadRecord(pNdb, rowNo, 1) != NDBT_OK){
242         errors++;
243         if (errors >= maxErrors){
244           result = NDBT_FAILED;
245           maxOpsLimit = i;
246         }
247       }
248 
249       // Avoid Transporter overload by executing after max 1000 ops.
250       int execResult = 0;
251       if (i >= maxOpsLimit)
252         execResult = hugoOps.execute_Commit(pNdb); //Commit after last op
253       else if ((i%1000) == 0)
254         execResult = hugoOps.execute_NoCommit(pNdb);
255       else
256         continue;
257 
258       switch(execResult){
259       case NDBT_OK:
260         break;
261 
262       default:
263         result = NDBT_FAILED;
264         // Fallthrough to '233' which also terminate test, but not 'FAILED'
265       case 233:  // Out of operation records in transaction coordinator
266         // OK - end test
267         endTest = true;
268         maxOpsLimit = i;
269         break;
270       }
271     } while (i < maxOpsLimit);
272 
273     ndbout << i << " operations used" << endl;
274 
275     hugoOps.closeTransaction(pNdb);
276 
277     l++;
278   }
279 
280   delete pNdb;
281 
282   return result;
283 }
284 
runTestGetValue(NDBT_Context * ctx,NDBT_Step * step)285 int runTestGetValue(NDBT_Context* ctx, NDBT_Step* step){
286 
287   int result = NDBT_OK;
288   const NdbDictionary::Table* pTab = ctx->getTab();
289 
290   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
291   if (pNdb == NULL){
292     ndbout << "pNdb == NULL" << endl;
293     return NDBT_FAILED;
294   }
295   if (pNdb->init(2048)){
296     NDB_ERR(pNdb->getNdbError());
297     delete pNdb;
298     return NDBT_FAILED;
299   }
300 
301   HugoOperations hugoOps(*pTab);
302 
303   for (int m = 1; m < 100; m++){
304     int errors = 0;
305     int maxErrors = 5;
306 
307     NdbConnection* pCon = pNdb->startTransaction();
308     if (pCon == NULL){
309       delete pNdb;
310       return NDBT_FAILED;
311     }
312 
313     NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
314     if (pOp == NULL){
315       pNdb->closeTransaction(pCon);
316       delete pNdb;
317       return NDBT_FAILED;
318     }
319 
320     if (pOp->readTuple() != 0){
321       pNdb->closeTransaction(pCon);
322       delete pNdb;
323       return NDBT_FAILED;
324     }
325 
326     for(int a = 0; a<pTab->getNoOfColumns(); a++){
327       if (pTab->getColumn(a)->getPrimaryKey() == true){
328 	if(hugoOps.equalForAttr(pOp, a, 1) != 0){
329 	  NDB_ERR(pCon->getNdbError());
330 	  pNdb->closeTransaction(pCon);
331 	  delete pNdb;
332 	  return NDBT_FAILED;
333 	}
334       }
335     }
336 
337     int i = 0;
338     int maxLimit = 1000*m;
339     do {
340 
341       if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
342 	const NdbError err = pCon->getNdbError();
343 	NDB_ERR(err);
344 	if (err.code == 0)
345 	  result = NDBT_FAILED;
346 	errors++;
347 	continue;
348       }
349 
350       i++;
351 
352     } while (errors < maxErrors && i < maxLimit);
353 
354     ndbout << i << " getValues called" << endl;
355 
356 
357     if (pCon->execute(Commit) != 0){
358       const NdbError err = pCon->getNdbError();
359       switch(err.code){
360       case 880: // TUP - Read too much
361       case 823: // TUP - Too much AI
362       case 4257: // NDBAPI - Too much AI
363       case 4002: // NDBAPI - send problem
364 	// OK errors
365 	NDB_ERR(pCon->getNdbError());
366 	break;
367       default:
368 	NDB_ERR(pCon->getNdbError());
369 	ndbout << "Illegal error" << endl;
370 	result= NDBT_FAILED;
371 	break;
372       }
373     }
374 
375     pNdb->closeTransaction(pCon);
376 
377   }// m
378 
379 
380   delete pNdb;
381 
382   return result;
383 }
384 
runTestEqual(NDBT_Context * ctx,NDBT_Step * step)385 int runTestEqual(NDBT_Context* ctx, NDBT_Step* step){
386   Uint32 loops = ctx->getNumLoops();
387   Uint32 l = 0;
388   int result = NDBT_OK;
389   const NdbDictionary::Table* pTab = ctx->getTab();
390 
391   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
392   if (pNdb == NULL){
393     ndbout << "pNdb == NULL" << endl;
394     return NDBT_FAILED;
395   }
396   if (pNdb->init(2048)){
397     NDB_ERR(pNdb->getNdbError());
398     delete pNdb;
399     return NDBT_FAILED;
400   }
401 
402   HugoOperations hugoOps(*pTab);
403 
404   while (l < loops){
405     for(int m = 1; m < 10; m++){
406       int errors = 0;
407       int maxErrors = 5;
408 
409       NdbConnection* pCon = pNdb->startTransaction();
410       if (pCon == NULL){
411 	ndbout << "Could not start transaction" << endl;
412 	delete pNdb;
413 	return NDBT_FAILED;
414       }
415 
416       NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
417       if (pOp == NULL){
418 	NDB_ERR(pCon->getNdbError());
419 	pNdb->closeTransaction(pCon);
420 	delete pNdb;
421 	return NDBT_FAILED;
422       }
423 
424       if (pOp->readTuple() != 0){
425 	NDB_ERR(pCon->getNdbError());
426 	pNdb->closeTransaction(pCon);
427 	delete pNdb;
428 	return NDBT_FAILED;
429       }
430 
431       int i = 0;
432       int maxLimit = 1000*m;
433       do {
434 
435 	if ((l%2)!=0){
436 	  // Forward
437 	  for(int a = 0; a<pTab->getNoOfColumns(); a++){
438 	    if (pTab->getColumn(a)->getPrimaryKey() == true){
439 	      if(hugoOps.equalForAttr(pOp, a, 1) != 0){
440 		const NdbError err = pCon->getNdbError();
441 		NDB_ERR(err);
442 		if (err.code == 0)
443 		  result = NDBT_FAILED;
444 		errors++;
445 	      }
446 	    }
447 	  }
448 	} else {
449 	  // Backward
450 	  for(int a = pTab->getNoOfColumns()-1; a>=0; a--){
451 	    if (pTab->getColumn(a)->getPrimaryKey() == true){
452 	      if(hugoOps.equalForAttr(pOp, a, 1) != 0){
453 		const NdbError err = pCon->getNdbError();
454 		NDB_ERR(err);
455 		if (err.code == 0)
456 		  result = NDBT_FAILED;
457 		errors++;
458 	      }
459 	    }
460 	  }
461 	}
462 
463 	i++;
464 
465       } while (errors < maxErrors && i < maxLimit);
466 
467       if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
468         const NdbError err = pCon->getNdbError();
469 	NDB_ERR(pCon->getNdbError());
470 	pNdb->closeTransaction(pCon);
471 	delete pNdb;
472         if (err.code == 4225) {
473           return NDBT_OK;
474         } else {
475           return NDBT_FAILED;
476         }//if
477       }
478 
479       ndbout << i << " equal called" << endl;
480 
481 
482       int check = pCon->execute(Commit);
483       if (check != 0){
484 	NDB_ERR(pCon->getNdbError());
485       }
486 
487       pNdb->closeTransaction(pCon);
488 
489     }// m
490     l++;
491 
492   }// l
493 
494   delete pNdb;
495   return result;
496 }
497 
runTestDeleteNdb(NDBT_Context * ctx,NDBT_Step * step)498 int runTestDeleteNdb(NDBT_Context* ctx, NDBT_Step* step){
499   Uint32 loops = ctx->getNumLoops();
500   Uint32 l = 0;
501   int result = NDBT_OK;
502   NdbRestarts restarts;
503   Vector<Ndb*> ndbVector;
504   const NdbDictionary::Table* pTab = ctx->getTab();
505   HugoTransactions hugoTrans(*pTab);
506   int records = ctx->getNumRecords();
507 
508   while (l < loops && result == NDBT_OK){
509 
510     // Create 5 ndb objects
511     for( int i = 0; i < 5; i++){
512       Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
513       if (pNdb == NULL){
514 	ndbout << "pNdb == NULL" << endl;
515 	result = NDBT_FAILED;
516 	goto end_test;
517       }
518       ndbVector.push_back(pNdb);
519 
520       if (pNdb->init()){
521 	NDB_ERR(pNdb->getNdbError());
522 	result = NDBT_FAILED;
523 	goto end_test;
524       }
525       if (pNdb->waitUntilReady() != 0){
526 	NDB_ERR(pNdb->getNdbError());
527 	result = NDBT_FAILED;
528 	goto end_test;
529       }
530       if (hugoTrans.pkReadRecords(pNdb, records) != 0){
531 	result = NDBT_FAILED;
532 	goto end_test;
533       }
534     }
535 
536     if ((l % 2) == 0){
537       // Restart random node
538       ndbout << "Restart random node " << endl;
539       if(restarts.executeRestart(ctx, "RestartRandomNodeAbort", 120) != 0){
540 	g_err << "Failed to executeRestart(RestartRandomNode)"<<endl;
541 	result = NDBT_FAILED;
542 	goto end_test;
543       }
544     } else {
545       // Restart all nodes
546       ndbout << "Restart all nodes " << endl;
547       if(restarts.executeRestart(ctx, "RestartAllNodesAbort", 120) != 0){
548 	g_err << "Failed to executeRestart(RestartAllNodes)"<<endl;
549 	result = NDBT_FAILED;
550 	goto end_test;
551       }
552     }
553 
554     // Delete the ndb objects
555     for(unsigned j = 0;  j < ndbVector.size(); j++)
556       delete ndbVector[j];
557     ndbVector.clear();
558     l++;
559   }
560 
561 
562  end_test:
563 
564   for(unsigned i = 0;  i < ndbVector.size(); i++)
565     delete ndbVector[i];
566   ndbVector.clear();
567 
568   return result;
569 }
570 
571 
runClearTable(NDBT_Context * ctx,NDBT_Step * step)572 int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
573   int records = ctx->getNumRecords();
574 
575   UtilTransactions utilTrans(*ctx->getTab());
576   if (utilTrans.clearTable2(GETNDB(step),  records) != 0){
577     return NDBT_FAILED;
578   }
579   return NDBT_OK;
580 }
runLoadTable(NDBT_Context * ctx,NDBT_Step * step)581 int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
582 
583   int records = ctx->getNumRecords();
584   HugoTransactions hugoTrans(*ctx->getTab());
585   if (hugoTrans.loadTable(GETNDB(step), records) != 0){
586     return NDBT_FAILED;
587   }
588   return NDBT_OK;
589 }
590 
runTestWaitUntilReady(NDBT_Context * ctx,NDBT_Step * step)591 int runTestWaitUntilReady(NDBT_Context* ctx, NDBT_Step* step){
592 
593   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
594 
595   // Forget about calling pNdb->init();
596 
597   if (pNdb->waitUntilReady() == 0){
598     ndbout << "waitUntilReady returned OK" << endl;
599     delete pNdb;
600     return NDBT_FAILED;
601   }
602   const NdbError err = pNdb->getNdbError();
603   delete pNdb;
604 
605   NDB_ERR(err);
606   if (err.code != 4256)
607     return NDBT_FAILED;
608 
609   return NDBT_OK;
610 }
611 
runGetNdbOperationNoTab(NDBT_Context * ctx,NDBT_Step * step)612 int runGetNdbOperationNoTab(NDBT_Context* ctx, NDBT_Step* step){
613 
614   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
615   if (pNdb == NULL){
616     ndbout << "pNdb == NULL" << endl;
617     return NDBT_FAILED;
618   }
619   if (pNdb->init()){
620     NDB_ERR(pNdb->getNdbError());
621     delete pNdb;
622     return NDBT_FAILED;
623   }
624 
625   NdbConnection* pCon = pNdb->startTransaction();
626   if (pCon == NULL){
627     delete pNdb;
628     return NDBT_FAILED;
629   }
630 
631   // Call getNdbOperation on an unknown table
632   NdbOperation* pOp = pCon->getNdbOperation("HUPP76");
633   if (pOp == NULL){
634     NdbError err = pCon->getNdbError();
635     NDB_ERR(err);
636     if (err.code == 0){
637       pNdb->closeTransaction(pCon);
638       delete pNdb;
639       return NDBT_FAILED;
640     }
641   }
642 
643   pNdb->closeTransaction(pCon);
644 
645   delete pNdb;
646 
647   return NDBT_OK;
648 }
649 
runBadColNameHandling(NDBT_Context * ctx,NDBT_Step * step)650 int runBadColNameHandling(NDBT_Context* ctx, NDBT_Step* step){
651   int result = NDBT_OK;
652   const NdbDictionary::Table* pTab = ctx->getTab();
653 
654 
655   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
656   if (pNdb == NULL){
657     ndbout << "pNdb == NULL" << endl;
658     return NDBT_FAILED;
659   }
660   if (pNdb->init()){
661     NDB_ERR(pNdb->getNdbError());
662     delete pNdb;
663     return NDBT_FAILED;
664   }
665 
666   const int CASES= 5;
667   int i;
668 
669   for (i= 0; i < CASES; i++)
670   {
671     ndbout << "Case " << i << endl;
672     NdbConnection* pCon = pNdb->startTransaction();
673     if (pCon == NULL){
674       pNdb->closeTransaction(pCon);
675       delete pNdb;
676       return NDBT_FAILED;
677     }
678 
679     /* Cases 0-3 use PK ops, 4 + use scans */
680     NdbOperation* pOp = (i < 4 ? pCon->getNdbOperation(pTab->getName()):
681                          pCon->getNdbScanOperation(pTab->getName()));
682     if (pOp == NULL){
683       NDB_ERR(pCon->getNdbError());
684       pNdb->closeTransaction(pCon);
685       delete pNdb;
686       return NDBT_FAILED;
687     }
688 
689     bool failed= false;
690     int expectedError= 0;
691     HugoOperations hugoOps(*pTab);
692 
693     switch(i) {
694     case 0:
695       if (pOp->readTuple() != 0){
696         NDB_ERR(pCon->getNdbError());
697         pNdb->closeTransaction(pCon);
698         delete pNdb;
699         return NDBT_FAILED;
700       }
701 
702       // getValue should fail, we check that we get correct errors
703       // in expected places.
704       expectedError= 4004;
705       failed= (pOp->getValue("MOST_IMPROBABLE2") == NULL);
706       break;
707 
708     case 1:
709       if (pOp->readTuple() != 0){
710         NDB_ERR(pCon->getNdbError());
711         pNdb->closeTransaction(pCon);
712         delete pNdb;
713         return NDBT_FAILED;
714       }
715 
716       // equal should fail, we check that we get correct errors
717       // in expected places.
718       expectedError= 4004;
719       failed= (pOp->equal("MOST_IMPROBABLE2", 0) != 0);
720       break;
721 
722     case 2:
723       if (pOp->writeTuple() != 0){
724         NDB_ERR(pCon->getNdbError());
725         pNdb->closeTransaction(pCon);
726         delete pNdb;
727         return NDBT_FAILED;
728       }
729 
730       // set equality on pk columns
731       for(int a = 0; a<pTab->getNoOfColumns(); a++){
732         if (pTab->getColumn(a)->getPrimaryKey() == true){
733           if(hugoOps.equalForAttr(pOp, a, 1) != 0){
734             const NdbError err = pCon->getNdbError();
735             NDB_ERR(err);
736             pNdb->closeTransaction(pCon);
737             delete pNdb;
738             return NDBT_FAILED;
739           }
740         }
741       }
742 
743       // setValue should fail, we check that we get correct errors
744       // in expected places.
745       expectedError= 4004;
746       failed= (pOp->setValue("MOST_IMPROBABLE2", 0) != 0);
747       break;
748 
749     case 3:
750       if (pOp->readTuple() != 0){
751         NDB_ERR(pCon->getNdbError());
752         pNdb->closeTransaction(pCon);
753         delete pNdb;
754         return NDBT_FAILED;
755       }
756 
757       // getBlobHandle should fail, we check that we get correct errors
758       // in expected places.
759       expectedError= 4004;
760       failed= (pOp->getBlobHandle("MOST_IMPROBABLE2") == NULL);
761       break;
762 
763     case 4:
764     {
765       NdbScanOperation* sop= (NdbScanOperation*) pOp;
766       if (sop->readTuples() != 0){
767         NDB_ERR(pCon->getNdbError());
768         pNdb->closeTransaction(pCon);
769         delete pNdb;
770         return NDBT_FAILED;
771       }
772 
773       // getBlobHandle should fail, we check that we get correct errors
774       // in expected places.
775       expectedError= 4004;
776       ndbout << "About to call getBlobHandle" << endl;
777       failed= (sop->getBlobHandle("MOST_IMPROBABLE2") == NULL);
778 
779       sop->close();
780       break;
781     }
782 
783     default:
784       break;
785     }
786 
787     if (failed)
788     {
789       const NdbError opErr= pOp->getNdbError();
790       const NdbError transErr = pCon->getNdbError();
791       NDB_ERR(opErr);
792       NDB_ERR(transErr);
793       if (opErr.code != transErr.code) {
794         ndbout << "Error reporting mismatch, expected "
795                << expectedError << endl;
796         result = NDBT_FAILED;
797       }
798       if (opErr.code != expectedError){
799         ndbout << "No or bad error detected, expected "
800                << expectedError << endl;
801         result = NDBT_FAILED;
802       }
803     } else {
804       ndbout << "Case " << i << " did not fail" << endl;
805       result = NDBT_FAILED;
806     }
807 
808     pNdb->closeTransaction(pCon);
809 
810     if (result == NDBT_FAILED)
811       break;
812   } // for
813 
814   delete pNdb;
815 
816   return result;
817 }
818 
runMissingOperation(NDBT_Context * ctx,NDBT_Step * step)819 int runMissingOperation(NDBT_Context* ctx, NDBT_Step* step){
820   int result = NDBT_OK;
821   const NdbDictionary::Table* pTab = ctx->getTab();
822 
823 
824   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
825   if (pNdb == NULL){
826     ndbout << "pNdb == NULL" << endl;
827     return NDBT_FAILED;
828   }
829   if (pNdb->init()){
830     NDB_ERR(pNdb->getNdbError());
831     delete pNdb;
832     return NDBT_FAILED;
833   }
834 
835   NdbConnection* pCon = pNdb->startTransaction();
836   if (pCon == NULL){
837     pNdb->closeTransaction(pCon);
838     delete pNdb;
839     return NDBT_FAILED;
840   }
841 
842   NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
843   if (pOp == NULL){
844     NDB_ERR(pCon->getNdbError());
845     pNdb->closeTransaction(pCon);
846     delete pNdb;
847     return NDBT_FAILED;
848   }
849 
850   // Forget about calling pOp->insertTuple();
851 
852   // Call getValue should not work
853   if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
854     const NdbError err = pCon->getNdbError();
855     NDB_ERR(err);
856     if (err.code == 0){
857       ndbout << "hupp" << endl;
858       result = NDBT_FAILED;
859     }
860   } else {
861       ndbout << "hupp2" << endl;
862     result = NDBT_FAILED;
863   }
864 
865   pNdb->closeTransaction(pCon);
866   delete pNdb;
867 
868   return result;
869 }
870 
runGetValueInUpdate(NDBT_Context * ctx,NDBT_Step * step)871 int runGetValueInUpdate(NDBT_Context* ctx, NDBT_Step* step){
872   const NdbDictionary::Table* pTab = ctx->getTab();
873 
874   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
875   if (pNdb == NULL){
876     ndbout << "pNdb == NULL" << endl;
877     return NDBT_FAILED;
878   }
879   if (pNdb->init()){
880     NDB_ERR(pNdb->getNdbError());
881     delete pNdb;
882     return NDBT_FAILED;
883   }
884 
885   NdbConnection* pCon = pNdb->startTransaction();
886   if (pCon == NULL){
887     pNdb->closeTransaction(pCon);
888     delete pNdb;
889     return NDBT_FAILED;
890   }
891 
892   NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
893   if (pOp == NULL){
894     NDB_ERR(pCon->getNdbError());
895     pNdb->closeTransaction(pCon);
896     delete pNdb;
897     return NDBT_FAILED;
898   }
899 
900   if (pOp->updateTuple() != 0){
901     pNdb->closeTransaction(pCon);
902     delete pNdb;
903     return NDBT_FAILED;
904   }
905 
906   // Call getValue should not work
907   if (pOp->getValue(pTab->getColumn(1)->getName()) == NULL) {
908     // It didn't work
909     const NdbError err = pCon->getNdbError();
910     NDB_ERR(err);
911     if (err.code == 0){
912       pNdb->closeTransaction(pCon);
913       delete pNdb;
914       return NDBT_FAILED;
915     }
916   } else {
917     // It worked, not good!
918     pNdb->closeTransaction(pCon);
919     delete pNdb;
920     return NDBT_FAILED;
921   }
922 
923   int check = pCon->execute(Commit);
924   if (check != 0){
925     NDB_ERR(pCon->getNdbError());
926   }
927 
928   pNdb->closeTransaction(pCon);
929   delete pNdb;
930 
931   return NDBT_OK;
932 }
933 
runUpdateWithoutValues(NDBT_Context * ctx,NDBT_Step * step)934 int runUpdateWithoutValues(NDBT_Context* ctx, NDBT_Step* step){
935   int result = NDBT_OK;
936   const NdbDictionary::Table* pTab = ctx->getTab();
937 
938   HugoOperations hugoOps(*pTab);
939 
940   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
941   if (pNdb == NULL){
942     ndbout << "pNdb == NULL" << endl;
943     return NDBT_FAILED;
944   }
945   if (pNdb->init()){
946     NDB_ERR(pNdb->getNdbError());
947     delete pNdb;
948     return NDBT_FAILED;
949   }
950 
951   NdbConnection* pCon = pNdb->startTransaction();
952   if (pCon == NULL){
953     pNdb->closeTransaction(pCon);
954     delete pNdb;
955     return NDBT_FAILED;
956   }
957 
958   NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
959   if (pOp == NULL){
960     NDB_ERR(pCon->getNdbError());
961     pNdb->closeTransaction(pCon);
962     delete pNdb;
963     return NDBT_FAILED;
964   }
965 
966   if (pOp->updateTuple() != 0){
967     pNdb->closeTransaction(pCon);
968     NDB_ERR(pOp->getNdbError());
969     delete pNdb;
970     return NDBT_FAILED;
971   }
972 
973   for(int a = 0; a<pTab->getNoOfColumns(); a++){
974     if (pTab->getColumn(a)->getPrimaryKey() == true){
975       if(hugoOps.equalForAttr(pOp, a, 1) != 0){
976 	NDB_ERR(pCon->getNdbError());
977 	pNdb->closeTransaction(pCon);
978 	delete pNdb;
979 	return NDBT_FAILED;
980       }
981     }
982   }
983 
984   // Dont' call any setValues
985 
986   // Execute should work
987   int check = pCon->execute(Commit);
988   if (check == 0){
989     ndbout << "execute worked" << endl;
990   } else {
991     NDB_ERR(pCon->getNdbError());
992     result = NDBT_FAILED;
993   }
994 
995   pNdb->closeTransaction(pCon);
996   delete pNdb;
997 
998   return result;
999 }
1000 
runUpdateWithoutKeys(NDBT_Context * ctx,NDBT_Step * step)1001 int runUpdateWithoutKeys(NDBT_Context* ctx, NDBT_Step* step){
1002   int result = NDBT_OK;
1003   const NdbDictionary::Table* pTab = ctx->getTab();
1004 
1005 
1006   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1007   if (pNdb == NULL){
1008     ndbout << "pNdb == NULL" << endl;
1009     return NDBT_FAILED;
1010   }
1011   if (pNdb->init()){
1012     NDB_ERR(pNdb->getNdbError());
1013     delete pNdb;
1014     return NDBT_FAILED;
1015   }
1016 
1017   NdbConnection* pCon = pNdb->startTransaction();
1018   if (pCon == NULL){
1019     pNdb->closeTransaction(pCon);
1020     delete pNdb;
1021     return NDBT_FAILED;
1022   }
1023 
1024   NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1025   if (pOp == NULL){
1026     NDB_ERR(pCon->getNdbError());
1027     pNdb->closeTransaction(pCon);
1028     delete pNdb;
1029     return NDBT_FAILED;
1030   }
1031 
1032   if (pOp->updateTuple() != 0){
1033     pNdb->closeTransaction(pCon);
1034     NDB_ERR(pOp->getNdbError());
1035     delete pNdb;
1036     return NDBT_FAILED;
1037   }
1038 
1039   // Dont' call any equal or setValues
1040 
1041   // Execute should not work
1042   int check = pCon->execute(Commit);
1043   if (check == 0){
1044     ndbout << "execute worked" << endl;
1045     result = NDBT_FAILED;
1046   } else {
1047     NDB_ERR(pCon->getNdbError());
1048   }
1049 
1050   pNdb->closeTransaction(pCon);
1051   delete pNdb;
1052 
1053   return result;
1054 }
1055 
1056 
runReadWithoutGetValue(NDBT_Context * ctx,NDBT_Step * step)1057 int runReadWithoutGetValue(NDBT_Context* ctx, NDBT_Step* step){
1058   int result = NDBT_OK;
1059   const NdbDictionary::Table* pTab = ctx->getTab();
1060 
1061   HugoOperations hugoOps(*pTab);
1062 
1063   Ndb* pNdb = GETNDB(step);
1064   Uint32 lm;
1065 
1066   for(Uint32 cm= 0; cm < 2; cm++)
1067   {
1068     for(lm= 0; lm <= NdbOperation::LM_CommittedRead; lm++)
1069     {
1070       NdbConnection* pCon = pNdb->startTransaction();
1071       if (pCon == NULL){
1072 	pNdb->closeTransaction(pCon);
1073 	return NDBT_FAILED;
1074       }
1075 
1076       NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1077       if (pOp == NULL){
1078 	NDB_ERR(pCon->getNdbError());
1079 	pNdb->closeTransaction(pCon);
1080 	return NDBT_FAILED;
1081       }
1082 
1083       if (pOp->readTuple((NdbOperation::LockMode)lm) != 0){
1084 	pNdb->closeTransaction(pCon);
1085 	NDB_ERR(pOp->getNdbError());
1086 	return NDBT_FAILED;
1087       }
1088 
1089       for(int a = 0; a<pTab->getNoOfColumns(); a++){
1090 	if (pTab->getColumn(a)->getPrimaryKey() == true){
1091 	  if(hugoOps.equalForAttr(pOp, a, 1) != 0){
1092 	    NDB_ERR(pCon->getNdbError());
1093 	    pNdb->closeTransaction(pCon);
1094 	    return NDBT_FAILED;
1095 	  }
1096 	}
1097       }
1098 
1099       // Dont' call any getValues
1100 
1101       // Execute should work
1102       int check = pCon->execute(cm == 0 ? NoCommit : Commit);
1103       if (check == 0){
1104 	ndbout << "execute worked" << endl;
1105       } else {
1106 	NDB_ERR(pCon->getNdbError());
1107 	result = NDBT_FAILED;
1108       }
1109 
1110       pNdb->closeTransaction(pCon);
1111     }
1112   }
1113 
1114   /**
1115    * Now test scans
1116    */
1117   for(lm= 0; lm <= NdbOperation::LM_CommittedRead; lm++)
1118   {
1119     NdbConnection* pCon = pNdb->startTransaction();
1120     if (pCon == NULL){
1121       pNdb->closeTransaction(pCon);
1122       return NDBT_FAILED;
1123     }
1124 
1125     NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1126     if (pOp == NULL){
1127       NDB_ERR(pCon->getNdbError());
1128       pNdb->closeTransaction(pCon);
1129       return NDBT_FAILED;
1130     }
1131 
1132     if ((pOp->readTuples((NdbOperation::LockMode)lm)) != 0){
1133       pNdb->closeTransaction(pCon);
1134       NDB_ERR(pOp->getNdbError());
1135       return NDBT_FAILED;
1136     }
1137 
1138 
1139     // Dont' call any getValues
1140 
1141     // Execute should work
1142     int check = pCon->execute(NoCommit);
1143     if (check == 0){
1144       ndbout << "execute worked" << endl;
1145     } else {
1146       NDB_ERR(pCon->getNdbError());
1147       result = NDBT_FAILED;
1148     }
1149 
1150     int res;
1151     while((res = pOp->nextResult()) == 0);
1152     pNdb->closeTransaction(pCon);
1153 
1154     if(res != 1)
1155       result = NDBT_FAILED;
1156   }
1157 
1158   return result;
1159 }
1160 
1161 
runCheckGetNdbErrorOperation(NDBT_Context * ctx,NDBT_Step * step)1162 int runCheckGetNdbErrorOperation(NDBT_Context* ctx, NDBT_Step* step){
1163   int result = NDBT_OK;
1164   const NdbDictionary::Table* pTab = ctx->getTab();
1165 
1166   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1167   if (pNdb == NULL){
1168     ndbout << "pNdb == NULL" << endl;
1169     return NDBT_FAILED;
1170   }
1171   if (pNdb->init(2048)){
1172     NDB_ERR(pNdb->getNdbError());
1173     delete pNdb;
1174     return NDBT_FAILED;
1175   }
1176 
1177   HugoOperations hugoOps(*pTab);
1178 
1179 
1180   NdbConnection* pCon = pNdb->startTransaction();
1181   if (pCon == NULL){
1182     ndbout << "Could not start transaction" << endl;
1183     delete pNdb;
1184     return NDBT_FAILED;
1185   }
1186 
1187   NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
1188   if (pOp == NULL){
1189     NDB_ERR(pCon->getNdbError());
1190     pNdb->closeTransaction(pCon);
1191     delete pNdb;
1192     return NDBT_FAILED;
1193   }
1194 
1195   // Dont call readTuple here
1196   // That's the error!
1197 
1198   for(int a = 0; a<pTab->getNoOfColumns(); a++){
1199     if (pTab->getColumn(a)->getPrimaryKey() == true){
1200       if(hugoOps.equalForAttr(pOp, a, 1) != 0){
1201 	// An error has occured, check that
1202 	// it's possible to get the NdbErrorOperation
1203 	const NdbError err = pCon->getNdbError();
1204 	NDB_ERR(err);
1205 	if (err.code == 0)
1206 	  result = NDBT_FAILED;
1207 
1208 	NdbOperation* pOp2 = pCon->getNdbErrorOperation();
1209 	if (pOp2 == NULL)
1210 	  result = NDBT_FAILED;
1211 	else {
1212 	  const NdbError err2 = pOp2->getNdbError();
1213 	  NDB_ERR(err2);
1214 	  if (err.code == 0)
1215 	    result = NDBT_FAILED;
1216 	}
1217       }
1218     }
1219   }
1220 
1221   pNdb->closeTransaction(pCon);
1222 
1223   delete pNdb;
1224   return result;
1225 }
1226 
1227 #define C2(x) { int _x= (x); if(_x == 0){ ndbout << "line: " << __LINE__ << endl;  return NDBT_FAILED;} }
1228 
runBug_11133(NDBT_Context * ctx,NDBT_Step * step)1229 int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){
1230   int result = NDBT_OK;
1231   const NdbDictionary::Table* pTab = ctx->getTab();
1232 
1233   HugoOperations hugoOps(*pTab);
1234 
1235   Ndb* pNdb = GETNDB(step);
1236   C2(hugoOps.startTransaction(pNdb) == 0);
1237   C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1238   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1239   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1240   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1241   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1242   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1243   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1244   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1245   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1246   C2(hugoOps.execute_Commit(pNdb) == 0);
1247   C2(hugoOps.closeTransaction(pNdb) == 0);
1248 
1249   C2(hugoOps.startTransaction(pNdb) == 0);
1250   C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1251   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1252   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1253   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1254   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1255   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1256   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1257   C2(hugoOps.execute_Commit(pNdb) == 0);
1258   C2(hugoOps.closeTransaction(pNdb) == 0);
1259 
1260   C2(hugoOps.startTransaction(pNdb) == 0);
1261   C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1262   C2(hugoOps.execute_Commit(pNdb) == 0);
1263   C2(hugoOps.closeTransaction(pNdb) == 0);
1264 
1265   C2(hugoOps.startTransaction(pNdb) == 0);
1266   C2(hugoOps.pkReadRecord(pNdb, 0, 1, NdbOperation::LM_Exclusive) == 0);
1267   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1268   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1269   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1270   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1271   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1272   C2(hugoOps.pkWriteRecord(pNdb, 0, 1) == 0);
1273   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1274   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1275   C2(hugoOps.execute_Commit(pNdb) == 0);
1276   C2(hugoOps.closeTransaction(pNdb) == 0);
1277 
1278   Ndb ndb2(&ctx->m_cluster_connection, "TEST_DB");
1279   C2(ndb2.init() == 0);
1280   C2(ndb2.waitUntilReady() == 0);
1281   HugoOperations hugoOps2(*pTab);
1282 
1283   C2(hugoOps.startTransaction(pNdb) == 0);
1284   C2(hugoOps.pkInsertRecord(pNdb, 0, 1) == 0);
1285   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1286   C2(hugoOps2.startTransaction(&ndb2) == 0);
1287   C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1288   C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1289   C2(hugoOps.execute_Commit(pNdb) == 0);
1290   C2(hugoOps2.wait_async(&ndb2) == 0);
1291   C2(hugoOps.closeTransaction(pNdb) == 0);
1292   C2(hugoOps2.closeTransaction(&ndb2) == 0);
1293 
1294   C2(hugoOps.startTransaction(pNdb) == 0);
1295   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1296   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1297   C2(hugoOps2.startTransaction(&ndb2) == 0);
1298   C2(hugoOps2.pkWriteRecord(&ndb2, 0, 1) == 0);
1299   C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1300   C2(hugoOps.execute_Commit(pNdb) == 0);
1301   C2(hugoOps2.wait_async(&ndb2) == 0);
1302   C2(hugoOps2.execute_Commit(pNdb) == 0);
1303   C2(hugoOps.closeTransaction(pNdb) == 0);
1304   C2(hugoOps2.closeTransaction(&ndb2) == 0);
1305 
1306   C2(hugoOps.startTransaction(pNdb) == 0);
1307   C2(hugoOps.pkUpdateRecord(pNdb, 0, 1) == 0);
1308   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1309   C2(hugoOps2.startTransaction(&ndb2) == 0);
1310   C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1311   C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1312   C2(hugoOps.execute_Commit(pNdb) == 0);
1313   C2(hugoOps2.wait_async(&ndb2) == 0);
1314   C2(hugoOps.closeTransaction(pNdb) == 0);
1315   C2(hugoOps2.closeTransaction(&ndb2) == 0);
1316 
1317   C2(hugoOps.startTransaction(pNdb) == 0);
1318   C2(hugoOps.pkDeleteRecord(pNdb, 0, 1) == 0);
1319   C2(hugoOps.execute_NoCommit(pNdb) == 0);
1320   C2(hugoOps2.startTransaction(&ndb2) == 0);
1321   C2(hugoOps2.pkWritePartialRecord(&ndb2, 0) == 0);
1322   C2(hugoOps2.execute_async(&ndb2, NdbTransaction::NoCommit) == 0);
1323   C2(hugoOps.execute_Commit(pNdb) == 0);
1324   C2(hugoOps2.wait_async(&ndb2) != 0);
1325   C2(hugoOps.closeTransaction(pNdb) == 0);
1326   C2(hugoOps2.closeTransaction(&ndb2) == 0);
1327 
1328   return result;
1329 }
1330 
runBug_WritePartialIgnoreError(NDBT_Context * ctx,NDBT_Step * step)1331 int runBug_WritePartialIgnoreError(NDBT_Context* ctx, NDBT_Step* step){
1332   int result = NDBT_OK;
1333   const NdbDictionary::Table* pTab = ctx->getTab();
1334 
1335   HugoOperations hugoOps(*pTab);
1336 
1337   Ndb* pNdb = GETNDB(step);
1338   C2(hugoOps.startTransaction(pNdb) == 0);
1339   C2(hugoOps.pkWritePartialRecord(pNdb, 0, 1) == 0);
1340   C2(hugoOps.execute_Commit(pNdb, AO_IgnoreError) == 839);
1341   C2(hugoOps.closeTransaction(pNdb) == 0);
1342 
1343   return result;
1344 }
1345 
runScan_4006(NDBT_Context * ctx,NDBT_Step * step)1346 int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){
1347   int result = NDBT_OK;
1348   const Uint32 max= 5;
1349   const NdbDictionary::Table* pTab = ctx->getTab();
1350 
1351   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1352   if (pNdb == NULL){
1353     ndbout << "pNdb == NULL" << endl;
1354     return NDBT_FAILED;
1355   }
1356   if (pNdb->init(max)){
1357     NDB_ERR(pNdb->getNdbError());
1358     delete pNdb;
1359     return NDBT_FAILED;
1360   }
1361 
1362   NdbConnection* pCon = pNdb->startTransaction();
1363   if (pCon == NULL){
1364     pNdb->closeTransaction(pCon);
1365     delete pNdb;
1366     return NDBT_FAILED;
1367   }
1368 
1369   Uint32 i;
1370   Vector<NdbScanOperation*> scans;
1371   for(i = 0; i<10*max; i++)
1372   {
1373     NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1374     if (pOp == NULL){
1375       NDB_ERR(pCon->getNdbError());
1376       pNdb->closeTransaction(pCon);
1377       delete pNdb;
1378       return NDBT_FAILED;
1379     }
1380 
1381     if (pOp->readTuples() != 0){
1382       pNdb->closeTransaction(pCon);
1383       NDB_ERR(pOp->getNdbError());
1384       delete pNdb;
1385       return NDBT_FAILED;
1386     }
1387     scans.push_back(pOp);
1388   }
1389 
1390   // Dont' call any equal or setValues
1391 
1392   // Execute should not work
1393   int check = pCon->execute(NoCommit);
1394   if (check == 0){
1395     ndbout << "execute worked" << endl;
1396   } else {
1397     NDB_ERR(pCon->getNdbError());
1398   }
1399 
1400   for(i= 0; i<scans.size(); i++)
1401   {
1402     NdbScanOperation* pOp= scans[i];
1403     while((check= pOp->nextResult()) == 0);
1404     if(check != 1)
1405     {
1406       NDB_ERR(pOp->getNdbError());
1407       pNdb->closeTransaction(pCon);
1408       delete pNdb;
1409       return NDBT_FAILED;
1410     }
1411   }
1412 
1413   pNdb->closeTransaction(pCon);
1414 
1415   Vector<NdbConnection*> cons;
1416   for(i= 0; i<10*max; i++)
1417   {
1418     pCon= pNdb->startTransaction();
1419     if(pCon)
1420       cons.push_back(pCon);
1421     else
1422       break;
1423   }
1424 
1425   for(i= 0; i<cons.size(); i++)
1426   {
1427     cons[i]->close();
1428   }
1429 
1430   if(cons.size() != max)
1431   {
1432     result= NDBT_FAILED;
1433   }
1434 
1435   delete pNdb;
1436 
1437   return result;
1438 }
1439 
1440 char pkIdxName[255];
1441 
createPkIndex(NDBT_Context * ctx,NDBT_Step * step)1442 int createPkIndex(NDBT_Context* ctx, NDBT_Step* step){
1443   bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
1444 
1445   const NdbDictionary::Table* pTab = ctx->getTab();
1446   Ndb* pNdb = GETNDB(step);
1447 
1448   bool logged = ctx->getProperty("LoggedIndexes", 1);
1449 
1450   // Create index
1451   BaseString::snprintf(pkIdxName, 255, "IDC_PK_%s", pTab->getName());
1452   if (orderedIndex)
1453     ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index "
1454 	   << pkIdxName << " (";
1455   else
1456     ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "unique index "
1457 	   << pkIdxName << " (";
1458 
1459   NdbDictionary::Index pIdx(pkIdxName);
1460   pIdx.setTable(pTab->getName());
1461   if (orderedIndex)
1462     pIdx.setType(NdbDictionary::Index::OrderedIndex);
1463   else
1464     pIdx.setType(NdbDictionary::Index::UniqueHashIndex);
1465   for (int c = 0; c< pTab->getNoOfColumns(); c++){
1466     const NdbDictionary::Column * col = pTab->getColumn(c);
1467     if(col->getPrimaryKey()){
1468       pIdx.addIndexColumn(col->getName());
1469       ndbout << col->getName() <<" ";
1470     }
1471   }
1472 
1473   pIdx.setStoredIndex(logged);
1474   ndbout << ") ";
1475   if (pNdb->getDictionary()->createIndex(pIdx) != 0){
1476     ndbout << "FAILED!" << endl;
1477     const NdbError err = pNdb->getDictionary()->getNdbError();
1478     NDB_ERR(err);
1479     return NDBT_FAILED;
1480   }
1481 
1482   ndbout << "OK!" << endl;
1483   return NDBT_OK;
1484 }
1485 
createPkIndex_Drop(NDBT_Context * ctx,NDBT_Step * step)1486 int createPkIndex_Drop(NDBT_Context* ctx, NDBT_Step* step){
1487   const NdbDictionary::Table* pTab = ctx->getTab();
1488   Ndb* pNdb = GETNDB(step);
1489 
1490   // Drop index
1491   ndbout << "Dropping index " << pkIdxName << " ";
1492   if (pNdb->getDictionary()->dropIndex(pkIdxName,
1493 				       pTab->getName()) != 0){
1494     ndbout << "FAILED!" << endl;
1495     NDB_ERR(pNdb->getDictionary()->getNdbError());
1496     return NDBT_FAILED;
1497   } else {
1498     ndbout << "OK!" << endl;
1499   }
1500 
1501   return NDBT_OK;
1502 }
1503 
1504 static
1505 int
op_row(NdbTransaction * pTrans,HugoOperations & hugoOps,const NdbDictionary::Table * pTab,int op,int row)1506 op_row(NdbTransaction* pTrans, HugoOperations& hugoOps,
1507        const NdbDictionary::Table* pTab, int op, int row)
1508 {
1509   NdbOperation * pOp = 0;
1510   switch(op){
1511   case 0:
1512   case 1:
1513   case 2:
1514   case 3:
1515   case 4:
1516   case 5:
1517   case 12:
1518     pOp = pTrans->getNdbOperation(pTab->getName());
1519     break;
1520   case 9:
1521     return 0;
1522   case 6:
1523   case 7:
1524   case 8:
1525   case 10:
1526   case 11:
1527     pOp = pTrans->getNdbIndexOperation(pkIdxName, pTab->getName());
1528   default:
1529     break;
1530   }
1531 
1532   switch(op){
1533   case 0:
1534   case 6:
1535     pOp->readTuple();
1536     break;
1537   case 1:
1538   case 7:
1539     pOp->committedRead();
1540     break;
1541   case 2:
1542   case 8:
1543     pOp->readTupleExclusive();
1544     break;
1545   case 3:
1546   case 9:
1547     pOp->insertTuple();
1548     break;
1549   case 4:
1550   case 10:
1551     pOp->updateTuple();
1552     break;
1553   case 5:
1554   case 11:
1555     pOp->deleteTuple();
1556     break;
1557   case 12:
1558     CHECK(!pOp->simpleRead());
1559     break;
1560   default:
1561     abort();
1562   }
1563 
1564   for(int a = 0; a<pTab->getNoOfColumns(); a++){
1565     if (pTab->getColumn(a)->getPrimaryKey() == true){
1566       if(hugoOps.equalForAttr(pOp, a, row) != 0){
1567 	return NDBT_FAILED;
1568       }
1569     }
1570   }
1571 
1572   switch(op){
1573   case 0:
1574   case 1:
1575   case 2:
1576   case 6:
1577   case 7:
1578   case 8:
1579   case 12:
1580     for(int a = 0; a<pTab->getNoOfColumns(); a++){
1581       CHECK(pOp->getValue(a));
1582     }
1583     break;
1584   case 3:
1585   case 4:
1586   case 10:
1587     for(int a = 0; a<pTab->getNoOfColumns(); a++){
1588       if (pTab->getColumn(a)->getPrimaryKey() == false){
1589 	if(hugoOps.setValueForAttr(pOp, a, row, 2) != 0){
1590 	  return NDBT_FAILED;
1591 	}
1592       }
1593     }
1594     break;
1595   case 5:
1596   case 11:
1597     pOp->deleteTuple();
1598     break;
1599   case 9:
1600   default:
1601     abort();
1602   }
1603 
1604   return NDBT_OK;
1605 }
1606 
print(int op)1607 static void print(int op)
1608 {
1609   const char * str = 0;
1610   switch(op){
1611   case 0:  str = "pk read-sh"; break;
1612   case 1:  str = "pk read-nl"; break;
1613   case 2:  str = "pk read-ex"; break;
1614   case 3:  str = "pk insert "; break;
1615   case 4:  str = "pk update "; break;
1616   case 5:  str = "pk delete "; break;
1617   case 6:  str = "uk read-sh"; break;
1618   case 7:  str = "uk read-nl"; break;
1619   case 8:  str = "uk read-ex"; break;
1620   case 9:  str = "noop      "; break;
1621   case 10: str = "uk update "; break;
1622   case 11: str = "uk delete "; break;
1623   case 12: str = "pk read-si"; break;
1624 
1625   default:
1626     abort();
1627   }
1628   printf("%s ", str);
1629 }
1630 
1631 int
runTestIgnoreError(NDBT_Context * ctx,NDBT_Step * step)1632 runTestIgnoreError(NDBT_Context* ctx, NDBT_Step* step)
1633 {
1634   Uint32 loops = ctx->getNumRecords();
1635   const NdbDictionary::Table* pTab = ctx->getTab();
1636 
1637   HugoOperations hugoOps(*pTab);
1638   HugoTransactions hugoTrans(*pTab);
1639 
1640   Ndb* pNdb = GETNDB(step);
1641 
1642   struct {
1643     ExecType et;
1644     AbortOption ao;
1645   } tests[] = {
1646     { Commit, AbortOnError },
1647     { Commit, AO_IgnoreError },
1648     { NoCommit, AbortOnError },
1649     { NoCommit, AO_IgnoreError },
1650   };
1651 
1652   printf("case: <op1>     <op2>       c/nc ao/ie\n");
1653   Uint32 tno = 0;
1654   for (Uint32 op1 = 0; op1 < 13; op1++)
1655   {
1656     // NOTE : I get a node crash if the following loop starts from 0!
1657     for (Uint32 op2 = op1; op2 < 13; op2++)
1658     {
1659       int ret;
1660       NdbTransaction* pTrans = 0;
1661 
1662       for (Uint32 i = 0; i<4; i++, tno++)
1663       {
1664 	if (loops != 1000 && loops != tno)
1665 	  continue;
1666 	ExecType et = tests[i].et;
1667 	AbortOption ao = tests[i].ao;
1668 
1669 	printf("%.3d : ", tno);
1670 	print(op1);
1671 	print(op2);
1672 	switch(et){
1673 	case Commit: printf("c    "); break;
1674 	case NoCommit: printf("nc   "); break;
1675         default: printf("bad exectype : %d\n", et); return NDBT_FAILED;
1676 	}
1677 	switch(ao){
1678 	case AbortOnError: printf("aoe  "); break;
1679 	case AO_IgnoreError: printf("ie   "); break;
1680         default: printf("bad abortoption : %d\n", ao); return NDBT_FAILED;
1681 	}
1682 	printf(": ");
1683 
1684 
1685 	hugoTrans.loadTable(pNdb, 1);
1686 	CHECK(pTrans = pNdb->startTransaction());
1687 	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
1688 	ret = pTrans->execute(et, ao);
1689 	pTrans->close();
1690 	printf("%d ", ret);
1691 	hugoTrans.clearTable(pNdb);
1692 
1693 	hugoTrans.loadTable(pNdb, 1);
1694 	CHECK(pTrans = pNdb->startTransaction());
1695 	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 1));
1696 	ret = pTrans->execute(et, ao);
1697 	pTrans->close();
1698 	printf("%d ", ret);
1699 	hugoTrans.clearTable(pNdb);
1700 
1701 	hugoTrans.loadTable(pNdb, 1);
1702 	CHECK(pTrans = pNdb->startTransaction());
1703 	CHECK(!op_row(pTrans, hugoOps, pTab, op1, 0));
1704 	CHECK(!op_row(pTrans, hugoOps, pTab, op2, 1));
1705 	ret = pTrans->execute(et, ao);
1706 	pTrans->close();
1707 	printf("%d\n", ret);
1708 	hugoTrans.clearTable(pNdb);
1709 
1710 	hugoTrans.clearTable(pNdb);
1711       }
1712     }
1713   }
1714   return NDBT_OK;
1715 }
1716 
1717 static
1718 Uint32
do_cnt(Ndb_cluster_connection * con)1719 do_cnt(Ndb_cluster_connection* con)
1720 {
1721   Uint32 cnt = 0;
1722   const Ndb* p = 0;
1723   con->lock_ndb_objects();
1724   while ((p = con->get_next_ndb_object(p)) != 0) cnt++;
1725   con->unlock_ndb_objects();
1726   return cnt;
1727 }
1728 
runCheckNdbObjectList(NDBT_Context * ctx,NDBT_Step * step)1729 int runCheckNdbObjectList(NDBT_Context* ctx, NDBT_Step* step)
1730 {
1731   Ndb_cluster_connection* con = &ctx->m_cluster_connection;
1732 
1733   Uint32 cnt1 = do_cnt(con);
1734   Vector<Ndb*> objs;
1735   for (Uint32 i = 0; i<100; i++)
1736   {
1737     Uint32 add = 1 + (rand() % 5);
1738     for (Uint32 j = 0; j<add; j++)
1739     {
1740       Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1741       if (pNdb == NULL){
1742 	ndbout << "pNdb == NULL" << endl;
1743 	return NDBT_FAILED;
1744       }
1745       objs.push_back(pNdb);
1746     }
1747     if (do_cnt(con) != (cnt1 + objs.size()))
1748       return NDBT_FAILED;
1749   }
1750 
1751   for (Uint32 i = 0; i<100 && objs.size(); i++)
1752   {
1753     Uint32 sub = 1 + rand() % objs.size();
1754     for (Uint32 j = 0; j<sub && objs.size(); j++)
1755     {
1756       Uint32 idx = rand() % objs.size();
1757       delete objs[idx];
1758       objs.erase(idx);
1759     }
1760     if (do_cnt(con) != (cnt1 + objs.size()))
1761       return NDBT_FAILED;
1762   }
1763 
1764   for (Uint32 i = 0; i<objs.size(); i++)
1765     delete objs[i];
1766 
1767   return (cnt1 == do_cnt(con)) ? NDBT_OK : NDBT_FAILED;
1768 }
1769 
1770 
1771 static Ndb_cluster_connection* g_cluster_connection;
1772 
runNdbClusterConnectionDelete_connection_owner(NDBT_Context * ctx,NDBT_Step * step)1773 int runNdbClusterConnectionDelete_connection_owner(NDBT_Context* ctx,
1774                                                    NDBT_Step* step)
1775 {
1776   // Get connectstring from main connection
1777   char constr[256];
1778   if (!ctx->m_cluster_connection.get_connectstring(constr,
1779                                                    sizeof(constr)))
1780   {
1781     g_err << "Too short buffer for connectstring" << endl;
1782     return NDBT_FAILED;
1783   }
1784 
1785   // Create a new cluster connection, connect it and assign
1786   // to pointer so the other thread can access it.
1787   Ndb_cluster_connection* con = new Ndb_cluster_connection(constr);
1788 
1789   const int retries = 12;
1790   const int retry_delay = 5;
1791   const int verbose = 1;
1792   if (con->connect(retries, retry_delay, verbose) != 0)
1793   {
1794     delete con;
1795     g_err << "Ndb_cluster_connection.connect failed" << endl;
1796     return NDBT_FAILED;
1797   }
1798 
1799   g_cluster_connection = con;
1800 
1801   // Signal other thread that cluster connection has been creted
1802   ctx->setProperty("CREATED", 1);
1803 
1804   // Now wait for the other thread to use the connection
1805   // until it signals this thread to continue and
1806   // delete the cluster connection(since the
1807   // other thread still have live Ndb objects created
1808   // in the connection, this thread should hang in
1809   // the delete until other thread has finished cleaning up)
1810   ctx->getPropertyWait("CREATED", 2);
1811 
1812   g_cluster_connection = NULL;
1813   delete con;
1814 
1815   return NDBT_OK;
1816 }
1817 
runNdbClusterConnectionDelete_connection_user(NDBT_Context * ctx,NDBT_Step * step)1818 int runNdbClusterConnectionDelete_connection_user(NDBT_Context* ctx, NDBT_Step* step)
1819 {
1820   // Wait for the cluster connection to be created by other thread
1821   ctx->getPropertyWait("CREATED", 1);
1822 
1823   Ndb_cluster_connection* con = g_cluster_connection;
1824 
1825   // Create some Ndb objects and start transactions
1826   class ActiveTransactions
1827   {
1828     Vector<NdbTransaction*> m_transactions;
1829 
1830   public:
1831     void release()
1832     {
1833       while(m_transactions.size())
1834       {
1835         NdbTransaction* trans = m_transactions[0];
1836         Ndb* ndb = trans->getNdb();
1837         g_info << "Deleting Ndb object " << ndb <<
1838                   "and transaction " << trans << endl;
1839         ndb->closeTransaction(trans);
1840         delete ndb;
1841         m_transactions.erase(0);
1842       }
1843       // The list should be empty
1844       assert(m_transactions.size() == 0);
1845     }
1846 
1847     ~ActiveTransactions()
1848     {
1849       release();
1850     }
1851 
1852     void push_back(NdbTransaction* trans)
1853     {
1854       m_transactions.push_back(trans);
1855     }
1856   } active_transactions;
1857 
1858   g_info << "Creating Ndb objects and transactions.." << endl;
1859   for (Uint32 i = 0; i<100; i++)
1860   {
1861     Ndb* ndb = new Ndb(con, "TEST_DB");
1862     if (ndb == NULL){
1863       g_err << "ndb == NULL" << endl;
1864       return NDBT_FAILED;
1865     }
1866     if (ndb->init(256) != 0){
1867       NDB_ERR(ndb->getNdbError());
1868       delete ndb;
1869       return NDBT_FAILED;
1870     }
1871 
1872     if (ndb->waitUntilReady() != 0){
1873       NDB_ERR(ndb->getNdbError());
1874       delete ndb;
1875       return NDBT_FAILED;
1876     }
1877 
1878     NdbTransaction* trans = ndb->startTransaction();
1879     if (trans == NULL){
1880       g_err << "trans == NULL" << endl;
1881       NDB_ERR(ndb->getNdbError());
1882       delete ndb;
1883       return NDBT_FAILED;
1884     }
1885 
1886     active_transactions.push_back(trans);
1887   }
1888   g_info << "  ok!" << endl;
1889 
1890   // Signal to cluster connection owner that Ndb objects have been created
1891   ctx->setProperty("CREATED", 2);
1892 
1893   // Delay a little and then start closing transactions and
1894   // deleting the Ndb objects
1895   NdbSleep_SecSleep(1);
1896 
1897   g_info << "Releasing transactions and related Ndb objects..." << endl;
1898   active_transactions.release();
1899   g_info << "  ok!" << endl;
1900   return NDBT_OK;
1901 }
1902 
1903 
1904 
1905 static void
testExecuteAsynchCallback(int res,NdbTransaction * con,void * data_ptr)1906 testExecuteAsynchCallback(int res, NdbTransaction *con, void *data_ptr)
1907 {
1908   int *res_ptr= (int *)data_ptr;
1909 
1910   *res_ptr= res;
1911 }
1912 
runTestExecuteAsynch(NDBT_Context * ctx,NDBT_Step * step)1913 int runTestExecuteAsynch(NDBT_Context* ctx, NDBT_Step* step){
1914   /* Test that NdbTransaction::executeAsynch() works (BUG#27495). */
1915   int result = NDBT_OK;
1916   const NdbDictionary::Table* pTab = ctx->getTab();
1917 
1918   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
1919   if (pNdb == NULL){
1920     ndbout << "pNdb == NULL" << endl;
1921     return NDBT_FAILED;
1922   }
1923   if (pNdb->init(2048)){
1924     NDB_ERR(pNdb->getNdbError());
1925     delete pNdb;
1926     return NDBT_FAILED;
1927   }
1928 
1929   NdbConnection* pCon = pNdb->startTransaction();
1930   if (pCon == NULL){
1931     NDB_ERR(pNdb->getNdbError());
1932     delete pNdb;
1933     return NDBT_FAILED;
1934   }
1935 
1936   NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName());
1937   if (pOp == NULL){
1938     NDB_ERR(pOp->getNdbError());
1939     pNdb->closeTransaction(pCon);
1940     delete pNdb;
1941     return NDBT_FAILED;
1942   }
1943 
1944   if (pOp->readTuples() != 0){
1945     NDB_ERR(pOp->getNdbError());
1946     pNdb->closeTransaction(pCon);
1947     delete pNdb;
1948     return NDBT_FAILED;
1949   }
1950 
1951   if (pOp->getValue(NdbDictionary::Column::FRAGMENT) == 0){
1952     NDB_ERR(pOp->getNdbError());
1953     pNdb->closeTransaction(pCon);
1954     delete pNdb;
1955     return NDBT_FAILED;
1956   }
1957   int res= 42;
1958   pCon->executeAsynch(NoCommit, testExecuteAsynchCallback, &res);
1959   while(pNdb->pollNdb(100000) == 0)
1960     ;
1961   if (res != 0){
1962     NDB_ERR(pCon->getNdbError());
1963     ndbout << "Error returned from execute: " << res << endl;
1964     result= NDBT_FAILED;
1965   }
1966 
1967   pNdb->closeTransaction(pCon);
1968 
1969   delete pNdb;
1970 
1971   return result;
1972 }
1973 
1974 template class Vector<NdbScanOperation*>;
1975 
1976 int
runBug28443(NDBT_Context * ctx,NDBT_Step * step)1977 runBug28443(NDBT_Context* ctx, NDBT_Step* step)
1978 {
1979   int result = NDBT_OK;
1980   int records = ctx->getNumRecords();
1981 
1982   NdbRestarter restarter;
1983 
1984   restarter.insertErrorInAllNodes(9003);
1985 
1986   for (int i = 0; i<ctx->getNumLoops(); i++)
1987   {
1988     HugoTransactions hugoTrans(*ctx->getTab());
1989     if (hugoTrans.loadTable(GETNDB(step), records, 2048) != 0)
1990     {
1991       result = NDBT_FAILED;
1992       goto done;
1993     }
1994     if (runClearTable(ctx, step) != 0)
1995     {
1996       result = NDBT_FAILED;
1997       goto done;
1998     }
1999   }
2000 
2001 done:
2002   restarter.insertErrorInAllNodes(9003);
2003 
2004   return result;
2005 }
2006 
2007 int
runBug37158(NDBT_Context * ctx,NDBT_Step * step)2008 runBug37158(NDBT_Context* ctx, NDBT_Step* step)
2009 {
2010   int result = NDBT_OK;
2011   Ndb* pNdb = GETNDB(step);
2012 
2013   for (int i = 0; i<ctx->getNumLoops(); i++)
2014   {
2015     HugoOperations hugoOps(*ctx->getTab());
2016     hugoOps.startTransaction(pNdb);
2017     if (hugoOps.pkWriteRecord(pNdb, 0) != 0)
2018     {
2019       result = NDBT_FAILED;
2020       goto done;
2021     }
2022 
2023 
2024     if (hugoOps.pkWritePartialRecord(pNdb, 1) != 0)
2025     {
2026       result = NDBT_FAILED;
2027       goto done;
2028     }
2029 
2030     if (hugoOps.pkWriteRecord(pNdb, 2) != 0)
2031     {
2032       result = NDBT_FAILED;
2033       goto done;
2034     }
2035 
2036     if (hugoOps.pkUpdateRecord(pNdb, 0) != 0)
2037     {
2038       result = NDBT_FAILED;
2039       goto done;
2040     }
2041 
2042     if (hugoOps.execute_Commit(pNdb, AO_IgnoreError) == 4011)
2043     {
2044       result = NDBT_FAILED;
2045       goto done;
2046     }
2047     hugoOps.closeTransaction(pNdb);
2048 
2049     if (runClearTable(ctx, step) != 0)
2050     {
2051       result = NDBT_FAILED;
2052       goto done;
2053     }
2054   }
2055 
2056 done:
2057 
2058   return result;
2059 }
2060 
2061 int
simpleReadAbortOnError(NDBT_Context * ctx,NDBT_Step * step)2062 simpleReadAbortOnError(NDBT_Context* ctx, NDBT_Step* step)
2063 {
2064   /* Simple read has some error handling issues
2065    * Setting the operation to be AbortOnError can expose these
2066    */
2067   Ndb* pNdb = GETNDB(step);
2068   const NdbDictionary::Table* pTab= ctx->getTab();
2069   HugoOperations hugoOps(*pTab);
2070   NdbRestarter restarter;
2071 
2072   hugoOps.startTransaction(pNdb);
2073   CHECK(!hugoOps.pkWriteRecord(pNdb,0));
2074   CHECK(!hugoOps.execute_Commit(pNdb, AbortOnError));
2075 
2076   NdbTransaction* trans;
2077 
2078   CHECK(trans= pNdb->startTransaction());
2079 
2080   /* Insert error 5047 which causes next LQHKEYREQ to fail due
2081    * to 'transporter overload'
2082    * Error insert is self-clearing
2083    */
2084   restarter.insertErrorInAllNodes(5047);
2085 
2086   /* Create SimpleRead on row 0, which exists (though we'll get
2087    * 'transporter overload for this'
2088    */
2089   NdbOperation* op;
2090   CHECK(op= trans->getNdbOperation(pTab));
2091 
2092   CHECK(!op->simpleRead());
2093 
2094   for(int a = 0; a<pTab->getNoOfColumns(); a++){
2095     if (pTab->getColumn(a)->getPrimaryKey() == true){
2096       if(hugoOps.equalForAttr(op, a, 0) != 0){
2097         restarter.insertErrorInAllNodes(0);
2098 	return NDBT_FAILED;
2099       }
2100     }
2101   }
2102   for(int a = 0; a<pTab->getNoOfColumns(); a++){
2103     CHECK(op->getValue(a));
2104   }
2105 
2106   CHECK(!op->setAbortOption(NdbOperation::AbortOnError));
2107 
2108   /* Create normal read on row 0 which will succeed */
2109   NdbOperation* op2;
2110   CHECK(op2= trans->getNdbOperation(pTab));
2111 
2112   CHECK(!op2->readTuple());
2113 
2114   for(int a = 0; a<pTab->getNoOfColumns(); a++){
2115     if (pTab->getColumn(a)->getPrimaryKey() == true){
2116       if(hugoOps.equalForAttr(op2, a, 0) != 0){
2117         restarter.insertErrorInAllNodes(0);
2118 	return NDBT_FAILED;
2119       }
2120     }
2121   }
2122   for(int a = 0; a<pTab->getNoOfColumns(); a++){
2123     CHECK(op2->getValue(a));
2124   }
2125 
2126   CHECK(!op2->setAbortOption(NdbOperation::AbortOnError));
2127 
2128 
2129   CHECK(trans->execute(NoCommit) == -1);
2130 
2131   CHECK(trans->getNdbError().code == 1218); // Transporter Overload
2132 
2133   restarter.insertErrorInAllNodes(0);
2134 
2135   return NDBT_OK;
2136 
2137 }
2138 
2139 
2140 int
testNdbRecordPkAmbiguity(NDBT_Context * ctx,NDBT_Step * step)2141 testNdbRecordPkAmbiguity(NDBT_Context* ctx, NDBT_Step* step)
2142 {
2143   /* NdbRecord Insert and Write can take 2 record and row ptrs
2144    * In all cases, the AttrInfo sent to TC for PK columns
2145    * should be the same as the KeyInfo sent to TC to avoid
2146    * inconsistency
2147    * Approach :
2148    *   1) Use Insert/Write to insert tuple with different
2149    *      values for pks in attr row
2150    *   2) Read back all data, including PKs
2151    *   3) Verify all values.
2152    */
2153   Ndb* pNdb = GETNDB(step);
2154   const NdbDictionary::Table* pTab= ctx->getTab();
2155   const NdbRecord* tabRec= pTab->getDefaultRecord();
2156   const Uint32 sizeOfTabRec= NdbDictionary::getRecordRowLength(tabRec);
2157   char keyRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2158   char attrRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2159   bzero(keyRowBuf, sizeof(keyRowBuf));
2160   bzero(attrRowBuf, sizeof(attrRowBuf));
2161 
2162   HugoCalculator calc(*pTab);
2163 
2164   const int numRecords= 100;
2165 
2166   for (int optype=0; optype < 2; optype++)
2167   {
2168     /* First, let's calculate the correct Hugo values for this row */
2169 
2170     for (int record=0; record < numRecords; record++)
2171     {
2172       int updates= 0;
2173       for (int col=0; col<pTab->getNoOfColumns(); col++)
2174       {
2175         char* valPtr= NdbDictionary::getValuePtr(tabRec,
2176                                                  keyRowBuf,
2177                                                  col);
2178         CHECK(valPtr != NULL);
2179 
2180         int len= pTab->getColumn(col)->getSizeInBytes();
2181         Uint32 real_len;
2182         bool isNull= (calc.calcValue(record, col, updates, valPtr,
2183                                      len, &real_len) == NULL);
2184         if (pTab->getColumn(col)->getNullable())
2185         {
2186           NdbDictionary::setNull(tabRec,
2187                                  keyRowBuf,
2188                                  col,
2189                                  isNull);
2190         }
2191       }
2192 
2193       /* Now copy the values to the Attr record */
2194       memcpy(attrRowBuf, keyRowBuf, sizeOfTabRec);
2195 
2196       Uint32 mippleAttempts= 3;
2197 
2198       while (memcmp(keyRowBuf, attrRowBuf, sizeOfTabRec) == 0)
2199       {
2200         /* Now doctor the PK values in the Attr record */
2201         for (int col=0; col<pTab->getNoOfColumns(); col++)
2202         {
2203           if (pTab->getColumn(col)->getPrimaryKey())
2204           {
2205             char* valPtr= NdbDictionary::getValuePtr(tabRec,
2206                                                      attrRowBuf,
2207                                                      col);
2208             CHECK(valPtr != NULL);
2209 
2210             int len= pTab->getColumn(col)->getSizeInBytes();
2211             Uint32 real_len;
2212             /* We use the PK value for some other record */
2213             int badRecord= record + (rand() % 1000);
2214             bool isNull= (calc.calcValue(badRecord, col, updates, valPtr,
2215                                          len, &real_len) == NULL);
2216             CHECK(! isNull);
2217           }
2218         }
2219 
2220         /* Can try to get variance only a limited number of times */
2221         CHECK(mippleAttempts-- != 0);
2222       }
2223 
2224       /* Ok, now have key and attr records with different values for
2225        * PK cols, let's try to insert
2226        */
2227       NdbTransaction* trans=pNdb->startTransaction();
2228       CHECK(trans != 0);
2229 
2230       const NdbOperation* op= NULL;
2231       if (optype == 0)
2232       {
2233         // ndbout << "Using insertTuple" << endl;
2234         op= trans->insertTuple(tabRec,
2235                                keyRowBuf,
2236                                tabRec,
2237                                attrRowBuf);
2238       }
2239       else
2240       {
2241         // ndbout << "Using writeTuple" << endl;
2242         op= trans->writeTuple(tabRec,
2243                               keyRowBuf,
2244                               tabRec,
2245                               attrRowBuf);
2246       }
2247       CHECK(op != 0);
2248 
2249       CHECK(trans->execute(Commit) == 0);
2250       trans->close();
2251 
2252       /* Now read back */
2253       memset(attrRowBuf, 0, sizeOfTabRec);
2254 
2255       Uint32 pkVal= 0;
2256       memcpy(&pkVal, NdbDictionary::getValuePtr(tabRec,
2257                                                 keyRowBuf,
2258                                                 0),
2259              sizeof(pkVal));
2260 
2261       trans= pNdb->startTransaction();
2262       op= trans->readTuple(tabRec,
2263                            keyRowBuf,
2264                            tabRec,
2265                            attrRowBuf);
2266       CHECK(op != 0);
2267       CHECK(trans->execute(Commit) == 0);
2268       CHECK(trans->getNdbError().code == 0);
2269       trans->close();
2270 
2271       /* Verify the values read back */
2272       for (int col=0; col<pTab->getNoOfColumns(); col++)
2273       {
2274         const char* valPtr= NdbDictionary::getValuePtr(tabRec,
2275                                                        attrRowBuf,
2276                                                        col);
2277         CHECK(valPtr != NULL);
2278 
2279         char calcBuff[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2280         int len= pTab->getColumn(col)->getSizeInBytes();
2281         Uint32 real_len;
2282         bool isNull= (calc.calcValue(record, col, updates, calcBuff,
2283                                      len, &real_len) == NULL);
2284         bool colIsNullable= pTab->getColumn(col)->getNullable();
2285         if (isNull)
2286         {
2287           CHECK(colIsNullable);
2288           if (!NdbDictionary::isNull(tabRec,
2289                                      attrRowBuf,
2290                                      col))
2291           {
2292             ndbout << "Error, col " << col
2293                    << " (pk=" <<  pTab->getColumn(col)->getPrimaryKey()
2294                    << ") should be Null, but is not" << endl;
2295             return NDBT_FAILED;
2296           }
2297         }
2298         else
2299         {
2300           if (colIsNullable)
2301           {
2302             if (NdbDictionary::isNull(tabRec,
2303                                       attrRowBuf,
2304                                       col))
2305             {
2306               ndbout << "Error, col " << col
2307                      << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
2308                      << ") should be non-Null but is null" << endl;
2309               return NDBT_FAILED;
2310             };
2311           }
2312 
2313           /* Compare actual data read back */
2314           if( memcmp(calcBuff, valPtr, real_len) != 0 )
2315           {
2316             ndbout << "Error, col " << col
2317                    << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
2318                    << ") should be equal, but isn't for record "
2319                    << record << endl;
2320             ndbout << "Expected :";
2321             for (Uint32 i=0; i < real_len; i++)
2322             {
2323               ndbout_c("%x ", calcBuff[i]);
2324             }
2325             ndbout << endl << "Received :";
2326             for (Uint32 i=0; i < real_len; i++)
2327             {
2328               ndbout_c("%x ", valPtr[i]);
2329             }
2330             ndbout << endl;
2331 
2332             return NDBT_FAILED;
2333           }
2334         }
2335       }
2336 
2337       /* Now delete the tuple */
2338       trans= pNdb->startTransaction();
2339       op= trans->deleteTuple(tabRec,
2340                              keyRowBuf,
2341                              tabRec);
2342       CHECK(op != 0);
2343       CHECK(trans->execute(Commit) == 0);
2344 
2345       trans->close();
2346     }
2347   }
2348 
2349   return NDBT_OK;
2350 
2351 }
2352 
2353 int
testNdbRecordPKUpdate(NDBT_Context * ctx,NDBT_Step * step)2354 testNdbRecordPKUpdate(NDBT_Context* ctx, NDBT_Step* step)
2355 {
2356   /* In general, we should be able to update primary key
2357    * values.  We cannot *change* them, but for cases where
2358    * a collation maps several discrete values to a single
2359    * normalised value, it should be possible to modify
2360    * the discrete value of the key, as the normalised
2361    * key value is unchanged.
2362    * Rather than testing with such a collation here, we
2363    * cop out and test for errors with a 'null' change.
2364    */
2365   Ndb* pNdb = GETNDB(step);
2366   const NdbDictionary::Table* pTab= ctx->getTab();
2367   const NdbRecord* tabRec= pTab->getDefaultRecord();
2368   char rowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2369   char badKeyRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
2370 
2371   HugoCalculator calc(*pTab);
2372 
2373   const int numRecords= 100;
2374 
2375   /* First, let's calculate the correct Hugo values for this row */
2376   for (int record=0; record < numRecords; record++)
2377   {
2378     int updates= 0;
2379     for (int col=0; col<pTab->getNoOfColumns(); col++)
2380     {
2381       char* valPtr= NdbDictionary::getValuePtr(tabRec,
2382                                                rowBuf,
2383                                                col);
2384       CHECK(valPtr != NULL);
2385 
2386       int len= pTab->getColumn(col)->getSizeInBytes();
2387       Uint32 real_len;
2388       bool isNull= (calc.calcValue(record, col, updates, valPtr,
2389                                    len, &real_len) == NULL);
2390       if (pTab->getColumn(col)->getNullable())
2391       {
2392         NdbDictionary::setNull(tabRec,
2393                                rowBuf,
2394                                col,
2395                                isNull);
2396       }
2397     }
2398 
2399     /* Create similar row, but with different id col (different
2400      * PK from p.o.v. of PK column update
2401      */
2402     memcpy(badKeyRowBuf, rowBuf, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2403     for (int col=0; col<pTab->getNoOfColumns(); col++)
2404     {
2405       if (calc.isIdCol(col))
2406       {
2407         char* valPtr= NdbDictionary::getValuePtr(tabRec,
2408                                                  badKeyRowBuf,
2409                                                  col);
2410         Uint32 badId= record+333;
2411         memcpy(valPtr, &badId, sizeof(badId));
2412       }
2413     }
2414 
2415     NdbTransaction* trans=pNdb->startTransaction();
2416     CHECK(trans != 0);
2417 
2418     const NdbOperation* op= trans->insertTuple(tabRec,
2419                                                rowBuf);
2420     CHECK(op != 0);
2421 
2422     CHECK(trans->execute(Commit) == 0);
2423     trans->close();
2424 
2425     /* Now update the PK columns */
2426     trans= pNdb->startTransaction();
2427     op= trans->updateTuple(tabRec,
2428                            rowBuf,
2429                            tabRec,
2430                            rowBuf);
2431     CHECK(op != 0);
2432     CHECK(trans->execute(Commit) == 0);
2433     CHECK(trans->getNdbError().code == 0);
2434     trans->close();
2435 
2436     /* Now update PK with scan takeover op */
2437     trans= pNdb->startTransaction();
2438 
2439     NdbScanOperation* scanOp=trans->scanTable(tabRec,
2440                                               NdbOperation::LM_Exclusive);
2441     CHECK(scanOp != 0);
2442 
2443     CHECK(trans->execute(NoCommit) == 0);
2444 
2445     /* Now update PK with lock takeover op */
2446     const char* rowPtr;
2447     CHECK(scanOp->nextResult(&rowPtr, true, true) == 0);
2448 
2449     op= scanOp->updateCurrentTuple(trans,
2450                                    tabRec,
2451                                    rowBuf);
2452     CHECK(op != NULL);
2453 
2454     CHECK(trans->execute(Commit) == 0);
2455 
2456     trans->close();
2457 
2458     /* Now attempt bad PK update with lock takeover op
2459      * This is interesting as NDBAPI normally takes the
2460      * value of PK columns in an update from the key
2461      * row - so it's not possible to pass a 'different'
2462      * value (except when collations are used).
2463      * Scan Takeover update takes the PK values from the
2464      * attribute record and so different values can
2465      * be supplied.
2466      * Here we check that different values result in the
2467      * kernel complaining.
2468      */
2469     trans= pNdb->startTransaction();
2470 
2471     scanOp=trans->scanTable(tabRec,
2472                             NdbOperation::LM_Exclusive);
2473     CHECK(scanOp != 0);
2474 
2475     CHECK(trans->execute(NoCommit) == 0);
2476 
2477     /* Now update PK with lock takeover op */
2478     CHECK(scanOp->nextResult(&rowPtr, true, true) == 0);
2479 
2480     op= scanOp->updateCurrentTuple(trans,
2481                                    tabRec,
2482                                    badKeyRowBuf);
2483     CHECK(op != NULL);
2484 
2485     CHECK(trans->execute(Commit) == -1);
2486     CHECK(trans->getNdbError().code == 897);
2487 
2488     trans->close();
2489 
2490     /* Now delete the tuple */
2491     trans= pNdb->startTransaction();
2492     op= trans->deleteTuple(tabRec,
2493                            rowBuf,
2494                            tabRec);
2495     CHECK(op != 0);
2496     CHECK(trans->execute(Commit) == 0);
2497 
2498     trans->close();
2499   }
2500 
2501   return NDBT_OK;
2502 
2503 }
2504 
2505 static
getKeyVal(int record,bool upper)2506 BaseString getKeyVal(int record, bool upper)
2507 {
2508   /* Create VARCHAR format key with upper or
2509    * lower case leading char
2510    */
2511   BaseString keyData;
2512   char c= 'a' + (record % ('z' - 'a'));
2513 
2514   keyData.appfmt("%cblahblah%d", c, record);
2515 
2516   if (upper)
2517     keyData.ndb_toupper();
2518 
2519   BaseString varCharKey;
2520   varCharKey.appfmt("%c%s", keyData.length(), keyData.c_str());
2521 
2522   return varCharKey;
2523 }
2524 
2525 int
testNdbRecordCICharPKUpdate(NDBT_Context * ctx,NDBT_Step * step)2526 testNdbRecordCICharPKUpdate(NDBT_Context* ctx, NDBT_Step* step)
2527 {
2528   /* Test a change to a CHAR primary key with a case insensitive
2529    * collation.
2530    */
2531   Ndb* pNdb = GETNDB(step);
2532   const NdbDictionary::Table* pTab= ctx->getTab();
2533 
2534   /* Run as a 'T1' testcase - do nothing for other tables */
2535   if (strcmp(pTab->getName(), "T1") != 0)
2536     return NDBT_OK;
2537 
2538   CHARSET_INFO* charset= NULL;
2539   const char* csname="latin1_general_ci";
2540   charset= get_charset_by_name(csname, MYF(0));
2541 
2542   if (charset == NULL)
2543   {
2544     ndbout << "Couldn't get charset " << csname << endl;
2545     return NDBT_FAILED;
2546   }
2547 
2548   /* Create table with required schema */
2549   NdbDictionary::Table tab;
2550   tab.setName("TAB_CICHARPKUPD");
2551 
2552   NdbDictionary::Column pk;
2553   pk.setName("PK");
2554   pk.setType(NdbDictionary::Column::Varchar);
2555   pk.setLength(20);
2556   pk.setNullable(false);
2557   pk.setPrimaryKey(true);
2558   pk.setCharset(charset);
2559   tab.addColumn(pk);
2560 
2561   NdbDictionary::Column data;
2562   data.setName("DATA");
2563   data.setType(NdbDictionary::Column::Unsigned);
2564   data.setNullable(false);
2565   data.setPrimaryKey(false);
2566   tab.addColumn(data);
2567 
2568   pNdb->getDictionary()->dropTable(tab.getName());
2569   if(pNdb->getDictionary()->createTable(tab) != 0)
2570   {
2571     ndbout << "Create table failed with error : "
2572            << pNdb->getDictionary()->getNdbError().code
2573            << pNdb->getDictionary()->getNdbError().message
2574            << endl;
2575     return NDBT_FAILED;
2576   }
2577 
2578   ndbout << (NDBT_Table&)tab << endl;
2579 
2580   pTab= pNdb->getDictionary()->getTable(tab.getName());
2581 
2582   const NdbRecord* tabRec= pTab->getDefaultRecord();
2583   const Uint32 rowLen= NDB_MAX_TUPLE_SIZE_IN_WORDS << 2;
2584   char ucRowBuf[ rowLen ];
2585   char lcRowBuf[ rowLen ];
2586   char readBuf[ rowLen ];
2587   char* ucPkPtr= NdbDictionary::getValuePtr(tabRec,
2588                                             ucRowBuf,
2589                                             0);
2590   Uint32* ucDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2591                                                           ucRowBuf,
2592                                                           1);
2593   char* lcPkPtr= NdbDictionary::getValuePtr(tabRec,
2594                                             lcRowBuf,
2595                                             0);
2596   Uint32* lcDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2597                                                           lcRowBuf,
2598                                                           1);
2599 
2600   char* readPkPtr= NdbDictionary::getValuePtr(tabRec,
2601                                               readBuf,
2602                                               0);
2603   Uint32* readDataPtr= (Uint32*) NdbDictionary::getValuePtr(tabRec,
2604                                                             readBuf,
2605                                                             1);
2606 
2607 
2608   const int numRecords= 100;
2609   BaseString upperKey;
2610   BaseString lowerKey;
2611 
2612   for (int record=0; record < numRecords; record++)
2613   {
2614     upperKey.assign(getKeyVal(record, true).c_str());
2615     lowerKey.assign(getKeyVal(record, false).c_str());
2616 
2617     memcpy(ucPkPtr, upperKey.c_str(), upperKey.length());
2618     memcpy(lcPkPtr, lowerKey.c_str(), lowerKey.length());
2619     memcpy(ucDataPtr, &record, sizeof(record));
2620     memcpy(lcDataPtr, &record, sizeof(record));
2621 
2622     /* Insert with upper case */
2623     NdbTransaction* trans=pNdb->startTransaction();
2624     CHECK(trans != 0);
2625 
2626     const NdbOperation* op= trans->insertTuple(tabRec,
2627                                                ucRowBuf);
2628     CHECK(op != 0);
2629 
2630     int rc= trans->execute(Commit);
2631     if (rc != 0)
2632       ndbout << "Error " << trans->getNdbError().message << endl;
2633     CHECK(rc == 0);
2634     trans->close();
2635 
2636     /* Read with upper case */
2637     trans=pNdb->startTransaction();
2638     CHECK(trans != 0);
2639     op= trans->readTuple(tabRec,
2640                          ucRowBuf,
2641                          tabRec,
2642                          readBuf);
2643     CHECK(op != 0);
2644     CHECK(trans->execute(Commit) == 0);
2645     trans->close();
2646 
2647     /* Check key and data read */
2648     CHECK(memcmp(ucPkPtr, readPkPtr, ucPkPtr[0]) == 0);
2649     CHECK(memcmp(ucDataPtr, readDataPtr, sizeof(int)) == 0);
2650 
2651     memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2652 
2653     /* Read with lower case */
2654     trans=pNdb->startTransaction();
2655     CHECK(trans != 0);
2656     op= trans->readTuple(tabRec,
2657                          lcRowBuf,
2658                          tabRec,
2659                          readBuf);
2660     CHECK(op != 0);
2661     CHECK(trans->execute(Commit) == 0);
2662     trans->close();
2663 
2664     /* Check key and data read */
2665     CHECK(memcmp(ucPkPtr, readPkPtr, ucPkPtr[0]) == 0);
2666     CHECK(memcmp(ucDataPtr, readDataPtr, sizeof(int)) == 0);
2667 
2668     memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2669 
2670     /* Now update just the PK column to lower case */
2671     trans= pNdb->startTransaction();
2672     unsigned char mask[1];
2673     mask[0]= 1;
2674     op= trans->updateTuple(tabRec,
2675                            lcRowBuf,
2676                            tabRec,
2677                            lcRowBuf,
2678                            mask);
2679     CHECK(op != 0);
2680     CHECK(trans->execute(Commit) == 0);
2681     CHECK(trans->getNdbError().code == 0);
2682     trans->close();
2683 
2684     /* Now check that we can read with the upper case key */
2685     memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2686 
2687     trans=pNdb->startTransaction();
2688     CHECK(trans != 0);
2689     op= trans->readTuple(tabRec,
2690                          ucRowBuf,
2691                          tabRec,
2692                          readBuf);
2693     CHECK(op != 0);
2694     CHECK(trans->execute(Commit) == 0);
2695     trans->close();
2696 
2697     /* Check key and data read */
2698     CHECK(memcmp(lcPkPtr, readPkPtr, lcPkPtr[0]) == 0);
2699     CHECK(memcmp(lcDataPtr, readDataPtr, sizeof(int)) == 0);
2700 
2701     /* Now check that we can read with the lower case key */
2702     memset(readBuf, 0, NDB_MAX_TUPLE_SIZE_IN_WORDS << 2);
2703 
2704     trans=pNdb->startTransaction();
2705     CHECK(trans != 0);
2706     op= trans->readTuple(tabRec,
2707                          lcRowBuf,
2708                          tabRec,
2709                          readBuf);
2710     CHECK(op != 0);
2711     CHECK(trans->execute(Commit) == 0);
2712     trans->close();
2713 
2714     /* Check key and data read */
2715     CHECK(memcmp(lcPkPtr, readPkPtr, lcPkPtr[0]) == 0);
2716     CHECK(memcmp(lcDataPtr, readDataPtr, sizeof(int)) == 0);
2717 
2718 
2719     /* Now delete the tuple */
2720     trans= pNdb->startTransaction();
2721     op= trans->deleteTuple(tabRec,
2722                            ucRowBuf,
2723                            tabRec);
2724      CHECK(op != 0);
2725      CHECK(trans->execute(Commit) == 0);
2726 
2727      trans->close();
2728   }
2729 
2730   pNdb->getDictionary()->dropTable(tab.getName());
2731 
2732   return NDBT_OK;
2733 
2734 }
2735 
2736 int
testNdbRecordRowLength(NDBT_Context * ctx,NDBT_Step * step)2737 testNdbRecordRowLength(NDBT_Context* ctx, NDBT_Step* step)
2738 {
2739   /* Bug#43891 ignored null bits at the end of an row
2740    * when calculating the row length, leading to various
2741    * problems
2742    */
2743   Ndb* pNdb = GETNDB(step);
2744   const NdbDictionary::Table* pTab= ctx->getTab();
2745   int numCols= pTab->getNoOfColumns();
2746   const NdbRecord* defaultRecord= pTab->getDefaultRecord();
2747 
2748   /* Create an NdbRecord structure with all the Null
2749    * bits at the end - to test that they are included
2750    * correctly in row length calculations.
2751    */
2752   NdbDictionary::RecordSpecification rsArray[ NDB_MAX_ATTRIBUTES_IN_TABLE ];
2753 
2754   bool hasNullable= false;
2755   Uint32 highestUsed= 9000;
2756   for (int attrId=0; attrId< numCols; attrId++)
2757   {
2758     NdbDictionary::RecordSpecification& rs= rsArray[attrId];
2759 
2760     rs.column= pTab->getColumn(attrId);
2761     CHECK(NdbDictionary::getOffset(defaultRecord,
2762                                    attrId,
2763                                    rs.offset));
2764     CHECK(NdbDictionary::getNullBitOffset(defaultRecord,
2765                                           attrId,
2766                                           rs.nullbit_byte_offset,
2767                                           rs.nullbit_bit_in_byte));
2768     if (rs.column->getNullable())
2769     {
2770       /* Shift null bit(s) to bytes beyond the end of the record */
2771       hasNullable= true;
2772       rs.nullbit_byte_offset= highestUsed++;
2773       rs.nullbit_bit_in_byte= 0;
2774     }
2775   }
2776 
2777   if (hasNullable)
2778   {
2779     printf("Testing");
2780     const NdbRecord* myRecord= pNdb->getDictionary()->createRecord(pTab,
2781                                                                    rsArray,
2782                                                                    numCols,
2783                                                                    sizeof(NdbDictionary::RecordSpecification));
2784     CHECK(myRecord != 0);
2785     Uint32 rowLength= NdbDictionary::getRecordRowLength(myRecord);
2786     if (rowLength != highestUsed)
2787     {
2788       ndbout << "Failure, expected row length " << highestUsed
2789              << " got row length " << rowLength
2790              << endl;
2791       return NDBT_FAILED;
2792     }
2793   }
2794 
2795   return NDBT_OK;
2796 }
2797 
2798 int
runBug44015(NDBT_Context * ctx,NDBT_Step * step)2799 runBug44015(NDBT_Context* ctx, NDBT_Step* step)
2800 {
2801   /* testNdbApi -n WeirdAssertFail
2802    * Generates phrase "here2" on 6.3 which is
2803    * output by DbtupExecQuery::handleReadReq()
2804    * detecting that the record's tuple checksum
2805    * is incorrect.
2806    * Later can generate assertion failure in
2807    * prepare_read
2808    *         ndbassert(src_len >= (dynstart - src_data));
2809    * resulting in node failure
2810    */
2811   Ndb* pNdb = GETNDB(step);
2812   const NdbDictionary::Table* pTab= ctx->getTab();
2813 
2814   int numIterations= 100;
2815   int numRecords= 1024;
2816 
2817   NdbTransaction* trans;
2818   HugoOperations hugoOps(*pTab);
2819 
2820   for (int iter=0; iter < numIterations; iter++)
2821   {
2822     ndbout << "Iter : " << iter << endl;
2823     CHECK((trans= pNdb->startTransaction()) != 0);
2824 
2825     CHECK(hugoOps.setTransaction(trans) == 0);
2826 
2827     CHECK(hugoOps.pkInsertRecord(pNdb,
2828                                  0,
2829                                  numRecords) == 0);
2830 
2831     /* Now execute the transaction */
2832     if ((trans->execute(NdbTransaction::NoCommit) != 0))
2833     {
2834       ndbout << "Execute failed, error is "
2835              << trans->getNdbError().code << " "
2836              << trans->getNdbError().message << endl;
2837       CHECK(0);
2838     }
2839 
2840     CHECK(trans->getNdbError().code == 0);
2841 
2842     /* Now delete the records in the same transaction
2843      * Need to do this manually as Hugo doesn't support it
2844      */
2845     CHECK(hugoOps.pkDeleteRecord(pNdb,
2846                                  0,
2847                                  numRecords) == 0);
2848 
2849     CHECK(trans->execute(NdbTransaction::NoCommit) == 0);
2850     CHECK(trans->getNdbError().code == 0);
2851 
2852     /* Now abort the transaction by closing it */
2853     trans->close();
2854 
2855     /* Force Hugo Transaction back to NULL */
2856     hugoOps.setTransaction(NULL, true);
2857   }
2858 
2859   ctx->stopTest();
2860 
2861   return NDBT_OK;
2862 }
2863 
runScanReadUntilStopped(NDBT_Context * ctx,NDBT_Step * step)2864 int runScanReadUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
2865   int result = NDBT_OK;
2866   int i = 0;
2867   int scan_flags = NdbScanOperation::SF_TupScan;
2868   NdbOperation::LockMode lm =
2869     (NdbOperation::LockMode)
2870     ctx->getProperty("ReadLockMode", (Uint32)NdbOperation::LM_CommittedRead);
2871 
2872   HugoTransactions hugoTrans(*ctx->getTab());
2873   while (ctx->isTestStopped() == false) {
2874     g_info << i << ": ";
2875     if (hugoTrans.scanReadRecords(GETNDB(step), 0, 0, 0,
2876                                   lm, scan_flags) != 0){
2877       return NDBT_FAILED;
2878     }
2879     i++;
2880   }
2881   return result;
2882 }
2883 
2884 int
runBug44065_org(NDBT_Context * ctx,NDBT_Step * step)2885 runBug44065_org(NDBT_Context* ctx, NDBT_Step* step)
2886 {
2887   /* testNdbApi -n WeirdAssertFail2
2888    * Results in assertion failure in DbtupCommit::execTUP_DEALLOCREQ()
2889    *   ndbassert(ptr->m_header_bits & Tuple_header::FREE);
2890    * Results in node failure
2891    */
2892   Ndb* pNdb = GETNDB(step);
2893   const NdbDictionary::Table* pTab= ctx->getTab();
2894 
2895   int numOuterIterations= 50;
2896   int numInnerIterations= 20;
2897   int numRecords= 200;
2898 
2899   NdbTransaction* trans;
2900 
2901   for (int outerIter=0; outerIter < numOuterIterations; outerIter++)
2902   {
2903     HugoOperations hugoOps(*pTab);
2904 
2905     int offset= (outerIter * numRecords);
2906     ndbout << "Outer Iter : " << outerIter
2907            << " " << offset << "-" << (offset + numRecords - 1) << endl;
2908 
2909     {
2910       HugoTransactions trans(*pTab);
2911       CHECK(trans.loadTableStartFrom(pNdb, offset, numRecords) == 0);
2912     }
2913 
2914     for (int iter=0; iter < numInnerIterations; iter++)
2915     {
2916       //ndbout << "Inner Iter : " << iter << endl;
2917       CHECK((trans= pNdb->startTransaction()) != 0);
2918 
2919       CHECK(hugoOps.setTransaction(trans) == 0);
2920 
2921       /* Delete the records */
2922       CHECK(hugoOps.pkDeleteRecord(pNdb,
2923                                    offset,
2924                                    numRecords) == 0);
2925 
2926       /* Re-insert them */
2927       CHECK(hugoOps.pkInsertRecord(pNdb,
2928                                    offset,
2929                                    numRecords) == 0);
2930 
2931       /* Now execute the transaction, with IgnoreError */
2932       if ((trans->execute(NdbTransaction::NoCommit,
2933                           NdbOperation::AO_IgnoreError) != 0))
2934       {
2935         NdbError err = trans->getNdbError();
2936         ndbout << "Execute failed, error is "
2937                << err.code << " " << endl;
2938         CHECK((err.classification == NdbError::TemporaryResourceError ||
2939                err.classification == NdbError::OverloadError ||
2940                err.classification == NdbError::TimeoutExpired));
2941         NdbSleep_MilliSleep(50);
2942       }
2943 
2944       /* Now abort the transaction by closing it without committing */
2945       trans->close();
2946 
2947       /* Force Hugo Transaction back to NULL */
2948       hugoOps.setTransaction(NULL, true);
2949     }
2950   }
2951 
2952   ctx->stopTest();
2953 
2954   return NDBT_OK;
2955 }
2956 
2957 static volatile int aValue = 0;
2958 
2959 void
a_callback(int,NdbTransaction *,void *)2960 a_callback(int, NdbTransaction*, void*)
2961 {
2962   ndbout_c("callback received!");
2963   aValue = 1;
2964 }
2965 
2966 int
runBug44065(NDBT_Context * ctx,NDBT_Step * step)2967 runBug44065(NDBT_Context* ctx, NDBT_Step* step)
2968 {
2969   /* testNdbApi -n WeirdAssertFail2
2970    * Results in assertion failure in DbtupCommit::execTUP_DEALLOCREQ()
2971    *   ndbassert(ptr->m_header_bits & Tuple_header::FREE);
2972    * Results in node failure
2973    */
2974   int rowno = 0;
2975   aValue = 0;
2976   Ndb* pNdb = GETNDB(step);
2977   Ndb * pNdb2 = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
2978   pNdb2->init();
2979   pNdb2->waitUntilReady();
2980 
2981   const NdbDictionary::Table* pTab= ctx->getTab();
2982 
2983   HugoOperations hugoOps1(*pTab);
2984   CHECK(hugoOps1.startTransaction(pNdb) == 0);
2985   CHECK(hugoOps1.pkInsertRecord(pNdb, rowno) == 0);
2986   CHECK(hugoOps1.execute_NoCommit(pNdb) == 0);
2987 
2988   {
2989     HugoOperations hugoOps2(*pTab);
2990     CHECK(hugoOps2.startTransaction(pNdb2) == 0);
2991 
2992     CHECK(hugoOps2.pkDeleteRecord(pNdb2, rowno) == 0);
2993     CHECK(hugoOps2.pkInsertRecord(pNdb2, rowno) == 0);
2994 
2995     NdbTransaction* trans = hugoOps2.getTransaction();
2996     aValue = 0;
2997 
2998     trans->executeAsynch(NdbTransaction::NoCommit, a_callback, 0);
2999     pNdb2->sendPreparedTransactions(1);
3000     CHECK(hugoOps1.execute_Commit(pNdb) == 0);
3001     ndbout_c("waiting for callback");
3002     while (aValue == 0)
3003     {
3004       pNdb2->pollNdb();
3005       NdbSleep_MilliSleep(100);
3006     }
3007     CHECK(hugoOps2.execute_Rollback(pNdb2) == 0);
3008   }
3009 
3010   delete pNdb2; // need to delete hugoOps2 before pNdb2
3011   ctx->stopTest();
3012 
3013   return NDBT_OK;
3014 }
3015 
testApiFailReqImpl(NDBT_Context * ctx,NDBT_Step * step)3016 int testApiFailReqImpl(NDBT_Context* ctx, NDBT_Step* step)
3017 {
3018   /* Setup a separate connection for running PK updates
3019    * with that will be disconnected without affecting
3020    * the test framework
3021    */
3022   if (otherConnection != NULL)
3023   {
3024     ndbout << "Connection not null" << endl;
3025     return NDBT_FAILED;
3026   }
3027 
3028   char connectString[256];
3029   ctx->m_cluster_connection.get_connectstring(connectString,
3030                                               sizeof(connectString));
3031 
3032   otherConnection= new Ndb_cluster_connection(connectString);
3033 
3034   if (otherConnection == NULL)
3035   {
3036     ndbout << "Connection is null" << endl;
3037     return NDBT_FAILED;
3038   }
3039 
3040   int rc= otherConnection->connect();
3041 
3042   if (rc!= 0)
3043   {
3044     ndbout << "Connect failed with rc " << rc << endl;
3045     return NDBT_FAILED;
3046   }
3047 
3048   /* Check that all nodes are alive - if one has failed
3049    * then probably we exposed bad API_FAILREQ handling
3050    */
3051   if (otherConnection->wait_until_ready(10,10) != 0)
3052   {
3053     ndbout << "Cluster connection was not ready" << endl;
3054     return NDBT_FAILED;
3055   }
3056 
3057   for (int i=0; i < MAX_STEPS; i++)
3058   {
3059     /* We must create the Ndb objects here as we
3060      * are still single threaded
3061      */
3062     stepNdbs[i]= new Ndb(otherConnection,
3063                          "TEST_DB");
3064     stepNdbs[i]->init();
3065     int rc= stepNdbs[i]->waitUntilReady(10);
3066 
3067     if (rc != 0)
3068     {
3069       ndbout << "Ndb " << i << " was not ready" << endl;
3070       return NDBT_FAILED;
3071     }
3072 
3073   }
3074 
3075   /* Now signal the 'worker' threads to start sending Pk
3076    * reads
3077    */
3078   ctx->setProperty(ApiFailTestRun, 1);
3079 
3080   /* Wait until all of them are running before proceeding */
3081   ctx->getPropertyWait(ApiFailTestsRunning,
3082                        ctx->getProperty(ApiFailNumberPkSteps));
3083 
3084   if (ctx->isTestStopped())
3085   {
3086     return NDBT_OK;
3087   }
3088 
3089   /* Clear the test-run flag so that they'll wait after
3090    * they hit an error
3091    */
3092   ctx->setProperty(ApiFailTestRun, (Uint32)0);
3093 
3094   /* Wait a little */
3095   sleep(1);
3096 
3097   /* Active more stringent checking of behaviour after
3098    * API_FAILREQ
3099    */
3100   NdbRestarter restarter;
3101 
3102   /* Activate 8078 - TCs will abort() if they get a TCKEYREQ
3103    * from the failed API after an API_FAILREQ message
3104    */
3105   ndbout << "Activating 8078" << endl;
3106   restarter.insertErrorInAllNodes(8078);
3107 
3108   /* Wait a little longer */
3109   sleep(1);
3110 
3111   /* Now cause our connection to disconnect
3112    * This results in TC receiving an API_FAILREQ
3113    * If there's an issue with API_FAILREQ 'cleanly'
3114    * stopping further signals, there should be
3115    * an assertion failure in TC
3116    */
3117   int otherNodeId = otherConnection->node_id();
3118 
3119   ndbout << "Forcing disconnect of node "
3120          << otherNodeId << endl;
3121 
3122   /* All dump 900 <nodeId> */
3123   int args[2]= {900, otherNodeId};
3124 
3125   restarter.dumpStateAllNodes( args, 2 );
3126 
3127 
3128   /* Now wait for all workers to finish
3129    * (Running worker count to get down to zero
3130    */
3131   ctx->getPropertyWait(ApiFailTestsRunning, (Uint32)0);
3132 
3133   if (ctx->isTestStopped())
3134   {
3135     return NDBT_OK;
3136   }
3137 
3138   /* Clean up error insert */
3139   restarter.insertErrorInAllNodes(0);
3140 
3141   /* Clean up allocated resources */
3142   for (int i= 0; i < MAX_STEPS; i++)
3143   {
3144     delete stepNdbs[i];
3145     stepNdbs[i]= NULL;
3146   }
3147 
3148   delete otherConnection;
3149   otherConnection= NULL;
3150 
3151   return NDBT_OK;
3152 }
3153 
3154 
testApiFailReq(NDBT_Context * ctx,NDBT_Step * step)3155 int testApiFailReq(NDBT_Context* ctx, NDBT_Step* step)
3156 {
3157   /* Perform a number of iterations, connecting,
3158    * sending lots of PK updates, inserting error
3159    * and then causing node failure
3160    */
3161   Uint32 iterations = 10;
3162   int rc = NDBT_OK;
3163 
3164   while (iterations --)
3165   {
3166     rc= testApiFailReqImpl(ctx, step);
3167 
3168     if (rc == NDBT_FAILED)
3169     {
3170       break;
3171     }
3172   } // while(iterations --)
3173 
3174   /* Avoid PkRead worker threads getting stuck */
3175   ctx->setProperty(ApiFailTestComplete, (Uint32) 1);
3176 
3177   return rc;
3178 }
3179 
runBulkPkReads(NDBT_Context * ctx,NDBT_Step * step)3180 int runBulkPkReads(NDBT_Context* ctx, NDBT_Step* step)
3181 {
3182   /* Run batched Pk reads */
3183 
3184   while(true)
3185   {
3186     /* Wait to be signalled to start running */
3187     while ((ctx->getProperty(ApiFailTestRun) == 0) &&
3188            (ctx->getProperty(ApiFailTestComplete) == 0) &&
3189            !ctx->isTestStopped())
3190     {
3191       ctx->wait_timeout(500); /* 500 millis */
3192     }
3193 
3194     if (ctx->isTestStopped() ||
3195         (ctx->getProperty(ApiFailTestComplete) != 0))
3196     {
3197       /* Asked to stop by main test thread */
3198       return NDBT_OK;
3199     }
3200     /* Indicate that we're underway */
3201     ctx->incProperty(ApiFailTestsRunning);
3202 
3203     Ndb* otherNdb = stepNdbs[step->getStepNo()];
3204     HugoOperations hugoOps(*ctx->getTab());
3205     Uint32 numRecords = ctx->getNumRecords();
3206     Uint32 batchSize = (1000 < numRecords)? 1000 : numRecords;
3207 
3208     ndbout << "Step number " << step->getStepNo()
3209            << " reading batches of " << batchSize
3210            << " rows " << endl;
3211 
3212     while(true)
3213     {
3214       if (hugoOps.startTransaction(otherNdb) != 0)
3215       {
3216         if (otherNdb->getNdbError().code == 4009)
3217         {
3218           /* Api disconnect sometimes manifests as Cluster failure
3219            * from API's point of view as it cannot seize() a
3220            * transaction from any Ndbd node
3221            * We treat this the same way as the later error cases
3222            */
3223           break;
3224         }
3225 
3226         ndbout << "Failed to start transaction.  Error : "
3227                << otherNdb->getNdbError().message << endl;
3228         return NDBT_FAILED;
3229       }
3230 
3231       for (Uint32 op = 0; op < batchSize; op++)
3232       {
3233         if (hugoOps.pkReadRecord(otherNdb,
3234                                  op) != 0)
3235         {
3236           ndbout << "Failed to define read of record number " << op << endl;
3237           ndbout << "Error : " << hugoOps.getTransaction()->getNdbError().message
3238                  << endl;
3239           return NDBT_FAILED;
3240         }
3241       }
3242 
3243       if (hugoOps.execute_Commit(otherNdb) != 0)
3244       {
3245         NdbError err = hugoOps.getTransaction()->getNdbError();
3246         ndbout << "Execute failed with Error : "
3247                << err.message
3248                << endl;
3249 
3250         hugoOps.closeTransaction(otherNdb);
3251 
3252         if ((err.code == 4002) || // send failed
3253             (err.code == 4010) || // Node failure
3254             (err.code == 4025) || // Node failure
3255             (err.code == 1218))   // Send buffer overload (reading larger tables)
3256         {
3257           /* Expected scenario due to injected Api disconnect
3258            * If there was a node failure due to assertion failure
3259            * then we'll detect it when we try to setup a new
3260            * connection
3261            */
3262           break;
3263         }
3264         return NDBT_FAILED;
3265       }
3266 
3267       hugoOps.closeTransaction(otherNdb);
3268     }
3269 
3270     /* Signal that we've finished running this iteration */
3271     ctx->decProperty(ApiFailTestsRunning);
3272   }
3273 
3274   return NDBT_OK;
3275 }
3276 
runReadColumnDuplicates(NDBT_Context * ctx,NDBT_Step * step)3277 int runReadColumnDuplicates(NDBT_Context* ctx, NDBT_Step* step){
3278 
3279   int result = NDBT_OK;
3280   const NdbDictionary::Table* pTab = ctx->getTab();
3281   HugoCalculator hc(*pTab);
3282   Uint32 numRecords = ctx->getNumRecords();
3283 
3284   Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB");
3285   if (pNdb == NULL){
3286     ndbout << "pNdb == NULL" << endl;
3287     return NDBT_FAILED;
3288   }
3289   if (pNdb->init()){
3290     NDB_ERR(pNdb->getNdbError());
3291     delete pNdb;
3292     return NDBT_FAILED;
3293   }
3294 
3295   HugoOperations hugoOps(*pTab);
3296 
3297   for (int m = 1; m < 100; m++){
3298     Uint32 record = (100 - m) % numRecords;
3299     NdbConnection* pCon = pNdb->startTransaction();
3300     if (pCon == NULL){
3301       delete pNdb;
3302       return NDBT_FAILED;
3303     }
3304 
3305     NdbOperation* pOp = pCon->getNdbOperation(pTab->getName());
3306     if (pOp == NULL){
3307       pNdb->closeTransaction(pCon);
3308       delete pNdb;
3309       return NDBT_FAILED;
3310     }
3311 
3312     if (pOp->readTuple() != 0){
3313       pNdb->closeTransaction(pCon);
3314       delete pNdb;
3315       return NDBT_FAILED;
3316     }
3317 
3318     int numCols= pTab->getNoOfColumns();
3319 
3320     for(int a = 0; a < numCols; a++){
3321       if (pTab->getColumn(a)->getPrimaryKey() == true){
3322 	if(hugoOps.equalForAttr(pOp, a, record) != 0){
3323 	  NDB_ERR(pCon->getNdbError());
3324 	  pNdb->closeTransaction(pCon);
3325 	  delete pNdb;
3326 	  return NDBT_FAILED;
3327 	}
3328       }
3329     }
3330 
3331     int dupColNum = m % numCols;
3332     int numReads = m + 1;
3333 
3334     NdbRecAttr* first = NULL;
3335     ndbout << "Reading record "
3336            << record << " Column "
3337            << dupColNum << " " << numReads
3338            << " times" << endl;
3339     while (numReads--)
3340     {
3341       NdbRecAttr* recAttr = pOp->getValue(dupColNum);
3342       if (recAttr == NULL) {
3343 	const NdbError err = pCon->getNdbError();
3344 	NDB_ERR(err);
3345         result = NDBT_FAILED;
3346         pNdb->closeTransaction(pCon);
3347 	break;
3348       }
3349       first = (first == NULL) ? recAttr : first;
3350     };
3351 
3352     if (result == NDBT_FAILED)
3353       break;
3354 
3355     if (pCon->execute(Commit) != 0){
3356       const NdbError err = pCon->getNdbError();
3357       NDB_ERR(err);
3358       result = NDBT_FAILED;
3359       pNdb->closeTransaction(pCon);
3360       break;
3361     }
3362 
3363     if (pCon->getNdbError().code != 0)
3364     {
3365       NdbError err = pCon->getNdbError();
3366       if (err.code == 880)
3367       {
3368         /* Tried to read too much error - this column
3369          * is probably too large.
3370          * Skip to next iteration
3371          */
3372         ndbout << "Reading too much in one op, skipping..." << endl;
3373         pNdb->closeTransaction(pCon);
3374         continue;
3375       }
3376       ndbout << "Error at execute time : " << err.code
3377              << ":" << err.message << endl;
3378       pNdb->closeTransaction(pCon);
3379       result = NDBT_FAILED;
3380       break;
3381     }
3382 
3383     /* Let's check the results */
3384 
3385 
3386     const NdbRecAttr* curr = first;
3387 
3388     for (int c= 0; c < (m+1); c++)
3389     {
3390       if (hc.verifyRecAttr(record,
3391                            0,
3392                            curr))
3393       {
3394         ndbout << "Mismatch on record "
3395                  << record << " column "
3396                  << dupColNum << " read number "
3397                  << c+1 << endl;
3398         result =  NDBT_FAILED;
3399         break;
3400       }
3401 
3402       ndbout << "/";
3403 
3404       curr = curr->next();
3405     }
3406 
3407     ndbout << endl;
3408 
3409     pNdb->closeTransaction(pCon);
3410 
3411     if (result == NDBT_FAILED)
3412       break;
3413 
3414     if (curr != NULL)
3415     {
3416       ndbout << "Error - extra RecAttr(s) found" << endl;
3417       result = NDBT_FAILED;
3418       break;
3419     }
3420 
3421   }// m
3422 
3423   delete pNdb;
3424 
3425   return result;
3426 }
3427 
3428 class TransGuard
3429 {
3430   NdbTransaction* pTrans;
3431 public:
TransGuard(NdbTransaction * p)3432   TransGuard(NdbTransaction * p) : pTrans(p) {}
~TransGuard()3433   ~TransGuard() { if (pTrans) pTrans->close(); pTrans = 0; }
3434 };
3435 
3436 int
runBug51775(NDBT_Context * ctx,NDBT_Step * step)3437 runBug51775(NDBT_Context* ctx, NDBT_Step* step)
3438 {
3439   Ndb* pNdb = GETNDB(step);
3440 
3441   NdbTransaction * pTrans1 = pNdb->startTransaction();
3442   if (pTrans1 == NULL)
3443   {
3444     NDB_ERR(pNdb->getNdbError());
3445     return NDBT_FAILED;
3446   }
3447   TransGuard g1(pTrans1);
3448 
3449   NdbTransaction * pTrans2 = pNdb->startTransaction();
3450   if (pTrans2 == NULL)
3451   {
3452     pTrans1->close();
3453     NDB_ERR(pNdb->getNdbError());
3454     return NDBT_FAILED;
3455   }
3456 
3457   TransGuard g2(pTrans2);
3458 
3459   {
3460     NdbOperation * pOp = pTrans1->getNdbOperation(ctx->getTab()->getName());
3461     if (pOp == NULL)
3462     {
3463       NDB_ERR(pOp->getNdbError());
3464       return NDBT_FAILED;
3465     }
3466 
3467     if (pOp->insertTuple() != 0)
3468     {
3469       NDB_ERR(pOp->getNdbError());
3470       return NDBT_FAILED;
3471     }
3472 
3473     HugoOperations hugoOps(* ctx->getTab());
3474     hugoOps.setValues(pOp, 0, 0);
3475   }
3476 
3477   {
3478     NdbOperation * pOp = pTrans2->getNdbOperation(ctx->getTab()->getName());
3479     if (pOp == NULL)
3480     {
3481       NDB_ERR(pOp->getNdbError());
3482       return NDBT_FAILED;
3483     }
3484 
3485     if (pOp->readTuple() != 0)
3486     {
3487       NDB_ERR(pOp->getNdbError());
3488       return NDBT_FAILED;
3489     }
3490 
3491     HugoOperations hugoOps(* ctx->getTab());
3492     hugoOps.equalForRow(pOp, 0);
3493     pOp->getValue(NdbDictionary::Column::FRAGMENT);
3494   }
3495 
3496 
3497   pTrans1->execute(NoCommit); // We now have un uncommitted insert
3498 
3499   /**
3500    * Now send a read...which will get 266
3501    */
3502   pTrans2->executeAsynch(NoCommit, 0, 0);
3503   int res = pNdb->pollNdb(1, 1000);
3504   ndbout_c("res: %u", res);
3505 
3506   NdbSleep_SecSleep(10);
3507   ndbout_c("pollNdb()");
3508   while (pNdb->pollNdb() + res == 0);
3509 
3510   return NDBT_OK;
3511 }
3512 
testFragmentedApiFailImpl(NDBT_Context * ctx,NDBT_Step * step)3513 int testFragmentedApiFailImpl(NDBT_Context* ctx, NDBT_Step* step)
3514 {
3515   /* Setup a separate connection for running scan operations
3516    * with that will be disconnected without affecting
3517    * the test framework
3518    */
3519   if (otherConnection != NULL)
3520   {
3521     g_err.println("FragApiFail : Connection not null");
3522     return NDBT_FAILED;
3523   }
3524 
3525   char connectString[256];
3526   ctx->m_cluster_connection.get_connectstring(connectString,
3527                                               sizeof(connectString));
3528 
3529   otherConnection= new Ndb_cluster_connection(connectString);
3530 
3531   if (otherConnection == NULL)
3532   {
3533     g_err.println("FragApiFail : Connection is null");
3534     return NDBT_FAILED;
3535   }
3536 
3537   int rc= otherConnection->connect();
3538 
3539   if (rc!= 0)
3540   {
3541     g_err.println("FragApiFail : Connect failed with rc %d", rc);
3542     return NDBT_FAILED;
3543   }
3544 
3545   /* Check that all nodes are alive - if one has failed
3546    * then probably we exposed bad API_FAILREQ handling
3547    */
3548   if (otherConnection->wait_until_ready(10,10) != 0)
3549   {
3550     g_err.println("FragApiFail : Cluster connection was not ready");
3551     return NDBT_FAILED;
3552   }
3553 
3554   for (int i=0; i < MAX_STEPS; i++)
3555   {
3556     /* We must create the Ndb objects here as we
3557      * are still single threaded
3558      */
3559     stepNdbs[i]= new Ndb(otherConnection,
3560                          "TEST_DB");
3561     stepNdbs[i]->init();
3562     int rc= stepNdbs[i]->waitUntilReady(10);
3563 
3564     if (rc != 0)
3565     {
3566       g_err.println("FragApiFail : Ndb %d was not ready", i);
3567       return NDBT_FAILED;
3568     }
3569 
3570   }
3571 
3572   /* Now signal the 'worker' threads to start sending Pk
3573    * reads
3574    */
3575   ctx->setProperty(ApiFailTestRun, 1);
3576 
3577   /* Wait until all of them are running before proceeding */
3578   ctx->getPropertyWait(ApiFailTestsRunning,
3579                        ctx->getProperty(ApiFailNumberPkSteps));
3580 
3581   if (ctx->isTestStopped())
3582   {
3583     return NDBT_OK;
3584   }
3585 
3586   /* Clear the test-run flag so that they'll wait after
3587    * they hit an error
3588    */
3589   ctx->setProperty(ApiFailTestRun, (Uint32)0);
3590 
3591   /* Wait a little */
3592   sleep(1);
3593 
3594   /* Now cause our connection to disconnect
3595    * This results in NDBD running API failure
3596    * code and cleaning up any in-assembly fragmented
3597    * signals
3598    */
3599   int otherNodeId = otherConnection->node_id();
3600 
3601   g_info.println("FragApiFail : Forcing disconnect of node %u", otherNodeId);
3602 
3603   /* All dump 900 <nodeId> */
3604   int args[2]= {900, otherNodeId};
3605 
3606   NdbRestarter restarter;
3607   restarter.dumpStateAllNodes( args, 2 );
3608 
3609   /* Now wait for all workers to finish
3610    * (Running worker count to get down to zero
3611    */
3612   ctx->getPropertyWait(ApiFailTestsRunning, (Uint32)0);
3613 
3614   if (ctx->isTestStopped())
3615   {
3616     return NDBT_OK;
3617   }
3618 
3619   /* Clean up allocated resources */
3620   for (int i= 0; i < MAX_STEPS; i++)
3621   {
3622     delete stepNdbs[i];
3623     stepNdbs[i]= NULL;
3624   }
3625 
3626   delete otherConnection;
3627   otherConnection= NULL;
3628 
3629   return NDBT_OK;
3630 }
3631 
testFragmentedApiFail(NDBT_Context * ctx,NDBT_Step * step)3632 int testFragmentedApiFail(NDBT_Context* ctx, NDBT_Step* step)
3633 {
3634   /* Perform a number of iterations, connecting,
3635    * sending lots of PK updates, inserting error
3636    * and then causing node failure
3637    */
3638   Uint32 iterations = 10;
3639   int rc = NDBT_OK;
3640 
3641   while (iterations --)
3642   {
3643     rc= testFragmentedApiFailImpl(ctx, step);
3644 
3645     if (rc == NDBT_FAILED)
3646     {
3647       break;
3648     }
3649   } // while(iterations --)
3650 
3651   /* Avoid scan worker threads getting stuck */
3652   ctx->setProperty(ApiFailTestComplete, (Uint32) 1);
3653 
3654   return rc;
3655 }
3656 
runFragmentedScanOtherApi(NDBT_Context * ctx,NDBT_Step * step)3657 int runFragmentedScanOtherApi(NDBT_Context* ctx, NDBT_Step* step)
3658 {
3659   /* We run a loop sending large scan requests that will be
3660    * fragmented.
3661    * The requests are so large that they actually fail on
3662    * arrival at TUP as there is too much ATTRINFO
3663    * That doesn't affect this testcase though, as it is
3664    * testing TC cleanup of fragmented signals from a
3665    * failed API
3666    */
3667   /* SEND > ((2 * MAX_SEND_MESSAGE_BYTESIZE) + SOME EXTRA)
3668    * This way we get at least 3 fragments
3669    * However, as this is generally > 64kB, it's too much AttrInfo for
3670    * a ScanTabReq, so the 'success' case returns error 874
3671    */
3672   const Uint32 PROG_WORDS= 16500;
3673 
3674   /* Use heap rather than stack as stack is too small in
3675    * STEP thread
3676    */
3677   Uint32* buff= new Uint32[ PROG_WORDS + 10 ]; // 10 extra for final 'return' etc.
3678   Uint32 stepNo = step->getStepNo();
3679 
3680   while(true)
3681   {
3682     /* Wait to be signalled to start running */
3683     while ((ctx->getProperty(ApiFailTestRun) == 0) &&
3684            (ctx->getProperty(ApiFailTestComplete) == 0) &&
3685            !ctx->isTestStopped())
3686     {
3687       ctx->wait_timeout(500); /* 500 millis */
3688     }
3689 
3690     if (ctx->isTestStopped() ||
3691         (ctx->getProperty(ApiFailTestComplete) != 0))
3692     {
3693       g_info.println("%u: Test stopped, exiting thread", stepNo);
3694       /* Asked to stop by main test thread */
3695       delete[] buff;
3696       return NDBT_OK;
3697     }
3698     /* Indicate that we're underway */
3699     ctx->incProperty(ApiFailTestsRunning);
3700 
3701     Ndb* otherNdb = stepNdbs[stepNo];
3702 
3703     while (true)
3704     {
3705       /* Start a transaction */
3706       NdbTransaction* trans= otherNdb->startTransaction();
3707       if (!trans)
3708       {
3709         const NdbError err = otherNdb->getNdbError();
3710 
3711         /* During this test, if we attempt to get a transaction
3712          * when the API is disconnected, we can get error 4009
3713          * (Cluster failure).  We treat this similarly to the
3714          * "Node failure caused abort of transaction" case
3715          */
3716         if (err.code == 4009)
3717         {
3718           g_info.println("%u: Failed to start transaction from Ndb object Error : %u %s",
3719                    stepNo, err.code, err.message);
3720           break;
3721         }
3722         g_err.println("ERR: %u: %u: Failed to start transaction from Ndb object Error : %u %s",
3723                       __LINE__, stepNo, err.code, err.message);
3724         delete[] buff;
3725         return NDBT_FAILED;
3726       }
3727 
3728       NdbScanOperation* scan= trans->getNdbScanOperation(ctx->getTab());
3729 
3730       if (scan == NULL)
3731       {
3732         /* getNdbScanOperation can fail in same way as startTransaction
3733          * since it starts a buddy transaction for scan operations.
3734          */
3735         const NdbError err = trans->getNdbError();
3736         if (err.code == 4009)
3737         {
3738           g_info.println("%u: Failed to get scan operation transaction Error : %u %s",
3739                    stepNo, err.code, err.message);
3740           trans->close();
3741           break;
3742         }
3743         g_err.println("ERR: %u: %u: Failed to get scan operation transaction Error : %u %s",
3744                  __LINE__, stepNo, err.code, err.message);
3745         trans->close();
3746         delete[] buff;
3747         return NDBT_FAILED;
3748       }
3749 
3750       CHECK(0 == scan->readTuples());
3751 
3752       /* Create a large program, to give a large SCANTABREQ */
3753       NdbInterpretedCode prog(ctx->getTab(),
3754                               buff, PROG_WORDS + 10);
3755 
3756       for (Uint32 w=0; w < PROG_WORDS; w++)
3757         CHECK(0 == prog.load_const_null(1));
3758 
3759       CHECK(0 == prog.interpret_exit_ok());
3760       CHECK(0 == prog.finalise());
3761 
3762       CHECK(0 == scan->setInterpretedCode(&prog));
3763 
3764       int ret = trans->execute(NdbTransaction::NoCommit);
3765 
3766       const NdbError execError= trans->getNdbError();
3767 
3768       if (ret != 0)
3769       {
3770         /* Transaction was aborted.  Should be due to node disconnect. */
3771         if(execError.classification != NdbError::NodeRecoveryError)
3772         {
3773           g_err.println("ERR: %u: %u: Execute aborted transaction with invalid error code: %u",
3774                    __LINE__, stepNo, execError.code);
3775           NDB_ERR_OUT(g_err, execError);
3776           trans->close();
3777           delete[] buff;
3778           return NDBT_FAILED;
3779         }
3780         g_info.println("%u: Execute aborted transaction with NR error code: %u",
3781                  stepNo, execError.code);
3782         trans->close();
3783         break;
3784       }
3785 
3786       /* Can get success (0), or 874 for too much AttrInfo, depending
3787        * on timing
3788        */
3789       if ((execError.code != 0) &&
3790           (execError.code != 874) &&
3791           (execError.code != 4002))
3792       {
3793         g_err.println("ERR: %u: %u: incorrect error code: %u", __LINE__, stepNo, execError.code);
3794         NDB_ERR_OUT(g_err, execError);
3795         trans->close();
3796         delete[] buff;
3797         return NDBT_FAILED;
3798       }
3799 
3800       /* nextResult will always fail */
3801       CHECK(-1 == scan->nextResult());
3802 
3803       NdbError scanError= scan->getNdbError();
3804 
3805       /* 'Success case' is 874 for too much AttrInfo */
3806       if (scanError.code != 874)
3807       {
3808        /* When disconnected, we get should get a node failure related error */
3809         if (scanError.classification == NdbError::NodeRecoveryError)
3810         {
3811           g_info.println("%u: Scan failed due to node failure/disconnect with error code %u",
3812                          stepNo, scanError.code);
3813           trans->close();
3814           break;
3815         }
3816         else
3817         {
3818           g_err.println("ERR: %u: %u: incorrect error code: %u", __LINE__, stepNo, scanError.code);
3819           NDB_ERR_OUT(g_err, scanError);
3820           trans->close();
3821           delete[] buff;
3822           return NDBT_FAILED;
3823         }
3824       }
3825 
3826       scan->close();
3827 
3828       trans->close();
3829     } // while (true)
3830 
3831     /* Node failure case - as expected */
3832     g_info.println("%u: Scan thread finished iteration", stepNo);
3833 
3834     /* Signal that we've finished running this iteration */
3835     ctx->decProperty(ApiFailTestsRunning);
3836   }
3837 
3838   delete[] buff;
3839   return NDBT_OK;
3840 }
3841 
outputLockMode(NdbOperation::LockMode lm)3842 void outputLockMode(NdbOperation::LockMode lm)
3843 {
3844   switch(lm)
3845   {
3846   case NdbOperation::LM_Exclusive:
3847     ndbout << "LM_Exclusive";
3848     break;
3849   case NdbOperation::LM_Read:
3850     ndbout << "LM_Read";
3851     break;
3852   case NdbOperation::LM_SimpleRead:
3853     ndbout << "LM_SimpleRead";
3854     break;
3855   case NdbOperation::LM_CommittedRead:
3856     ndbout << "LM_CommittedRead";
3857     break;
3858   }
3859 }
3860 
chooseLockMode(bool onlyRealLocks=false)3861 NdbOperation::LockMode chooseLockMode(bool onlyRealLocks = false)
3862 {
3863   Uint32 choice;
3864 
3865   if (onlyRealLocks)
3866   {
3867     choice = rand() % 2;
3868   }
3869   else
3870   {
3871     choice = rand() % 4;
3872   }
3873 
3874   NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
3875 
3876   switch(choice)
3877   {
3878   case 0:
3879     lm = NdbOperation::LM_Exclusive;
3880     break;
3881   case 1:
3882     lm = NdbOperation::LM_Read;
3883     break;
3884   case 2:
3885     lm = NdbOperation::LM_SimpleRead;
3886     break;
3887   case 3:
3888   default:
3889     lm = NdbOperation::LM_CommittedRead;
3890     break;
3891   }
3892 
3893   outputLockMode(lm);
3894   ndbout << endl;
3895 
3896   return lm;
3897 }
3898 
chooseConflictingLockMode(NdbOperation::LockMode lm)3899 NdbOperation::LockMode chooseConflictingLockMode(NdbOperation::LockMode lm)
3900 {
3901   NdbOperation::LockMode conflicting = NdbOperation::LM_Exclusive;
3902 
3903   switch (lm)
3904   {
3905   case NdbOperation::LM_Exclusive:
3906     conflicting = (((rand() % 2) == 0) ?
3907                    NdbOperation::LM_Exclusive :
3908                    NdbOperation::LM_Read);
3909 
3910     break;
3911   case NdbOperation::LM_Read:
3912     conflicting = NdbOperation::LM_Exclusive;
3913     break;
3914   default:
3915     abort(); // SimpleRead + CommittedRead can't conflict reliably
3916   }
3917 
3918   ndbout << "conflicting with ";
3919   outputLockMode(lm);
3920   ndbout << " using ";
3921   outputLockMode(conflicting);
3922   ndbout << endl;
3923   return conflicting;
3924 }
3925 
3926 #define CHECKN(c, o, e) { if (!(c)) {                     \
3927     ndbout << "Failed on line " << __LINE__ << endl;    \
3928     ndbout << (o)->getNdbError() << endl;               \
3929     return e; } }
3930 
defineReadAllColsOp(HugoOperations * hugoOps,NdbTransaction * trans,const NdbDictionary::Table * pTab,NdbOperation::LockMode lm,Uint32 rowNum)3931 NdbOperation* defineReadAllColsOp(HugoOperations* hugoOps,
3932                                   NdbTransaction* trans,
3933                                   const NdbDictionary::Table* pTab,
3934                                   NdbOperation::LockMode lm,
3935                                   Uint32 rowNum)
3936 {
3937   NdbOperation* op = trans->getNdbOperation(pTab);
3938   CHECKN(op != NULL, trans, NULL);
3939 
3940   CHECKN(op->readTuple(lm) == 0, op, NULL);
3941 
3942   hugoOps->equalForRow(op, rowNum);
3943 
3944   for(int c = 0; c < pTab->getNoOfColumns(); c++)
3945   {
3946     if(!pTab->getColumn(c)->getPrimaryKey())
3947     {
3948       CHECKN(op->getValue(pTab->getColumn(c)->getName()) != NULL, op, NULL);
3949     }
3950   }
3951 
3952   return op;
3953 }
3954 
checkReadRc(HugoOperations * hugoOps,Ndb * ndb,const NdbDictionary::Table * pTab,NdbOperation::LockMode lm,Uint32 rowNum,int expectedRc)3955 bool checkReadRc(HugoOperations* hugoOps,
3956                  Ndb* ndb,
3957                  const NdbDictionary::Table* pTab,
3958                  NdbOperation::LockMode lm,
3959                  Uint32 rowNum,
3960                  int expectedRc)
3961 {
3962   NdbTransaction* trans = ndb->startTransaction();
3963   CHECKN(trans != NULL, ndb, false);
3964 
3965   NdbOperation* readOp = defineReadAllColsOp(hugoOps,
3966                                              trans,
3967                                              pTab,
3968                                              lm,
3969                                              rowNum);
3970   CHECKN(readOp != NULL, trans, false);
3971 
3972   int execRc = trans->execute(Commit);
3973 
3974   if (expectedRc)
3975   {
3976     /* Here we assume that the error is on the transaction
3977      * which may not be the case for some errors
3978      */
3979     if (trans->getNdbError().code != expectedRc)
3980     {
3981       ndbout << "Expected " << expectedRc << " at " << __LINE__ << endl;
3982       ndbout << "Got " << trans->getNdbError() << endl;
3983       return false;
3984     }
3985   }
3986   else
3987   {
3988     CHECKN(execRc == 0, trans, false);
3989     CHECKN(readOp->getNdbError().code == 0, readOp, false);
3990   }
3991 
3992   trans->close();
3993 
3994   return true;
3995 }
3996 
checkReadDeadlocks(HugoOperations * hugoOps,Ndb * ndb,const NdbDictionary::Table * pTab,NdbOperation::LockMode lm,Uint32 rowNum)3997 bool checkReadDeadlocks(HugoOperations* hugoOps,
3998                         Ndb* ndb,
3999                         const NdbDictionary::Table* pTab,
4000                         NdbOperation::LockMode lm,
4001                         Uint32 rowNum)
4002 {
4003   return checkReadRc(hugoOps, ndb, pTab, lm, rowNum, 266);
4004 }
4005 
checkReadSucceeds(HugoOperations * hugoOps,Ndb * ndb,const NdbDictionary::Table * pTab,NdbOperation::LockMode lm,Uint32 rowNum)4006 bool checkReadSucceeds(HugoOperations* hugoOps,
4007                        Ndb* ndb,
4008                        const NdbDictionary::Table* pTab,
4009                        NdbOperation::LockMode lm,
4010                        Uint32 rowNum)
4011 {
4012   return checkReadRc(hugoOps, ndb, pTab, lm, rowNum, 0);
4013 }
4014 
runTestUnlockBasic(NDBT_Context * ctx,NDBT_Step * step)4015 int runTestUnlockBasic(NDBT_Context* ctx, NDBT_Step* step)
4016 {
4017   /* Basic tests that we can lock and unlock rows
4018    * using the unlock mechanism
4019    * Some minor side-validation that the API rejects
4020    * readLockInfo for non Exclusive / Shared lock modes
4021    * and that double-release of the lockhandle is caught
4022    */
4023   const NdbDictionary::Table* pTab = ctx->getTab();
4024 
4025   HugoOperations hugoOps(*pTab);
4026 
4027   const Uint32 iterations = 200;
4028 
4029   for (Uint32 iter = 0; iter < iterations; iter++)
4030   {
4031     Uint32 rowNum = iter % ctx->getNumRecords();
4032 
4033     NdbTransaction* trans = GETNDB(step)->startTransaction();
4034     CHECKN(trans != NULL, GETNDB(step), NDBT_FAILED);
4035 
4036     ndbout << "First transaction operation using ";
4037     NdbOperation::LockMode lm = chooseLockMode();
4038 
4039     NdbOperation* op = defineReadAllColsOp(&hugoOps,
4040                                            trans,
4041                                            pTab,
4042                                            lm,
4043                                            rowNum);
4044     CHECKN(op != NULL, trans, NDBT_FAILED);
4045 
4046     if (op->getLockHandle() == NULL)
4047     {
4048       if ((lm == NdbOperation::LM_CommittedRead) ||
4049           (lm == NdbOperation::LM_SimpleRead))
4050       {
4051         if (op->getNdbError().code == 4549)
4052         {
4053           /* As expected, go to next iteration */
4054           ndbout << "Definition error as expected, moving to next" << endl;
4055           trans->close();
4056           continue;
4057         }
4058         ndbout << "Expected 4549, got :" << endl;
4059       }
4060       ndbout << op->getNdbError() << endl;
4061       ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
4062       return NDBT_FAILED;
4063     }
4064 
4065     CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4066 
4067     const NdbLockHandle* lh = op->getLockHandle();
4068     CHECKN(lh != NULL, op, NDBT_FAILED);
4069 
4070     /* Ok, let's use another transaction to try and get a
4071      * lock on the row (exclusive or shared)
4072      */
4073     NdbTransaction* trans2 = GETNDB(step)->startTransaction();
4074     CHECKN(trans2 != NULL, GETNDB(step), NDBT_FAILED);
4075 
4076 
4077     ndbout << "Second transaction operation using ";
4078     NdbOperation::LockMode lm2 = chooseLockMode();
4079 
4080     NdbOperation* op2 = defineReadAllColsOp(&hugoOps,
4081                                             trans2,
4082                                             pTab,
4083                                             lm2,
4084                                             rowNum);
4085     CHECKN(op2 != NULL, trans2, NDBT_FAILED);
4086 
4087     /* Execute can succeed if both lock modes are LM read
4088      * otherwise we'll deadlock (266)
4089      */
4090     bool expectOk = ((lm2 == NdbOperation::LM_CommittedRead) ||
4091                      ((lm == NdbOperation::LM_Read) &&
4092                       ((lm2 == NdbOperation::LM_Read) ||
4093                        (lm2 == NdbOperation::LM_SimpleRead))));
4094 
4095     /* Exclusive read locks primary only, and SimpleRead locks
4096      * Primary or Backup, so SimpleRead may or may not succeed
4097      */
4098     bool unknownCase = ((lm == NdbOperation::LM_Exclusive) &&
4099                         (lm2 == NdbOperation::LM_SimpleRead));
4100 
4101     if (trans2->execute(NoCommit) != 0)
4102     {
4103       if (expectOk ||
4104           (trans2->getNdbError().code != 266))
4105       {
4106         ndbout << trans2->getNdbError() << endl;
4107         ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
4108         return NDBT_FAILED;
4109       }
4110     }
4111     else
4112     {
4113       if (!expectOk  && !unknownCase)
4114       {
4115         ndbout << "Expected deadlock but had success!" << endl;
4116         return NDBT_FAILED;
4117       }
4118     }
4119     trans2->close();
4120 
4121     /* Now let's try to create an unlockRow operation, and
4122      * execute it
4123      */
4124     const NdbOperation* unlockOp = trans->unlock(lh);
4125 
4126     CHECKN(unlockOp != NULL, trans, NDBT_FAILED);
4127 
4128     CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4129 
4130     /* Now let's try to get an exclusive lock on the row from
4131      * another transaction which can only be possible if the
4132      * original lock has been removed.
4133      */
4134     CHECK(checkReadSucceeds(&hugoOps,
4135                             GETNDB(step),
4136                             pTab,
4137                             NdbOperation::LM_Exclusive,
4138                             rowNum));
4139     ndbout << "Third transaction operation using LM_Exclusive succeeded" << endl;
4140 
4141     Uint32 choice = rand() % 3;
4142     switch(choice)
4143     {
4144     case 0:
4145       ndbout << "Closing transaction" << endl;
4146       trans->close();
4147       break;
4148     case 1:
4149       ndbout << "Releasing handle and closing transaction" << endl;
4150       CHECKN(trans->releaseLockHandle(lh) == 0, trans, NDBT_FAILED);
4151       trans->close();
4152       break;
4153     case 2:
4154       ndbout << "Attempting to release the handle twice" << endl;
4155       CHECKN(trans->releaseLockHandle(lh) == 0, trans, NDBT_FAILED);
4156 
4157       if ((trans->releaseLockHandle(lh) != -1) ||
4158           (trans->getNdbError().code != 4551))
4159       {
4160         ndbout << "Expected 4551, but got no error " << endl;
4161         ndbout << " at "<<__FILE__ << ":" <<__LINE__ << endl;
4162         return NDBT_FAILED;
4163       }
4164 
4165       trans->close();
4166       break;
4167     default:
4168       abort();
4169       break;
4170     }
4171   } // for (Uint32 iter
4172 
4173   return NDBT_OK;
4174 }
4175 
runTestUnlockRepeat(NDBT_Context * ctx,NDBT_Step * step)4176 int runTestUnlockRepeat(NDBT_Context* ctx, NDBT_Step* step)
4177 {
4178   /* Transaction A locks 2 rows
4179    * It repeatedly unlocks and re-locks one row, but leaves
4180    * the other locked
4181    * Transaction B verifies that it can only lock the unlocked
4182    * row when it is unlocked, and can never lock the row which
4183    * is never unlocked!
4184    */
4185 
4186   const NdbDictionary::Table* pTab = ctx->getTab();
4187 
4188   HugoOperations hugoOps(*pTab);
4189 
4190   const Uint32 outerLoops = 2;
4191   const Uint32 iterations = 10;
4192 
4193   Ndb* ndb = GETNDB(step);
4194 
4195   /* Transaction A will take a lock on otherRowNum and hold it
4196    * throughout.
4197    * RowNum will be locked and unlocked each iteration
4198    */
4199   Uint32 otherRowNum = ctx->getNumRecords() - 1;
4200 
4201   for (Uint32 outerLoop = 0; outerLoop < outerLoops; outerLoop ++)
4202   {
4203     NdbTransaction* transA = ndb->startTransaction();
4204     CHECKN(transA != NULL, ndb, NDBT_FAILED);
4205 
4206     NdbOperation::LockMode lockAOtherMode;
4207     ndbout << "TransA : Try to lock otherRowNum in mode ";
4208 
4209     switch (outerLoop % 2) {
4210     case 0:
4211       ndbout << "LM_Exclusive" << endl;
4212       lockAOtherMode = NdbOperation::LM_Exclusive;
4213       break;
4214     default:
4215       ndbout << "LM_Read" << endl;
4216       lockAOtherMode = NdbOperation::LM_Read;
4217       break;
4218     }
4219 
4220     NdbOperation* lockAOtherRowNum = defineReadAllColsOp(&hugoOps,
4221                                                          transA,
4222                                                          pTab,
4223                                                          lockAOtherMode,
4224                                                          otherRowNum);
4225     CHECKN(lockAOtherRowNum != NULL, transA, NDBT_FAILED);
4226 
4227     CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4228 
4229     ndbout << "TransA : Got initial lock on otherRowNum" << endl;
4230 
4231     for (Uint32 iter = 0; iter < iterations; iter++)
4232     {
4233       Uint32 rowNum = iter % (ctx->getNumRecords() - 1);
4234 
4235       ndbout << "  TransA : Try to lock rowNum with mode ";
4236       NdbOperation::LockMode lockAMode = chooseLockMode(true); // Exclusive or LM_Read
4237 
4238       /* Transaction A takes a lock on rowNum */
4239       NdbOperation* lockARowNum = defineReadAllColsOp(&hugoOps,
4240                                                       transA,
4241                                                       pTab,
4242                                                       lockAMode,
4243                                                       rowNum);
4244       CHECKN(lockARowNum != NULL, transA, NDBT_FAILED);
4245 
4246       const NdbLockHandle* lockAHandle = lockARowNum->getLockHandle();
4247       CHECKN(lockAHandle != NULL, lockARowNum, NDBT_FAILED);
4248 
4249       CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4250 
4251       ndbout << "    TransA : Got lock on rowNum" << endl;
4252 
4253       /* Now transaction B checks that it cannot get a conflicting lock
4254        * on rowNum
4255        */
4256       ndbout << "  TransB : Try to lock rowNum by ";
4257 
4258       CHECK(checkReadDeadlocks(&hugoOps,
4259                                ndb,
4260                                pTab,
4261                                chooseConflictingLockMode(lockAMode),
4262                                rowNum));
4263 
4264       ndbout << "    TransB : Failed to get lock on rowNum as expected" << endl;
4265 
4266       /* Now transaction A unlocks rowNum */
4267       const NdbOperation* unlockOpA = transA->unlock(lockAHandle);
4268       CHECKN(unlockOpA != NULL, transA, NDBT_FAILED);
4269 
4270       CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4271 
4272       ndbout << "  TransA : Unlocked rowNum" << endl;
4273 
4274       /* Now transaction B attempts to gain a lock on RowNum */
4275       NdbTransaction* transB = ndb->startTransaction();
4276       CHECKN(transB != NULL, ndb, NDBT_FAILED);
4277 
4278       ndbout << "  TransB : Try to lock rowNum with mode ";
4279       NdbOperation::LockMode lockBMode = chooseLockMode(true);
4280 
4281       NdbOperation* tryLockBRowNum2 = defineReadAllColsOp(&hugoOps,
4282                                                           transB,
4283                                                           pTab,
4284                                                           lockBMode,
4285                                                           rowNum);
4286       CHECKN(tryLockBRowNum2 != NULL, transB, NDBT_FAILED);
4287 
4288       CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4289 
4290       ndbout << "    TransB : Got lock on rowNum" << endl;
4291 
4292       ndbout << "  TransB : Try to lock other row by ";
4293       NdbOperation::LockMode lockBOtherMode = chooseConflictingLockMode(lockAOtherMode);
4294 
4295       /* Now transaction B attempts to gain a lock on OtherRowNum
4296        * which should fail as transaction A still has it locked
4297        */
4298       NdbOperation* tryLockBOtherRowNum = defineReadAllColsOp(&hugoOps,
4299                                                               transB,
4300                                                               pTab,
4301                                                               lockBOtherMode,
4302                                                               otherRowNum);
4303       CHECKN(tryLockBOtherRowNum != NULL, transB, NDBT_FAILED);
4304 
4305       CHECKN(transB->execute(NoCommit) == -1, transB, NDBT_FAILED);
4306 
4307       if (transB->getNdbError().code != 266)
4308       {
4309         ndbout << "Error was expecting 266, but got " << transB->getNdbError() << endl;
4310         ndbout << "At line " << __LINE__ << endl;
4311         return NDBT_FAILED;
4312       }
4313 
4314       ndbout << "    TransB : Failed to get lock on otherRowNum as expected" << endl;
4315 
4316       transB->close();
4317     }
4318 
4319     transA->close();
4320   }
4321 
4322   return NDBT_OK;
4323 }
4324 
4325 
runTestUnlockMulti(NDBT_Context * ctx,NDBT_Step * step)4326 int runTestUnlockMulti(NDBT_Context* ctx, NDBT_Step* step)
4327 {
4328   const NdbDictionary::Table* pTab = ctx->getTab();
4329 
4330   /* Verifies that a single transaction (or multiple
4331    * transactions) taking multiple locks on the same
4332    * row using multiple operations behaves correctly
4333    * as the operations unlock their locks.
4334    *
4335    * Transaction A will lock the row to depth A
4336    * Transaction A may use an exclusive lock as its first lock
4337    * Transaction B will lock the row to depth B
4338    *   iff transaction A did not use exclusive locks
4339    *
4340    * Once all locks are in place, the locks placed are
4341    * removed.
4342    * The code checks that the row remains locked until
4343    * all locking operations are unlocked
4344    * The code checks that the row is unlocked when all
4345    * locking operations are unlocked.
4346    *
4347    * Depth A and B and whether A uses exclusive or not
4348    * are varied.
4349    */
4350 
4351   HugoOperations hugoOps(*pTab);
4352 
4353   const Uint32 MinLocks = 3;
4354   const Uint32 MaxLocksPerTrans = 20;
4355   Uint32 rowNum = ctx->getNumRecords() - 1;
4356   Uint32 numLocksInTransA = rand() % MaxLocksPerTrans;
4357   numLocksInTransA = (numLocksInTransA > MinLocks) ?
4358     numLocksInTransA : MinLocks;
4359   bool useExclusiveInA = ((rand() % 2) == 0);
4360 
4361   Uint32 numLocksInTransB = useExclusiveInA ? 0 :
4362     (rand() % MaxLocksPerTrans);
4363 
4364   Uint32 maxLocks = (numLocksInTransA > numLocksInTransB) ?
4365     numLocksInTransA : numLocksInTransB;
4366 
4367   ndbout << "NumLocksInTransA " << numLocksInTransA
4368          << " NumLocksInTransB " << numLocksInTransB
4369          << " useExclusiveInA " << useExclusiveInA
4370          << endl;
4371 
4372   NdbOperation* transAOps[ MaxLocksPerTrans ];
4373   NdbOperation* transBOps[ MaxLocksPerTrans ];
4374 
4375   /* First the lock phase when transA and transB
4376    * claim locks (with LockHandles)
4377    * As this occurs, transC attempts to obtain
4378    * a conflicting lock and fails.
4379    */
4380   Ndb* ndb = GETNDB(step);
4381 
4382   NdbTransaction* transA = ndb->startTransaction();
4383   CHECKN(transA != NULL, ndb, NDBT_FAILED);
4384 
4385   NdbTransaction* transB = ndb->startTransaction();
4386   CHECKN(transB != NULL, ndb, NDBT_FAILED);
4387 
4388   ndbout << "Locking phase" << endl << endl;
4389   for(Uint32 depth=0; depth < maxLocks; depth++)
4390   {
4391     ndbout << "Depth " << depth << endl;
4392     NdbOperation::LockMode lmA;
4393     /* TransA */
4394     if (depth < numLocksInTransA)
4395     {
4396       ndbout << "  TransA : Locking with mode ";
4397       if ((depth == 0) && useExclusiveInA)
4398       {
4399         lmA = NdbOperation::LM_Exclusive;
4400         ndbout << "LM_Exclusive" << endl;
4401       }
4402       else if (!useExclusiveInA)
4403       {
4404         lmA = NdbOperation::LM_Read;
4405         ndbout << "LM_Read" << endl;
4406       }
4407       else
4408       {
4409         lmA = chooseLockMode(true); // LM_Exclusive or LM_Read;
4410       }
4411 
4412       NdbOperation* lockA = defineReadAllColsOp(&hugoOps,
4413                                                 transA,
4414                                                 pTab,
4415                                                 lmA,
4416                                                 rowNum);
4417       CHECKN(lockA != NULL, transA, NDBT_FAILED);
4418       CHECKN(lockA->getLockHandle() != NULL, lockA, NDBT_FAILED);
4419 
4420       transAOps[ depth ] = lockA;
4421 
4422       CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4423       ndbout << "  TransA : Succeeded" << endl;
4424     }
4425 
4426     /* TransB */
4427     if (depth < numLocksInTransB)
4428     {
4429       ndbout << "  TransB : Locking with mode LM_Read" << endl;
4430 
4431       NdbOperation* lockB = defineReadAllColsOp(&hugoOps,
4432                                                 transB,
4433                                                 pTab,
4434                                                 NdbOperation::LM_Read,
4435                                                 rowNum);
4436       CHECKN(lockB != NULL, transB, NDBT_FAILED);
4437       CHECKN(lockB->getLockHandle() != NULL, lockB, NDBT_FAILED);
4438 
4439       transBOps[ depth ] = lockB;
4440 
4441       CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4442       ndbout << "  TransB : Succeeded" << endl;
4443     }
4444   }
4445 
4446   ndbout << "Unlocking phase" << endl << endl;
4447 
4448   for(Uint32 depth = 0; depth < maxLocks; depth++)
4449   {
4450     Uint32 level = maxLocks - depth - 1;
4451 
4452     ndbout << "Depth " << level << endl;
4453 
4454     ndbout << "  TransC : Trying to lock row with lockmode ";
4455     NdbOperation::LockMode lmC;
4456     if (useExclusiveInA)
4457     {
4458       lmC = chooseLockMode(true); // LM_Exclusive or LM_Read;
4459     }
4460     else
4461     {
4462       ndbout << "LM_Exclusive" << endl;
4463       lmC = NdbOperation::LM_Exclusive;
4464     }
4465 
4466     CHECK(checkReadDeadlocks(&hugoOps,
4467                              ndb,
4468                              pTab,
4469                              lmC,
4470                              rowNum));
4471 
4472     ndbout << "  TransC failed as expected" << endl;
4473 
4474     if (level < numLocksInTransB)
4475     {
4476       const NdbLockHandle* lockHandleB = transBOps[ level ]->getLockHandle();
4477       CHECKN(lockHandleB != NULL, transBOps[ level ], NDBT_FAILED);
4478 
4479       const NdbOperation* unlockB = transB->unlock(lockHandleB);
4480       CHECKN(unlockB != NULL, transB, NDBT_FAILED);
4481 
4482       CHECKN(transB->execute(NoCommit) == 0, transB, NDBT_FAILED);
4483       ndbout << "  TransB unlock succeeded" << endl;
4484     }
4485 
4486     if (level < numLocksInTransA)
4487     {
4488       const NdbLockHandle* lockHandleA = transAOps[ level ]->getLockHandle();
4489       CHECKN(lockHandleA != NULL, transAOps[ level ], NDBT_FAILED);
4490 
4491       const NdbOperation* unlockA = transA->unlock(lockHandleA);
4492       CHECKN(unlockA != NULL, transA, NDBT_FAILED);
4493 
4494       CHECKN(transA->execute(NoCommit) == 0, transA, NDBT_FAILED);
4495       ndbout << "  TransA unlock succeeded" << endl;
4496     }
4497   }
4498 
4499 
4500   /* Finally, all are unlocked and transC can successfully
4501    * obtain a conflicting lock
4502    */
4503   CHECK(checkReadSucceeds(&hugoOps,
4504                           ndb,
4505                           pTab,
4506                           NdbOperation::LM_Exclusive,
4507                           rowNum));
4508 
4509   ndbout << "TransC LM_Exclusive lock succeeded" << endl;
4510 
4511   transA->close();
4512   transB->close();
4513 
4514   return NDBT_OK;
4515 }
4516 
4517 
runTestUnlockScan(NDBT_Context * ctx,NDBT_Step * step)4518 int runTestUnlockScan(NDBT_Context* ctx, NDBT_Step* step)
4519 {
4520   /* Performs a table scan with LM_Read or LM_Exclusive
4521    * and lock takeovers for a number of the rows returned
4522    * Validates that some of the taken-over locks are held
4523    * before unlocking them and validating that they
4524    * are released.
4525    */
4526   const NdbDictionary::Table* pTab = ctx->getTab();
4527 
4528   HugoCalculator calc(*pTab);
4529   HugoOperations hugoOps(*pTab);
4530 
4531   /*
4532      1) Perform scan of the table with LM_Read / LM_Exclusive
4533      2) Takeover some of the rows with read and lockinfo
4534      3) Unlock the rows
4535      4) Check that they are unlocked
4536   */
4537   Ndb* ndb = GETNDB(step);
4538 
4539   const int iterations = 2;
4540 
4541   const int maxNumTakeovers = 15;
4542   NdbOperation* takeoverOps[ maxNumTakeovers ];
4543   Uint32 takeoverColIds[ maxNumTakeovers ];
4544 
4545   int numTakeovers = MIN(maxNumTakeovers, ctx->getNumRecords());
4546   int takeoverMod = ctx->getNumRecords() / numTakeovers;
4547 
4548   ndbout << "numTakeovers is " << numTakeovers
4549          << " takeoverMod is " << takeoverMod << endl;
4550 
4551   for (int iter = 0; iter < iterations; iter++)
4552   {
4553     ndbout << "Scanning table with lock mode : ";
4554     NdbOperation::LockMode lmScan = chooseLockMode(true); // LM_Exclusive or LM_Read
4555 
4556     NdbTransaction* trans = ndb->startTransaction();
4557     CHECKN(trans != NULL, ndb, NDBT_FAILED);
4558 
4559     /* Define scan */
4560     NdbScanOperation* scan = trans->getNdbScanOperation(pTab);
4561     CHECKN(scan != NULL, trans, NDBT_FAILED);
4562 
4563     Uint32 scanFlags = NdbScanOperation::SF_KeyInfo;
4564 
4565     CHECKN(scan->readTuples(lmScan, scanFlags) == 0, scan, NDBT_FAILED);
4566 
4567     NdbRecAttr* idColRecAttr = NULL;
4568 
4569     for(int c = 0; c < pTab->getNoOfColumns(); c++)
4570     {
4571       NdbRecAttr* ra = scan->getValue(pTab->getColumn(c)->getName());
4572       CHECKN(ra != NULL, scan, NDBT_FAILED);
4573       if (calc.isIdCol(c))
4574       {
4575         CHECK(idColRecAttr == NULL);
4576         idColRecAttr = ra;
4577       }
4578     }
4579     CHECK(idColRecAttr != NULL);
4580 
4581     CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4582 
4583     int rowsRead = 0;
4584     int rowsTakenover = 0;
4585     while (scan->nextResult(true) == 0)
4586     {
4587       if ((rowsTakenover < maxNumTakeovers) &&
4588           (0 == (rowsRead % takeoverMod)))
4589       {
4590         /* We're going to take the lock for this row into
4591          * a separate operation
4592          */
4593         Uint32 rowId = idColRecAttr->u_32_value();
4594         ndbout << "  Taking over lock on result num " << rowsRead
4595                << " row (" << rowId << ")" << endl;
4596         NdbOperation* readTakeoverOp = scan->lockCurrentTuple();
4597         CHECKN(readTakeoverOp != NULL, scan, NDBT_FAILED);
4598 
4599         CHECKN(readTakeoverOp->getLockHandle() != NULL, readTakeoverOp, NDBT_FAILED);
4600         takeoverOps[ rowsTakenover ] = readTakeoverOp;
4601         takeoverColIds[ rowsTakenover ] = rowId;
4602 
4603         CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4604 
4605         CHECKN(readTakeoverOp->getNdbError().code == 0, readTakeoverOp, NDBT_FAILED);
4606 
4607 // // Uncomment to check that takeover keeps lock.
4608 //         if (0 == (rowsTakenover % 7))
4609 //         {
4610 //           ndbout << "  Validating taken-over lock holds on rowid "
4611 //                  << takeoverColIds[ rowsTakenover ]
4612 //                  << " by ";
4613 //           /* Occasionally validate the lock held by the scan */
4614 //           CHECK(checkReadDeadlocks(&hugoOps,
4615 //                                    ndb,
4616 //                                    pTab,
4617 //                                    chooseConflictingLockMode(lmScan),
4618 //                                    takeoverColIds[ rowsTakenover ]));
4619 //         }
4620 
4621         rowsTakenover ++;
4622 
4623       }
4624 
4625       rowsRead ++;
4626     }
4627 
4628     scan->close();
4629 
4630     ndbout << "Scan complete : rows read : " << rowsRead
4631            << " rows locked : " << rowsTakenover << endl;
4632 
4633     ndbout << "Now unlocking rows individually" << endl;
4634     for (int lockedRows = 0; lockedRows < rowsTakenover; lockedRows ++)
4635     {
4636       if (0 == (lockedRows % 3))
4637       {
4638         ndbout << "  First validating that lock holds on rowid "
4639                << takeoverColIds[ lockedRows ]
4640                << " by ";
4641         /* Occasionally check that the lock held by the scan still holds */
4642         CHECK(checkReadDeadlocks(&hugoOps,
4643                                  ndb,
4644                                  pTab,
4645                                  chooseConflictingLockMode(lmScan),
4646                                  takeoverColIds[ lockedRows ]));
4647         ndbout << "  Lock is held" << endl;
4648       }
4649 
4650       /* Unlock the row */
4651       const NdbLockHandle* lockHandle = takeoverOps[ lockedRows ]->getLockHandle();
4652       CHECKN(lockHandle != NULL, takeoverOps[ lockedRows ], NDBT_FAILED);
4653 
4654       const NdbOperation* unlockOp = trans->unlock(lockHandle);
4655       CHECKN(unlockOp, trans, NDBT_FAILED);
4656 
4657       CHECKN(trans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4658 
4659       /* Now check that the row's unlocked */
4660       CHECK(checkReadSucceeds(&hugoOps,
4661                               ndb,
4662                               pTab,
4663                               NdbOperation::LM_Exclusive,
4664                               takeoverColIds[ lockedRows ]));
4665       ndbout << "  Row " << takeoverColIds[ lockedRows ]
4666              << " unlocked successfully" << endl;
4667     }
4668 
4669     /* Lastly, verify that scan with LM_Exclusive in separate transaction
4670      * can scan whole table without locking on anything
4671      */
4672     ndbout << "Validating unlocking code with LM_Exclusive table scan" << endl;
4673 
4674     NdbTransaction* otherTrans = ndb->startTransaction();
4675     CHECKN(otherTrans != NULL, ndb, NDBT_FAILED);
4676 
4677     NdbScanOperation* otherScan = otherTrans->getNdbScanOperation(pTab);
4678     CHECKN(otherScan != NULL, otherTrans, NDBT_FAILED);
4679 
4680     CHECKN(otherScan->readTuples(NdbOperation::LM_Exclusive) == 0, otherScan, NDBT_FAILED);
4681 
4682     for(int c = 0; c < pTab->getNoOfColumns(); c++)
4683     {
4684       NdbRecAttr* ra = otherScan->getValue(pTab->getColumn(c)->getName());
4685       CHECKN(ra != NULL, otherScan, NDBT_FAILED);
4686     }
4687 
4688     CHECKN(otherTrans->execute(NoCommit) == 0, trans, NDBT_FAILED);
4689 
4690     int nextRc = 0;
4691     while (0 == (nextRc = otherScan->nextResult(true)))
4692     {};
4693 
4694     if (nextRc != 1)
4695     {
4696       ndbout << "Final scan with lock did not complete successfully" << endl;
4697       ndbout << otherScan->getNdbError() << endl;
4698       ndbout << "at line " << __LINE__ << endl;
4699       return NDBT_FAILED;
4700     }
4701 
4702     otherScan->close();
4703     otherTrans->close();
4704 
4705     ndbout << "All locked rows unlocked" << endl;
4706 
4707     trans->close();
4708   }
4709 
4710   return NDBT_OK;
4711 }
4712 
4713 #include <NdbMgmd.hpp>
4714 
4715 class NodeIdReservations {
4716   bool m_ids[MAX_NODES];
4717   NdbMutex m_mutex;
4718 public:
lock(unsigned id)4719   void lock(unsigned id)
4720   {
4721     require(id < NDB_ARRAY_SIZE(m_ids));
4722     NdbMutex_Lock(&m_mutex);
4723     //ndbout  << "locking nodeid: " << id << endl;
4724     if (m_ids[id])
4725     {
4726       //already locked!
4727       g_err << "Nodeid " << id << " is already locked! Crashing!" << endl;
4728       abort();
4729     }
4730     m_ids[id] = true;
4731     NdbMutex_Unlock(&m_mutex);
4732   }
4733 
unlock(unsigned id)4734   void unlock(unsigned id)
4735   {
4736     require(id < NDB_ARRAY_SIZE(m_ids));
4737     NdbMutex_Lock(&m_mutex);
4738     //ndbout  << "unlocking nodeid: " << id << endl;
4739     if (!m_ids[id])
4740     {
4741       //already unlocked!
4742       abort();
4743     }
4744     m_ids[id] = false;
4745     NdbMutex_Unlock(&m_mutex);
4746   }
4747 
NodeIdReservations()4748   NodeIdReservations() {
4749     bzero(m_ids, sizeof(m_ids));
4750     NdbMutex_Init(&m_mutex);
4751   }
4752 
4753   class Reserve {
4754     unsigned m_id;
4755     NodeIdReservations& m_res;
4756 
4757     Reserve(); // Not impl.
4758     Reserve(const Reserve&); // Not impl.
4759   public:
Reserve(NodeIdReservations & res,unsigned id)4760     Reserve(NodeIdReservations& res, unsigned id) :
4761         m_id(id), m_res(res) {
4762       m_res.lock(m_id);
4763     }
4764 
unlock()4765     void unlock() {
4766       m_res.unlock(m_id);
4767       m_id = 0;
4768     }
4769 
~Reserve()4770     ~Reserve(){
4771       if (m_id)
4772       {
4773         m_res.unlock(m_id);
4774       }
4775     }
4776   };
4777 };
4778 
4779 NodeIdReservations g_reservations;
4780 
4781 
runNdbClusterConnectInit(NDBT_Context * ctx,NDBT_Step * step)4782 int runNdbClusterConnectInit(NDBT_Context* ctx, NDBT_Step* step)
4783 {
4784   // Find number of unconnected API nodes slot to use for test
4785   Uint32 api_nodes = 0;
4786   {
4787     NdbMgmd mgmd;
4788 
4789     if (!mgmd.connect())
4790       return NDBT_FAILED;
4791 
4792     ndb_mgm_node_type
4793       node_types[2] = { NDB_MGM_NODE_TYPE_API,
4794                         NDB_MGM_NODE_TYPE_UNKNOWN };
4795 
4796     ndb_mgm_cluster_state *cs = ndb_mgm_get_status2(mgmd.handle(), node_types);
4797     if (cs == NULL)
4798     {
4799       printf("ndb_mgm_get_status2 failed, error: %d - %s\n",
4800              ndb_mgm_get_latest_error(mgmd.handle()),
4801              ndb_mgm_get_latest_error_msg(mgmd.handle()));
4802       return NDBT_FAILED;
4803     }
4804 
4805     for(int i = 0; i < cs->no_of_nodes; i++ )
4806     {
4807       ndb_mgm_node_state *ns = cs->node_states + i;
4808       require(ns->node_type == NDB_MGM_NODE_TYPE_API);
4809       if (ns->node_status == NDB_MGM_NODE_STATUS_CONNECTED)
4810       {
4811         // Node is already connected, don't use in test
4812         continue;
4813       }
4814       api_nodes++;
4815     }
4816     free(cs);
4817   }
4818 
4819   if (api_nodes <= 1)
4820   {
4821     ndbout << "Too few API node slots available, failing test" << endl;
4822     return NDBT_FAILED;
4823   }
4824   // Don't try to use nodeid allocated by main cluster connection
4825   api_nodes--;
4826 
4827   ndbout << "Found " << api_nodes << " unconnected API nodes" << endl;
4828   ctx->setProperty("API_NODES", api_nodes);
4829   return NDBT_OK;
4830 }
4831 
4832 
runNdbClusterConnect(NDBT_Context * ctx,NDBT_Step * step)4833 int runNdbClusterConnect(NDBT_Context* ctx, NDBT_Step* step)
4834 {
4835   const Uint32 api_nodes = ctx->getProperty("API_NODES");
4836   const Uint32 step_no = step->getStepNo();
4837   const Uint32 timeout_after_first_alive = ctx->getProperty("TimeoutAfterFirst",
4838                                                             30);
4839   if (step_no > api_nodes)
4840   {
4841     // Don't run with more threads than API node slots
4842     return NDBT_OK;
4843   }
4844 
4845   // Get connectstring from main connection
4846   char constr[256];
4847   if (!ctx->m_cluster_connection.get_connectstring(constr,
4848                                                    sizeof(constr)))
4849   {
4850     g_err << "Too short buffer for connectstring" << endl;
4851     return NDBT_FAILED;
4852   }
4853 
4854   Uint32 l = 0;
4855   const Uint32 loops = ctx->getNumLoops();
4856   while (l < loops && !ctx->isTestStopped())
4857   {
4858     g_info << "loop: " << l << endl;
4859     if (ctx->getProperty("WAIT") > 0)
4860     {
4861       ndbout_c("thread %u waiting", step_no);
4862       ctx->incProperty("WAITING");
4863       while (ctx->getProperty("WAIT") > 0 && !ctx->isTestStopped())
4864         NdbSleep_MilliSleep(10);
4865       ndbout_c("thread %u waiting complete", step_no);
4866     }
4867     Ndb_cluster_connection con(constr);
4868 
4869     const int retries = 12;
4870     const int retry_delay = 5;
4871     const int verbose = 1;
4872     if (con.connect(retries, retry_delay, verbose) != 0)
4873     {
4874       g_err << "Ndb_cluster_connection.connect failed" << endl;
4875       return NDBT_FAILED;
4876     }
4877 
4878     // Check that the connection got a unique nodeid
4879     NodeIdReservations::Reserve res(g_reservations, con.node_id());
4880 
4881     const int timeout = 30;
4882     int ret = con.wait_until_ready(timeout, timeout_after_first_alive);
4883     if (! (ret == 0 || (timeout_after_first_alive == 0 && ret > 0)))
4884     {
4885       g_err << "Cluster connection was not ready, nodeid: "
4886             << con.node_id() << endl;
4887       abort();
4888       return NDBT_FAILED;
4889     }
4890 
4891     // Create and init Ndb object
4892     Ndb ndb(&con, "TEST_DB");
4893     if (ndb.init() != 0)
4894     {
4895       NDB_ERR(ndb.getNdbError());
4896       return NDBT_FAILED;
4897     }
4898 
4899     const int max_sleep = 25;
4900     NdbSleep_MilliSleep(10 + rand() % max_sleep);
4901 
4902     l++;
4903     res.unlock(); // make sure it's called before ~Ndb_cluster_connection
4904   }
4905 
4906   ctx->incProperty("runNdbClusterConnect_FINISHED");
4907 
4908   return NDBT_OK;
4909 }
4910 
4911 int
runRestarts(NDBT_Context * ctx,NDBT_Step * step)4912 runRestarts(NDBT_Context* ctx, NDBT_Step* step)
4913 {
4914   int result = NDBT_OK;
4915   Uint32 threads = ctx->getProperty("API_NODES", (unsigned)0);
4916   Uint32 sr = ctx->getProperty("ClusterRestart", (unsigned)0);
4917   Uint32 master = ctx->getProperty("Master", (unsigned)0);
4918   Uint32 slow = ctx->getProperty("SlowNR", (unsigned)0);
4919   NdbRestarter restarter;
4920 
4921   if (restarter.waitClusterStarted() != 0)
4922   {
4923     g_err << "Cluster failed to start" << endl;
4924     return NDBT_FAILED;
4925   }
4926 
4927   if (sr == 0 && restarter.getNumDbNodes() < 2)
4928     return NDBT_OK;
4929 
4930   while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads
4931          && !ctx->isTestStopped())
4932   {
4933     ndbout_c("%u %u",
4934              ctx->getProperty("runNdbClusterConnect_FINISHED"),
4935              threads);
4936     if (sr == 0)
4937     {
4938       int id = rand() % restarter.getNumDbNodes();
4939       int nodeId = restarter.getDbNodeId(id);
4940       if (master == 1)
4941       {
4942         nodeId = restarter.getMasterNodeId();
4943       }
4944       else if (master == 2)
4945       {
4946         nodeId = restarter.getRandomNotMasterNodeId(rand());
4947       }
4948       ndbout << "Restart node " << nodeId
4949              << "(master: " << restarter.getMasterNodeId() << ")"
4950              << endl;
4951       if (restarter.restartOneDbNode(nodeId, false, true, true) != 0)
4952       {
4953         g_err << "Failed to restartNextDbNode" << endl;
4954         result = NDBT_FAILED;
4955         break;
4956       }
4957 
4958       if (restarter.waitNodesNoStart(&nodeId, 1))
4959       {
4960         g_err << "Failed to waitNodesNoStart" << endl;
4961         result = NDBT_FAILED;
4962         break;
4963       }
4964 
4965       if (slow)
4966       {
4967         /**
4968          * Block starting node in sp4
4969          */
4970         int dump[] = { 71, 4 };
4971         restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump));
4972       }
4973 
4974       if (restarter.startNodes(&nodeId, 1))
4975       {
4976         g_err << "Failed to start node" << endl;
4977         result = NDBT_FAILED;
4978         break;
4979       }
4980 
4981       if (slow)
4982       {
4983         Uint32 blockTime = 3 * 60 * 1000;
4984         Uint64 end = NdbTick_CurrentMillisecond() + blockTime;
4985         while (ctx->getProperty("runNdbClusterConnect_FINISHED") < threads
4986                && !ctx->isTestStopped() &&
4987                NdbTick_CurrentMillisecond() < end)
4988         {
4989           NdbSleep_MilliSleep(100);
4990         }
4991 
4992         // unblock
4993         int dump[] = { 71 };
4994         restarter.dumpStateOneNode(nodeId, dump, NDB_ARRAY_SIZE(dump));
4995       }
4996     }
4997     else
4998     {
4999       ndbout << "Blocking threads" << endl;
5000       ctx->setProperty("WAITING", Uint32(0));
5001       ctx->setProperty("WAIT", 1);
5002       while (ctx->getProperty("WAITING") <
5003              (threads - ctx->getProperty("runNdbClusterConnect_FINISHED")) &&
5004              !ctx->isTestStopped())
5005       {
5006         NdbSleep_MilliSleep(10);
5007       }
5008 
5009       ndbout << "Restart cluster" << endl;
5010       if (restarter.restartAll2(Uint32(NdbRestarter::NRRF_NOSTART |
5011                                        NdbRestarter::NRRF_ABORT)) != 0)
5012       {
5013         g_err << "Failed to restartAll" << endl;
5014         result = NDBT_FAILED;
5015         break;
5016       }
5017 
5018       ctx->setProperty("WAITING", Uint32(0));
5019       ctx->setProperty("WAIT", Uint32(0));
5020 
5021       ndbout << "Starting cluster" << endl;
5022       restarter.startAll();
5023     }
5024 
5025     if (restarter.waitClusterStarted() != 0)
5026     {
5027       g_err << "Cluster failed to start" << endl;
5028       result = NDBT_FAILED;
5029       break;
5030     }
5031   }
5032 
5033   return result;
5034 }
5035 
runCheckAllNodesStarted(NDBT_Context * ctx,NDBT_Step * step)5036 int runCheckAllNodesStarted(NDBT_Context* ctx, NDBT_Step* step){
5037   NdbRestarter restarter;
5038 
5039   if (restarter.waitClusterStarted(1) != 0)
5040   {
5041     g_err << "All nodes was not started " << endl;
5042     return NDBT_FAILED;
5043   }
5044 
5045   return NDBT_OK;
5046 }
5047 
5048 
5049 
5050 static bool
check_connect_no_such_host()5051 check_connect_no_such_host()
5052 {
5053   for (int i = 0; i < 3; i++)
5054   {
5055     const char* no_such_host = "no_such_host:1186";
5056     Ndb_cluster_connection con(no_such_host);
5057 
5058     const int verbose = 1;
5059     int res = con.connect(i, i, verbose);
5060     if (res != 1)
5061     {
5062       g_err << "Ndb_cluster_connection.connect(" << i << "," << i
5063             << ", 1) to '" << no_such_host << "' returned " << res
5064             << " instead of expected 1" << endl;
5065       return false;
5066     }
5067     g_info << "Ndb_cluster_connection.connect(" << i << "," << i
5068            << ", 1) to '" << no_such_host << "' returned " << res
5069            << " and message '" << con.get_latest_error_msg() << "'"<< endl;
5070   }
5071   return true;
5072 }
5073 
5074 
5075 static bool
check_connect_until_no_more_nodeid(const char * constr)5076 check_connect_until_no_more_nodeid(const char* constr)
5077 {
5078   bool result = true;
5079   Vector<Ndb_cluster_connection*> connections;
5080   while(true)
5081   {
5082     Ndb_cluster_connection* con = new Ndb_cluster_connection(constr);
5083     if (!con)
5084     {
5085       g_err << "Failed to create another Ndb_cluster_connection" << endl;
5086       result = false;
5087       break;
5088     }
5089     connections.push_back(con);
5090     g_info << "connections: " << connections.size() << endl;
5091 
5092     const int verbose = 1;
5093     int res = con->connect(0, 0, verbose);
5094     if (res != 0)
5095     {
5096       g_info << "Ndb_cluster_connection.connect(0,0,1) returned " << res
5097              << " and error message set to : '" << con->get_latest_error_msg()
5098              << "'" << endl;
5099 
5100       if (res != 1)
5101       {
5102         // The error returned should be 1
5103         g_err << "Unexpected return code " << res << " returned" << endl;
5104         result = false;
5105       }
5106       else if (strstr(con->get_latest_error_msg(),
5107                       "No free node id found for mysqld(API)") == NULL)
5108       {
5109         // The error message should end with "No free node id
5110         // found for mysqld(API)" since this host is configured in the config
5111         g_err << "Unexpected error message " << con->get_latest_error_msg()
5112               << " returned" << endl;
5113         result = false;
5114       }
5115       else
5116       {
5117         ndbout << "check_connect_until_no_more_nodeid OK!" << endl;
5118       }
5119       break;
5120     }
5121   }
5122 
5123   while(connections.size())
5124   {
5125     Ndb_cluster_connection* con = connections[0];
5126     g_info << "releasing connection, size: " << connections.size() << endl;
5127     delete con;
5128     connections.erase(0);
5129   }
5130   require(connections.size() == 0);
5131 
5132   return result;
5133 }
5134 
5135 
runNdbClusterConnectionConnect(NDBT_Context * ctx,NDBT_Step * step)5136 int runNdbClusterConnectionConnect(NDBT_Context* ctx, NDBT_Step* step)
5137 {
5138   // Get connectstring from main connection
5139   char constr[256];
5140   if(!ctx->m_cluster_connection.get_connectstring(constr,
5141                                                   sizeof(constr)))
5142   {
5143     g_err << "Too short buffer for connectstring" << endl;
5144     return NDBT_FAILED;
5145   }
5146 
5147   if (!check_connect_no_such_host() ||
5148       !check_connect_until_no_more_nodeid(constr))
5149   {
5150     return NDBT_FAILED;
5151   }
5152 
5153   return NDBT_OK;
5154 }
5155 
5156 /* Testing fragmented signal send/receive */
5157 
5158 /*
5159   SectionStore
5160 
5161   Abstraction of long section storage api.
5162   Used by FragmentAssembler to assemble received long sections
5163 */
5164 class SectionStore
5165 {
5166 public:
~SectionStore()5167   virtual ~SectionStore() {};
5168   virtual int appendToSection(Uint32 secId, LinearSectionPtr ptr) = 0;
5169 };
5170 
5171 /*
5172   Basic Section Store
5173 
5174   Naive implementation using malloc.  Real usage might use something better.
5175 */
5176 class BasicSectionStore : public SectionStore
5177 {
5178 public:
BasicSectionStore()5179   BasicSectionStore()
5180   {
5181     init();
5182   };
5183 
~BasicSectionStore()5184   ~BasicSectionStore()
5185   {
5186     freeStorage();
5187   };
5188 
init()5189   void init()
5190   {
5191     ptrs[0].p = NULL;
5192     ptrs[0].sz = 0;
5193 
5194     ptrs[2] = ptrs[1] = ptrs[0];
5195   }
5196 
freeStorage()5197   void freeStorage()
5198   {
5199     free(ptrs[0].p);
5200     free(ptrs[1].p);
5201     free(ptrs[2].p);
5202   }
5203 
appendToSection(Uint32 secId,LinearSectionPtr ptr)5204   virtual int appendToSection(Uint32 secId, LinearSectionPtr ptr)
5205   {
5206     /* Potentially expensive re-alloc + copy */
5207     require(secId < 3);
5208 
5209     Uint32 existingSz = ptrs[secId].sz;
5210     Uint32* existingBuff = ptrs[secId].p;
5211 
5212     Uint32 newSize = existingSz + ptr.sz;
5213     Uint32* newBuff = (Uint32*) realloc(existingBuff, newSize * 4);
5214 
5215     if (!newBuff)
5216       return -1;
5217 
5218     memcpy(newBuff + existingSz, ptr.p, ptr.sz * 4);
5219 
5220     ptrs[secId].p = newBuff;
5221     ptrs[secId].sz = existingSz + ptr.sz;
5222 
5223     return 0;
5224   }
5225 
5226   LinearSectionPtr ptrs[3];
5227 };
5228 
5229 
5230 
5231 /*
5232   FragmentAssembler
5233 
5234   Used to assemble sections from multiple fragment signals, and
5235   produce a 'normal' signal.
5236 
5237   Requires a SectionStore implementation to accumulate the section
5238   fragments
5239 
5240   Might be useful generic utility, or not.
5241 
5242   Usage :
5243     FragmentAssembler fa(ss);
5244     while (!fa.isComplete())
5245     {
5246       sig = waitSignal();
5247       ss.handleSignal(sig, sections);
5248     }
5249 
5250     fa.getSignalHeader();
5251     fa.getSignalBody();
5252     fa.getSectionStore(); ..
5253 
5254 */
5255 class FragmentAssembler
5256 {
5257 public:
5258   enum AssemblyError
5259   {
5260     NoError = 0,
5261     FragmentSequence = 1,
5262     FragmentSource = 2,
5263     FragmentIdentity = 3,
5264     SectionAppend = 4
5265   };
5266 
FragmentAssembler(SectionStore * _secStore)5267   FragmentAssembler(SectionStore* _secStore):
5268     secsReceived(0),
5269     secStore(_secStore),
5270     complete(false),
5271     fragId(0),
5272     sourceNode(0),
5273     error(NoError)
5274   {}
5275 
handleSignal(const SignalHeader * sigHead,const Uint32 * sigBody,LinearSectionPtr * sections)5276   int handleSignal(const SignalHeader* sigHead,
5277                    const Uint32* sigBody,
5278                    LinearSectionPtr* sections)
5279   {
5280     Uint32 sigLen = sigHead->theLength;
5281 
5282     if (fragId == 0)
5283     {
5284       switch (sigHead->m_fragmentInfo)
5285       {
5286       case 0:
5287       {
5288         /* Not fragmented, pass through */
5289         sh = *sigHead;
5290         memcpy(signalBody, sigBody, sigLen * 4);
5291         Uint32 numSecs = sigHead->m_noOfSections;
5292         for (Uint32 i=0; i<numSecs; i++)
5293         {
5294           if (secStore->appendToSection(i, sections[i]) != 0)
5295           {
5296             error = SectionAppend;
5297             return -1;
5298           }
5299         }
5300         complete = true;
5301         break;
5302       }
5303       case 1:
5304       {
5305         /* Start of fragmented signal */
5306         Uint32 incomingFragId;
5307         Uint32 incomingSourceNode;
5308         Uint32 numSecsInFragment;
5309 
5310         if (handleFragmentSections(sigHead, sigBody, sections,
5311                                    &incomingFragId, &incomingSourceNode,
5312                                    &numSecsInFragment) != 0)
5313           return -1;
5314 
5315         require(incomingFragId != 0);
5316         fragId = incomingFragId;
5317         sourceNode = incomingSourceNode;
5318         require(numSecsInFragment > 0);
5319 
5320         break;
5321       }
5322       default:
5323       {
5324         /* Error, out of sequence fragment */
5325         error = FragmentSequence;
5326         return -1;
5327         break;
5328       }
5329       }
5330     }
5331     else
5332     {
5333       /* FragId != 0 */
5334       switch (sigHead->m_fragmentInfo)
5335       {
5336       case 0:
5337       case 1:
5338       {
5339         /* Error, out of sequence fragment */
5340         error = FragmentSequence;
5341         return -1;
5342       }
5343       case 2:
5344         /* Fall through */
5345       case 3:
5346       {
5347         /* Body fragment */
5348         Uint32 incomingFragId;
5349         Uint32 incomingSourceNode;
5350         Uint32 numSecsInFragment;
5351 
5352         if (handleFragmentSections(sigHead, sigBody, sections,
5353                                    &incomingFragId, &incomingSourceNode,
5354                                    &numSecsInFragment) != 0)
5355           return -1;
5356 
5357         if (incomingSourceNode != sourceNode)
5358         {
5359           /* Error in source node */
5360           error = FragmentSource;
5361           return -1;
5362         }
5363         if (incomingFragId != fragId)
5364         {
5365           error = FragmentIdentity;
5366           return -1;
5367         }
5368 
5369         if (sigHead->m_fragmentInfo == 3)
5370         {
5371           /* Final fragment, contains actual signal body */
5372           memcpy(signalBody,
5373                  sigBody,
5374                  sigLen * 4);
5375           sh = *sigHead;
5376           sh.theLength = sigLen - (numSecsInFragment + 1);
5377           sh.m_noOfSections =
5378             ((secsReceived & 4)? 1 : 0) +
5379             ((secsReceived & 2)? 1 : 0) +
5380             ((secsReceived & 1)? 1 : 0);
5381           sh.m_fragmentInfo = 0;
5382 
5383           complete=true;
5384         }
5385         break;
5386       }
5387       default:
5388       {
5389         /* Bad fragmentinfo field */
5390         error = FragmentSequence;
5391         return -1;
5392       }
5393       }
5394     }
5395 
5396     return 0;
5397   }
5398 
handleSignal(NdbApiSignal * signal,LinearSectionPtr * sections)5399   int handleSignal(NdbApiSignal* signal,
5400                    LinearSectionPtr* sections)
5401   {
5402     return handleSignal(signal, signal->getDataPtr(), sections);
5403   }
5404 
isComplete()5405   bool isComplete()
5406   {
5407     return complete;
5408   }
5409 
5410   /* Valid if isComplete() */
getSignalHeader()5411   SignalHeader getSignalHeader()
5412   {
5413     return sh;
5414   }
5415 
5416   /* Valid if isComplete() */
getSignalBody()5417   Uint32* getSignalBody()
5418   {
5419     return signalBody;
5420   }
5421 
5422   /* Valid if isComplete() */
getSourceNode()5423   Uint32 getSourceNode()
5424   {
5425     return sourceNode;
5426   }
5427 
getSectionStore()5428   SectionStore* getSectionStore()
5429   {
5430     return secStore;
5431   }
5432 
getError() const5433   AssemblyError getError() const
5434   {
5435     return error;
5436   }
5437 
5438 private:
handleFragmentSections(const SignalHeader * sigHead,const Uint32 * sigBody,LinearSectionPtr * sections,Uint32 * incomingFragId,Uint32 * incomingSourceNode,Uint32 * numSecsInFragment)5439   int handleFragmentSections(const SignalHeader* sigHead,
5440                              const Uint32* sigBody,
5441                              LinearSectionPtr* sections,
5442                              Uint32* incomingFragId,
5443                              Uint32* incomingSourceNode,
5444                              Uint32* numSecsInFragment)
5445   {
5446     Uint32 sigLen = sigHead->theLength;
5447 
5448     *numSecsInFragment = sigHead->m_noOfSections;
5449     require(sigLen >= (1 + *numSecsInFragment));
5450 
5451     *incomingFragId = sigBody[sigLen - 1];
5452     *incomingSourceNode = refToNode(sigHead->theSendersBlockRef);
5453     const Uint32* secIds = &sigBody[sigLen - (*numSecsInFragment) - 1];
5454 
5455     for (Uint32 i=0; i < *numSecsInFragment; i++)
5456     {
5457       secsReceived |= (1 < secIds[i]);
5458 
5459       if (secStore->appendToSection(secIds[i], sections[i]) != 0)
5460       {
5461         error = SectionAppend;
5462         return -1;
5463       }
5464     }
5465 
5466     return 0;
5467   }
5468 
5469   Uint32 secsReceived;
5470   SectionStore* secStore;
5471   bool complete;
5472   Uint32 fragId;
5473   Uint32 sourceNode;
5474   SignalHeader sh;
5475   Uint32 signalBody[NdbApiSignal::MaxSignalWords];
5476   AssemblyError error;
5477 };
5478 
5479 static const Uint32 MAX_SEND_BYTES=32768; /* Align with TransporterDefinitions.hpp */
5480 static const Uint32 MAX_SEND_WORDS=MAX_SEND_BYTES/4;
5481 static const Uint32 SEGMENT_WORDS= 60; /* Align with SSPool etc */
5482 static const Uint32 SEGMENT_BYTES = SEGMENT_WORDS * 4;
5483 //static const Uint32 MAX_SEGS_PER_SEND=64; /* 6.3 */
5484 static const Uint32 MAX_SEGS_PER_SEND = (MAX_SEND_BYTES / SEGMENT_BYTES) - 2; /* Align with TransporterFacade.cpp */
5485 static const Uint32 MAX_WORDS_PER_SEND = MAX_SEGS_PER_SEND * SEGMENT_WORDS;
5486 static const Uint32 HALF_MAX_WORDS_PER_SEND = MAX_WORDS_PER_SEND / 2;
5487 static const Uint32 THIRD_MAX_WORDS_PER_SEND = MAX_WORDS_PER_SEND / 3;
5488 static const Uint32 MEDIUM_SIZE = 5000;
5489 
5490 /* Most problems occurred with sections lengths around the boundary
5491  * of the max amount sent - MAX_WORDS_PER_SEND, so we define interesting
5492  * sizes so that we test behavior around these boundaries
5493  */
5494 static Uint32 interestingSizes[] =
5495 {
5496   0,
5497   1,
5498   MEDIUM_SIZE,
5499   THIRD_MAX_WORDS_PER_SEND -1,
5500   THIRD_MAX_WORDS_PER_SEND,
5501   THIRD_MAX_WORDS_PER_SEND +1,
5502   HALF_MAX_WORDS_PER_SEND -1,
5503   HALF_MAX_WORDS_PER_SEND,
5504   HALF_MAX_WORDS_PER_SEND + 1,
5505   MAX_WORDS_PER_SEND -1,
5506   MAX_WORDS_PER_SEND,
5507   MAX_WORDS_PER_SEND + 1,
5508   (2* MAX_SEND_WORDS) + 1,
5509   1234 /* Random */
5510 };
5511 
5512 
5513 /*
5514    FragSignalChecker
5515 
5516    Class for testing fragmented signal send + receive
5517 */
5518 class FragSignalChecker
5519 {
5520 public:
5521 
5522   Uint32* buffer;
5523 
FragSignalChecker()5524   FragSignalChecker()
5525   {
5526     buffer= NULL;
5527     init();
5528   }
5529 
~FragSignalChecker()5530   ~FragSignalChecker()
5531   {
5532     free(buffer);
5533   }
5534 
init()5535   void init()
5536   {
5537     buffer = (Uint32*) malloc(getBufferSize());
5538 
5539     if (buffer)
5540     {
5541       /* Init to a known pattern */
5542       for (Uint32 i = 0; i < (getBufferSize()/4); i++)
5543       {
5544         buffer[i] = i;
5545       }
5546     }
5547   }
5548 
getNumInterestingSizes()5549   static Uint32 getNumInterestingSizes()
5550   {
5551     return sizeof(interestingSizes) / sizeof(Uint32);
5552   }
5553 
getNumIterationsRequired()5554   static Uint32 getNumIterationsRequired()
5555   {
5556     /* To get combinatorial coverage, need each of 3
5557      * sections with each of the interesting sizes
5558      */
5559     Uint32 numSizes = getNumInterestingSizes();
5560     return numSizes * numSizes * numSizes;
5561   }
5562 
getSecSz(Uint32 secNum,Uint32 iter)5563   static Uint32 getSecSz(Uint32 secNum, Uint32 iter)
5564   {
5565     require(secNum < 3);
5566     Uint32 numSizes = getNumInterestingSizes();
5567     Uint32 divisor = (secNum == 0 ? 1 :
5568                       secNum == 1 ? numSizes :
5569                       numSizes * numSizes);
5570     /* offset ensures only end sections are 0 length */
5571     Uint32 index = (iter / divisor) % numSizes;
5572     if ((index == 0) && (iter >= (divisor * numSizes)))
5573       index = 1; /* Avoid lower numbered section being empty */
5574     Uint32 value = interestingSizes[index];
5575     if(value == 1234)
5576     {
5577       value = 1 + (rand() % (2* MAX_WORDS_PER_SEND));
5578     }
5579     return value;
5580   }
5581 
getBufferSize()5582   static Uint32 getBufferSize()
5583   {
5584     const Uint32 MaxSectionWords = (2 * MAX_SEND_WORDS) + 1;
5585     const Uint32 MaxTotalSectionsWords = MaxSectionWords * 3;
5586     return MaxTotalSectionsWords * 4;
5587   }
5588 
sendRequest(SignalSender * ss,Uint32 * sizes)5589   int sendRequest(SignalSender* ss,
5590                   Uint32* sizes)
5591   {
5592     /*
5593      * We want to try out various interactions between the
5594      * 3 sections and the length of the data sent
5595      * - All fit in one 'chunk'
5596      * - None fit in one 'chunk'
5597      * - Each ends on a chunk boundary
5598      *
5599      * Max send size is ~ 32kB
5600      * Segment size is 60 words / 240 bytes
5601      *  -> 136 segments / chunk
5602      *  -> 134 segments / chunk 'normally' sent
5603      *  -> 32160 bytes
5604      */
5605     g_err << "Sending "
5606           << sizes[0]
5607           << " " << sizes[1]
5608           << " " << sizes[2]
5609           << endl;
5610 
5611     const Uint32 numSections =
5612       (sizes[0] ? 1 : 0) +
5613       (sizes[1] ? 1 : 0) +
5614       (sizes[2] ? 1 : 0);
5615     const Uint32 testType = 40;
5616     const Uint32 fragmentLength = 1;
5617     const Uint32 print = 0;
5618     const Uint32 len = 5 + numSections;
5619     SimpleSignal request(false);
5620 
5621     Uint32* signalBody = request.getDataPtrSend();
5622     signalBody[0] = ss->getOwnRef();
5623     signalBody[1] = testType;
5624     signalBody[2] = fragmentLength;
5625     signalBody[3] = print;
5626     signalBody[4] = 0; /* Return count */
5627     signalBody[5] = sizes[0];
5628     signalBody[6] = sizes[1];
5629     signalBody[7] = sizes[2];
5630 
5631 
5632     request.ptr[0].sz = sizes[0];
5633     request.ptr[0].p = &buffer[0];
5634     request.ptr[1].sz = sizes[1];
5635     request.ptr[1].p = &buffer[sizes[0]];
5636     request.ptr[2].sz = sizes[2];
5637     request.ptr[2].p = &buffer[sizes[0] + sizes[1]];
5638 
5639     request.header.m_noOfSections= numSections;
5640 
5641     int rc = 0;
5642     ss->lock();
5643     rc = ss->sendFragmentedSignal(ss->get_an_alive_node(),
5644                                   request,
5645                                   CMVMI,
5646                                   GSN_TESTSIG,
5647                                   len);
5648     ss->unlock();
5649 
5650     if (rc != 0)
5651     {
5652       g_err << "Error sending signal" << endl;
5653       return rc;
5654     }
5655 
5656     return 0;
5657   }
5658 
waitResponse(SignalSender * ss,Uint32 * expectedSz)5659   int waitResponse(SignalSender* ss,
5660                    Uint32* expectedSz)
5661   {
5662     /* Here we need to wait for all of the signals which
5663      * comprise a fragmented send, and check that
5664      * the data is as expected
5665      */
5666     BasicSectionStore bss;
5667     FragmentAssembler fa(&bss);
5668 
5669     while(true)
5670     {
5671       ss->lock();
5672       SimpleSignal* response = ss->waitFor(10000);
5673       ss->unlock();
5674 
5675       if (!response)
5676       {
5677         g_err << "Timed out waiting for response" << endl;
5678         return -1;
5679       }
5680 
5681       //response->print();
5682 
5683       if (response->header.theVerId_signalNumber == GSN_TESTSIG)
5684       {
5685         if (fa.handleSignal(&response->header,
5686                             response->getDataPtr(),
5687                             response->ptr) != 0)
5688         {
5689           g_err << "Error assembling fragmented signal."
5690                 << "  Error is "
5691                 << (Uint32) fa.getError()
5692                 << endl;
5693           return -1;
5694         }
5695 
5696         if (fa.isComplete())
5697         {
5698           Uint32 expectedWord = 0;
5699           for (Uint32 i=0; i < 3; i++)
5700           {
5701             if (bss.ptrs[i].sz != expectedSz[i])
5702             {
5703               g_err << "Wrong size for section : "
5704                     << i
5705                     << " expected " << expectedSz[i]
5706                     << " but received " << bss.ptrs[i].sz
5707                     << endl;
5708               return -1;
5709             }
5710 
5711             for (Uint32 d=0; d < expectedSz[i]; d++)
5712             {
5713               if (bss.ptrs[i].p[d] != expectedWord)
5714               {
5715                 g_err << "Bad data in section "
5716                       << i
5717                       << " at word number "
5718                       << d
5719                       << ".  Expected "
5720                       << expectedWord
5721                       << " but found "
5722                       << bss.ptrs[i].p[d]
5723                       << endl;
5724                 return -1;
5725               }
5726               expectedWord++;
5727             }
5728           }
5729 
5730           break;
5731         }
5732 
5733       }
5734     }
5735 
5736     return 0;
5737   }
5738 
runTest(SignalSender * ss)5739   int runTest(SignalSender* ss)
5740   {
5741     for (Uint32 iter=0;
5742          iter < getNumIterationsRequired();
5743          iter++)
5744     {
5745       int rc;
5746       Uint32 sizes[3];
5747       sizes[0] = getSecSz(0, iter);
5748       sizes[1] = getSecSz(1, iter);
5749       sizes[2] = getSecSz(2, iter);
5750 
5751       /* Build request, including sections */
5752       rc = sendRequest(ss, sizes);
5753       if (rc != 0)
5754       {
5755         g_err << "Failed sending request on iteration " << iter
5756               << " with rc " << rc << endl;
5757         return NDBT_FAILED;
5758       }
5759 
5760       /* Wait for response */
5761       rc = waitResponse(ss, sizes);
5762       if (rc != 0)
5763       {
5764         g_err << "Failed waiting for response on iteration " << iter
5765               << " with rc " << rc << endl;
5766         return NDBT_FAILED;
5767       }
5768     }
5769 
5770     return NDBT_OK;
5771   }
5772 };
5773 
5774 
testFragmentedSend(NDBT_Context * ctx,NDBT_Step * step)5775 int testFragmentedSend(NDBT_Context* ctx, NDBT_Step* step){
5776   Ndb* pNdb= GETNDB(step);
5777   Ndb_cluster_connection* conn = &pNdb->get_ndb_cluster_connection();
5778   SignalSender ss(conn);
5779   FragSignalChecker fsc;
5780 
5781   return fsc.runTest(&ss);
5782 }
5783 
5784 static int
runReceiveTRANSIDAIAfterRollback(NDBT_Context * ctx,NDBT_Step * step)5785 runReceiveTRANSIDAIAfterRollback(NDBT_Context* ctx, NDBT_Step* step)
5786 {
5787   Ndb* const ndb = GETNDB(step);
5788   NdbRestarter restarter;
5789 
5790   do {
5791     // fill table with 10 rows.
5792     const NdbDictionary::Table * pTab = ctx->getTab();
5793     HugoTransactions hugoTrans(*pTab);
5794     if(hugoTrans.loadTable(ndb, 10) != 0) {
5795       g_err << "Failed to load table" << endl;
5796       break;
5797     }
5798     // do error injection in data nodes
5799     if (restarter.insertErrorInAllNodes(8107) != 0){
5800       g_err << "Failed to insert error 8107" << endl;
5801       break;
5802     }
5803     if (restarter.insertErrorInAllNodes(4037) != 0){
5804       g_err << "Failed to insert error 4037" << endl;
5805       break;
5806     }
5807 
5808     // do error injection in ndbapi
5809     DBUG_SET_INITIAL("+d,ndb_delay_close_txn,ndb_delay_transid_ai");
5810 
5811     // start transaction
5812     NdbTransaction* const trans = ndb->startTransaction();
5813     if (trans == NULL)
5814     {
5815       g_err << "ndb->startTransaction() gave unexpected error : "
5816             << ndb->getNdbError() << endl;
5817       break;
5818     }
5819     NdbOperation* const op = trans->getNdbOperation(pTab);
5820     if (op == NULL)
5821     {
5822       g_err << "trans->getNdbOperation() gave unexpected error : "
5823             << trans->getNdbError() << endl;
5824       break;
5825     }
5826 
5827     // start primary key read with shared lock
5828     HugoOperations hugoOps(*ctx->getTab());
5829     if(hugoOps.startTransaction(ndb)) {
5830       g_err << "hugoOps.startTransaction() gave unexpected error : "
5831             << hugoOps.getTransaction()->getNdbError() << endl;
5832       break;
5833     }
5834     if(hugoOps.pkReadRecord(ndb, 1, 1, NdbOperation::LM_Read)) {
5835       g_err << "hugoOps.pkReadRecord() gave unexpected error : "
5836             << hugoOps.getTransaction()->getNdbError() << endl;
5837       break;
5838     }
5839     if(hugoOps.execute_Commit(ndb) != 0) {
5840       g_err << "hugoOps.execute_Commit() gave unexpected error : "
5841             << hugoOps.getTransaction()->getNdbError() << endl;
5842       break;
5843     }
5844 
5845     // all ok, test passes
5846     ndb->closeTransaction(trans);
5847 
5848     // clean up
5849     DBUG_SET_INITIAL("-d,ndb_delay_close_txn,ndb_delay_transid_ai");
5850     restarter.insertErrorInAllNodes(0);
5851     return NDBT_OK;
5852   } while(0);
5853 
5854   // clean up for error path
5855   DBUG_SET_INITIAL("-d,ndb_delay_close_txn,ndb_delay_transid_ai");
5856   restarter.insertErrorInAllNodes(0);
5857   return NDBT_FAILED;
5858 }
5859 
5860 int
testNdbRecordSpecificationCompatibility(NDBT_Context * ctx,NDBT_Step * step)5861 testNdbRecordSpecificationCompatibility(NDBT_Context* ctx, NDBT_Step* step)
5862 {
5863   /* Test for checking the compatibility of RecordSpecification
5864    * when compiling old code with newer header.
5865    * Create an instance of RecordSpecification_v1 and try to pass
5866    * it to the NdbApi createRecord.
5867    */
5868 
5869   Ndb* pNdb = GETNDB(step);
5870   const NdbDictionary::Table* pTab= ctx->getTab();
5871   int numCols= pTab->getNoOfColumns();
5872   const NdbRecord* defaultRecord= pTab->getDefaultRecord();
5873 
5874   NdbDictionary::RecordSpecification_v1 rsArray[ NDB_MAX_ATTRIBUTES_IN_TABLE ];
5875 
5876   for (int attrId=0; attrId< numCols; attrId++)
5877   {
5878     NdbDictionary::RecordSpecification_v1& rs= rsArray[attrId];
5879 
5880     rs.column= pTab->getColumn(attrId);
5881     rs.offset= 0;
5882     rs.nullbit_byte_offset= 0;
5883     rs.nullbit_bit_in_byte= 0;
5884     CHECK(NdbDictionary::getOffset(defaultRecord,
5885                                    attrId,
5886                                    rs.offset));
5887     CHECK(NdbDictionary::getNullBitOffset(defaultRecord,
5888                                           attrId,
5889                                           rs.nullbit_byte_offset,
5890                                           rs.nullbit_bit_in_byte));
5891   }
5892   const NdbRecord* tabRec= pNdb->getDictionary()->createRecord(pTab,
5893                               (NdbDictionary::RecordSpecification*)rsArray,
5894                               numCols,
5895                               sizeof(NdbDictionary::RecordSpecification_v1));
5896   CHECK(tabRec != 0);
5897 
5898   char keyRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
5899   char attrRowBuf[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
5900   bzero(keyRowBuf, sizeof(keyRowBuf));
5901   bzero(attrRowBuf, sizeof(attrRowBuf));
5902 
5903   HugoCalculator calc(*pTab);
5904 
5905   const int numRecords= 100;
5906 
5907   for (int record=0; record < numRecords; record++)
5908   {
5909     int updates= 0;
5910     /* calculate the Hugo values for this row */
5911     for (int col=0; col<pTab->getNoOfColumns(); col++)
5912     {
5913       char* valPtr= NdbDictionary::getValuePtr(tabRec,
5914                                                keyRowBuf,
5915                                                col);
5916       CHECK(valPtr != NULL);
5917       int len= pTab->getColumn(col)->getSizeInBytes();
5918       Uint32 real_len;
5919       bool isNull= (calc.calcValue(record, col, updates, valPtr,
5920                                    len, &real_len) == NULL);
5921       if (pTab->getColumn(col)->getNullable())
5922       {
5923         NdbDictionary::setNull(tabRec,
5924                                keyRowBuf,
5925                                col,
5926                                isNull);
5927       }
5928     }
5929 
5930     /* insert the row */
5931     NdbTransaction* trans=pNdb->startTransaction();
5932     CHECK(trans != 0);
5933     CHECK(trans->getNdbError().code == 0);
5934 
5935     const NdbOperation* op= NULL;
5936     op= trans->insertTuple(tabRec,
5937                            keyRowBuf);
5938     CHECK(op != 0);
5939 
5940     CHECK(trans->execute(Commit) == 0);
5941     trans->close();
5942 
5943     /* Now read back */
5944     Uint32 pkVal= 0;
5945     memcpy(&pkVal, NdbDictionary::getValuePtr(tabRec,
5946                                               keyRowBuf,
5947                                               0),
5948            sizeof(pkVal));
5949 
5950     trans= pNdb->startTransaction();
5951     op= trans->readTuple(tabRec,
5952                          keyRowBuf,
5953                          tabRec,
5954                          attrRowBuf);
5955     CHECK(op != 0);
5956     CHECK(trans->execute(Commit) == 0);
5957     CHECK(trans->getNdbError().code == 0);
5958     trans->close();
5959 
5960     /* Verify the values read back */
5961     for (int col=0; col<pTab->getNoOfColumns(); col++)
5962     {
5963       const char* valPtr= NdbDictionary::getValuePtr(tabRec,
5964                                                      attrRowBuf,
5965                                                      col);
5966       CHECK(valPtr != NULL);
5967 
5968       char calcBuff[ NDB_MAX_TUPLE_SIZE_IN_WORDS << 2 ];
5969       int len= pTab->getColumn(col)->getSizeInBytes();
5970       Uint32 real_len;
5971       bool isNull= (calc.calcValue(record, col, updates, calcBuff,
5972                                    len, &real_len) == NULL);
5973       bool colIsNullable= pTab->getColumn(col)->getNullable();
5974       if (isNull)
5975       {
5976         CHECK(colIsNullable);
5977         if (!NdbDictionary::isNull(tabRec,
5978                                    attrRowBuf,
5979                                    col))
5980         {
5981           ndbout << "Error, col " << col
5982               << " (pk=" <<  pTab->getColumn(col)->getPrimaryKey()
5983                   << ") should be Null, but is not" << endl;
5984           return NDBT_FAILED;
5985         }
5986       }
5987       else
5988       {
5989         if (colIsNullable)
5990         {
5991           if (NdbDictionary::isNull(tabRec,
5992                                     attrRowBuf,
5993                                     col))
5994           {
5995             ndbout << "Error, col " << col
5996                 << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
5997                 << ") should be non-Null but is null" << endl;
5998             return NDBT_FAILED;
5999           };
6000         }
6001 
6002         /* Compare actual data read back */
6003         if( memcmp(calcBuff, valPtr, real_len) != 0 )
6004         {
6005           ndbout << "Error, col " << col
6006               << " (pk=" << pTab->getColumn(col)->getPrimaryKey()
6007               << ") should be equal, but isn't for record "
6008               << record << endl;
6009           ndbout << "Expected :";
6010           for (Uint32 i=0; i < real_len; i++)
6011           {
6012             ndbout_c("%x ", calcBuff[i]);
6013           }
6014           ndbout << endl << "Received :";
6015           for (Uint32 i=0; i < real_len; i++)
6016           {
6017             ndbout_c("%x ", valPtr[i]);
6018           }
6019           ndbout << endl;
6020 
6021           return NDBT_FAILED;
6022         }
6023       }
6024     }
6025 
6026     /* Now delete the tuple */
6027     trans= pNdb->startTransaction();
6028     op= trans->deleteTuple(tabRec,
6029                            keyRowBuf,
6030                            tabRec);
6031     CHECK(op != 0);
6032     CHECK(trans->execute(Commit) == 0);
6033 
6034     trans->close();
6035   }
6036 
6037   return NDBT_OK;
6038 }
6039 
testSchemaObjectOwnerCheck(NDBT_Context * ctx,NDBT_Step * step)6040 int testSchemaObjectOwnerCheck(NDBT_Context* ctx, NDBT_Step* step)
6041 {
6042   Ndb* const ndb = GETNDB(step);
6043   Ndb *otherNdb = NULL;
6044   NdbDictionary::Dictionary* const dict = ndb->getDictionary();
6045   NdbTransaction *trans = ndb->startTransaction();
6046   NdbRestarter restarter;
6047   int result = NDBT_OK;
6048 
6049   do
6050   {
6051     ndbout << "Creating table with index" << endl;
6052     NdbDictionary::Table tab;
6053     NdbDictionary::Index idx;
6054     tab.setName("SchemaObjOwnerCheck_tab");
6055     tab.setLogging(true);
6056 
6057     // create column
6058     NdbDictionary::Column col("col1");
6059     col.setType(NdbDictionary::Column::Unsigned);
6060     col.setPrimaryKey(true);
6061     tab.addColumn(col);
6062 
6063     // create index on column
6064     idx.setTable("SchemaObjOwnerCheck_tab");
6065     idx.setName("SchemaObjOwnerCheck_idx");
6066     idx.setType(NdbDictionary::Index::UniqueHashIndex);
6067     idx.setLogging(false);
6068     idx.addColumnName("col1");
6069 
6070     NdbError error;
6071     if(tab.validate(error) == -1)
6072     {
6073       ndbout << "Failed to create table" << endl;
6074       break;
6075     }
6076 
6077     if (dict->createTable(tab) == -1) {
6078       g_err << "Failed to create SchemaObjOwnerCheck_tab table." << endl;
6079       result = NDBT_FAILED;
6080       break;
6081     }
6082     if (dict->createIndex(idx) == -1) {
6083       g_err << "Failed to create index, error: " << dict->getNdbError() << endl;
6084       result = NDBT_FAILED;
6085       break;
6086     }
6087 
6088     ndbout << "Setting up other connection to acquire schema objects." << endl;
6089     char connectString[256];
6090     ctx->m_cluster_connection.get_connectstring(connectString,
6091                                                 sizeof(connectString));
6092     otherConnection= new Ndb_cluster_connection(connectString);
6093     if (otherConnection == NULL)
6094     {
6095       ndbout << "otherConnection is null" << endl;
6096       result = NDBT_FAILED;
6097       break;
6098     }
6099     int rc= otherConnection->connect();
6100     if (rc != 0)
6101     {
6102       ndbout << "Connect of otherConnection failed with rc " << rc << endl;
6103       result = NDBT_FAILED;
6104       break;
6105     }
6106     if (otherConnection->wait_until_ready(10,10) != 0)
6107     {
6108       ndbout << "Cluster connection otherConnection was not ready" << endl;
6109       result = NDBT_FAILED;
6110       break;
6111     }
6112     otherNdb = new Ndb(otherConnection, "TEST_DB");
6113     if(!otherNdb)
6114     {
6115       ndbout << "Failed to acquire Ndb object from otherConnection" << endl;
6116       result = NDBT_FAILED;
6117       break;
6118     }
6119     otherNdb->init();
6120     if(otherNdb->waitUntilReady(10) != 0)
6121     {
6122       ndbout << "Failed to init Ndb object from otherConnection" << endl;
6123       result = NDBT_FAILED;
6124       break;
6125     }
6126     const NdbDictionary::Table *otherTable = otherNdb->getDictionary()->getTable("SchemaObjOwnerCheck_tab");
6127     if(!otherTable)
6128     {
6129       ndbout << "Failed to get Ndb table from otherConnection" << endl;
6130       result = NDBT_FAILED;
6131       break;
6132     }
6133     const NdbDictionary::Index *otherIndex = otherNdb->getDictionary()->getIndex("SchemaObjOwnerCheck_idx", "SchemaObjOwnerCheck_tab");
6134     if(!otherIndex)
6135     {
6136       ndbout << "Failed to get Ndb index from otherConnection" << endl;
6137       result = NDBT_FAILED;
6138       break;
6139     }
6140 
6141     ndbout << "Enabling schema object ownership check on ctx connection" << endl;
6142     trans->setSchemaObjOwnerChecks(true);
6143 
6144     ndbout << "Attempting to acquire Ndb*Operations on schema objects ";
6145     ndbout << "which belong to other connection" << endl;
6146     NdbOperation *op = trans->getNdbOperation(otherTable);
6147     const NdbError err1 = trans->getNdbError();
6148     if(err1.code != 1231)
6149     {
6150       ndbout << "Failed to detect Table with wrong owner for NdbOperation" << endl;
6151       result = NDBT_FAILED;
6152       break;
6153     }
6154     NdbScanOperation *scanop = trans->getNdbScanOperation(otherTable);
6155     const NdbError err2 = trans->getNdbError();
6156     if(err2.code != 1231)
6157     {
6158       ndbout << "Failed to detect Table with wrong owner for NdbScanOperation" << endl;
6159       result = NDBT_FAILED;
6160       break;
6161     }
6162     NdbIndexScanOperation *idxscanop = trans->getNdbIndexScanOperation(otherIndex, otherTable);
6163     const NdbError err3 = trans->getNdbError();
6164     if(err3.code != 1231)
6165     {
6166       ndbout << "Failed to detect Table/Index with wrong owner for NdbIndexScanOperation" << endl;
6167       result = NDBT_FAILED;
6168       break;
6169     }
6170     NdbIndexOperation *idxop = trans->getNdbIndexOperation(otherIndex);
6171     const NdbError err4 = trans->getNdbError();
6172     if(err4.code != 1231)
6173     {
6174       ndbout << "Failed to detect Index with wrong owner for NdbIndexOperation" << endl;
6175       result = NDBT_FAILED;
6176       break;
6177     }
6178     ndbout << "Success: ownership check detected wrong owner" << endl;
6179 
6180     ndbout << "Disabling schema object ownership check on valid connection" << endl;
6181     trans->setSchemaObjOwnerChecks(false);
6182 
6183     ndbout << "Attempting to acquire Ndb*Operations ";
6184     ndbout << "on valid schema objects from other connection" << endl;
6185     op = trans->getNdbOperation(otherTable);
6186     scanop = trans->getNdbScanOperation(otherTable);
6187     idxscanop = trans->getNdbIndexScanOperation(otherIndex, otherTable);
6188     idxop = trans->getNdbIndexOperation(otherIndex);
6189 
6190     if(!op || !scanop || !idxscanop || !idxop)  // failure to acquire at least one op
6191     {
6192       ndbout << "Failed to acquire ";
6193       if(!op)        ndbout << "NdbOperation, ";
6194       if(!scanop)    ndbout << "NdbScanOperation, ";
6195       if(!idxscanop) ndbout << "NdbIndexScanOperation, ";
6196       if(!idxop)     ndbout << "NdbIndexOperation, ";
6197       ndbout << "error: " << trans->getNdbError().message << endl;
6198       result = NDBT_FAILED;
6199       break;
6200     }
6201     ndbout << "Success: ownership check skipped, wrong owner not detected" << endl;
6202 
6203     ndbout << "Enabling schema object ownership check on valid connection" << endl;
6204     trans->setSchemaObjOwnerChecks(true);
6205 
6206     ndbout << "Acquiring schema objects from current connection" << endl;
6207     const NdbDictionary::Table *table = ndb->getDictionary()->getTable("SchemaObjOwnerCheck_tab");
6208     if(!table)
6209     {
6210       ndbout << "Failed to get Ndb table from connection" << endl;
6211       result = NDBT_FAILED;
6212       break;
6213     }
6214     const NdbDictionary::Index *index = ndb->getDictionary()->getIndex("SchemaObjOwnerCheck_idx", "SchemaObjOwnerCheck_tab");
6215     if(!index)
6216     {
6217       ndbout << "Failed to get Ndb index from connection" << endl;
6218       result = NDBT_FAILED;
6219       break;
6220     }
6221 
6222     ndbout << "Attempting to acquire Ndb*Operations ";
6223     ndbout << "on owned schema objects with different db" << endl;
6224     ndb->setDatabaseName("notexist");
6225     NdbOperation *op2 = trans->getNdbOperation(table);
6226     NdbScanOperation *scanop2 = trans->getNdbScanOperation(table);
6227     NdbIndexScanOperation *idxscanop2 = trans->getNdbIndexScanOperation(index, table);
6228     NdbIndexOperation *idxop2 = trans->getNdbIndexOperation(index, table);
6229 
6230     if(!op2 || !scanop2 || !idxscanop2 || !idxop2)  // failure to acquire at least one op
6231     {
6232       ndbout << "Failed to acquire ";
6233       if(!op)        ndbout << "NdbOperation, ";
6234       if(!scanop)    ndbout << "NdbScanOperation, ";
6235       if(!idxscanop) ndbout << "NdbIndexScanOperation, ";
6236       if(!idxop)     ndbout << "NdbIndexOperation, ";
6237       ndbout << "error: " << trans->getNdbError().message << endl;
6238       result = NDBT_FAILED;
6239       break;
6240     }
6241     ndbout << "Success: acquired Ndb*Operations on owned schema objects" << endl;
6242   } while(false);
6243 
6244   ndbout << "Cleanup" << endl;
6245   ndb->setDatabaseName("TEST_DB");
6246   if (dict->dropIndex("SchemaObjOwnerCheck_idx", "SchemaObjOwnerCheck_tab") == -1)
6247   {
6248     g_err << "Failed to drop SchemaObjOwnerCheck_idx index." << endl;
6249     result = NDBT_FAILED;
6250   }
6251   if (dict->dropTable("SchemaObjOwnerCheck_tab") == -1)
6252   {
6253     g_err << "Failed to drop SchemaObjOwnerCheck_tab table." << endl;
6254     result = NDBT_FAILED;
6255   }
6256 
6257   trans->setSchemaObjOwnerChecks(false);
6258   ndb->closeTransaction(trans);
6259 
6260   if(otherNdb)
6261   {
6262     delete otherNdb;
6263     otherNdb = NULL;
6264   }
6265   if(otherConnection)
6266   {
6267     delete otherConnection;
6268     otherConnection = NULL;
6269   }
6270   return result;
6271 }
6272 
6273 NDBT_TESTSUITE(testNdbApi);
6274 TESTCASE("MaxNdb",
6275 	 "Create Ndb objects until no more can be created\n"){
6276   INITIALIZER(runTestMaxNdb);
6277 }
6278 TESTCASE("MaxTransactions",
6279 	 "Start transactions until no more can be created\n"){
6280   INITIALIZER(runTestMaxTransaction);
6281 }
6282 TESTCASE("MaxOperations",
6283 	"Get operations until no more can be created\n"){
6284   INITIALIZER(runLoadTable);
6285   INITIALIZER(runTestMaxOperations);
6286   FINALIZER(runClearTable);
6287 }
6288 TESTCASE("MaxGetValue",
6289 	"Call getValue loads of time\n"){
6290   INITIALIZER(runLoadTable);
6291   INITIALIZER(runTestGetValue);
6292   FINALIZER(runClearTable);
6293 }
6294 TESTCASE("MaxEqual",
6295 	"Call equal loads of time\n"){
6296   INITIALIZER(runTestEqual);
6297 }
6298 TESTCASE("DeleteNdb",
6299 	"Make sure that a deleted Ndb object is properly deleted\n"
6300 	"and removed from transporter\n"){
6301   INITIALIZER(runLoadTable);
6302   INITIALIZER(runTestDeleteNdb);
6303   FINALIZER(runClearTable);
6304 }
6305 TESTCASE("WaitUntilReady",
6306 	"Make sure you get an error message when calling waitUntilReady\n"
6307 	"without an init'ed Ndb\n"){
6308   INITIALIZER(runTestWaitUntilReady);
6309 }
6310 TESTCASE("GetOperationNoTab",
6311 	"Call getNdbOperation on a table that does not exist\n"){
6312   INITIALIZER(runGetNdbOperationNoTab);
6313 }
6314 TESTCASE("BadColNameHandling",
6315          "Call methods with an invalid column name and check error handling\n"){
6316   INITIALIZER(runBadColNameHandling);
6317 }
6318 TESTCASE("MissingOperation",
6319 	"Missing operation request(insertTuple) should give an error code\n"){
6320   INITIALIZER(runMissingOperation);
6321 }
6322 TESTCASE("GetValueInUpdate",
6323 	"Test that it's not possible to perform getValue in an update\n"){
6324   INITIALIZER(runLoadTable);
6325   INITIALIZER(runGetValueInUpdate);
6326   FINALIZER(runClearTable);
6327 }
6328 TESTCASE("UpdateWithoutKeys",
6329 	"Test that it's not possible to perform update without setting\n"
6330 	 "PKs"){
6331   INITIALIZER(runLoadTable);
6332   INITIALIZER(runUpdateWithoutKeys);
6333   FINALIZER(runClearTable);
6334 }
6335 TESTCASE("UpdateWithoutValues",
6336 	"Test that it's not possible to perform update without setValues\n"){
6337   INITIALIZER(runLoadTable);
6338   INITIALIZER(runUpdateWithoutValues);
6339   FINALIZER(runClearTable);
6340 }
6341 TESTCASE("NdbErrorOperation",
6342 	 "Test that NdbErrorOperation is properly set"){
6343   INITIALIZER(runCheckGetNdbErrorOperation);
6344 }
6345 TESTCASE("ReadWithoutGetValue",
6346 	 "Test that it's possible to perform read wo/ getvalue's\n"){
6347   INITIALIZER(runLoadTable);
6348   INITIALIZER(runReadWithoutGetValue);
6349   FINALIZER(runClearTable);
6350 }
6351 TESTCASE("Bug_11133",
6352 	 "Test ReadEx-Delete-Write\n"){
6353   INITIALIZER(runBug_11133);
6354   FINALIZER(runClearTable);
6355 }
6356 TESTCASE("Bug_WritePartialIgnoreError",
6357 	 "Test WritePartialIgnoreError\n"){
6358   INITIALIZER(runBug_WritePartialIgnoreError);
6359   FINALIZER(runClearTable);
6360 }
6361 TESTCASE("Scan_4006",
6362 	 "Check that getNdbScanOperation does not get 4006\n"){
6363   INITIALIZER(runLoadTable);
6364   INITIALIZER(runScan_4006);
6365   FINALIZER(runClearTable);
6366 }
6367 TESTCASE("IgnoreError", ""){
6368   INITIALIZER(createPkIndex);
6369   STEP(runTestIgnoreError);
6370   FINALIZER(runClearTable);
6371   FINALIZER(createPkIndex_Drop);
6372 }
6373 TESTCASE("CheckNdbObjectList",
6374 	 ""){
6375   INITIALIZER(runCheckNdbObjectList);
6376 }
6377 TESTCASE("DeleteClusterConnectionWhileUsed",
6378          "Make sure that deleting of Ndb_cluster_connection will"
6379          "not return until all it's Ndb objects has been deleted."){
6380   STEP(runNdbClusterConnectionDelete_connection_owner)
6381   STEP(runNdbClusterConnectionDelete_connection_user);
6382 }
6383 TESTCASE("ExecuteAsynch",
6384 	 "Check that executeAsync() works (BUG#27495)\n"){
6385   INITIALIZER(runTestExecuteAsynch);
6386 }
6387 TESTCASE("Bug28443",
6388 	 ""){
6389   INITIALIZER(runBug28443);
6390 }
6391 TESTCASE("Bug37158",
6392 	 ""){
6393   INITIALIZER(runBug37158);
6394 }
6395 TESTCASE("SimpleReadAbortOnError",
6396          "Test behaviour of Simple reads with Abort On Error"){
6397   INITIALIZER(simpleReadAbortOnError);
6398 }
6399 TESTCASE("NdbRecordPKAmbiguity",
6400          "Test behaviour of NdbRecord insert with ambig. pk values"){
6401   INITIALIZER(testNdbRecordPkAmbiguity);
6402 }
6403 TESTCASE("NdbRecordPKUpdate",
6404          "Verify that primary key columns can be updated"){
6405   INITIALIZER(testNdbRecordPKUpdate);
6406 }
6407 TESTCASE("NdbRecordCICharPKUpdate",
6408          "Verify that a case-insensitive char pk column can be updated"){
6409   INITIALIZER(testNdbRecordCICharPKUpdate);
6410 }
6411 TESTCASE("NdbRecordRowLength",
6412          "Verify that the record row length calculation is correct") {
6413   INITIALIZER(testNdbRecordRowLength);
6414 }
6415 TESTCASE("Bug44015",
6416          "Rollback insert followed by delete to get corruption") {
6417   STEP(runBug44015);
6418   STEPS(runScanReadUntilStopped, 10);
6419 }
6420 TESTCASE("Bug44065_org",
6421          "Rollback no-change update on top of existing data") {
6422   INITIALIZER(runBug44065_org);
6423 }
6424 TESTCASE("Bug44065",
6425          "Rollback no-change update on top of existing data") {
6426   INITIALIZER(runBug44065);
6427 }
6428 TESTCASE("ApiFailReqBehaviour",
6429          "Check ApiFailReq cleanly marks Api disconnect") {
6430   // Some flags to enable the various threads to cooperate
6431   TC_PROPERTY(ApiFailTestRun, (Uint32)0);
6432   TC_PROPERTY(ApiFailTestComplete, (Uint32)0);
6433   TC_PROPERTY(ApiFailTestsRunning, (Uint32)0);
6434   TC_PROPERTY(ApiFailNumberPkSteps, (Uint32)5); // Num threads below
6435   INITIALIZER(runLoadTable);
6436   // 5 threads to increase probability of pending
6437   // TCKEYREQ after API_FAILREQ
6438   STEP(runBulkPkReads);
6439   STEP(runBulkPkReads);
6440   STEP(runBulkPkReads);
6441   STEP(runBulkPkReads);
6442   STEP(runBulkPkReads);
6443   STEP(testApiFailReq);
6444   FINALIZER(runClearTable);
6445 }
6446 TESTCASE("ReadColumnDuplicates",
6447          "Check NdbApi behaves ok when reading same column multiple times") {
6448   INITIALIZER(runLoadTable);
6449   STEP(runReadColumnDuplicates);
6450   FINALIZER(runClearTable);
6451 }
6452 TESTCASE("Bug51775", "")
6453 {
6454   INITIALIZER(runBug51775);
6455 }
6456 TESTCASE("FragmentedApiFailure",
6457          "Test in-assembly fragment cleanup code for API failure") {
6458   // We reuse some of the infrastructure from ApiFailReqBehaviour here
6459   TC_PROPERTY(ApiFailTestRun, (Uint32)0);
6460   TC_PROPERTY(ApiFailTestComplete, (Uint32)0);
6461   TC_PROPERTY(ApiFailTestsRunning, (Uint32)0);
6462   TC_PROPERTY(ApiFailNumberPkSteps, (Uint32)5); // Num threads below
6463   // 5 threads to increase probability of fragmented signal being
6464   // in-assembly when disconnect occurs
6465   STEP(runFragmentedScanOtherApi);
6466   STEP(runFragmentedScanOtherApi);
6467   STEP(runFragmentedScanOtherApi);
6468   STEP(runFragmentedScanOtherApi);
6469   STEP(runFragmentedScanOtherApi);
6470   STEP(testFragmentedApiFail);
6471 };
6472 TESTCASE("UnlockBasic",
6473          "Check basic op unlock behaviour") {
6474   INITIALIZER(runLoadTable);
6475   STEP(runTestUnlockBasic);
6476   FINALIZER(runClearTable);
6477 }
6478 TESTCASE("UnlockRepeat",
6479          "Check repeated lock/unlock behaviour") {
6480   INITIALIZER(runLoadTable);
6481   STEP(runTestUnlockRepeat);
6482   FINALIZER(runClearTable);
6483 }
6484 TESTCASE("UnlockMulti",
6485          "Check unlock behaviour with multiple operations") {
6486   INITIALIZER(runLoadTable);
6487   STEP(runTestUnlockMulti);
6488   FINALIZER(runClearTable);
6489 }
6490 TESTCASE("UnlockScan",
6491          "Check unlock behaviour with scan lock-takeover") {
6492   INITIALIZER(runLoadTable);
6493   STEP(runTestUnlockScan);
6494   FINALIZER(runClearTable);
6495 }
6496 TESTCASE("NdbClusterConnect",
6497          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6498 {
6499   INITIALIZER(runNdbClusterConnectInit);
6500   STEPS(runNdbClusterConnect, MAX_NODES);
6501 }
6502 TESTCASE("NdbClusterConnectionConnect",
6503          "Test Ndb_cluster_connection::connect()")
6504 {
6505   INITIALIZER(runNdbClusterConnectionConnect);
6506 }
6507 TESTCASE("NdbClusterConnectNR",
6508          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6509 {
6510   TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
6511   INITIALIZER(runNdbClusterConnectInit);
6512   STEPS(runNdbClusterConnect, MAX_NODES);
6513   STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
6514 }
6515 TESTCASE("NdbClusterConnectNR_master",
6516          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6517 {
6518   TC_PROPERTY("Master", 1);
6519   TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
6520   INITIALIZER(runNdbClusterConnectInit);
6521   STEPS(runNdbClusterConnect, MAX_NODES);
6522   STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
6523 }
6524 TESTCASE("NdbClusterConnectNR_non_master",
6525          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6526 {
6527   TC_PROPERTY("Master", 2);
6528   TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
6529   INITIALIZER(runNdbClusterConnectInit);
6530   STEPS(runNdbClusterConnect, MAX_NODES);
6531   STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
6532 }
6533 TESTCASE("NdbClusterConnectNR_slow",
6534          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6535 {
6536   TC_PROPERTY("Master", 2);
6537   TC_PROPERTY("TimeoutAfterFirst", (Uint32)0);
6538   TC_PROPERTY("SlowNR", 1);
6539   INITIALIZER(runNdbClusterConnectInit);
6540   STEPS(runNdbClusterConnect, MAX_NODES);
6541   STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
6542 }
6543 TESTCASE("NdbClusterConnectSR",
6544          "Make sure that every Ndb_cluster_connection get a unique nodeid")
6545 {
6546   TC_PROPERTY("ClusterRestart", (Uint32)1);
6547   INITIALIZER(runNdbClusterConnectInit);
6548   STEPS(runNdbClusterConnect, MAX_NODES);
6549   STEP(runRestarts); // Note after runNdbClusterConnect or else counting wrong
6550 }
6551 TESTCASE("TestFragmentedSend",
6552          "Test fragmented send behaviour"){
6553   INITIALIZER(testFragmentedSend);
6554 }
6555 TESTCASE("ReceiveTRANSIDAIAfterRollback",
6556          "Delay the delivery of TRANSID_AI results from the data node." \
6557          "Abort a transaction with a timeout so that the "\
6558          "transaction closing and TRANSID_AI processing are interleaved." \
6559          "Confirm that this interleaving does not result in a core."
6560 ){
6561   STEP(runReceiveTRANSIDAIAfterRollback);
6562   FINALIZER(runClearTable);
6563 }
6564 TESTCASE("RecordSpecificationBackwardCompatibility",
6565          "Test RecordSpecification struct's backward compatibility"){
6566   STEP(testNdbRecordSpecificationCompatibility);
6567 }
6568 TESTCASE("SchemaObjectOwnerCheck",
6569          "Test use of schema objects with non-owning connections"){
6570   STEP(testSchemaObjectOwnerCheck);
6571 }
6572 NDBT_TESTSUITE_END(testNdbApi);
6573 
main(int argc,const char ** argv)6574 int main(int argc, const char** argv){
6575   ndb_init();
6576   NDBT_TESTSUITE_INSTANCE(testNdbApi);
6577   //  TABLE("T1");
6578   return testNdbApi.execute(argc, argv);
6579 }
6580 
6581 template class Vector<Ndb*>;
6582 template class Vector<NdbConnection*>;
6583 template class Vector<Ndb_cluster_connection*>;
6584