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