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