1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <NDBT.hpp>
26 #include <NDBT_Test.hpp>
27 #include <HugoTransactions.hpp>
28 #include <UtilTransactions.hpp>
29 #include <NdbRestarter.hpp>
30 #include <Vector.hpp>
31 #include <signaldata/DumpStateOrd.hpp>
32 #include <../../include/kernel/ndb_limits.h>
33 #include <../../include/kernel/trigger_definitions.h>
34 #include <signaldata/DictTabInfo.hpp>
35 #include <random.h>
36 #include <NdbAutoPtr.hpp>
37 #include <NdbMixRestarter.hpp>
38 #include <NdbSqlUtil.hpp>
39 #include <NdbEnv.h>
40 #include <ndb_rand.h>
41 #include <Bitmask.hpp>
42 #include <../src/kernel/ndbd.hpp>
43 
44 #define ERR_INSERT_MASTER_FAILURE1 6013
45 #define ERR_INSERT_MASTER_FAILURE2 6014
46 #define ERR_INSERT_MASTER_FAILURE3 6015
47 
48 #define ERR_INSERT_PARTIAL_START_FAIL 6140
49 #define ERR_INSERT_PARTIAL_PARSE_FAIL 6141
50 #define ERR_INSERT_PARTIAL_FLUSH_PREPARE_FAIL 6142
51 #define ERR_INSERT_PARTIAL_PREPARE_FAIL 6143
52 #define ERR_INSERT_PARTIAL_ABORT_PARSE_FAIL 6144
53 #define ERR_INSERT_PARTIAL_ABORT_PREPARE_FAIL 6145
54 #define ERR_INSERT_PARTIAL_FLUSH_COMMIT_FAIL 6146
55 #define ERR_INSERT_PARTIAL_COMMIT_FAIL 6147
56 #define ERR_INSERT_PARTIAL_FLUSH_COMPLETE_FAIL 6148
57 #define ERR_INSERT_PARTIAL_COMPLETE_FAIL 6149
58 #define ERR_INSERT_PARTIAL_END_FAIL 6150
59 
60 #define FAIL_BEGIN 0
61 #define FAIL_CREATE 1
62 #define FAIL_END 2
63 #define SUCCEED_COMMIT 3
64 #define SUCCEED_ABORT 4
65 
66 #define ndb_master_failure 1
67 
68 char f_tablename[256];
69 
70 #define CHECK(b) if (!(b)) { \
71   g_err << "ERR: "<< step->getName() \
72          << " failed on line " << __LINE__ << endl; \
73   result = NDBT_FAILED; \
74   break; }
75 
76 #define CHECK2(b, c) if (!(b)) { \
77   g_err << "ERR: "<< step->getName() \
78          << " failed on line " << __LINE__ << ": " << c << endl; \
79   result = NDBT_FAILED; \
80   goto end; }
81 
runLoadTable(NDBT_Context * ctx,NDBT_Step * step)82 int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
83   Ndb* pNdb = GETNDB(step);
84   int records = ctx->getNumRecords();
85   HugoTransactions hugoTrans(*ctx->getTab());
86   if (hugoTrans.loadTable(pNdb, records) != 0){
87     return NDBT_FAILED;
88   }
89   return NDBT_OK;
90 }
91 
runCreateInvalidTables(NDBT_Context * ctx,NDBT_Step * step)92 int runCreateInvalidTables(NDBT_Context* ctx, NDBT_Step* step){
93   Ndb* pNdb = GETNDB(step);
94   int result = NDBT_OK;
95 
96   char failTabName[256];
97 
98   const int expectedDictErrors[6]= {720,
99                                     4317,
100                                     737,
101                                     739,
102                                     736,
103                                     740 };
104 
105   for (int i = 0; i < 10; i++){
106     BaseString::snprintf(failTabName, 256, "F%d", i);
107 
108     const NdbDictionary::Table* pFailTab = NDBT_Tables::getTable(failTabName);
109     if (pFailTab != NULL){
110       ndbout << "|- " << failTabName << endl;
111 
112       // Try to create table in db
113       if (pFailTab->createTableInDb(pNdb) == 0){
114         ndbout << failTabName << " created, this was not expected"<< endl;
115         result = NDBT_FAILED;
116       }
117 
118       // Ensure any error is roughly as expected
119       int errorCode=pNdb->getDictionary()->getNdbError().code;
120       bool errorOk= false;
121       for (int e=0; e < 6; e++)
122         errorOk |= (errorCode == expectedDictErrors[e]);
123 
124       if (!errorOk)
125       {
126         ndbout << "Failure, got dict error : " << pNdb->getDictionary()->
127           getNdbError().code << endl;
128         return NDBT_FAILED;
129       }
130 
131       // Verify that table is not in db
132       const NdbDictionary::Table* pTab2 =
133 	NDBT_Table::discoverTableFromDb(pNdb, failTabName) ;
134       if (pTab2 != NULL){
135         ndbout << failTabName << " was found in DB, this was not expected"<< endl;
136         result = NDBT_FAILED;
137 	if (pFailTab->equal(*pTab2) == true){
138 	  ndbout << "It was equal" << endl;
139 	} else {
140 	  ndbout << "It was not equal" << endl;
141 	}
142 	int records = 1000;
143 	HugoTransactions hugoTrans(*pTab2);
144 	if (hugoTrans.loadTable(pNdb, records) != 0){
145 	  ndbout << "It can NOT be loaded" << endl;
146 	} else{
147 	  ndbout << "It can be loaded" << endl;
148 
149 	  UtilTransactions utilTrans(*pTab2);
150 	  if (utilTrans.clearTable(pNdb, records, 64) != 0){
151 	    ndbout << "It can NOT be cleared" << endl;
152 	  } else{
153 	    ndbout << "It can be cleared" << endl;
154 	  }
155 	}
156 
157 	if (pNdb->getDictionary()->dropTable(pTab2->getName()) == -1){
158 	  ndbout << "It can NOT be dropped" << endl;
159 	} else {
160 	  ndbout << "It can be dropped" << endl;
161 	}
162       }
163     }
164   }
165   return result;
166 }
167 
runCreateTheTable(NDBT_Context * ctx,NDBT_Step * step)168 int runCreateTheTable(NDBT_Context* ctx, NDBT_Step* step){
169   Ndb* pNdb = GETNDB(step);
170   const NdbDictionary::Table* pTab = ctx->getTab();
171 
172   // Try to create table in db
173   if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
174     return NDBT_FAILED;
175   }
176 
177   // Verify that table is in db
178   const NdbDictionary::Table* pTab2 =
179     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
180   if (pTab2 == NULL){
181     ndbout << pTab->getName() << " was not found in DB"<< endl;
182     return NDBT_FAILED;
183   }
184   ctx->setTab(pTab2);
185 
186   BaseString::snprintf(f_tablename, sizeof(f_tablename),
187                        "%s", pTab->getName());
188 
189   return NDBT_OK;
190 }
191 
runDropTheTable(NDBT_Context * ctx,NDBT_Step * step)192 int runDropTheTable(NDBT_Context* ctx, NDBT_Step* step){
193   Ndb* pNdb = GETNDB(step);
194 
195   // Drop table
196   pNdb->getDictionary()->dropTable(f_tablename);
197 
198   return NDBT_OK;
199 }
200 
runSetDropTableConcurrentLCP(NDBT_Context * ctx,NDBT_Step * step)201 int runSetDropTableConcurrentLCP(NDBT_Context *ctx, NDBT_Step *step)
202 {
203   NdbRestarter restarter;
204   if(restarter.insertErrorInAllNodes(5088) != 0)
205   {
206     g_err << "failed to set error insert"<< endl;
207     return NDBT_FAILED;
208   }
209   return NDBT_OK;
210 }
211 
runSetMinTimeBetweenLCP(NDBT_Context * ctx,NDBT_Step * step)212 int runSetMinTimeBetweenLCP(NDBT_Context *ctx, NDBT_Step *step)
213 {
214   NdbRestarter restarter;
215   int result;
216   int val = DumpStateOrd::DihMinTimeBetweenLCP;
217   if (restarter.dumpStateAllNodes(&val, 1) != 0)
218   {
219     do { CHECK(0); } while(0);
220     g_err << "Failed to set LCP to min value" << endl;
221     return NDBT_FAILED;
222   }
223   return NDBT_OK;
224 }
225 
runResetMinTimeBetweenLCP(NDBT_Context * ctx,NDBT_Step * step)226 int runResetMinTimeBetweenLCP(NDBT_Context *ctx, NDBT_Step *step)
227 {
228   NdbRestarter restarter;
229   int result;
230   int val2[] = { DumpStateOrd::DihMinTimeBetweenLCP, 0 };
231   if (restarter.dumpStateAllNodes(val2, 2) != 0)
232   {
233     do { CHECK(0); } while(0);
234     g_err << "Failed to set LCP to min value" << endl;
235     return NDBT_FAILED;
236   }
237   return NDBT_OK;
238 }
239 
runSetDropTableConcurrentLCP2(NDBT_Context * ctx,NDBT_Step * step)240 int runSetDropTableConcurrentLCP2(NDBT_Context *ctx, NDBT_Step *step)
241 {
242   NdbRestarter restarter;
243   if(restarter.insertErrorInAllNodes(5089) != 0)
244   {
245     g_err << "failed to set error insert"<< endl;
246     return NDBT_FAILED;
247   }
248   return NDBT_OK;
249 }
250 
251 /*******
252  * Precondition:
253  *    'DataMemory' has been filled until insertion failed
254  *    due to 'DbIsFull'. The table 'TRANSACTION' should
255  *    not exist in the DB
256  *
257  * Test:
258  *    Creation of the (empty) table 'TRANSACTION'
259  *    should succeed even if 'DbIsFull'. However,
260  *    insertion of the first row should fail.
261  *
262  * Postcond:
263  *    The created table 'TRANSACTION is removed.
264  *    DataMemory is still full.
265  */
runCreateTableWhenDbIsFull(NDBT_Context * ctx,NDBT_Step * step)266 int runCreateTableWhenDbIsFull(NDBT_Context* ctx, NDBT_Step* step){
267   Ndb* pNdb = GETNDB(step);
268   int result = NDBT_OK;
269   const char* tabName = "TRANSACTION"; //Use a util table
270 
271   // Precondition is that 'DataMemory' filled to max.
272   // So we skip test if a DiskStorage table was filled
273   for (Uint32 i = 0; i<(Uint32)ctx->getTab()->getNoOfColumns(); i++)
274   {
275     if (ctx->getTab()->getColumn(i)->getStorageType() ==
276         NdbDictionary::Column::StorageTypeDisk)
277     {
278       ndbout << "Skip test for *disk* tables" << endl;
279       return NDBT_OK;
280     }
281   }
282 
283   const NdbDictionary::Table* pTab = NDBT_Tables::getTable(tabName);
284   while (pTab != NULL){ //Always 'break' without looping
285     ndbout << "|- " << tabName << endl;
286 
287     // Verify that table is not in db
288     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) != NULL){
289       ndbout << tabName << " was found in DB"<< endl;
290       result = NDBT_FAILED;
291       break;
292     }
293 
294     // Create (empty) table in db, should succeed even if 'DbIsFull'
295     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
296       ndbout << tabName << " was not created when DB is full"<< endl;
297       result = NDBT_FAILED;
298       break;
299     }
300 
301     // Verify that table is now in db
302     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) == NULL){
303       ndbout << tabName << " was not visible in DB"<< endl;
304       result = NDBT_FAILED;
305       break;
306     }
307 
308     // As 'DbIsFull', insert of a single record should fail
309     HugoOperations hugoOps(*pTab);
310     CHECK(hugoOps.startTransaction(pNdb) == 0);
311     CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0);
312     CHECK(hugoOps.execute_Commit(pNdb) != 0); //Should fail
313     CHECK(hugoOps.closeTransaction(pNdb) == 0);
314 
315     break;
316   }
317 
318   // Drop table (if exist, so we dont care about errors)
319   pNdb->getDictionary()->dropTable(tabName);
320   return result;
321 }
322 
runDropTableWhenDbIsFull(NDBT_Context * ctx,NDBT_Step * step)323 int runDropTableWhenDbIsFull(NDBT_Context* ctx, NDBT_Step* step){
324   Ndb* pNdb = GETNDB(step);
325   int result = NDBT_OK;
326   const char* tabName = "TRANSACTION"; //Use a util table
327 
328   const NdbDictionary::Table* pTab = NDBT_Table::discoverTableFromDb(pNdb, tabName);
329   if (pTab != NULL){
330     ndbout << "|- TRANSACTION" << endl;
331 
332     // Try to drop table in db
333     if (pNdb->getDictionary()->dropTable(pTab->getName()) == -1){
334       result = NDBT_FAILED;
335     }
336 
337     // Verify that table is not in db
338     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) != NULL){
339       ndbout << tabName << " was found in DB"<< endl;
340       result = NDBT_FAILED;
341     }
342   }
343 
344   return result;
345 
346 }
347 
348 
runCreateAndDrop(NDBT_Context * ctx,NDBT_Step * step)349 int runCreateAndDrop(NDBT_Context* ctx, NDBT_Step* step){
350   Ndb* pNdb = GETNDB(step);
351   int loops = ctx->getNumLoops();
352   int i = 0;
353 
354   const NdbDictionary::Table* pTab = ctx->getTab();
355   ndbout << "|- " << pTab->getName() << endl;
356 
357   while (i < loops){
358 
359     ndbout << i << ": ";
360     // Try to create table in db
361     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
362       return NDBT_FAILED;
363     }
364 
365     // Verify that table is in db
366     const NdbDictionary::Table* pTab2 =
367       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
368     if (pTab2 == NULL){
369       ndbout << pTab->getName() << " was not found in DB"<< endl;
370       return NDBT_FAILED;
371     }
372 
373     if (pNdb->getDictionary()->dropTable(pTab2->getName())){
374       ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
375       return NDBT_FAILED;
376     }
377 
378     // Verify that table is not in db
379     const NdbDictionary::Table* pTab3 =
380       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
381     if (pTab3 != NULL){
382       ndbout << pTab3->getName() << " was found in DB"<< endl;
383       return NDBT_FAILED;
384     }
385     i++;
386   }
387 
388   return NDBT_OK;
389 }
390 
runCreateAndDropAtRandom(NDBT_Context * ctx,NDBT_Step * step)391 int runCreateAndDropAtRandom(NDBT_Context* ctx, NDBT_Step* step)
392 {
393   myRandom48Init((long)NdbTick_CurrentMillisecond());
394   Ndb* pNdb = GETNDB(step);
395   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
396   int loops = ctx->getNumLoops();
397   int records = ctx->getNumRecords();
398 
399   int numAllTables = NDBT_Tables::getNumTables();
400   struct TabList {
401     int exists; // -1 = skip, 0 = no, 1 = yes
402     const NdbDictionary::Table* pTab; // retrieved
403     TabList() { exists = -1; pTab = 0; }
404   };
405   TabList* tabList = new TabList [ numAllTables ];
406   int numTables = 0;
407   int num;
408   for (num = 0; num < numAllTables; num++) {
409     const NdbDictionary::Table* pTab = NDBT_Tables::getTable(num);
410     if (pTab->checkColumns(0, 0) & 2) // skip disk
411       continue;
412     tabList[num].exists = 0;
413     (void)pDic->dropTable(pTab->getName());
414     numTables++;
415   }
416   int numExists = 0;
417 
418   const bool createIndexes = ctx->getProperty("CreateIndexes");
419   const bool loadData = ctx->getProperty("LoadData");
420 
421   NdbRestarter restarter;
422   int result = NDBT_OK;
423   int bias = 1; // 0-less 1-more
424   int i = 0;
425 
426   while (i < loops && result == NDBT_OK) {
427     num = myRandom48(numAllTables);
428     if (tabList[num].exists == -1)
429       continue;
430     g_info << "loop " << i << " tabs " << numExists << "/" << numTables << endl;
431     const NdbDictionary::Table* pTab = NDBT_Tables::getTable(num);
432     char tabName[200];
433     strcpy(tabName, pTab->getName());
434 
435     if (tabList[num].exists == 0) {
436       if (bias == 0 && myRandom48(100) < 80)
437         continue;
438       g_info << tabName << ": create" << endl;
439       if (pDic->createTable(*pTab) != 0) {
440         const NdbError err = pDic->getNdbError();
441         g_err << tabName << ": create failed: " << err << endl;
442         result = NDBT_FAILED;
443         break;
444       }
445       const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
446       if (pTab2 == NULL) {
447         const NdbError err = pDic->getNdbError();
448         g_err << tabName << ": verify create failed: " << err << endl;
449         result = NDBT_FAILED;
450         break;
451       }
452       tabList[num].pTab = pTab2;
453       if (loadData) {
454         g_info << tabName << ": load data" << endl;
455         HugoTransactions hugoTrans(*pTab2);
456         if (hugoTrans.loadTable(pNdb, records) != 0) {
457           g_err << tabName << ": loadTable failed" << endl;
458           result = NDBT_FAILED;
459           break;
460         }
461       }
462       if (createIndexes) {
463         int icount = myRandom48(10);
464         int inum;
465         for (inum = 0; inum < icount; inum++) {
466           const int tcols = pTab2->getNoOfColumns();
467           require(tcols != 0);
468           int icols = 1 + myRandom48(tcols);
469           if (icols > NDB_MAX_ATTRIBUTES_IN_INDEX)
470             icols = NDB_MAX_ATTRIBUTES_IN_INDEX;
471           char indName[200];
472           sprintf(indName, "%s_X%d", tabName, inum);
473           NdbDictionary::Index ind(indName);
474           ind.setTable(tabName);
475           ind.setType(NdbDictionary::Index::OrderedIndex);
476           ind.setLogging(false);
477           Bitmask<MAX_ATTRIBUTES_IN_TABLE> mask;
478           char ilist[200];
479           ilist[0] = 0;
480           int ic;
481           for (ic = 0; ic < icols; ic++) {
482             int tc = myRandom48(tcols);
483             const NdbDictionary::Column* c = pTab2->getColumn(tc);
484             require(c != 0);
485             if (mask.get(tc) ||
486                 c->getType() == NdbDictionary::Column::Blob ||
487                 c->getType() == NdbDictionary::Column::Text ||
488                 c->getType() == NdbDictionary::Column::Bit ||
489                 c->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
490               continue;
491             ind.addColumn(*c);
492             mask.set(tc);
493             sprintf(ilist + strlen(ilist), " %d", tc);
494           }
495           if (mask.isclear())
496             continue;
497           g_info << indName << ": columns:" << ilist << endl;
498           if (pDic->createIndex(ind) == 0) {
499             g_info << indName << ": created" << endl;
500           } else {
501             const NdbError err = pDic->getNdbError();
502             g_err << indName << ": create index failed: " << err << endl;
503             if (err.code != 826 && // Too many tables and attributes..
504                 err.code != 903 && // Too many ordered indexes..
505                 err.code != 904 && // Out of fragment records..
506                 err.code != 905 && // Out of attribute records..
507                 err.code != 707 && // No more table metadata records..
508                 err.code != 708)   // No more attribute metadata records..
509             {
510               result = NDBT_FAILED;
511               break;
512             }
513           }
514         }
515       }
516       if (loadData) {
517         // first update a random table to flush global variables
518         int num3 = 0;
519         while (1) {
520           num3 = myRandom48(numAllTables);
521           if (num == num3 || tabList[num3].exists == 1)
522             break;
523         }
524         const NdbDictionary::Table* pTab3 = tabList[num3].pTab;
525         require(pTab3 != 0);
526         char tabName3[200];
527         strcpy(tabName3, pTab3->getName());
528         HugoTransactions hugoTrans(*pTab3);
529         g_info << tabName3 << ": update data" << endl;
530         if (hugoTrans.pkUpdateRecords(pNdb, records) != 0) {
531           g_err << tabName3 << ": pkUpdateRecords failed" << endl;
532           result = NDBT_FAILED;
533           break;
534         }
535       }
536       if (loadData) {
537         HugoTransactions hugoTrans(*pTab2);
538         g_info << tabName << ": update data" << endl;
539         if (hugoTrans.pkUpdateRecords(pNdb, records) != 0) {
540           g_err << "pkUpdateRecords failed" << endl;
541           result = NDBT_FAILED;
542           break;
543         }
544       }
545       tabList[num].exists = 1;
546       require(numExists < numTables);
547       numExists++;
548       if (numExists == numTables)
549         bias = 0;
550     }
551     else if (tabList[num].exists == 1) {
552       if (bias == 1 && myRandom48(100) < 80)
553         continue;
554       g_info << tabName << ": drop" << endl;
555       if (restarter.insertErrorInAllNodes(4013) != 0) {
556         g_err << "error insert failed" << endl;
557         result = NDBT_FAILED;
558         break;
559       }
560       if (pDic->dropTable(tabName) != 0) {
561         const NdbError err = pDic->getNdbError();
562         g_err << tabName << ": drop failed: " << err << endl;
563         result = NDBT_FAILED;
564         break;
565       }
566       const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
567       if (pTab2 != NULL) {
568         g_err << tabName << ": verify drop: table exists" << endl;
569         result = NDBT_FAILED;
570         break;
571       }
572       if (pDic->getNdbError().code != 709 &&
573           pDic->getNdbError().code != 723) {
574         const NdbError err = pDic->getNdbError();
575         g_err << tabName << ": verify drop: " << err << endl;
576         result = NDBT_FAILED;
577         break;
578       }
579       tabList[num].exists = 0;
580       require(numExists > 0);
581       numExists--;
582       if (numExists == 0)
583         bias = 1;
584     }
585     i++;
586   }
587 
588   for (num = 0; num < numAllTables; num++)
589     if (tabList[num].exists == 1)
590       pDic->dropTable(NDBT_Tables::getTable(num)->getName());
591 
592   delete [] tabList;
593   return result;
594 }
595 
596 
runCreateAndDropWithData(NDBT_Context * ctx,NDBT_Step * step)597 int runCreateAndDropWithData(NDBT_Context* ctx, NDBT_Step* step){
598   Ndb* pNdb = GETNDB(step);
599   int loops = ctx->getNumLoops();
600   int records = ctx->getNumRecords();
601   int i = 0;
602 
603   NdbRestarter restarter;
604   int val = DumpStateOrd::DihMinTimeBetweenLCP;
605   if(restarter.dumpStateAllNodes(&val, 1) != 0){
606     int result;
607     do { CHECK(0); } while (0);
608     g_err << "Unable to change timebetween LCP" << endl;
609     return NDBT_FAILED;
610   }
611 
612   const NdbDictionary::Table* pTab = ctx->getTab();
613   ndbout << "|- " << pTab->getName() << endl;
614 
615   while (i < loops){
616     ndbout << i << ": ";
617     // Try to create table in db
618 
619     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
620       return NDBT_FAILED;
621     }
622 
623     // Verify that table is in db
624     const NdbDictionary::Table* pTab2 =
625       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
626     if (pTab2 == NULL){
627       ndbout << pTab->getName() << " was not found in DB"<< endl;
628       return NDBT_FAILED;
629     }
630 
631     HugoTransactions hugoTrans(*pTab2);
632     if (hugoTrans.loadTable(pNdb, records) != 0){
633       return NDBT_FAILED;
634     }
635 
636     int count = 0;
637     UtilTransactions utilTrans(*pTab2);
638     if (utilTrans.selectCount(pNdb, 64, &count) != 0){
639       return NDBT_FAILED;
640     }
641     if (count != records){
642       ndbout << count <<" != "<<records << endl;
643       return NDBT_FAILED;
644     }
645 
646     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
647       ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
648       return NDBT_FAILED;
649     }
650 
651     // Verify that table is not in db
652     const NdbDictionary::Table* pTab3 =
653       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
654     if (pTab3 != NULL){
655       ndbout << pTab3->getName() << " was found in DB"<< endl;
656       return NDBT_FAILED;
657     }
658 
659 
660     i++;
661   }
662 
663   return NDBT_OK;
664 }
665 
runFillTable(NDBT_Context * ctx,NDBT_Step * step)666 int runFillTable(NDBT_Context* ctx, NDBT_Step* step){
667   Ndb* pNdb = GETNDB(step);
668   HugoTransactions hugoTrans(*ctx->getTab());
669   if (hugoTrans.fillTable(pNdb) != 0){
670     return NDBT_FAILED;
671   }
672   return NDBT_OK;
673 }
674 
runClearTable(NDBT_Context * ctx,NDBT_Step * step)675 int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
676   Ndb* pNdb = GETNDB(step);
677   int records = ctx->getNumRecords();
678 
679   UtilTransactions utilTrans(*ctx->getTab());
680   if (utilTrans.clearTable(pNdb,  records) != 0){
681     return NDBT_FAILED;
682   }
683   return NDBT_OK;
684 }
685 
runCreateAndDropDuring(NDBT_Context * ctx,NDBT_Step * step)686 int runCreateAndDropDuring(NDBT_Context* ctx, NDBT_Step* step){
687   int result = NDBT_OK;
688   int loops = ctx->getNumLoops();
689   int i = 0;
690 
691   const NdbDictionary::Table* pTab = ctx->getTab();
692   ndbout << "|- " << pTab->getName() << endl;
693 
694   while (i < loops && result == NDBT_OK){
695     ndbout << i << ": " << endl;
696     // Try to create table in db
697 
698     Ndb* pNdb = GETNDB(step);
699     g_debug << "Creating table" << endl;
700 
701     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
702       g_err << "createTableInDb failed" << endl;
703       result =  NDBT_FAILED;
704       continue;
705     }
706 
707     g_debug << "Verifying creation of table" << endl;
708 
709     // Verify that table is in db
710     const NdbDictionary::Table* pTab2 =
711       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
712     if (pTab2 == NULL){
713       g_err << pTab->getName() << " was not found in DB"<< endl;
714       result =  NDBT_FAILED;
715       continue;
716     }
717 
718     NdbSleep_MilliSleep(3000);
719 
720     g_debug << "Dropping table" << endl;
721 
722     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
723       g_err << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
724       result =  NDBT_FAILED;
725       continue;
726     }
727 
728     g_debug << "Verifying dropping of table" << endl;
729 
730     // Verify that table is not in db
731     const NdbDictionary::Table* pTab3 =
732       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
733     if (pTab3 != NULL){
734       g_err << pTab3->getName() << " was found in DB"<< endl;
735       result =  NDBT_FAILED;
736       continue;
737     }
738     i++;
739   }
740   ctx->stopTest();
741 
742   return result;
743 }
744 
745 
runUseTableUntilStopped(NDBT_Context * ctx,NDBT_Step * step)746 int runUseTableUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
747   int records = ctx->getNumRecords();
748 
749   const NdbDictionary::Table* pTab = ctx->getTab();
750 
751   while (ctx->isTestStopped() == false) {
752     // g_info << i++ << ": ";
753 
754 
755     // Delete and recreate Ndb object
756     // Otherwise you always get Invalid Schema Version
757     // It would be a nice feature to remove this two lines
758     //step->tearDown();
759     //step->setUp();
760 
761     Ndb* pNdb = GETNDB(step);
762 
763     const NdbDictionary::Table* pTab2 =
764       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
765     if (pTab2 == NULL)
766       continue;
767 
768     int res;
769     HugoTransactions hugoTrans(*pTab2);
770     if ((res = hugoTrans.loadTable(pNdb, records)) != 0){
771       NdbError err = pNdb->getNdbError(res);
772       if(err.classification == NdbError::SchemaError){
773 	pNdb->getDictionary()->invalidateTable(pTab->getName());
774       }
775       continue;
776     }
777 
778     if ((res = hugoTrans.clearTable(pNdb,  records)) != 0){
779       NdbError err = pNdb->getNdbError(res);
780       if(err.classification == NdbError::SchemaError){
781 	pNdb->getDictionary()->invalidateTable(pTab->getName());
782       }
783       continue;
784     }
785   }
786   g_info << endl;
787   return NDBT_OK;
788 }
789 
runUseTableUntilStopped2(NDBT_Context * ctx,NDBT_Step * step)790 int runUseTableUntilStopped2(NDBT_Context* ctx, NDBT_Step* step){
791   int records = ctx->getNumRecords();
792 
793   Ndb* pNdb = GETNDB(step);
794   const NdbDictionary::Table* pTab = ctx->getTab();
795   const NdbDictionary::Table* pTab2 =
796     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
797 
798   if (pTab2 == NULL) {
799     g_err << "Table: " << pTab->getName()
800           << ", not 'discovered' on line " << __LINE__
801           << endl;
802     return NDBT_FAILED;
803   }
804   HugoTransactions hugoTrans(*pTab2);
805 
806   int i = 0;
807   while (ctx->isTestStopped() == false)
808   {
809     ndbout_c("loop: %u", i++);
810 
811 
812     // Delete and recreate Ndb object
813     // Otherwise you always get Invalid Schema Version
814     // It would be a nice feature to remove this two lines
815     //step->tearDown();
816     //step->setUp();
817 
818 
819     int res;
820     if ((res = hugoTrans.loadTable(pNdb, records)) != 0){
821       NdbError err = pNdb->getNdbError(res);
822       if(err.classification == NdbError::SchemaError){
823 	pNdb->getDictionary()->invalidateTable(pTab->getName());
824       }
825       continue;
826     }
827 
828     if ((res = hugoTrans.scanUpdateRecords(pNdb, records)) != 0)
829     {
830       NdbError err = pNdb->getNdbError(res);
831       if(err.classification == NdbError::SchemaError){
832 	pNdb->getDictionary()->invalidateTable(pTab->getName());
833       }
834       continue;
835     }
836 
837     if ((res = hugoTrans.clearTable(pNdb,  records)) != 0){
838       NdbError err = pNdb->getNdbError(res);
839       if(err.classification == NdbError::SchemaError){
840 	pNdb->getDictionary()->invalidateTable(pTab->getName());
841       }
842       continue;
843     }
844   }
845   g_info << endl;
846   return NDBT_OK;
847 }
848 
runUseTableUntilStopped3(NDBT_Context * ctx,NDBT_Step * step)849 int runUseTableUntilStopped3(NDBT_Context* ctx, NDBT_Step* step){
850   int records = ctx->getNumRecords();
851 
852   Ndb* pNdb = GETNDB(step);
853   const NdbDictionary::Table* pTab = ctx->getTab();
854   const NdbDictionary::Table* pTab2 =
855     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
856   if (pTab2 == NULL) {
857     g_err << "Table : " << pTab->getName()
858           << ", not 'discovered' on line " << __LINE__
859           << endl;
860     return NDBT_FAILED;
861   }
862   HugoTransactions hugoTrans(*pTab2);
863 
864   int i = 0;
865   while (ctx->isTestStopped() == false)
866   {
867     ndbout_c("loop: %u", i++);
868 
869 
870     // Delete and recreate Ndb object
871     // Otherwise you always get Invalid Schema Version
872     // It would be a nice feature to remove this two lines
873     //step->tearDown();
874     //step->setUp();
875 
876 
877     int res;
878     if ((res = hugoTrans.scanUpdateRecords(pNdb, records)) != 0)
879     {
880       NdbError err = pNdb->getNdbError(res);
881       if(err.classification == NdbError::SchemaError){
882 	pNdb->getDictionary()->invalidateTable(pTab->getName());
883       }
884       continue;
885     }
886   }
887   g_info << endl;
888   return NDBT_OK;
889 }
890 
891 /**
892  * This is a regression test for bug 14190114
893  * "CLUSTER CRASH DUE TO NDBREQUIRE IN ./LOCALPROXY.HPP DBLQH (LINE: 234)".
894  * This bug occurs if there is a takeover (i.e. the master node crashes)
895  * while an LQH block is executing a DROP_TAB_REQ signal. It only affects
896  * multi-threaded ndb.
897  */
898 static int
runDropTakeoverTest(NDBT_Context * ctx,NDBT_Step * step)899 runDropTakeoverTest(NDBT_Context* ctx, NDBT_Step* step)
900 {
901   NdbRestarter restarter;
902   if (restarter.getNumDbNodes() == 1)
903   {
904     g_info << "Cannot do this test with just one datanode." << endl;
905     return NDBT_OK;
906   }
907 
908   Ndb* const ndb = GETNDB(step);
909   NdbDictionary::Dictionary* const dict = ndb->getDictionary();
910 
911   // First we create a table that is a copy of ctx->getTab().
912   NdbDictionary::Table copyTab(*ctx->getTab());
913   const char* copyName = "copyTab";
914 
915   copyTab.setName(copyName);
916   if (dict->createTable(copyTab) != 0)
917   {
918     g_err << "Failed to create table " << copyName << endl
919           << dict->getNdbError() << endl;
920     return NDBT_FAILED;
921   }
922 
923   /**
924    * Find the node id of the master node and another data node that is not
925    * the master.
926    */
927   const int masterNodeId = restarter.getMasterNodeId();
928   const int nonMasterNodeId =
929     masterNodeId == restarter.getDbNodeId(0) ?
930     restarter.getDbNodeId(1) :
931     restarter.getDbNodeId(0);
932 
933   /**
934    * This error insert makes LQH resend the DROP_TAB_REQ to itself (with a
935    * long delay) rather than executing it.
936    * This makes it appear as if though the LQH block spends a long time
937    * executing the DROP_TAB_REQ signal.
938    */
939   g_info << "Insert error 5076 in node " << nonMasterNodeId << endl;
940   restarter.insertErrorInNode(nonMasterNodeId, 5076);
941   /**
942    * This error insert makes the master node crash when one of its LQH
943    * blocks tries to execute a DROP_TAB_REQ signal. This will then trigger
944    * a takeover.
945    */
946   g_info << "Insert error 5077 in node " << masterNodeId << endl;
947   restarter.insertErrorInNode(masterNodeId, 5077);
948 
949   // dropTable should succeed with the new master.
950   g_info << "Trying to drop table " << copyName << endl;
951   if (dict->dropTable(copyName))
952   {
953     g_err << "Unexpectedly failed to drop table " << copyName << endl;
954     return NDBT_FAILED;
955   }
956 
957   /**
958    * Check that only old master is dead. Bug 14190114 would cause other nodes
959    * to die as well.
960    */
961   const int deadNodeId = restarter.checkClusterAlive(&masterNodeId, 1);
962   if (deadNodeId != 0)
963   {
964     g_err << "NodeId " << deadNodeId << " is down." << endl;
965     return NDBT_FAILED;
966   }
967 
968   // Verify that old master comes back up, and that no other node crashed.
969   g_info << "Waiting for all nodes to be up." << endl;
970   if (restarter.waitClusterStarted() != 0)
971   {
972     g_err << "One or more cluster nodes are not up." << endl;
973     return NDBT_FAILED;
974   }
975 
976   /**
977    * The 'drop table' operation should have been rolled forward, since the
978    * node crash happened in the complete phase. Verify that the table is
979    * gone.
980    */
981   g_info << "Verifying that table " << copyName << " was deleted." << endl;
982   if (dict->getTable(copyName) == NULL)
983   {
984     if (dict->getNdbError().code != 723) // 723 = no such table existed.
985     {
986       g_err << "dict->getTable() for " << copyName
987             << " failed in unexpedted way:" << endl
988             << dict->getNdbError() << endl;
989       return NDBT_FAILED;
990     }
991   }
992   else
993   {
994     g_err << "Transaction dropping " << copyName << " was not rolled forward"
995           << endl;
996     return NDBT_FAILED;
997   }
998 
999   /**
1000    * Do another dictionary transaction, to verify that the cluster allows that.
1001    */
1002   NdbDictionary::Table extraTab(*ctx->getTab());
1003   const char* extraName = "extraTab";
1004 
1005   extraTab.setName(extraName);
1006   g_info << "Trying to create table " << extraName << endl;
1007   if (dict->createTable(extraTab) != 0)
1008   {
1009     g_err << "Failed to create table " << extraName << endl
1010           << dict->getNdbError() << endl;
1011     return NDBT_FAILED;
1012   }
1013 
1014   // Clean up by dropping extraTab.
1015   g_info << "Trying to drop table " << extraName << endl;
1016   if (dict->dropTable(extraName) != 0)
1017   {
1018     g_err << "Failed to drop table " << extraName << endl
1019           << dict->getNdbError() << endl;
1020     return NDBT_FAILED;
1021   }
1022 
1023   return NDBT_OK;
1024 }
1025 
1026 int
runCreateMaxTables(NDBT_Context * ctx,NDBT_Step * step)1027 runCreateMaxTables(NDBT_Context* ctx, NDBT_Step* step)
1028 {
1029   char tabName[256];
1030   int numTables = ctx->getProperty("tables", 1000);
1031   Ndb* pNdb = GETNDB(step);
1032   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
1033   int i = 0;
1034   for (i = 0; i < numTables; i++) {
1035     BaseString::snprintf(tabName, 256, "MAXTAB%d", i);
1036     if (pNdb->waitUntilReady(30) != 0) {
1037       // Db is not ready, return with failure
1038       return NDBT_FAILED;
1039     }
1040     const NdbDictionary::Table* pTab = ctx->getTab();
1041     //ndbout << "|- " << tabName << endl;
1042     // Set new name for T1
1043     NdbDictionary::Table newTab(* pTab);
1044     newTab.setName(tabName);
1045     // Drop any old (or try to)
1046     (void)pDic->dropTable(newTab.getName());
1047     // Try to create table in db
1048     if (newTab.createTableInDb(pNdb) != 0) {
1049       ndbout << tabName << " could not be created: "
1050              << pDic->getNdbError() << endl;
1051       if (pDic->getNdbError().code == 707 ||
1052           pDic->getNdbError().code == 708 ||
1053           pDic->getNdbError().code == 826 ||
1054           pDic->getNdbError().code == 827)
1055         break;
1056       return NDBT_FAILED;
1057     }
1058     // Verify that table exists in db
1059     const NdbDictionary::Table* pTab3 =
1060       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1061     if (pTab3 == NULL){
1062       ndbout << tabName << " was not found in DB: "
1063              << pDic->getNdbError() << endl;
1064       return NDBT_FAILED;
1065     }
1066     if (! newTab.equal(*pTab3)) {
1067       ndbout << "It was not equal" << endl; abort();
1068       return NDBT_FAILED;
1069     }
1070     int records = ctx->getNumRecords();
1071     HugoTransactions hugoTrans(*pTab3);
1072     if (hugoTrans.loadTable(pNdb, records) != 0) {
1073       ndbout << "It can NOT be loaded" << endl;
1074       return NDBT_FAILED;
1075     }
1076     UtilTransactions utilTrans(*pTab3);
1077     if (utilTrans.clearTable(pNdb, records, 64) != 0) {
1078       ndbout << "It can NOT be cleared" << endl;
1079       return NDBT_FAILED;
1080     }
1081   }
1082   if (pNdb->waitUntilReady(30) != 0) {
1083     // Db is not ready, return with failure
1084     return NDBT_FAILED;
1085   }
1086   ctx->setProperty("maxtables", i);
1087   // HURRAAA!
1088   return NDBT_OK;
1089 }
1090 
runDropMaxTables(NDBT_Context * ctx,NDBT_Step * step)1091 int runDropMaxTables(NDBT_Context* ctx, NDBT_Step* step)
1092 {
1093   char tabName[256];
1094   int numTables = ctx->getProperty("maxtables", (Uint32)0);
1095   Ndb* pNdb = GETNDB(step);
1096   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
1097   for (int i = 0; i < numTables; i++) {
1098     BaseString::snprintf(tabName, 256, "MAXTAB%d", i);
1099     if (pNdb->waitUntilReady(30) != 0) {
1100       // Db is not ready, return with failure
1101       return NDBT_FAILED;
1102     }
1103     // Verify that table exists in db
1104     const NdbDictionary::Table* pTab3 =
1105       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1106     if (pTab3 == NULL) {
1107       ndbout << tabName << " was not found in DB: "
1108              << pDic->getNdbError() << endl;
1109       return NDBT_FAILED;
1110     }
1111     // Try to drop table in db
1112     if (pDic->dropTable(pTab3->getName()) != 0) {
1113       ndbout << tabName << " could not be dropped: "
1114              << pDic->getNdbError() << endl;
1115       return NDBT_FAILED;
1116     }
1117   }
1118   return NDBT_OK;
1119 }
1120 
runTestFragmentTypes(NDBT_Context * ctx,NDBT_Step * step)1121 int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){
1122   int records = ctx->getNumRecords();
1123   int fragTtype = ctx->getProperty("FragmentType");
1124   Ndb* pNdb = GETNDB(step);
1125   int result = NDBT_OK;
1126   NdbRestarter restarter;
1127 
1128   if (pNdb->waitUntilReady(30) != 0){
1129     // Db is not ready, return with failure
1130     return NDBT_FAILED;
1131   }
1132 
1133   const NdbDictionary::Table* pTab = ctx->getTab();
1134   pNdb->getDictionary()->dropTable(pTab->getName());
1135 
1136   NdbDictionary::Table newTab(* pTab);
1137   // Set fragment type for table
1138   newTab.setFragmentType((NdbDictionary::Object::FragmentType)fragTtype);
1139 
1140   // Try to create table in db
1141   if (newTab.createTableInDb(pNdb) != 0){
1142     ndbout << newTab.getName() << " could not be created"
1143 	   << ", fragmentType = "<<fragTtype <<endl;
1144     ndbout << pNdb->getDictionary()->getNdbError() << endl;
1145     return NDBT_FAILED;
1146   }
1147 
1148   // Verify that table exists in db
1149   const NdbDictionary::Table* pTab3 =
1150     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName()) ;
1151   if (pTab3 == NULL){
1152     ndbout << pTab->getName() << " was not found in DB"<< endl;
1153     return NDBT_FAILED;
1154 
1155   }
1156 
1157   if (pTab3->getFragmentType() != fragTtype){
1158     ndbout << pTab->getName() << " fragmentType error "<< endl;
1159     result = NDBT_FAILED;
1160     goto drop_the_tab;
1161   }
1162 /**
1163    This test does not work since fragmentation is
1164    decided by the kernel, hence the fragementation
1165    attribute on the column will differ
1166 
1167   if (newTab.equal(*pTab3) == false){
1168     ndbout << "It was not equal" << endl;
1169     result = NDBT_FAILED;
1170     goto drop_the_tab;
1171   }
1172 */
1173   do {
1174 
1175     HugoTransactions hugoTrans(*pTab3);
1176     UtilTransactions utilTrans(*pTab3);
1177     int count;
1178     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1179     CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1180     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1181     CHECK(count == records);
1182     CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0);
1183     CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0);
1184     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1185     CHECK(count == (records/2));
1186 
1187     // restart all
1188     ndbout << "Restarting cluster" << endl;
1189     CHECK(restarter.restartAll() == 0);
1190     int timeout = 120;
1191     CHECK(restarter.waitClusterStarted(timeout) == 0);
1192     CHECK(pNdb->waitUntilReady(timeout) == 0);
1193 
1194     // Verify content
1195     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1196     CHECK(count == (records/2));
1197 
1198     CHECK(utilTrans.clearTable(pNdb, records) == 0);
1199     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1200     CHECK(utilTrans.clearTable(pNdb, records) == 0);
1201     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1202     CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1203     CHECK(utilTrans.clearTable(pNdb, records, 64) == 0);
1204 
1205   } while(false);
1206 
1207  drop_the_tab:
1208 
1209   // Try to drop table in db
1210   if (pNdb->getDictionary()->dropTable(pTab3->getName()) != 0){
1211     ndbout << pTab3->getName()  << " could not be dropped"<< endl;
1212     result =  NDBT_FAILED;
1213   }
1214 
1215   return result;
1216 }
1217 
1218 
runTestTemporaryTables(NDBT_Context * ctx,NDBT_Step * step)1219 int runTestTemporaryTables(NDBT_Context* ctx, NDBT_Step* step){
1220   int result = NDBT_OK;
1221   int loops = ctx->getNumLoops();
1222   int records = ctx->getNumRecords();
1223   Ndb* pNdb = GETNDB(step);
1224   int i = 0;
1225   NdbRestarter restarter;
1226 
1227   const NdbDictionary::Table* pTab = ctx->getTab();
1228   ndbout << "|- " << pTab->getName() << endl;
1229 
1230   NdbDictionary::Table newTab(* pTab);
1231   // Set table as temporary
1232   newTab.setStoredTable(false);
1233 
1234   // Try to create table in db
1235   if (newTab.createTableInDb(pNdb) != 0){
1236     return NDBT_FAILED;
1237   }
1238 
1239   // Verify that table is in db
1240   const NdbDictionary::Table* pTab2 =
1241     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1242   if (pTab2 == NULL){
1243     ndbout << pTab->getName() << " was not found in DB"<< endl;
1244     return NDBT_FAILED;
1245   }
1246 
1247   if (pTab2->getStoredTable() != false){
1248     ndbout << pTab->getName() << " was not temporary in DB"<< endl;
1249     result = NDBT_FAILED;
1250     goto drop_the_tab;
1251   }
1252 
1253 
1254   while (i < loops && result == NDBT_OK){
1255     ndbout << i << ": ";
1256 
1257     HugoTransactions hugoTrans(*pTab2);
1258     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1259 
1260     int count = 0;
1261     UtilTransactions utilTrans(*pTab2);
1262     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1263     CHECK(count == records);
1264 
1265     // restart all
1266     ndbout << "Restarting cluster" << endl;
1267     CHECK(restarter.restartAll() == 0);
1268     int timeout = 120;
1269     CHECK(restarter.waitClusterStarted(timeout) == 0);
1270     CHECK(pNdb->waitUntilReady(timeout) == 0);
1271 
1272     ndbout << "Verifying records..." << endl;
1273     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1274     CHECK(count == 0);
1275 
1276     i++;
1277   }
1278 
1279  drop_the_tab:
1280 
1281 
1282   if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1283     ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
1284     result = NDBT_FAILED;
1285   }
1286 
1287   // Verify that table is not in db
1288   const NdbDictionary::Table* pTab3 =
1289     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1290   if (pTab3 != NULL){
1291     ndbout << pTab3->getName() << " was found in DB"<< endl;
1292     result = NDBT_FAILED;
1293   }
1294 
1295   return result;
1296 }
1297 
runPkSizes(NDBT_Context * ctx,NDBT_Step * step)1298 int runPkSizes(NDBT_Context* ctx, NDBT_Step* step){
1299   int result = NDBT_OK;
1300   char tabName[256];
1301   int minPkSize = 1;
1302   ndbout << "minPkSize=" <<minPkSize<<endl;
1303   int maxPkSize = MAX_KEY_SIZE_IN_WORDS * 4;
1304   ndbout << "maxPkSize=" <<maxPkSize<<endl;
1305   Ndb* pNdb = GETNDB(step);
1306   int numRecords = ctx->getNumRecords();
1307 
1308   for (int i = minPkSize; i < maxPkSize; i++){
1309     BaseString::snprintf(tabName, 256, "TPK_%d", i);
1310 
1311     int records = numRecords;
1312     int max = ~0;
1313     // Limit num records for small PKs
1314     if (i == 1)
1315       max = 99;
1316     if (i == 2)
1317       max = 999;
1318     if (i == 3)
1319       max = 9999;
1320     if (records > max)
1321       records = max;
1322     ndbout << "records =" << records << endl;
1323 
1324     if (pNdb->waitUntilReady(30) != 0){
1325       // Db is not ready, return with failure
1326       return NDBT_FAILED;
1327     }
1328 
1329     ndbout << "|- " << tabName << endl;
1330 
1331     if (NDBT_Tables::createTable(pNdb, tabName) != 0){
1332       ndbout << tabName << " could not be created"<< endl;
1333       return NDBT_FAILED;
1334     }
1335 
1336     // Verify that table exists in db
1337     const NdbDictionary::Table* pTab3 =
1338       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1339     if (pTab3 == NULL){
1340       g_err << tabName << " was not found in DB"<< endl;
1341       return NDBT_FAILED;
1342     }
1343 
1344     //    ndbout << *pTab3 << endl;
1345 
1346     if (pTab3->equal(*NDBT_Tables::getTable(tabName)) == false){
1347       g_err << "It was not equal" << endl;
1348       return NDBT_FAILED;
1349     }
1350 
1351     do {
1352       // Do it all
1353       HugoTransactions hugoTrans(*pTab3);
1354       UtilTransactions utilTrans(*pTab3);
1355       int count;
1356       CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1357       CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1358       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1359       CHECK(count == records);
1360       CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0);
1361       CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0);
1362       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1363       CHECK(count == (records/2));
1364       CHECK(utilTrans.clearTable(pNdb, records) == 0);
1365 
1366 #if 0
1367       // Fill table
1368       CHECK(hugoTrans.fillTable(pNdb) == 0);
1369       CHECK(utilTrans.clearTable2(pNdb, records) == 0);
1370       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1371       CHECK(count == 0);
1372 #endif
1373     } while(false);
1374 
1375     // Drop table
1376     if (pNdb->getDictionary()->dropTable(pTab3->getName()) != 0){
1377       ndbout << "Failed to drop "<<pTab3->getName()<<" in db" << endl;
1378       return NDBT_FAILED;
1379     }
1380   }
1381   return result;
1382 }
1383 
runStoreFrm(NDBT_Context * ctx,NDBT_Step * step)1384 int runStoreFrm(NDBT_Context* ctx, NDBT_Step* step){
1385   Ndb* pNdb = GETNDB(step);
1386   const NdbDictionary::Table* pTab = ctx->getTab();
1387   int result = NDBT_OK;
1388   int loops = ctx->getNumLoops();
1389 
1390   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1391 
1392     Uint32 dataLen = (Uint32)myRandom48(MAX_FRM_DATA_SIZE);
1393     // size_t dataLen = 10;
1394     unsigned char data[MAX_FRM_DATA_SIZE];
1395 
1396     char start = l + 248;
1397     for(Uint32 i = 0; i < dataLen; i++){
1398       data[i] = start;
1399       start++;
1400     }
1401 #if 0
1402     ndbout << "dataLen="<<dataLen<<endl;
1403     for (Uint32 i = 0; i < dataLen; i++){
1404       unsigned char c = data[i];
1405       ndbout << hex << c << ", ";
1406     }
1407     ndbout << endl;
1408 #endif
1409 
1410     NdbDictionary::Table newTab(* pTab);
1411     void* pData = &data;
1412     newTab.setFrm(pData, dataLen);
1413 
1414     // Try to create table in db
1415     if (newTab.createTableInDb(pNdb) != 0){
1416       result = NDBT_FAILED;
1417       continue;
1418     }
1419 
1420     // Verify that table is in db
1421     const NdbDictionary::Table* pTab2 =
1422       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1423     if (pTab2 == NULL){
1424       g_err << pTab->getName() << " was not found in DB"<< endl;
1425       result = NDBT_FAILED;
1426       continue;
1427     }
1428 
1429     const void* pData2 = pTab2->getFrmData();
1430     Uint32 resultLen = pTab2->getFrmLength();
1431     if (dataLen != resultLen){
1432       g_err << "Length of data failure" << endl
1433 	    << " expected = " << dataLen << endl
1434 	    << " got = " << resultLen << endl;
1435       result = NDBT_FAILED;
1436     }
1437 
1438     // Verfiy the frm data
1439     if (memcmp(pData, pData2, resultLen) != 0){
1440       g_err << "Wrong data received" << endl;
1441       for (size_t i = 0; i < dataLen; i++){
1442 	unsigned char c = ((unsigned char*)pData2)[i];
1443 	g_err << hex << c << ", ";
1444       }
1445       g_err << endl;
1446       result = NDBT_FAILED;
1447     }
1448 
1449     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1450       g_err << "It can NOT be dropped" << endl;
1451       result = NDBT_FAILED;
1452     }
1453   }
1454 
1455   return result;
1456 }
1457 
runStoreFrmError(NDBT_Context * ctx,NDBT_Step * step)1458 int runStoreFrmError(NDBT_Context* ctx, NDBT_Step* step){
1459   Ndb* pNdb = GETNDB(step);
1460   const NdbDictionary::Table* pTab = ctx->getTab();
1461   int result = NDBT_OK;
1462   int loops = ctx->getNumLoops();
1463 
1464   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1465 
1466     const Uint32 dataLen = MAX_FRM_DATA_SIZE + 10;
1467     unsigned char data[dataLen];
1468 
1469     char start = l + 248;
1470     for(Uint32 i = 0; i < dataLen; i++){
1471       data[i] = start;
1472       start++;
1473     }
1474 #if 0
1475     ndbout << "dataLen="<<dataLen<<endl;
1476     for (Uint32 i = 0; i < dataLen; i++){
1477       unsigned char c = data[i];
1478       ndbout << hex << c << ", ";
1479     }
1480     ndbout << endl;
1481 #endif
1482 
1483     NdbDictionary::Table newTab(* pTab);
1484 
1485     void* pData = &data;
1486     newTab.setFrm(pData, dataLen);
1487 
1488     // Try to create table in db
1489     if (newTab.createTableInDb(pNdb) == 0){
1490       result = NDBT_FAILED;
1491       continue;
1492     }
1493 
1494     const NdbDictionary::Table* pTab2 =
1495       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1496     if (pTab2 != NULL){
1497       g_err << pTab->getName() << " was found in DB"<< endl;
1498       result = NDBT_FAILED;
1499       if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1500 	g_err << "It can NOT be dropped" << endl;
1501 	result = NDBT_FAILED;
1502       }
1503 
1504       continue;
1505     }
1506 
1507   }
1508 
1509   return result;
1510 }
1511 
verifyTablesAreEqual(const NdbDictionary::Table * pTab,const NdbDictionary::Table * pTab2)1512 int verifyTablesAreEqual(const NdbDictionary::Table* pTab, const NdbDictionary::Table* pTab2){
1513   // Verify that getPrimaryKey only returned true for primary keys
1514   for (int i = 0; i < pTab2->getNoOfColumns(); i++){
1515     const NdbDictionary::Column* col = pTab->getColumn(i);
1516     const NdbDictionary::Column* col2 = pTab2->getColumn(i);
1517     if (col->getPrimaryKey() != col2->getPrimaryKey()){
1518       g_err << "col->getPrimaryKey() != col2->getPrimaryKey()" << endl;
1519       return NDBT_FAILED;
1520     }
1521   }
1522 
1523   if (!pTab->equal(*pTab2)){
1524     g_err << "equal failed" << endl;
1525     g_info << *(NDBT_Table*)pTab; // gcc-4.1.2
1526     g_info << *(NDBT_Table*)pTab2;
1527     return NDBT_FAILED;
1528   }
1529   return NDBT_OK;
1530 }
1531 
runGetPrimaryKey(NDBT_Context * ctx,NDBT_Step * step)1532 int runGetPrimaryKey(NDBT_Context* ctx, NDBT_Step* step){
1533   Ndb* pNdb = GETNDB(step);
1534   const NdbDictionary::Table* pTab = ctx->getTab();
1535   ndbout << "|- " << pTab->getName() << endl;
1536   g_info << *(NDBT_Table*)pTab;
1537   // Try to create table in db
1538   if (pTab->createTableInDb(pNdb) != 0){
1539     return NDBT_FAILED;
1540   }
1541 
1542   const NdbDictionary::Table* pTab2 =
1543     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1544   if (pTab2 == NULL){
1545     ndbout << pTab->getName() << " was not found in DB"<< endl;
1546     return NDBT_FAILED;
1547   }
1548 
1549   int result = NDBT_OK;
1550   if (verifyTablesAreEqual(pTab, pTab2) != NDBT_OK)
1551     result = NDBT_FAILED;
1552 
1553 
1554 #if 0
1555   // Create an index on the table and see what
1556   // the function returns now
1557   char name[200];
1558   sprintf(name, "%s_X007", pTab->getName());
1559   NDBT_Index* pInd = new NDBT_Index(name);
1560   pInd->setTable(pTab->getName());
1561   pInd->setType(NdbDictionary::Index::UniqueHashIndex);
1562   //  pInd->setLogging(false);
1563   for (int i = 0; i < 2; i++){
1564     const NDBT_Attribute* pAttr = pTab->getAttribute(i);
1565     pInd->addAttribute(*pAttr);
1566   }
1567   g_info << "Create index:" << endl << *pInd;
1568   if (pInd->createIndexInDb(pNdb, false) != 0){
1569     result = NDBT_FAILED;
1570   }
1571   delete pInd;
1572 
1573   const NdbDictionary::Table* pTab3 =
1574     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1575   if (pTab3 == NULL){
1576     ndbout << pTab->getName() << " was not found in DB"<< endl;
1577     return NDBT_FAILED;
1578   }
1579 
1580   if (verifyTablesAreEqual(pTab, pTab3) != NDBT_OK)
1581     result = NDBT_FAILED;
1582   if (verifyTablesAreEqual(pTab2, pTab3) != NDBT_OK)
1583     result = NDBT_FAILED;
1584 #endif
1585 
1586 #if 0
1587   if (pTab2->getDictionary()->dropTable(pNdb) != 0){
1588     ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
1589     return NDBT_FAILED;
1590   }
1591 
1592   // Verify that table is not in db
1593   const NdbDictionary::Table* pTab4 =
1594     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1595   if (pTab4 != NULL){
1596     ndbout << pTab4->getName() << " was found in DB"<< endl;
1597     return NDBT_FAILED;
1598   }
1599 #endif
1600 
1601   return result;
1602 }
1603 
1604 #define APIERROR(error) \
1605   { g_err << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
1606               << error.code << ", msg: " << error.message << "." << endl; \
1607   }
1608 
1609 int
runCreateAutoincrementTable(NDBT_Context * ctx,NDBT_Step * step)1610 runCreateAutoincrementTable(NDBT_Context* ctx, NDBT_Step* step){
1611 
1612   Uint32 startvalues[5] = {256-2, 0, 256*256-2, ~Uint32(0), 256*256*256-2};
1613 
1614   int ret = NDBT_OK;
1615 
1616   for (int jj = 0; jj < 5 && ret == NDBT_OK; jj++) {
1617     char tabname[] = "AUTOINCTAB";
1618     Uint32 startvalue = startvalues[jj];
1619 
1620     NdbDictionary::Table myTable;
1621     NdbDictionary::Column myColumn;
1622 
1623     Ndb* myNdb = GETNDB(step);
1624     NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
1625 
1626 
1627     if (myDict->getTable(tabname) != NULL) {
1628       g_err << "NDB already has example table: " << tabname << endl;
1629       APIERROR(myNdb->getNdbError());
1630       return NDBT_FAILED;
1631     }
1632 
1633     myTable.setName(tabname);
1634 
1635     myColumn.setName("ATTR1");
1636     myColumn.setType(NdbDictionary::Column::Unsigned);
1637     myColumn.setLength(1);
1638     myColumn.setPrimaryKey(true);
1639     myColumn.setNullable(false);
1640     myColumn.setAutoIncrement(true);
1641     if (startvalue != ~Uint32(0)) // check that default value starts with 1
1642       myColumn.setAutoIncrementInitialValue(startvalue);
1643     myTable.addColumn(myColumn);
1644 
1645     if (myDict->createTable(myTable) == -1) {
1646       g_err << "Failed to create table " << tabname << endl;
1647       APIERROR(myNdb->getNdbError());
1648       return NDBT_FAILED;
1649     }
1650 
1651 
1652     if (startvalue == ~Uint32(0)) // check that default value starts with 1
1653       startvalue = 1;
1654 
1655     for (int i = 0; i < 16; i++) {
1656 
1657       Uint64 value;
1658       if (myNdb->getAutoIncrementValue(tabname, value, 1) == -1) {
1659         g_err << "getAutoIncrementValue failed on " << tabname << endl;
1660         APIERROR(myNdb->getNdbError());
1661         return NDBT_FAILED;
1662       }
1663       else if (value != (startvalue+i)) {
1664         g_err << "value = " << value << " expected " << startvalue+i << endl;;
1665         APIERROR(myNdb->getNdbError());
1666         //      ret = NDBT_FAILED;
1667         //      break;
1668       }
1669     }
1670 
1671     if (myDict->dropTable(tabname) == -1) {
1672       g_err << "Failed to drop table " << tabname << endl;
1673       APIERROR(myNdb->getNdbError());
1674       ret = NDBT_FAILED;
1675     }
1676   }
1677 
1678   return ret;
1679 }
1680 
1681 int
runTableRename(NDBT_Context * ctx,NDBT_Step * step)1682 runTableRename(NDBT_Context* ctx, NDBT_Step* step){
1683 
1684   int result = NDBT_OK;
1685 
1686   Ndb* pNdb = GETNDB(step);
1687   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
1688   int records = ctx->getNumRecords();
1689   const int loops = ctx->getNumLoops();
1690 
1691   ndbout << "|- " << ctx->getTab()->getName() << endl;
1692 
1693   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1694     const NdbDictionary::Table* pTab = ctx->getTab();
1695 
1696     // Try to create table in db
1697     if (pTab->createTableInDb(pNdb) != 0){
1698       return NDBT_FAILED;
1699     }
1700 
1701     // Verify that table is in db
1702     const NdbDictionary::Table* pTab2 =
1703       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1704     if (pTab2 == NULL){
1705       ndbout << pTab->getName() << " was not found in DB"<< endl;
1706       return NDBT_FAILED;
1707     }
1708     ctx->setTab(pTab2);
1709 
1710     // Load table
1711     HugoTransactions hugoTrans(*ctx->getTab());
1712     if (hugoTrans.loadTable(pNdb, records) != 0){
1713       return NDBT_FAILED;
1714     }
1715 
1716     // Rename table
1717     BaseString pTabName(pTab->getName());
1718     BaseString pTabNewName(pTabName);
1719     pTabNewName.append("xx");
1720 
1721     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
1722     if (oldTable) {
1723       NdbDictionary::Table newTable = *oldTable;
1724       newTable.setName(pTabNewName.c_str());
1725       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
1726 	     "TableRename failed");
1727     }
1728     else {
1729       result = NDBT_FAILED;
1730     }
1731 
1732     // Verify table contents
1733     NdbDictionary::Table pNewTab(pTabNewName.c_str());
1734 
1735     UtilTransactions utilTrans(pNewTab);
1736     if (utilTrans.clearTable(pNdb,  records) != 0){
1737       continue;
1738     }
1739 
1740     // Drop table
1741     dict->dropTable(pNewTab.getName());
1742   }
1743  end:
1744 
1745   return result;
1746 }
1747 
1748 int
runTableRenameSR(NDBT_Context * ctx,NDBT_Step * step)1749 runTableRenameSR(NDBT_Context* ctx, NDBT_Step* step){
1750   NdbRestarter restarter;
1751   if(restarter.getNumDbNodes() < 2)
1752     return NDBT_OK;
1753 
1754   int result = NDBT_OK;
1755 
1756   Ndb* pNdb = GETNDB(step);
1757   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
1758   int records = ctx->getNumRecords();
1759   const int loops = ctx->getNumLoops();
1760 
1761   ndbout << "|- " << ctx->getTab()->getName() << endl;
1762 
1763   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1764     // Rename table
1765     const NdbDictionary::Table* pTab = ctx->getTab();
1766 
1767     // Try to create table in db
1768     if (pTab->createTableInDb(pNdb) != 0){
1769       return NDBT_FAILED;
1770     }
1771 
1772     // Verify that table is in db
1773     const NdbDictionary::Table* pTab2 =
1774       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1775     if (pTab2 == NULL){
1776       ndbout << pTab->getName() << " was not found in DB"<< endl;
1777       return NDBT_FAILED;
1778     }
1779     ctx->setTab(pTab2);
1780 
1781     // Load table
1782     HugoTransactions hugoTrans(*ctx->getTab());
1783     if (hugoTrans.loadTable(pNdb, records) != 0){
1784       return NDBT_FAILED;
1785     }
1786 
1787     BaseString pTabName(pTab->getName());
1788     BaseString pTabNewName(pTabName);
1789     pTabNewName.append("xx");
1790 
1791     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
1792     if (oldTable) {
1793       NdbDictionary::Table newTable = *oldTable;
1794       newTable.setName(pTabNewName.c_str());
1795       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
1796 	     "TableRename failed");
1797     }
1798     else {
1799       result = NDBT_FAILED;
1800     }
1801 
1802     // Restart cluster
1803 
1804     /**
1805      * Need to run LCP at high rate otherwise
1806      * packed replicas become "to many"
1807      */
1808     int val = DumpStateOrd::DihMinTimeBetweenLCP;
1809     if(restarter.dumpStateAllNodes(&val, 1) != 0){
1810       do { CHECK(0); } while(0);
1811       g_err << "Failed to set LCP to min value" << endl;
1812       return NDBT_FAILED;
1813     }
1814 
1815     CHECK2(restarter.restartAll() == 0,
1816 	   "failed to set restartOneDbNode");
1817 
1818     CHECK2(restarter.waitClusterStarted() == 0,
1819 	   "waitClusterStarted failed");
1820 
1821     // Verify table contents
1822     NdbDictionary::Table pNewTab(pTabNewName.c_str());
1823 
1824     UtilTransactions utilTrans(pNewTab);
1825     if (utilTrans.clearTable(pNdb,  records) != 0){
1826       continue;
1827     }
1828 
1829     // Drop table
1830     dict->dropTable(pTabNewName.c_str());
1831   }
1832  end:
1833   return result;
1834 }
1835 
1836 /*
1837   Run online alter table add attributes.
1838  */
1839 int
runTableAddAttrs(NDBT_Context * ctx,NDBT_Step * step)1840 runTableAddAttrs(NDBT_Context* ctx, NDBT_Step* step){
1841 
1842   int result = NDBT_OK;
1843 
1844   Ndb* pNdb = GETNDB(step);
1845   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
1846   int records = ctx->getNumRecords();
1847   const int loops = ctx->getNumLoops();
1848 
1849   ndbout << "|- " << ctx->getTab()->getName() << endl;
1850 
1851   NdbDictionary::Table myTab= *(ctx->getTab());
1852 
1853   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1854     // Try to create table in db
1855 
1856     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
1857       return NDBT_FAILED;
1858     }
1859 
1860     // Verify that table is in db
1861     const NdbDictionary::Table* pTab2 =
1862       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
1863     if (pTab2 == NULL){
1864       ndbout << myTab.getName() << " was not found in DB"<< endl;
1865       return NDBT_FAILED;
1866     }
1867     ctx->setTab(pTab2);
1868 
1869     /*
1870       Check that table already has a varpart, otherwise add attr is
1871       not possible.
1872     */
1873     if (pTab2->getForceVarPart() == false)
1874     {
1875       const NdbDictionary::Column *col;
1876       for (Uint32 i= 0; (col= pTab2->getColumn(i)) != 0; i++)
1877       {
1878         if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
1879             (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
1880           break;
1881       }
1882       if (col == 0)
1883       {
1884         /* Alter table add attribute not applicable, just mark success. */
1885         dict->dropTable(pTab2->getName());
1886         break;
1887       }
1888     }
1889 
1890     // Load table
1891     HugoTransactions beforeTrans(*ctx->getTab());
1892     if (beforeTrans.loadTable(pNdb, records) != 0){
1893       return NDBT_FAILED;
1894     }
1895 
1896     // Add attributes to table.
1897     BaseString pTabName(pTab2->getName());
1898 
1899     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
1900     if (oldTable) {
1901       NdbDictionary::Table newTable= *oldTable;
1902 
1903       NDBT_Attribute newcol1("NEWKOL1", NdbDictionary::Column::Unsigned, 1,
1904                             false, true, 0,
1905                             NdbDictionary::Column::StorageTypeMemory, true);
1906       newTable.addColumn(newcol1);
1907       NDBT_Attribute newcol2("NEWKOL2", NdbDictionary::Column::Char, 14,
1908                             false, true, 0,
1909                             NdbDictionary::Column::StorageTypeMemory, true);
1910       newTable.addColumn(newcol2);
1911       NDBT_Attribute newcol3("NEWKOL3", NdbDictionary::Column::Bit, 20,
1912                             false, true, 0,
1913                             NdbDictionary::Column::StorageTypeMemory, true);
1914       newTable.addColumn(newcol3);
1915       NDBT_Attribute newcol4("NEWKOL4", NdbDictionary::Column::Varbinary, 42,
1916                             false, true, 0,
1917                             NdbDictionary::Column::StorageTypeMemory, true);
1918       newTable.addColumn(newcol4);
1919 
1920       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
1921 	     "TableAddAttrs failed");
1922       /* Need to purge old version and reload new version after alter table. */
1923       dict->invalidateTable(pTabName.c_str());
1924     }
1925     else {
1926       result = NDBT_FAILED;
1927     }
1928 
1929     {
1930       const NdbDictionary::Table* pTab = dict->getTable(pTabName.c_str());
1931       CHECK2(pTab != NULL, "Table not found");
1932       HugoTransactions afterTrans(*pTab);
1933 
1934       ndbout << "delete...";
1935       if (afterTrans.clearTable(pNdb) != 0)
1936       {
1937         return NDBT_FAILED;
1938       }
1939       ndbout << endl;
1940 
1941       ndbout << "insert...";
1942       if (afterTrans.loadTable(pNdb, records) != 0){
1943         return NDBT_FAILED;
1944       }
1945       ndbout << endl;
1946 
1947       ndbout << "update...";
1948       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
1949       {
1950         return NDBT_FAILED;
1951       }
1952       ndbout << endl;
1953 
1954       ndbout << "delete...";
1955       if (afterTrans.clearTable(pNdb) != 0)
1956       {
1957         return NDBT_FAILED;
1958       }
1959       ndbout << endl;
1960     }
1961 
1962     // Drop table.
1963     dict->dropTable(pTabName.c_str());
1964   }
1965  end:
1966 
1967   return result;
1968 }
1969 
1970 /*
1971   Run online alter table add attributes while running simultaneous
1972   transactions on it in separate thread.
1973  */
1974 int
runTableAddAttrsDuring(NDBT_Context * ctx,NDBT_Step * step)1975 runTableAddAttrsDuring(NDBT_Context* ctx, NDBT_Step* step){
1976 
1977   int result = NDBT_OK;
1978   int abortAlter = ctx->getProperty("AbortAlter", Uint32(0));
1979 
1980   int records = ctx->getNumRecords();
1981   const int loops = ctx->getNumLoops();
1982   NdbRestarter res;
1983 
1984   ndbout << "|- " << ctx->getTab()->getName() << endl;
1985 
1986   NdbDictionary::Table myTab= *(ctx->getTab());
1987 
1988   if (myTab.getForceVarPart() == false)
1989   {
1990     const NdbDictionary::Column *col;
1991     for (Uint32 i= 0; (col= myTab.getColumn(i)) != 0; i++)
1992     {
1993       if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
1994           (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
1995         break;
1996     }
1997     if (col == 0)
1998     {
1999       ctx->stopTest();
2000       return NDBT_OK;
2001     }
2002   }
2003 
2004   //if
2005 
2006   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2007     ndbout << l << ": " << endl;
2008 
2009     Ndb* pNdb = GETNDB(step);
2010     NdbDictionary::Dictionary* dict = pNdb->getDictionary();
2011 
2012     /*
2013       Check that table already has a varpart, otherwise add attr is
2014       not possible.
2015     */
2016 
2017     // Add attributes to table.
2018     ndbout << "Altering table" << endl;
2019 
2020     const NdbDictionary::Table * oldTable = dict->getTable(myTab.getName());
2021     if (oldTable) {
2022       NdbDictionary::Table newTable= *oldTable;
2023 
2024       char name[256];
2025       BaseString::snprintf(name, sizeof(name), "NEWCOL%d", l);
2026       NDBT_Attribute newcol1(name, NdbDictionary::Column::Unsigned, 1,
2027                              false, true, 0,
2028                              NdbDictionary::Column::StorageTypeMemory, true);
2029       newTable.addColumn(newcol1);
2030       //ToDo: check #loops, how many columns l
2031 
2032       if (abortAlter == 0)
2033       {
2034         CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2035                "TableAddAttrsDuring failed");
2036       }
2037       else
2038       {
2039         int nodeId = res.getNode(NdbRestarter::NS_RANDOM);
2040         res.insertErrorInNode(nodeId, 4029);
2041         CHECK2(dict->alterTable(*oldTable, newTable) != 0,
2042                "TableAddAttrsDuring failed");
2043       }
2044 
2045       dict->invalidateTable(myTab.getName());
2046       const NdbDictionary::Table * newTab = dict->getTable(myTab.getName());
2047       CHECK2(newTab != NULL, "'newTab' not found");
2048       HugoTransactions hugoTrans(* newTab);
2049       hugoTrans.scanUpdateRecords(pNdb, records);
2050     }
2051     else {
2052       result= NDBT_FAILED;
2053       break;
2054     }
2055   }
2056  end:
2057 
2058   ctx->stopTest();
2059 
2060   return result;
2061 }
2062 
2063 static void
f(const NdbDictionary::Column * col)2064 f(const NdbDictionary::Column * col){
2065   if(col == 0){
2066     abort();
2067   }
2068 }
2069 
2070 int
runTestDictionaryPerf(NDBT_Context * ctx,NDBT_Step * step)2071 runTestDictionaryPerf(NDBT_Context* ctx, NDBT_Step* step){
2072   Vector<char*> cols;
2073   Vector<const NdbDictionary::Table*> tabs;
2074   int i;
2075 
2076   Ndb* pNdb = GETNDB(step);
2077 
2078   const Uint32 count = NDBT_Tables::getNumTables();
2079   for (i=0; i < (int)count; i++){
2080     const NdbDictionary::Table * tab = NDBT_Tables::getTable(i);
2081     pNdb->getDictionary()->createTable(* tab);
2082 
2083     const NdbDictionary::Table * tab2 = pNdb->getDictionary()->getTable(tab->getName());
2084 
2085     for(int j = 0; j<tab->getNoOfColumns(); j++){
2086       cols.push_back((char*)tab2);
2087       cols.push_back(strdup(tab->getColumn(j)->getName()));
2088     }
2089   }
2090 
2091   const Uint32 times = 10000000;
2092 
2093   ndbout_c("%d tables and %d columns",
2094 	   NDBT_Tables::getNumTables(), cols.size()/2);
2095 
2096   char ** tcols = cols.getBase();
2097 
2098   srand((unsigned int)time(0));
2099   Uint32 size = cols.size() / 2;
2100   //char ** columns = &cols[0];
2101   Uint64 start = NdbTick_CurrentMillisecond();
2102   for(i = 0; i<(int)times; i++){
2103     int j = 2 * (rand() % size);
2104     const NdbDictionary::Table* tab = (const NdbDictionary::Table*)tcols[j];
2105     const char * col = tcols[j+1];
2106     const NdbDictionary::Column* column = tab->getColumn(col);
2107     f(column);
2108   }
2109   Uint64 stop = NdbTick_CurrentMillisecond();
2110   stop -= start;
2111 
2112   Uint64 per = stop;
2113   per *= 1000;
2114   per /= times;
2115 
2116   ndbout_c("%d random getColumn(name) in %lld ms -> %u us/get",
2117 	   times, stop, Uint32(per));
2118 
2119   return NDBT_OK;
2120 }
2121 
2122 int
runCreateLogfileGroup(NDBT_Context * ctx,NDBT_Step * step)2123 runCreateLogfileGroup(NDBT_Context* ctx, NDBT_Step* step){
2124   Ndb* pNdb = GETNDB(step);
2125   NdbDictionary::LogfileGroup lg;
2126   lg.setName("DEFAULT-LG");
2127   lg.setUndoBufferSize(8*1024*1024);
2128 
2129   int res;
2130   res = pNdb->getDictionary()->createLogfileGroup(lg);
2131   if(res != 0){
2132     g_err << "Failed to create logfilegroup:"
2133 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2134     return NDBT_FAILED;
2135   }
2136 
2137   NdbDictionary::Undofile uf;
2138   uf.setPath("undofile01.dat");
2139   uf.setSize(5*1024*1024);
2140   uf.setLogfileGroup("DEFAULT-LG");
2141 
2142   res = pNdb->getDictionary()->createUndofile(uf);
2143   if(res != 0){
2144     g_err << "Failed to create undofile:"
2145 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2146     return NDBT_FAILED;
2147   }
2148 
2149   uf.setPath("undofile02.dat");
2150   uf.setSize(5*1024*1024);
2151   uf.setLogfileGroup("DEFAULT-LG");
2152 
2153   res = pNdb->getDictionary()->createUndofile(uf);
2154   if(res != 0){
2155     g_err << "Failed to create undofile:"
2156 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2157     return NDBT_FAILED;
2158   }
2159 
2160   return NDBT_OK;
2161 }
2162 
2163 int
runCreateTablespace(NDBT_Context * ctx,NDBT_Step * step)2164 runCreateTablespace(NDBT_Context* ctx, NDBT_Step* step){
2165   Ndb* pNdb = GETNDB(step);
2166   NdbDictionary::Tablespace lg;
2167   lg.setName("DEFAULT-TS");
2168   lg.setExtentSize(1024*1024);
2169   lg.setDefaultLogfileGroup("DEFAULT-LG");
2170 
2171   int res;
2172   res = pNdb->getDictionary()->createTablespace(lg);
2173   if(res != 0){
2174     g_err << "Failed to create tablespace:"
2175 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2176     return NDBT_FAILED;
2177   }
2178 
2179   NdbDictionary::Datafile uf;
2180   uf.setPath("datafile01.dat");
2181   uf.setSize(10*1024*1024);
2182   uf.setTablespace("DEFAULT-TS");
2183 
2184   res = pNdb->getDictionary()->createDatafile(uf);
2185   if(res != 0){
2186     g_err << "Failed to create datafile:"
2187 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2188     return NDBT_FAILED;
2189   }
2190 
2191   return NDBT_OK;
2192 }
2193 int
runCreateDiskTable(NDBT_Context * ctx,NDBT_Step * step)2194 runCreateDiskTable(NDBT_Context* ctx, NDBT_Step* step){
2195   Ndb* pNdb = GETNDB(step);
2196 
2197   NdbDictionary::Table tab = *ctx->getTab();
2198   tab.setTablespaceName("DEFAULT-TS");
2199 
2200   for(Uint32 i = 0; i<(Uint32)tab.getNoOfColumns(); i++)
2201     if(!tab.getColumn(i)->getPrimaryKey())
2202       tab.getColumn(i)->setStorageType(NdbDictionary::Column::StorageTypeDisk);
2203 
2204   int res;
2205   res = pNdb->getDictionary()->createTable(tab);
2206   if(res != 0){
2207     g_err << "Failed to create table:"
2208 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2209     return NDBT_FAILED;
2210   }
2211 
2212   return NDBT_OK;
2213 }
2214 
getColumnMaxLength(const NdbDictionary::Column * c)2215 int getColumnMaxLength(const NdbDictionary::Column* c)
2216 {
2217   int length= c->getLength();
2218   if (c->getArrayType() == NDB_ARRAYTYPE_FIXED)
2219   {
2220     /* Not yet set - need to calculate from type etc. */
2221     DictTabInfo::Attribute attrDesc;
2222 
2223     attrDesc.init();
2224     attrDesc.AttributeExtType= c->getType();
2225     attrDesc.AttributeExtLength= c->getLength();
2226     attrDesc.AttributeExtPrecision= c->getPrecision();
2227     attrDesc.AttributeExtScale= c->getScale();
2228 
2229     if (!attrDesc.translateExtType())
2230     {
2231       return 0;
2232     }
2233 
2234     if (attrDesc.AttributeSize == 0)
2235     {
2236       // bits...
2237       length = 4 * ((c->getLength() + 31) / 32);
2238     }
2239     else
2240     {
2241       length = ((1 << attrDesc.AttributeSize) * c->getLength()) >> 3;
2242     }
2243   }
2244 
2245   return length;
2246 }
2247 
2248 #include <NDBT_Tables.hpp>
2249 
2250 #define SAFTY 300
2251 
runFailAddFragment(NDBT_Context * ctx,NDBT_Step * step)2252 int runFailAddFragment(NDBT_Context* ctx, NDBT_Step* step){
2253   static int acclst[] = { 3001, 6200, 6202 };
2254   static int tuplst[] = { 4007, 4008, 4009, 4010, 4032, 4033, 4034 };
2255   static int tuxlst[] = { 12001, 12002, 12003, 12004,
2256                           6201, 6203 };
2257   static unsigned acccnt = sizeof(acclst)/sizeof(acclst[0]);
2258   static unsigned tupcnt = sizeof(tuplst)/sizeof(tuplst[0]);
2259   static unsigned tuxcnt = sizeof(tuxlst)/sizeof(tuxlst[0]);
2260 
2261   NdbRestarter restarter;
2262   int nodeId = restarter.getMasterNodeId();
2263   Ndb* pNdb = GETNDB(step);
2264   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
2265   NdbDictionary::Table tab(*ctx->getTab());
2266   tab.setFragmentType(NdbDictionary::Object::FragAllLarge);
2267 
2268   int errNo = 0;
2269 #ifdef NDB_USE_GET_ENV
2270   char buf[100];
2271   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
2272   {
2273     errNo = atoi(buf);
2274     ndbout_c("Using errno: %u", errNo);
2275   }
2276 #endif
2277   const NdbDictionary::Table* origTab= ctx->getTab();
2278   HugoCalculator calc(*origTab);
2279 
2280   // Add defaults to some columns
2281   for (int colNum= 0; colNum < tab.getNoOfColumns(); colNum++)
2282   {
2283     const NdbDictionary::Column* origCol= origTab->getColumn(colNum);
2284     NdbDictionary::Column* col= tab.getColumn(colNum);
2285     if (!origCol->getPrimaryKey())
2286     {
2287       if (myRandom48(2) == 0)
2288       {
2289         char defaultBuf[ NDB_MAX_TUPLE_SIZE ];
2290         Uint32 real_len;
2291         Uint32 updatesVal = myRandom48(1 << 16);
2292         const char* def= calc.calcValue(0, colNum, updatesVal,
2293                                         defaultBuf,
2294                                         getColumnMaxLength(origCol),
2295                                         &real_len);
2296         if (col->setDefaultValue(def, real_len) != 0)
2297         {
2298           ndbout_c("Error setting default value\n");
2299           return NDBT_FAILED;
2300         }
2301         NdbDictionary::NdbDataPrintFormat dpf;
2302         ndbout << "Set default for column " << origCol->getName()
2303                << " to ";
2304 
2305         NdbDictionary::printFormattedValue(ndbout,
2306                                            dpf,
2307                                            col,
2308                                            def);
2309         ndbout << endl;
2310       }
2311     }
2312   }
2313 
2314   // ordered index on first few columns
2315   NdbDictionary::Index idx("X");
2316   idx.setTable(tab.getName());
2317   idx.setType(NdbDictionary::Index::OrderedIndex);
2318   idx.setLogging(false);
2319   for (int cnt = 0, i_hate_broken_compilers = 0;
2320        cnt < 3 &&
2321        i_hate_broken_compilers < tab.getNoOfColumns();
2322        i_hate_broken_compilers++) {
2323     if (NdbSqlUtil::check_column_for_ordered_index
2324         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
2325         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
2326         NdbDictionary::Column::StorageTypeDisk)
2327     {
2328       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
2329       cnt++;
2330     }
2331   }
2332 
2333   for (Uint32 i = 0; i<(Uint32)tab.getNoOfColumns(); i++)
2334   {
2335     if (tab.getColumn(i)->getStorageType() ==
2336         NdbDictionary::Column::StorageTypeDisk)
2337     {
2338       NDBT_Tables::create_default_tablespace(pNdb);
2339       break;
2340     }
2341   }
2342 
2343   const int loops = ctx->getNumLoops();
2344   int result = NDBT_OK;
2345   (void)pDic->dropTable(tab.getName());
2346 
2347   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
2348   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
2349 
2350   for (int l = 0; l < loops; l++) {
2351     for (unsigned i0 = 0; i0 < acccnt; i0++) {
2352       unsigned j = (l == 0 ? i0 : myRandom48(acccnt));
2353       int errval = acclst[j];
2354       if (errNo != 0 && errNo != errval)
2355         continue;
2356       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
2357       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
2358       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
2359              "failed to set error insert");
2360       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2361       CHECK2(pDic->createTable(tab) != 0,
2362              "failed to fail after error insert " << errval);
2363       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
2364              "failed to clean error insert value");
2365       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
2366       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2367       CHECK2(pDic->createTable(tab) == 0,
2368              pDic->getNdbError());
2369       CHECK2(pDic->dropTable(tab.getName()) == 0,
2370              pDic->getNdbError());
2371     }
2372     for (unsigned i1 = 0; i1 < tupcnt; i1++) {
2373       unsigned j = (l == 0 ? i1 : myRandom48(tupcnt));
2374       int errval = tuplst[j];
2375       if (errNo != 0 && errNo != errval)
2376         continue;
2377       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
2378       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
2379       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
2380              "failed to set error insert");
2381       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2382       CHECK2(pDic->createTable(tab) != 0,
2383              "failed to fail after error insert " << errval);
2384       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
2385              "failed to clean error insert value");
2386       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
2387       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2388       CHECK2(pDic->createTable(tab) == 0,
2389              pDic->getNdbError());
2390       CHECK2(pDic->dropTable(tab.getName()) == 0,
2391              pDic->getNdbError());
2392     }
2393     for (unsigned i2 = 0; i2 < tuxcnt; i2++) {
2394       unsigned j = (l == 0 ? i2 : myRandom48(tuxcnt));
2395       int errval = tuxlst[j];
2396       if (errNo != 0 && errNo != errval)
2397         continue;
2398       CHECK2(pDic->createTable(tab) == 0,
2399              pDic->getNdbError());
2400 
2401       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
2402       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
2403       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
2404              "failed to set error insert");
2405       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2406 
2407       CHECK2(pDic->createIndex(idx) != 0,
2408              "failed to fail after error insert " << errval);
2409       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
2410              "failed to clean error insert value");
2411       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
2412       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2413       CHECK2(pDic->createIndex(idx) == 0,
2414              pDic->getNdbError());
2415       CHECK2(pDic->dropTable(tab.getName()) == 0,
2416              pDic->getNdbError());
2417     }
2418   }
2419 end:
2420   return result;
2421 }
2422 
2423 // NFNR
2424 
2425 // Restarter controls dict ops : 1-run 2-pause 3-stop
2426 // synced by polling...
2427 
2428 static bool
send_dict_ops_cmd(NDBT_Context * ctx,Uint32 cmd)2429 send_dict_ops_cmd(NDBT_Context* ctx, Uint32 cmd)
2430 {
2431   ctx->setProperty("DictOps_CMD", cmd);
2432   while (1) {
2433     if (ctx->isTestStopped())
2434       return false;
2435     if (ctx->getProperty("DictOps_ACK") == cmd)
2436       break;
2437     NdbSleep_MilliSleep(100);
2438   }
2439   return true;
2440 }
2441 
2442 static bool
recv_dict_ops_run(NDBT_Context * ctx)2443 recv_dict_ops_run(NDBT_Context* ctx)
2444 {
2445   while (1) {
2446     if (ctx->isTestStopped())
2447       return false;
2448     Uint32 cmd = ctx->getProperty("DictOps_CMD");
2449     ctx->setProperty("DictOps_ACK", cmd);
2450     if (cmd == 1)
2451       break;
2452     if (cmd == 3)
2453       return false;
2454     NdbSleep_MilliSleep(100);
2455   }
2456   return true;
2457 }
2458 
2459 int
runRestarts(NDBT_Context * ctx,NDBT_Step * step)2460 runRestarts(NDBT_Context* ctx, NDBT_Step* step)
2461 {
2462   static int errlst_master[] = {   // non-crashing
2463     7175,       // send one fake START_PERMREF
2464     0
2465   };
2466   static int errlst_node[] = {
2467     7174,       // crash before sending DICT_LOCK_REQ
2468     7176,       // pretend master does not support DICT lock
2469     7121,       // crash at receive START_PERMCONF
2470     0
2471   };
2472   const uint errcnt_master = sizeof(errlst_master)/sizeof(errlst_master[0]);
2473   const uint errcnt_node = sizeof(errlst_node)/sizeof(errlst_node[0]);
2474 
2475   myRandom48Init((long)NdbTick_CurrentMillisecond());
2476   NdbRestarter restarter;
2477   int result = NDBT_OK;
2478   const int loops = ctx->getNumLoops();
2479 
2480   for (int l = 0; l < loops && result == NDBT_OK; l++) {
2481     g_info << "1: === loop " << l << " ===" << endl;
2482 
2483     // assuming 2-way replicated
2484 
2485     int numnodes = restarter.getNumDbNodes();
2486     CHECK(numnodes >= 1);
2487     if (numnodes == 1)
2488       break;
2489 
2490     int masterNodeId = restarter.getMasterNodeId();
2491     CHECK(masterNodeId != -1);
2492 
2493     // for more complex cases need more restarter support methods
2494 
2495     int nodeIdList[2] = { 0, 0 };
2496     int nodeIdCnt = 0;
2497 
2498     if (numnodes >= 2) {
2499       int rand = myRandom48(numnodes);
2500       int nodeId = restarter.getRandomNotMasterNodeId(rand);
2501       CHECK(nodeId != -1);
2502       nodeIdList[nodeIdCnt++] = nodeId;
2503     }
2504 
2505     if (numnodes >= 4 && myRandom48(2) == 0) {
2506       int rand = myRandom48(numnodes);
2507       int nodeId = restarter.getRandomNodeOtherNodeGroup(nodeIdList[0], rand);
2508       CHECK(nodeId != -1);
2509       if (nodeId != masterNodeId)
2510         nodeIdList[nodeIdCnt++] = nodeId;
2511     }
2512 
2513     g_info << "1: master=" << masterNodeId << " nodes=" << nodeIdList[0] << "," << nodeIdList[1] << endl;
2514 
2515     const uint timeout = 60; //secs for node wait
2516     const unsigned maxsleep = 2000; //ms
2517 
2518     bool NF_ops = ctx->getProperty("Restart_NF_ops");
2519     uint NF_type = ctx->getProperty("Restart_NF_type");
2520     bool NR_ops = ctx->getProperty("Restart_NR_ops");
2521     bool NR_error = ctx->getProperty("Restart_NR_error");
2522 
2523     g_info << "1: " << (NF_ops ? "run" : "pause") << " dict ops" << endl;
2524     if (! send_dict_ops_cmd(ctx, NF_ops ? 1 : 2))
2525       break;
2526     NdbSleep_MilliSleep(myRandom48(maxsleep));
2527 
2528     {
2529       for (int i = 0; i < nodeIdCnt; i++) {
2530         int nodeId = nodeIdList[i];
2531 
2532         bool nostart = true;
2533         bool abort = NF_type == 0 ? myRandom48(2) : (NF_type == 2);
2534         bool initial = myRandom48(2);
2535 
2536         char flags[40];
2537         strcpy(flags, "flags: nostart");
2538         if (abort)
2539           strcat(flags, ",abort");
2540         if (initial)
2541           strcat(flags, ",initial");
2542 
2543         g_info << "1: restart " << nodeId << " " << flags << endl;
2544         CHECK(restarter.restartOneDbNode(nodeId, initial, nostart, abort) == 0);
2545       }
2546     }
2547 
2548     g_info << "1: wait for nostart" << endl;
2549     CHECK(restarter.waitNodesNoStart(nodeIdList, nodeIdCnt, timeout) == 0);
2550     NdbSleep_MilliSleep(myRandom48(maxsleep));
2551 
2552     int err_master = 0;
2553     int err_node[2] = { 0, 0 };
2554 
2555     if (NR_error) {
2556       err_master = errlst_master[l % errcnt_master];
2557 
2558       // limitation: cannot have 2 node restarts and crash_insert
2559       // one node may die for real (NF during startup)
2560 
2561       for (int i = 0; i < nodeIdCnt && nodeIdCnt == 1; i++) {
2562         err_node[i] = errlst_node[l % errcnt_node];
2563 
2564         // 7176 - no DICT lock protection
2565 
2566         if (err_node[i] == 7176) {
2567           g_info << "1: no dict ops due to error insert "
2568                  << err_node[i] << endl;
2569           NR_ops = false;
2570         }
2571       }
2572     }
2573 
2574     g_info << "1: " << (NR_ops ? "run" : "pause") << " dict ops" << endl;
2575     if (! send_dict_ops_cmd(ctx, NR_ops ? 1 : 2))
2576       break;
2577     NdbSleep_MilliSleep(myRandom48(maxsleep));
2578 
2579     g_info << "1: start nodes" << endl;
2580     CHECK(restarter.startNodes(nodeIdList, nodeIdCnt) == 0);
2581 
2582     if (NR_error) {
2583       {
2584         int err = err_master;
2585         if (err != 0) {
2586           g_info << "1: insert master error " << err << endl;
2587           CHECK(restarter.insertErrorInNode(masterNodeId, err) == 0);
2588         }
2589       }
2590 
2591       for (int i = 0; i < nodeIdCnt; i++) {
2592         int nodeId = nodeIdList[i];
2593 
2594         int err = err_node[i];
2595         if (err != 0) {
2596           g_info << "1: insert node " << nodeId << " error " << err << endl;
2597           CHECK(restarter.insertErrorInNode(nodeId, err) == 0);
2598         }
2599       }
2600     }
2601     NdbSleep_MilliSleep(myRandom48(maxsleep));
2602 
2603     g_info << "1: wait cluster started" << endl;
2604     CHECK(restarter.waitClusterStarted(timeout) == 0);
2605     NdbSleep_MilliSleep(myRandom48(maxsleep));
2606 
2607     g_info << "1: restart done" << endl;
2608   }
2609 
2610   g_info << "1: stop dict ops" << endl;
2611   send_dict_ops_cmd(ctx, 3);
2612 
2613   return result;
2614 }
2615 
2616 int
runDictOps(NDBT_Context * ctx,NDBT_Step * step)2617 runDictOps(NDBT_Context* ctx, NDBT_Step* step)
2618 {
2619   myRandom48Init((long)NdbTick_CurrentMillisecond());
2620   int result = NDBT_OK;
2621 
2622   for (int l = 0; result == NDBT_OK; l++) {
2623     if (! recv_dict_ops_run(ctx))
2624       break;
2625 
2626     g_info << "2: === loop " << l << " ===" << endl;
2627 
2628     Ndb* pNdb = GETNDB(step);
2629     NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
2630     const NdbDictionary::Table* pTab = ctx->getTab();
2631     //const char* tabName = pTab->getName(); //XXX what goes on?
2632     char tabName[40];
2633     strcpy(tabName, pTab->getName());
2634 
2635     const unsigned long maxsleep = 100; //ms
2636 
2637     g_info << "2: create table" << endl;
2638     {
2639       uint count = 0;
2640     try_create:
2641       count++;
2642       if (pDic->createTable(*pTab) != 0) {
2643         const NdbError err = pDic->getNdbError();
2644         if (count == 1)
2645           g_err << "2: " << tabName << ": create failed: " << err << endl;
2646         if (err.code != 711) {
2647           result = NDBT_FAILED;
2648           break;
2649         }
2650         NdbSleep_MilliSleep(myRandom48(maxsleep));
2651         goto try_create;
2652       }
2653     }
2654     NdbSleep_MilliSleep(myRandom48(maxsleep));
2655 
2656     g_info << "2: verify create" << endl;
2657     const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
2658     if (pTab2 == NULL) {
2659       const NdbError err = pDic->getNdbError();
2660       g_err << "2: " << tabName << ": verify create: " << err << endl;
2661       result = NDBT_FAILED;
2662       break;
2663     }
2664     NdbSleep_MilliSleep(myRandom48(maxsleep));
2665 
2666     // replace by the Retrieved table
2667     pTab = pTab2;
2668 
2669     // create indexes
2670     const char** indlist = NDBT_Tables::getIndexes(tabName);
2671     uint indnum = 0;
2672     while (indlist != 0 && *indlist != 0) {
2673       uint count = 0;
2674     try_create_index:
2675       count++;
2676       if (count == 1)
2677         g_info << "2: create index " << indnum << " " << *indlist << endl;
2678       NdbDictionary::Index ind;
2679       char indName[200];
2680       sprintf(indName, "%s_X%u", tabName, indnum);
2681       ind.setName(indName);
2682       ind.setTable(tabName);
2683       if (strcmp(*indlist, "UNIQUE") == 0) {
2684         ind.setType(NdbDictionary::Index::UniqueHashIndex);
2685         ind.setLogging(pTab->getLogging());
2686       } else if (strcmp(*indlist, "ORDERED") == 0) {
2687         ind.setType(NdbDictionary::Index::OrderedIndex);
2688         ind.setLogging(false);
2689       } else {
2690         require(false);
2691       }
2692       const char** indtemp = indlist;
2693       while (*++indtemp != 0) {
2694         ind.addColumn(*indtemp);
2695       }
2696       if (pDic->createIndex(ind) != 0) {
2697         const NdbError err = pDic->getNdbError();
2698         if (count == 1)
2699           g_err << "2: " << indName << ": create failed: " << err << endl;
2700         if (err.code != 711) {
2701           result = NDBT_FAILED;
2702           break;
2703         }
2704         NdbSleep_MilliSleep(myRandom48(maxsleep));
2705         goto try_create_index;
2706       }
2707       indlist = ++indtemp;
2708       indnum++;
2709     }
2710     if (result == NDBT_FAILED)
2711       break;
2712 
2713     uint indcount = indnum;
2714 
2715     int records = myRandom48(ctx->getNumRecords());
2716     g_info << "2: load " << records << " records" << endl;
2717     HugoTransactions hugoTrans(*pTab);
2718     if (hugoTrans.loadTable(pNdb, records) != 0) {
2719       // XXX get error code from hugo
2720       g_err << "2: " << tabName << ": load failed" << endl;
2721       result = NDBT_FAILED;
2722       break;
2723     }
2724     NdbSleep_MilliSleep(myRandom48(maxsleep));
2725 
2726     // drop indexes
2727     indnum = 0;
2728     while (indnum < indcount) {
2729       uint count = 0;
2730     try_drop_index:
2731       count++;
2732       if (count == 1)
2733         g_info << "2: drop index " << indnum << endl;
2734       char indName[200];
2735       sprintf(indName, "%s_X%u", tabName, indnum);
2736       if (pDic->dropIndex(indName, tabName) != 0) {
2737         const NdbError err = pDic->getNdbError();
2738         if (count == 1)
2739           g_err << "2: " << indName << ": drop failed: " << err << endl;
2740         if (err.code != 711) {
2741           result = NDBT_FAILED;
2742           break;
2743         }
2744         NdbSleep_MilliSleep(myRandom48(maxsleep));
2745         goto try_drop_index;
2746       }
2747       indnum++;
2748     }
2749     if (result == NDBT_FAILED)
2750       break;
2751 
2752     g_info << "2: drop" << endl;
2753     {
2754       uint count = 0;
2755     try_drop:
2756       count++;
2757       if (pDic->dropTable(tabName) != 0) {
2758         const NdbError err = pDic->getNdbError();
2759         if (count == 1)
2760           g_err << "2: " << tabName << ": drop failed: " << err << endl;
2761         if (err.code != 711) {
2762           result = NDBT_FAILED;
2763           break;
2764         }
2765         NdbSleep_MilliSleep(myRandom48(maxsleep));
2766         goto try_drop;
2767       }
2768     }
2769     NdbSleep_MilliSleep(myRandom48(maxsleep));
2770 
2771     g_info << "2: verify drop" << endl;
2772     const NdbDictionary::Table* pTab3 = pDic->getTable(tabName);
2773     if (pTab3 != NULL) {
2774       g_err << "2: " << tabName << ": verify drop: table exists" << endl;
2775       result = NDBT_FAILED;
2776       break;
2777     }
2778     if (pDic->getNdbError().code != 709 &&
2779         pDic->getNdbError().code != 723) {
2780       const NdbError err = pDic->getNdbError();
2781       g_err << "2: " << tabName << ": verify drop: " << err << endl;
2782       result = NDBT_FAILED;
2783       break;
2784     }
2785     NdbSleep_MilliSleep(myRandom48(maxsleep));
2786   }
2787 
2788   return result;
2789 }
2790 
2791 int
runBug21755(NDBT_Context * ctx,NDBT_Step * step)2792 runBug21755(NDBT_Context* ctx, NDBT_Step* step)
2793 {
2794   char buf[256];
2795   NdbRestarter res;
2796   NdbDictionary::Table pTab0 = * ctx->getTab();
2797   NdbDictionary::Table pTab1 = pTab0;
2798 
2799   if (res.getNumDbNodes() < 2)
2800     return NDBT_OK;
2801 
2802   Ndb* pNdb = GETNDB(step);
2803   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
2804 
2805   if (pDic->createTable(pTab0))
2806   {
2807     ndbout << pDic->getNdbError() << endl;
2808     return NDBT_FAILED;
2809   }
2810 
2811   NdbDictionary::Index idx0;
2812   BaseString::snprintf(buf, sizeof(buf), "%s-idx", pTab0.getName());
2813   idx0.setName(buf);
2814   idx0.setType(NdbDictionary::Index::OrderedIndex);
2815   idx0.setTable(pTab0.getName());
2816   idx0.setStoredIndex(false);
2817   for (Uint32 i = 0; i<(Uint32)pTab0.getNoOfColumns(); i++)
2818   {
2819     const NdbDictionary::Column * col = pTab0.getColumn(i);
2820     if(col->getPrimaryKey()){
2821       idx0.addIndexColumn(col->getName());
2822     }
2823   }
2824 
2825   if (pDic->createIndex(idx0))
2826   {
2827     ndbout << pDic->getNdbError() << endl;
2828     return NDBT_FAILED;
2829   }
2830 
2831   BaseString::snprintf(buf, sizeof(buf), "%s-2", pTab1.getName());
2832   pTab1.setName(buf);
2833 
2834   if (pDic->createTable(pTab1))
2835   {
2836     ndbout << pDic->getNdbError() << endl;
2837     return NDBT_FAILED;
2838   }
2839 
2840   {
2841     const NdbDictionary::Table* pTab = pDic->getTable(pTab0.getName());
2842     if (pTab == NULL) {
2843       g_err << "Table 'pTab0': " << pTab0.getName()
2844             << ", not found on line " << __LINE__
2845             <<", error: " << pDic->getNdbError()
2846             << endl;
2847       return NDBT_FAILED;
2848     }
2849     HugoTransactions t0 (*pTab);
2850     t0.loadTable(pNdb, 1000);
2851   }
2852 
2853   {
2854     const NdbDictionary::Table* pTab = pDic->getTable(pTab1.getName());
2855     if (pTab == NULL) {
2856       g_err << "Table 'pTab1': " << pTab1.getName()
2857             << ", not found on line " << __LINE__
2858             <<", error: " << pDic->getNdbError()
2859             << endl;
2860       return NDBT_FAILED;
2861     }
2862     HugoTransactions t1 (*pTab);
2863     t1.loadTable(pNdb, 1000);
2864   }
2865 
2866   int node = res.getRandomNotMasterNodeId(rand());
2867   res.restartOneDbNode(node, false, true, true);
2868 
2869   if (pDic->dropTable(pTab1.getName()))
2870   {
2871     ndbout << pDic->getNdbError() << endl;
2872     return NDBT_FAILED;
2873   }
2874 
2875   BaseString::snprintf(buf, sizeof(buf), "%s-idx2", pTab0.getName());
2876   idx0.setName(buf);
2877   if (pDic->createIndex(idx0))
2878   {
2879     ndbout << pDic->getNdbError() << endl;
2880     return NDBT_FAILED;
2881   }
2882 
2883   res.waitNodesNoStart(&node, 1);
2884   res.startNodes(&node, 1);
2885 
2886   if (res.waitClusterStarted())
2887   {
2888     return NDBT_FAILED;
2889   }
2890 
2891   if (pDic->dropTable(pTab0.getName()))
2892   {
2893     ndbout << pDic->getNdbError() << endl;
2894     return NDBT_FAILED;
2895   }
2896 
2897   return NDBT_OK;
2898 }
2899 
2900 static
2901 int
create_tablespace(NdbDictionary::Dictionary * pDict,const char * lgname,const char * tsname,const char * dfname)2902 create_tablespace(NdbDictionary::Dictionary* pDict,
2903                   const char * lgname,
2904                   const char * tsname,
2905                   const char * dfname)
2906 {
2907   NdbDictionary::Tablespace ts;
2908   ts.setName(tsname);
2909   ts.setExtentSize(1024*1024);
2910   ts.setDefaultLogfileGroup(lgname);
2911 
2912   if(pDict->createTablespace(ts) != 0)
2913   {
2914     g_err << "Failed to create tablespace:"
2915           << endl << pDict->getNdbError() << endl;
2916     return NDBT_FAILED;
2917   }
2918 
2919   NdbDictionary::Datafile df;
2920   df.setPath(dfname);
2921   df.setSize(1*1024*1024);
2922   df.setTablespace(tsname);
2923 
2924   if(pDict->createDatafile(df) != 0)
2925   {
2926     g_err << "Failed to create datafile:"
2927           << endl << pDict->getNdbError() << endl;
2928     return NDBT_FAILED;
2929   }
2930   return 0;
2931 }
2932 
2933 int
runBug24631(NDBT_Context * ctx,NDBT_Step * step)2934 runBug24631(NDBT_Context* ctx, NDBT_Step* step)
2935 {
2936   char tsname[256];
2937   char dfname[256];
2938   char lgname[256];
2939   char ufname[256];
2940   NdbRestarter res;
2941 
2942   if (res.getNumDbNodes() < 2)
2943     return NDBT_OK;
2944 
2945   Ndb* pNdb = GETNDB(step);
2946   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
2947 
2948   NdbDictionary::Dictionary::List list;
2949   if (pDict->listObjects(list) == -1)
2950     return NDBT_FAILED;
2951 
2952   const char * lgfound = 0;
2953 
2954   for (Uint32 i = 0; i<list.count; i++)
2955   {
2956     switch(list.elements[i].type){
2957     case NdbDictionary::Object::LogfileGroup:
2958       lgfound = list.elements[i].name;
2959       break;
2960     default:
2961       break;
2962     }
2963     if (lgfound)
2964       break;
2965   }
2966 
2967   if (lgfound == 0)
2968   {
2969     BaseString::snprintf(lgname, sizeof(lgname), "LG-%u", rand());
2970     NdbDictionary::LogfileGroup lg;
2971 
2972     lg.setName(lgname);
2973     lg.setUndoBufferSize(8*1024*1024);
2974     if(pDict->createLogfileGroup(lg) != 0)
2975     {
2976       g_err << "Failed to create logfilegroup:"
2977 	    << endl << pDict->getNdbError() << endl;
2978       return NDBT_FAILED;
2979     }
2980 
2981     NdbDictionary::Undofile uf;
2982     BaseString::snprintf(ufname, sizeof(ufname), "%s-%u", lgname, rand());
2983     uf.setPath(ufname);
2984     uf.setSize(2*1024*1024);
2985     uf.setLogfileGroup(lgname);
2986 
2987     if(pDict->createUndofile(uf) != 0)
2988     {
2989       g_err << "Failed to create undofile:"
2990             << endl << pDict->getNdbError() << endl;
2991       return NDBT_FAILED;
2992     }
2993   }
2994   else
2995   {
2996     BaseString::snprintf(lgname, sizeof(lgname), "%s", lgfound);
2997   }
2998 
2999   BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand());
3000   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u.dat", tsname, rand());
3001 
3002   if (create_tablespace(pDict, lgname, tsname, dfname))
3003     return NDBT_FAILED;
3004 
3005 
3006   int node = res.getRandomNotMasterNodeId(rand());
3007   res.restartOneDbNode(node, false, true, true);
3008   NdbSleep_SecSleep(3);
3009 
3010   if (pDict->dropDatafile(pDict->getDatafile(0, dfname)) != 0)
3011   {
3012     g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
3013     return NDBT_FAILED;
3014   }
3015 
3016   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3017   {
3018     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3019     return NDBT_FAILED;
3020   }
3021 
3022   if (res.waitNodesNoStart(&node, 1))
3023     return NDBT_FAILED;
3024 
3025   res.startNodes(&node, 1);
3026   if (res.waitClusterStarted())
3027     return NDBT_FAILED;
3028 
3029   if (create_tablespace(pDict, lgname, tsname, dfname))
3030     return NDBT_FAILED;
3031 
3032   if (pDict->dropDatafile(pDict->getDatafile(0, dfname)) != 0)
3033   {
3034     g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
3035     return NDBT_FAILED;
3036   }
3037 
3038   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3039   {
3040     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3041     return NDBT_FAILED;
3042   }
3043 
3044   if (lgfound == 0)
3045   {
3046     if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgname)) != 0)
3047       return NDBT_FAILED;
3048   }
3049 
3050   return NDBT_OK;
3051 }
3052 
3053 int
runBug29186(NDBT_Context * ctx,NDBT_Step * step)3054 runBug29186(NDBT_Context* ctx, NDBT_Step* step)
3055 {
3056   int lgError = 15000;
3057   int tsError = 16000;
3058   char lgname[256];
3059   char ufname[256];
3060   char tsname[256];
3061   char dfname[256];
3062 
3063   NdbRestarter restarter;
3064 
3065   if (restarter.getNumDbNodes() < 2){
3066     ctx->stopTest();
3067     return NDBT_OK;
3068   }
3069 
3070   Ndb* pNdb = GETNDB(step);
3071   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3072   NdbDictionary::Dictionary::List list;
3073 
3074   if (pDict->listObjects(list) == -1)
3075     return NDBT_FAILED;
3076 
3077   // 1.create logfile group
3078   const char * lgfound = 0;
3079 
3080   for (Uint32 i = 0; i<list.count; i++)
3081   {
3082     switch(list.elements[i].type){
3083     case NdbDictionary::Object::LogfileGroup:
3084       lgfound = list.elements[i].name;
3085       break;
3086     default:
3087       break;
3088     }
3089     if (lgfound)
3090       break;
3091   }
3092 
3093   if (lgfound == 0)
3094   {
3095     BaseString::snprintf(lgname, sizeof(lgname), "LG-%u", rand());
3096     NdbDictionary::LogfileGroup lg;
3097 
3098     lg.setName(lgname);
3099     lg.setUndoBufferSize(8*1024*1024);
3100     if(pDict->createLogfileGroup(lg) != 0)
3101     {
3102       g_err << "Failed to create logfilegroup:"
3103             << endl << pDict->getNdbError() << endl;
3104       return NDBT_FAILED;
3105     }
3106   }
3107   else
3108   {
3109     BaseString::snprintf(lgname, sizeof(lgname), "%s", lgfound);
3110   }
3111 
3112   if(restarter.waitClusterStarted(60)){
3113     g_err << "waitClusterStarted failed"<< endl;
3114     return NDBT_FAILED;
3115   }
3116 
3117   if(restarter.insertErrorInAllNodes(lgError) != 0){
3118     g_err << "failed to set error insert"<< endl;
3119     return NDBT_FAILED;
3120   }
3121 
3122   g_info << "error inserted"  << endl;
3123   g_info << "waiting some before add log file"  << endl;
3124   g_info << "starting create log file group"  << endl;
3125 
3126   NdbDictionary::Undofile uf;
3127   BaseString::snprintf(ufname, sizeof(ufname), "%s-%u", lgname, rand());
3128   uf.setPath(ufname);
3129   uf.setSize(2*1024*1024);
3130   uf.setLogfileGroup(lgname);
3131 
3132   if(pDict->createUndofile(uf) == 0)
3133   {
3134     g_err << "Create log file group should fail on error_insertion " << lgError << endl;
3135     return NDBT_FAILED;
3136   }
3137 
3138   //clear lg error
3139   if(restarter.insertErrorInAllNodes(15099) != 0){
3140     g_err << "failed to set error insert"<< endl;
3141     return NDBT_FAILED;
3142   }
3143   NdbSleep_SecSleep(5);
3144 
3145   //lg error has been cleared, so we can add undo file
3146   if(pDict->createUndofile(uf) != 0)
3147   {
3148     g_err << "Failed to create undofile:"
3149           << endl << pDict->getNdbError() << endl;
3150     return NDBT_FAILED;
3151   }
3152 
3153   if(restarter.waitClusterStarted(60)){
3154     g_err << "waitClusterStarted failed"<< endl;
3155     return NDBT_FAILED;
3156   }
3157 
3158   if(restarter.insertErrorInAllNodes(tsError) != 0){
3159     g_err << "failed to set error insert"<< endl;
3160     return NDBT_FAILED;
3161   }
3162   g_info << "error inserted"  << endl;
3163   g_info << "waiting some before create table space"  << endl;
3164   g_info << "starting create table space"  << endl;
3165 
3166   //r = runCreateTablespace(ctx, step);
3167   BaseString::snprintf(tsname,  sizeof(tsname), "TS-%u", rand());
3168   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u-1.dat", tsname, rand());
3169 
3170   NdbDictionary::Tablespace ts;
3171   ts.setName(tsname);
3172   ts.setExtentSize(1024*1024);
3173   ts.setDefaultLogfileGroup(lgname);
3174 
3175   if(pDict->createTablespace(ts) != 0)
3176   {
3177     g_err << "Failed to create tablespace:"
3178           << endl << pDict->getNdbError() << endl;
3179     return NDBT_FAILED;
3180   }
3181 
3182   NdbDictionary::Datafile df;
3183   df.setPath(dfname);
3184   df.setSize(1*1024*1024);
3185   df.setTablespace(tsname);
3186 
3187   if(pDict->createDatafile(df) == 0)
3188   {
3189     g_err << "Create table space should fail on error_insertion " << tsError << endl;
3190     return NDBT_FAILED;
3191   }
3192   //Clear the inserted error
3193   if(restarter.insertErrorInAllNodes(16099) != 0){
3194     g_err << "failed to set error insert"<< endl;
3195     return NDBT_FAILED;
3196   }
3197   NdbSleep_SecSleep(5);
3198 
3199   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3200   {
3201     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3202     return NDBT_FAILED;
3203   }
3204 
3205   if (lgfound == 0)
3206   {
3207     if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgname)) != 0)
3208       return NDBT_FAILED;
3209   }
3210 
3211   return NDBT_OK;
3212 }
3213 
3214 struct RandSchemaOp
3215 {
RandSchemaOpRandSchemaOp3216   RandSchemaOp(unsigned * randseed = 0) {
3217     if (randseed == 0)
3218     {
3219       ownseed = (unsigned)NdbTick_CurrentMillisecond();
3220       seed = &ownseed;
3221     }
3222     else
3223     {
3224       seed = randseed;
3225     }
3226   }
3227   struct Obj
3228   {
3229     BaseString m_name;
3230     Uint32 m_type;
3231     struct Obj* m_parent;
3232     Vector<Obj*> m_dependant;
3233   };
3234 
3235   Vector<Obj*> m_objects;
3236 
3237   int schema_op(Ndb*);
3238   int validate(Ndb*);
3239   int cleanup(Ndb*);
3240 
3241   Obj* get_obj(Uint32 mask);
3242   int create_table(Ndb*);
3243   int create_index(Ndb*, Obj*);
3244   int alter_table(Ndb*, Obj*);
3245   int drop_obj(Ndb*, Obj*);
3246 
3247   void remove_obj(Obj*);
3248 private:
3249   unsigned * seed;
3250   unsigned ownseed;
3251 };
3252 
3253 template class Vector<RandSchemaOp::Obj*>;
3254 
3255 int
schema_op(Ndb * ndb)3256 RandSchemaOp::schema_op(Ndb* ndb)
3257 {
3258   struct Obj* obj = 0;
3259   Uint32 type = 0;
3260 loop:
3261   switch(ndb_rand_r(seed) % 5){
3262   case 0:
3263     return create_table(ndb);
3264   case 1:
3265     if ((obj = get_obj(1 << NdbDictionary::Object::UserTable)) == 0)
3266       goto loop;
3267     return create_index(ndb, obj);
3268   case 2:
3269     type = (1 << NdbDictionary::Object::UserTable);
3270     goto drop_object;
3271   case 3:
3272     type =
3273       (1 << NdbDictionary::Object::UniqueHashIndex) |
3274       (1 << NdbDictionary::Object::OrderedIndex);
3275     goto drop_object;
3276   case 4:
3277     if ((obj = get_obj(1 << NdbDictionary::Object::UserTable)) == 0)
3278       goto loop;
3279     return alter_table(ndb, obj);
3280   default:
3281     goto loop;
3282   }
3283 
3284 drop_object:
3285   if ((obj = get_obj(type)) == 0)
3286     goto loop;
3287   return drop_obj(ndb, obj);
3288 }
3289 
3290 RandSchemaOp::Obj*
get_obj(Uint32 mask)3291 RandSchemaOp::get_obj(Uint32 mask)
3292 {
3293   Vector<Obj*> tmp;
3294   for (Uint32 i = 0; i<m_objects.size(); i++)
3295   {
3296     if ((1 << m_objects[i]->m_type) & mask)
3297       tmp.push_back(m_objects[i]);
3298   }
3299 
3300   if (tmp.size())
3301   {
3302     return tmp[ndb_rand_r(seed)%tmp.size()];
3303   }
3304   return 0;
3305 }
3306 
3307 int
create_table(Ndb * ndb)3308 RandSchemaOp::create_table(Ndb* ndb)
3309 {
3310   int numTables = NDBT_Tables::getNumTables();
3311   int num = ndb_rand_r(seed) % numTables;
3312   NdbDictionary::Table pTab = * NDBT_Tables::getTable(num);
3313 
3314   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3315   pTab.setForceVarPart(true);
3316 
3317   if (pDict->getTable(pTab.getName()))
3318   {
3319     char buf[100];
3320     BaseString::snprintf(buf, sizeof(buf), "%s-%d",
3321                          pTab.getName(), ndb_rand_r(seed));
3322     pTab.setName(buf);
3323     if (pDict->createTable(pTab))
3324       return NDBT_FAILED;
3325   }
3326   else
3327   {
3328     if (NDBT_Tables::createTable(ndb, pTab.getName()))
3329     {
3330       return NDBT_FAILED;
3331     }
3332   }
3333 
3334   ndbout_c("create table %s",  pTab.getName());
3335   const NdbDictionary::Table* tab2 = pDict->getTable(pTab.getName());
3336   if (tab2 == NULL) {
3337     g_err << "Table : " << pTab.getName()
3338           << ", not found on line " << __LINE__
3339           <<", error: " << pDict->getNdbError()
3340           << endl;
3341     return NDBT_FAILED;
3342   }
3343   HugoTransactions trans(*tab2);
3344   trans.loadTable(ndb, 1000);
3345 
3346   Obj *obj = new Obj;
3347   obj->m_name.assign(pTab.getName());
3348   obj->m_type = NdbDictionary::Object::UserTable;
3349   obj->m_parent = 0;
3350   m_objects.push_back(obj);
3351 
3352   return NDBT_OK;
3353 }
3354 
3355 int
create_index(Ndb * ndb,Obj * tab)3356 RandSchemaOp::create_index(Ndb* ndb, Obj* tab)
3357 {
3358   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3359   const NdbDictionary::Table * pTab = pDict->getTable(tab->m_name.c_str());
3360 
3361   if (pTab == 0)
3362   {
3363     return NDBT_FAILED;
3364   }
3365 
3366   bool ordered = ndb_rand_r(seed) & 1;
3367   bool stored = ndb_rand_r(seed) & 1;
3368 
3369   Uint32 type = ordered ?
3370     NdbDictionary::Index::OrderedIndex :
3371     NdbDictionary::Index::UniqueHashIndex;
3372 
3373   char buf[255];
3374   BaseString::snprintf(buf, sizeof(buf), "%s-%s",
3375                        pTab->getName(),
3376                        ordered ? "OI" : "UI");
3377 
3378   if (pDict->getIndex(buf, pTab->getName()))
3379   {
3380     // Index exists...let it be ok
3381     return NDBT_OK;
3382   }
3383 
3384   ndbout_c("create index %s", buf);
3385   NdbDictionary::Index idx0;
3386   idx0.setName(buf);
3387   idx0.setType((NdbDictionary::Index::Type)type);
3388   idx0.setTable(pTab->getName());
3389   idx0.setStoredIndex(ordered ? false : stored);
3390 
3391   for (Uint32 i = 0; i<(Uint32)pTab->getNoOfColumns(); i++)
3392   {
3393     if (pTab->getColumn(i)->getPrimaryKey())
3394       idx0.addColumn(pTab->getColumn(i)->getName());
3395   }
3396   if (pDict->createIndex(idx0))
3397   {
3398     ndbout << pDict->getNdbError() << endl;
3399     return NDBT_FAILED;
3400   }
3401   Obj *obj = new Obj;
3402   obj->m_name.assign(buf);
3403   obj->m_type = type;
3404   obj->m_parent = tab;
3405   m_objects.push_back(obj);
3406 
3407   tab->m_dependant.push_back(obj);
3408   return NDBT_OK;
3409 }
3410 
3411 int
drop_obj(Ndb * ndb,Obj * obj)3412 RandSchemaOp::drop_obj(Ndb* ndb, Obj* obj)
3413 {
3414   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3415 
3416   if (obj->m_type == NdbDictionary::Object::UserTable)
3417   {
3418     ndbout_c("drop table %s", obj->m_name.c_str());
3419     /**
3420      * Drop of table automatically drops all indexes
3421      */
3422     if (pDict->dropTable(obj->m_name.c_str()))
3423     {
3424       return NDBT_FAILED;
3425     }
3426     while(obj->m_dependant.size())
3427     {
3428       remove_obj(obj->m_dependant[0]);
3429     }
3430     remove_obj(obj);
3431   }
3432   else if (obj->m_type == NdbDictionary::Object::UniqueHashIndex ||
3433            obj->m_type == NdbDictionary::Object::OrderedIndex)
3434   {
3435     ndbout_c("drop index %s", obj->m_name.c_str());
3436     if (pDict->dropIndex(obj->m_name.c_str(),
3437                          obj->m_parent->m_name.c_str()))
3438     {
3439       return NDBT_FAILED;
3440     }
3441     remove_obj(obj);
3442   }
3443   return NDBT_OK;
3444 }
3445 
3446 void
remove_obj(Obj * obj)3447 RandSchemaOp::remove_obj(Obj* obj)
3448 {
3449   Uint32 i;
3450   if (obj->m_parent)
3451   {
3452     bool found = false;
3453     for (i = 0; i<obj->m_parent->m_dependant.size(); i++)
3454     {
3455       if (obj->m_parent->m_dependant[i] == obj)
3456       {
3457         found = true;
3458         obj->m_parent->m_dependant.erase(i);
3459         break;
3460       }
3461     }
3462     require(found);
3463   }
3464 
3465   {
3466     bool found = false;
3467     for (i = 0; i<m_objects.size(); i++)
3468     {
3469       if (m_objects[i] == obj)
3470       {
3471         found = true;
3472         m_objects.erase(i);
3473         break;
3474       }
3475     }
3476     require(found);
3477   }
3478   delete obj;
3479 }
3480 
3481 int
alter_table(Ndb * ndb,Obj * obj)3482 RandSchemaOp::alter_table(Ndb* ndb, Obj* obj)
3483 {
3484   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3485   const NdbDictionary::Table * pOld = pDict->getTable(obj->m_name.c_str());
3486   NdbDictionary::Table tNew = * pOld;
3487 
3488   BaseString ops;
3489   unsigned mask = 3;
3490 
3491   unsigned type;
3492   while (ops.length() == 0 && (mask != 0))
3493   {
3494     switch((type = (ndb_rand_r(seed) & 1))){
3495     default:
3496     case 0:{
3497       if ((mask & (1 << type)) == 0)
3498         break;
3499       BaseString name;
3500       name.assfmt("newcol_%d", tNew.getNoOfColumns());
3501       NdbDictionary::Column col(name.c_str());
3502       col.setType(NdbDictionary::Column::Unsigned);
3503       col.setDynamic(true);
3504       col.setPrimaryKey(false);
3505       col.setNullable(true);
3506       NdbDictionary::Table save = tNew;
3507       tNew.addColumn(col);
3508       if (!pDict->supportedAlterTable(* pOld, tNew))
3509       {
3510         ndbout_c("not supported...");
3511         mask &= ~(1 << type);
3512         tNew = save;
3513         break;
3514       }
3515       ops.append(" addcol");
3516       break;
3517     }
3518     case 1:{
3519       BaseString name;
3520       do
3521       {
3522         unsigned no = ndb_rand_r(seed);
3523         name.assfmt("%s_%u", pOld->getName(), no);
3524       } while (pDict->getTable(name.c_str()));
3525       tNew.setName(name.c_str());
3526       ops.appfmt(" rename: %s", name.c_str());
3527       break;
3528     }
3529 
3530     }
3531   }
3532 
3533   if (ops.length())
3534   {
3535     ndbout_c("altering %s ops: %s", pOld->getName(), ops.c_str());
3536     if (pDict->alterTable(*pOld, tNew) != 0)
3537     {
3538       g_err << pDict->getNdbError() << endl;
3539       return NDBT_FAILED;
3540     }
3541     pDict->invalidateTable(pOld->getName());
3542     if (strcmp(pOld->getName(), tNew.getName()))
3543     {
3544       obj->m_name.assign(tNew.getName());
3545     }
3546   }
3547 
3548   return NDBT_OK;
3549 }
3550 
3551 
3552 int
validate(Ndb * ndb)3553 RandSchemaOp::validate(Ndb* ndb)
3554 {
3555   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3556   for (Uint32 i = 0; i<m_objects.size(); i++)
3557   {
3558     if (m_objects[i]->m_type == NdbDictionary::Object::UserTable)
3559     {
3560       const NdbDictionary::Table* tab2 =
3561         pDict->getTable(m_objects[i]->m_name.c_str());
3562 
3563       if (tab2 == NULL) {
3564         g_err << "Table: " << m_objects[i]->m_name.c_str()
3565               << ", not found on line " << __LINE__
3566               <<", error: " << pDict->getNdbError()
3567               << endl;
3568         return NDBT_FAILED;
3569       }
3570       HugoTransactions trans(*tab2);
3571       trans.scanUpdateRecords(ndb, 1000);
3572       trans.clearTable(ndb);
3573       trans.loadTable(ndb, 1000);
3574     }
3575   }
3576 
3577   return NDBT_OK;
3578 }
3579 
3580 /*
3581       SystemTable = 1,        ///< System table
3582       UserTable = 2,          ///< User table (may be temporary)
3583       UniqueHashIndex = 3,    ///< Unique un-ordered hash index
3584       OrderedIndex = 6,       ///< Non-unique ordered index
3585       HashIndexTrigger = 7,   ///< Index maintenance, internal
3586       IndexTrigger = 8,       ///< Index maintenance, internal
3587       SubscriptionTrigger = 9,///< Backup or replication, internal
3588       ReadOnlyConstraint = 10,///< Trigger, internal
3589       Tablespace = 20,        ///< Tablespace
3590       LogfileGroup = 21,      ///< Logfile group
3591       Datafile = 22,          ///< Datafile
3592       Undofile = 23           ///< Undofile
3593 */
3594 
3595 int
cleanup(Ndb * ndb)3596 RandSchemaOp::cleanup(Ndb* ndb)
3597 {
3598   Int32 i;
3599   for (i = m_objects.size() - 1; i >= 0; i--)
3600   {
3601     switch(m_objects[i]->m_type){
3602     case NdbDictionary::Object::UniqueHashIndex:
3603     case NdbDictionary::Object::OrderedIndex:
3604       if (drop_obj(ndb, m_objects[i]))
3605         return NDBT_FAILED;
3606 
3607       break;
3608     default:
3609       break;
3610     }
3611   }
3612 
3613   for (i = m_objects.size() - 1; i >= 0; i--)
3614   {
3615     switch(m_objects[i]->m_type){
3616     case NdbDictionary::Object::UserTable:
3617       if (drop_obj(ndb, m_objects[i]))
3618         return NDBT_FAILED;
3619       break;
3620     default:
3621       break;
3622     }
3623   }
3624 
3625   require(m_objects.size() == 0);
3626   return NDBT_OK;
3627 }
3628 
3629 extern unsigned opt_seed;
3630 
3631 int
runDictRestart(NDBT_Context * ctx,NDBT_Step * step)3632 runDictRestart(NDBT_Context* ctx, NDBT_Step* step)
3633 {
3634   Ndb* pNdb = GETNDB(step);
3635   int loops = ctx->getNumLoops();
3636 
3637   unsigned seed = opt_seed;
3638   NdbMixRestarter res(&seed);
3639   RandSchemaOp dict(&seed);
3640   if (res.getNumDbNodes() < 2)
3641     return NDBT_OK;
3642 
3643   if (res.init(ctx, step))
3644     return NDBT_FAILED;
3645 
3646   for (int i = 0; i<loops; i++)
3647   {
3648     for (Uint32 j = 0; j<10; j++)
3649       if (dict.schema_op(pNdb))
3650         return NDBT_FAILED;
3651 
3652     if (res.dostep(ctx, step))
3653       return NDBT_FAILED;
3654 
3655     if (dict.validate(pNdb))
3656       return NDBT_FAILED;
3657   }
3658 
3659   if (res.finish(ctx, step))
3660     return NDBT_FAILED;
3661 
3662   if (dict.validate(pNdb))
3663     return NDBT_FAILED;
3664 
3665   if (dict.cleanup(pNdb))
3666     return NDBT_FAILED;
3667 
3668   return NDBT_OK;
3669 }
3670 
3671 int
runBug29501(NDBT_Context * ctx,NDBT_Step * step)3672 runBug29501(NDBT_Context* ctx, NDBT_Step* step) {
3673   NdbRestarter res;
3674   NdbDictionary::LogfileGroup lg;
3675   lg.setName("DEFAULT-LG");
3676   lg.setUndoBufferSize(8*1024*1024);
3677 
3678   if (res.getNumDbNodes() < 2)
3679     return NDBT_OK;
3680 
3681   Ndb* pNdb = GETNDB(step);
3682   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3683 
3684   int node = res.getRandomNotMasterNodeId(rand());
3685   res.restartOneDbNode(node, true, true, false);
3686 
3687   if(pDict->createLogfileGroup(lg) != 0){
3688     g_err << "Failed to create logfilegroup:"
3689         << endl << pDict->getNdbError() << endl;
3690     return NDBT_FAILED;
3691   }
3692 
3693   NdbDictionary::Undofile uf;
3694   uf.setPath("undofile01.dat");
3695   uf.setSize(5*1024*1024);
3696   uf.setLogfileGroup("DEFAULT-LG");
3697 
3698   if(pDict->createUndofile(uf) != 0){
3699     g_err << "Failed to create undofile:"
3700         << endl << pDict->getNdbError() << endl;
3701     return NDBT_FAILED;
3702   }
3703 
3704   res.waitNodesNoStart(&node, 1);
3705   res.startNodes(&node, 1);
3706 
3707   if (res.waitClusterStarted()){
3708   	g_err << "Node restart failed"
3709   	<< endl << pDict->getNdbError() << endl;
3710       return NDBT_FAILED;
3711   }
3712 
3713   if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lg.getName())) != 0){
3714   	g_err << "Drop of LFG Failed"
3715   	<< endl << pDict->getNdbError() << endl;
3716     return NDBT_FAILED;
3717   }
3718 
3719   return NDBT_OK;
3720 }
3721 
3722 int
runDropDDObjects(NDBT_Context * ctx,NDBT_Step * step)3723 runDropDDObjects(NDBT_Context* ctx, NDBT_Step* step){
3724   //Purpose is to drop all tables, data files, Table spaces and LFG's
3725   Uint32 i = 0;
3726 
3727   Ndb* pNdb = GETNDB(step);
3728   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3729 
3730   NdbDictionary::Dictionary::List list;
3731   if (pDict->listObjects(list) == -1)
3732     return NDBT_FAILED;
3733 
3734   //Search the list and drop all tables found
3735   const char * tableFound = 0;
3736   for (i = 0; i < list.count; i++){
3737     switch(list.elements[i].type){
3738       case NdbDictionary::Object::UserTable:
3739         tableFound = list.elements[i].name;
3740         if(tableFound != 0){
3741           if(strcmp(list.elements[i].database, "TEST_DB") == 0 &&
3742              !is_prefix(tableFound, "NDB$BLOB"))
3743           {
3744       	    if(pDict->dropTable(tableFound) != 0){
3745               g_err << "Failed to drop table: " << tableFound << pDict->getNdbError() << endl;
3746               return NDBT_FAILED;
3747             }
3748           }
3749         }
3750         tableFound = 0;
3751         break;
3752       default:
3753         break;
3754     }
3755   }
3756 
3757   //Search the list and drop all data file found
3758   const char * dfFound = 0;
3759   for (i = 0; i < list.count; i++){
3760     switch(list.elements[i].type){
3761       case NdbDictionary::Object::Datafile:
3762         dfFound = list.elements[i].name;
3763         if(dfFound != 0){
3764       	  if(pDict->dropDatafile(pDict->getDatafile(0, dfFound)) != 0){
3765             g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
3766             return NDBT_FAILED;
3767           }
3768         }
3769         dfFound = 0;
3770         break;
3771       default:
3772         break;
3773     }
3774   }
3775 
3776   //Search the list and drop all Table Spaces Found
3777   const char * tsFound  = 0;
3778   for (i = 0; i <list.count; i++){
3779     switch(list.elements[i].type){
3780       case NdbDictionary::Object::Tablespace:
3781         tsFound = list.elements[i].name;
3782         if(tsFound != 0){
3783           if(pDict->dropTablespace(pDict->getTablespace(tsFound)) != 0){
3784             g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3785             return NDBT_FAILED;
3786           }
3787         }
3788         tsFound = 0;
3789         break;
3790       default:
3791         break;
3792     }
3793   }
3794 
3795   //Search the list and drop all LFG Found
3796   //Currently only 1 LGF is supported, but written for future
3797   //when more then one is supported.
3798   const char * lgFound  = 0;
3799   for (i = 0; i < list.count; i++){
3800     switch(list.elements[i].type){
3801       case NdbDictionary::Object::LogfileGroup:
3802         lgFound = list.elements[i].name;
3803         if(lgFound != 0){
3804           if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgFound)) != 0){
3805             g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3806             return NDBT_FAILED;
3807           }
3808        }
3809         lgFound = 0;
3810         break;
3811       default:
3812         break;
3813     }
3814   }
3815 
3816   return NDBT_OK;
3817 }
3818 
3819 int
runWaitStarted(NDBT_Context * ctx,NDBT_Step * step)3820 runWaitStarted(NDBT_Context* ctx, NDBT_Step* step){
3821 
3822   NdbRestarter restarter;
3823   restarter.waitClusterStarted(300);
3824 
3825   NdbSleep_SecSleep(3);
3826   return NDBT_OK;
3827 }
3828 
3829 int
testDropDDObjectsSetup(NDBT_Context * ctx,NDBT_Step * step)3830 testDropDDObjectsSetup(NDBT_Context* ctx, NDBT_Step* step){
3831   //Purpose is to setup to test DropDDObjects
3832   char tsname[256];
3833   char dfname[256];
3834 
3835   Ndb* pNdb = GETNDB(step);
3836   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3837 
3838   NdbDictionary::LogfileGroup lg;
3839   lg.setName("DEFAULT-LG");
3840   lg.setUndoBufferSize(8*1024*1024);
3841 
3842 
3843   if(pDict->createLogfileGroup(lg) != 0){
3844     g_err << "Failed to create logfilegroup:"
3845         << endl << pDict->getNdbError() << endl;
3846     return NDBT_FAILED;
3847   }
3848 
3849   NdbDictionary::Undofile uf;
3850   uf.setPath("undofile01.dat");
3851   uf.setSize(5*1024*1024);
3852   uf.setLogfileGroup("DEFAULT-LG");
3853 
3854   if(pDict->createUndofile(uf) != 0){
3855     g_err << "Failed to create undofile:"
3856         << endl << pDict->getNdbError() << endl;
3857     return NDBT_FAILED;
3858   }
3859 
3860   BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand());
3861   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u.dat", tsname, rand());
3862 
3863   if (create_tablespace(pDict, lg.getName(), tsname, dfname)){
3864   	g_err << "Failed to create undofile:"
3865         << endl << pDict->getNdbError() << endl;
3866     return NDBT_FAILED;
3867   }
3868 
3869   return NDBT_OK;
3870 }
3871 
3872 int
runBug36072(NDBT_Context * ctx,NDBT_Step * step)3873 runBug36072(NDBT_Context* ctx, NDBT_Step* step)
3874 {
3875   Ndb* pNdb = GETNDB(step);
3876   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3877   NdbRestarter res;
3878 
3879   int err[] = { 6016,
3880 #if BUG_46856
3881                 6017,
3882 #endif
3883                 0 };
3884   for (Uint32 i = 0; err[i] != 0; i++)
3885   {
3886     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
3887 
3888     if (res.dumpStateAllNodes(val2, 2))
3889       return NDBT_FAILED;
3890 
3891     if (res.insertErrorInAllNodes(932)) // arbit
3892       return NDBT_FAILED;
3893 
3894     int code = err[i];
3895 
3896     if (code == 6016)
3897     {
3898       if (res.insertErrorInAllNodes(code))
3899         return NDBT_FAILED;
3900     }
3901 
3902     NdbDictionary::LogfileGroup lg;
3903     lg.setName("DEFAULT-LG");
3904     lg.setUndoBufferSize(8*1024*1024);
3905 
3906     NdbDictionary::Undofile uf;
3907     uf.setPath("undofile01.dat");
3908     uf.setSize(5*1024*1024);
3909     uf.setLogfileGroup("DEFAULT-LG");
3910 
3911     int r = pDict->createLogfileGroup(lg);
3912     if (code == 6017)
3913     {
3914       if (r)
3915       {
3916         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
3917         return NDBT_FAILED;
3918       }
3919 
3920       if (res.insertErrorInAllNodes(err[i]))
3921         return NDBT_FAILED;
3922 
3923       pDict->createUndofile(uf);
3924     }
3925 
3926     if (res.waitClusterNoStart())
3927       return NDBT_FAILED;
3928 
3929     res.startAll();
3930     if (res.waitClusterStarted())
3931       return NDBT_FAILED;
3932 
3933     if (code == 6016)
3934     {
3935       NdbDictionary::LogfileGroup lg2 = pDict->getLogfileGroup("DEFAULT-LG");
3936       NdbError err= pDict->getNdbError();
3937       if( (int) err.classification == (int) ndberror_cl_none)
3938       {
3939         ndbout << __LINE__ << endl;
3940         return NDBT_FAILED;
3941       }
3942 
3943       if (pDict->createLogfileGroup(lg) != 0)
3944       {
3945         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
3946         return NDBT_FAILED;
3947       }
3948     }
3949     else
3950     {
3951       NdbDictionary::Undofile uf2 = pDict->getUndofile(0, "undofile01.dat");
3952       NdbError err= pDict->getNdbError();
3953       if( (int) err.classification == (int) ndberror_cl_none)
3954       {
3955         ndbout << __LINE__ << endl;
3956         return NDBT_FAILED;
3957       }
3958 
3959       if (pDict->createUndofile(uf) != 0)
3960       {
3961         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
3962         return NDBT_FAILED;
3963       }
3964     }
3965 
3966     {
3967       NdbDictionary::LogfileGroup lg2 = pDict->getLogfileGroup("DEFAULT-LG");
3968       NdbError err= pDict->getNdbError();
3969       if( (int) err.classification != (int) ndberror_cl_none)
3970       {
3971         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
3972         return NDBT_FAILED;
3973       }
3974 
3975       if (pDict->dropLogfileGroup(lg2))
3976       {
3977         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
3978         return NDBT_FAILED;
3979       }
3980     }
3981   }
3982 
3983   return NDBT_OK;
3984 }
3985 
3986 int
restartClusterInitial(NDBT_Context * ctx,NDBT_Step * step)3987 restartClusterInitial(NDBT_Context* ctx, NDBT_Step* step)
3988 {
3989   NdbRestarter res;
3990 
3991   res.restartAll2(NdbRestarter::NRRF_INITIAL |
3992                   NdbRestarter::NRRF_NOSTART |
3993                   NdbRestarter::NRRF_ABORT);
3994   if (res.waitClusterNoStart())
3995     return NDBT_FAILED;
3996 
3997   res.startAll();
3998   if (res.waitClusterStarted())
3999     return NDBT_FAILED;
4000 
4001   return NDBT_OK;
4002 }
4003 
4004 
4005 int
DropDDObjectsVerify(NDBT_Context * ctx,NDBT_Step * step)4006 DropDDObjectsVerify(NDBT_Context* ctx, NDBT_Step* step){
4007   //Purpose is to verify test DropDDObjects worked
4008   Uint32 i = 0;
4009 
4010   Ndb* pNdb = GETNDB(step);
4011   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4012 
4013   NdbDictionary::Dictionary::List list;
4014   if (pDict->listObjects(list) == -1)
4015     return NDBT_FAILED;
4016 
4017     bool ddFound  = false;
4018   for (i = 0; i <list.count; i++){
4019     switch(list.elements[i].type){
4020       case NdbDictionary::Object::Tablespace:
4021         ddFound = true;
4022         break;
4023       case NdbDictionary::Object::LogfileGroup:
4024         ddFound = true;
4025         break;
4026       default:
4027         break;
4028     }
4029     if(ddFound == true){
4030       g_err << "DropDDObjects Failed: DD found:"
4031         << endl;
4032       return NDBT_FAILED;
4033     }
4034   }
4035   return NDBT_OK;
4036 }
4037 
4038 // Bug48604
4039 
4040 // string messages between local/remote steps identified by stepNo-1
4041 // each Msg<loc><rem> waits for Ack<loc><rem>
4042 
4043 static const uint MaxMsg = 100;
4044 
4045 static bool
send_msg(NDBT_Context * ctx,int loc,int rem,const char * msg)4046 send_msg(NDBT_Context* ctx, int loc, int rem, const char* msg)
4047 {
4048   char msgName[20], ackName[20];
4049   sprintf(msgName, "Msg%d%d", loc, rem);
4050   sprintf(ackName, "Ack%d%d", loc, rem);
4051   g_info << loc << ": send to:" << rem << " msg:" << msg << endl;
4052   ctx->setProperty(msgName, msg);
4053   int cnt = 0;
4054   while (1)
4055   {
4056     if (ctx->isTestStopped())
4057       return false;
4058     int ret;
4059     if ((ret = ctx->getProperty(ackName, (Uint32)0)) != 0)
4060       break;
4061     if (++cnt % 100 == 0)
4062       g_info << loc << ": send to:" << rem << " wait for ack" << endl;
4063     NdbSleep_MilliSleep(10);
4064   }
4065   ctx->setProperty(ackName, (Uint32)0);
4066   return true;
4067 }
4068 
4069 static bool
poll_msg(NDBT_Context * ctx,int loc,int rem,char * msg)4070 poll_msg(NDBT_Context* ctx, int loc, int rem, char* msg)
4071 {
4072   char msgName[20], ackName[20];
4073   sprintf(msgName, "Msg%d%d", rem, loc);
4074   sprintf(ackName, "Ack%d%d", rem, loc);
4075   const char* ptr;
4076   if ((ptr = ctx->getProperty(msgName, (char*)0)) != 0 && ptr[0] != 0)
4077   {
4078     require(strlen(ptr) < MaxMsg);
4079     memset(msg, 0, MaxMsg);
4080     strcpy(msg, ptr);
4081     g_info << loc << ": recv from:" << rem << " msg:" << msg << endl;
4082     ctx->setProperty(msgName, "");
4083     ctx->setProperty(ackName, (Uint32)1);
4084     return true;
4085   }
4086   return false;
4087 }
4088 
4089 static int
recv_msg(NDBT_Context * ctx,int loc,int rem,char * msg)4090 recv_msg(NDBT_Context* ctx, int loc, int rem, char* msg)
4091 {
4092   uint cnt = 0;
4093   while (1)
4094   {
4095     if (ctx->isTestStopped())
4096       return false;
4097     if (poll_msg(ctx, loc, rem, msg))
4098       break;
4099     if (++cnt % 100 == 0)
4100       g_info << loc << ": recv from:" << rem << " wait for msg" << endl;
4101     NdbSleep_MilliSleep(10);
4102   }
4103   return true;
4104 }
4105 
4106 const char* tabName_Bug48604 = "TBug48604";
4107 const char* indName_Bug48604 = "TBug48604X1";
4108 
4109 static const NdbDictionary::Table*
runBug48604createtable(NDBT_Context * ctx,NDBT_Step * step)4110 runBug48604createtable(NDBT_Context* ctx, NDBT_Step* step)
4111 {
4112   Ndb* pNdb = GETNDB(step);
4113   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4114   const NdbDictionary::Table* pTab = 0;
4115   int result = NDBT_OK;
4116   do
4117   {
4118     NdbDictionary::Table tab(tabName_Bug48604);
4119     {
4120       NdbDictionary::Column col("a");
4121       col.setType(NdbDictionary::Column::Unsigned);
4122       col.setPrimaryKey(true);
4123       tab.addColumn(col);
4124     }
4125     {
4126       NdbDictionary::Column col("b");
4127       col.setType(NdbDictionary::Column::Unsigned);
4128       col.setNullable(false);
4129       tab.addColumn(col);
4130     }
4131     CHECK(pDic->createTable(tab) == 0);
4132     CHECK((pTab = pDic->getTable(tabName_Bug48604)) != 0);
4133   }
4134   while (0);
4135   return pTab;
4136 }
4137 
4138 static const NdbDictionary::Index*
runBug48604createindex(NDBT_Context * ctx,NDBT_Step * step)4139 runBug48604createindex(NDBT_Context* ctx, NDBT_Step* step)
4140 {
4141   Ndb* pNdb = GETNDB(step);
4142   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4143   const NdbDictionary::Index* pInd = 0;
4144   int result = NDBT_OK;
4145   do {
4146     NdbDictionary::Index ind(indName_Bug48604);
4147     ind.setTable(tabName_Bug48604);
4148     ind.setType(NdbDictionary::Index::OrderedIndex);
4149     ind.setLogging(false);
4150     ind.addColumn("b");
4151     g_info << "index create.." << endl;
4152     CHECK(pDic->createIndex(ind) == 0);
4153     CHECK((pInd = pDic->getIndex(indName_Bug48604, tabName_Bug48604)) != 0);
4154     g_info << "index created" << endl;
4155     return pInd;
4156   }
4157   while (0);
4158   return pInd;
4159 }
4160 
4161 int
runBug48604(NDBT_Context * ctx,NDBT_Step * step)4162 runBug48604(NDBT_Context* ctx, NDBT_Step* step)
4163 {
4164   Ndb* pNdb = GETNDB(step);
4165   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4166   const NdbDictionary::Table* pTab = 0;
4167   const NdbDictionary::Index* pInd = 0;
4168   (void)pDic->dropTable(tabName_Bug48604);
4169   int loc = step->getStepNo() - 1;
4170   require(loc == 0);
4171   g_err << "main" << endl;
4172   int result = NDBT_OK;
4173   int loops = ctx->getNumLoops();
4174   char msg[MaxMsg];
4175 
4176   do
4177   {
4178     CHECK((pTab = runBug48604createtable(ctx, step)) != 0);
4179     CHECK(send_msg(ctx, 0, 1, "s"));
4180 
4181     int loop = 0;
4182     while (result == NDBT_OK && loop++ < loops)
4183     {
4184       g_err << "loop:" << loop << endl;
4185       {
4186         // create index fully while uncommitted ops wait
4187         const char* ops[][3] =
4188         {
4189           { "ozin", "oc", "oa" },       // 0: before 1-2: after
4190           { "oziun", "oc", "oa" },
4191           { "ozidn", "oc", "oa" },
4192           { "ozicun", "oc", "oa" },
4193           { "ozicuuun", "oc", "oa" },
4194           { "ozicdn", "oc", "oa" },
4195           { "ozicdin", "oc", "oa" },
4196           { "ozicdidiuuudidn", "oc", "oa" },
4197           { "ozicdidiuuudidin", "oc", "oa" }
4198         };
4199         const int cnt = sizeof(ops)/sizeof(ops[0]);
4200         int i;
4201         for (i = 0; result == NDBT_OK && i < cnt; i++)
4202         {
4203           int j;
4204           for (j = 1; result == NDBT_OK && j <= 2; j++)
4205           {
4206             if (ops[i][j] == 0)
4207               continue;
4208             CHECK(send_msg(ctx, 0, 1, ops[i][0]));
4209             CHECK(recv_msg(ctx, 0, 1, msg) && msg[0] == 'o');
4210             CHECK((pInd = runBug48604createindex(ctx, step)) != 0);
4211             CHECK(send_msg(ctx, 0, 1, ops[i][j]));
4212             CHECK(recv_msg(ctx, 0, 1, msg) && msg[0] == 'o');
4213 
4214             CHECK(pDic->dropIndex(indName_Bug48604, tabName_Bug48604) == 0);
4215             g_info << "index dropped" << endl;
4216           }
4217         }
4218       }
4219     }
4220   }
4221   while (0);
4222 
4223   (void)send_msg(ctx, 0, 1, "x");
4224   ctx->stopTest();
4225   g_err << "main: exit:" << result << endl;
4226   return result;
4227 }
4228 
4229 int
runBug48604ops(NDBT_Context * ctx,NDBT_Step * step)4230 runBug48604ops(NDBT_Context* ctx, NDBT_Step* step)
4231 {
4232   Ndb* pNdb = GETNDB(step);
4233   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4234   const NdbDictionary::Table* pTab = 0;
4235   //const NdbDictionary::Index* pInd = 0;
4236   int loc = step->getStepNo() - 1;
4237   require(loc > 0);
4238   g_err << "ops: loc:" << loc << endl;
4239   int result = NDBT_OK;
4240   int records = ctx->getNumRecords();
4241   char msg[MaxMsg];
4242 
4243   do
4244   {
4245     CHECK(recv_msg(ctx, loc, 0, msg));
4246     require(msg[0] == 's');
4247     CHECK((pTab = pDic->getTable(tabName_Bug48604)) != 0);
4248     HugoOperations ops(*pTab);
4249     bool have_trans = false;
4250     int opseq = 0;
4251 
4252     while (result == NDBT_OK && !ctx->isTestStopped())
4253     {
4254       CHECK(recv_msg(ctx, loc, 0, msg));
4255       if (msg[0] == 'x')
4256         break;
4257       if (msg[0] == 'o')
4258       {
4259         char* p = &msg[1];
4260         int c;
4261         while (result == NDBT_OK && (c = *p++) != 0)
4262         {
4263           if (c == 'n')
4264           {
4265             require(have_trans);
4266             CHECK(ops.execute_NoCommit(pNdb) == 0);
4267             g_info << loc << ": not committed" << endl;
4268             continue;
4269           }
4270           if (c == 'c')
4271           {
4272             require(have_trans);
4273             CHECK(ops.execute_Commit(pNdb) == 0);
4274             ops.closeTransaction(pNdb);
4275             have_trans = false;
4276             g_info << loc << ": committed" << endl;
4277             continue;
4278           }
4279           if (c == 'a')
4280           {
4281             require(have_trans);
4282             CHECK(ops.execute_Rollback(pNdb) == 0);
4283             ops.closeTransaction(pNdb);
4284             have_trans = false;
4285             g_info << loc << ": aborted" << endl;
4286             continue;
4287           }
4288           if (c == 'i' || c == 'u' || c == 'd')
4289           {
4290             if (!have_trans)
4291             {
4292               CHECK(ops.startTransaction(pNdb) == 0);
4293               have_trans = true;
4294               g_info << loc << ": trans started" << endl;
4295             }
4296             int i;
4297             for (i = 0; result == NDBT_OK && i < records; i++)
4298             {
4299               if (c == 'i')
4300                   CHECK(ops.pkInsertRecord(pNdb, i, 1, opseq) == 0);
4301               if (c == 'u')
4302                 CHECK(ops.pkUpdateRecord(pNdb, i, 1, opseq) == 0);
4303               if (c == 'd')
4304                 CHECK(ops.pkDeleteRecord(pNdb, i, 1) == 0);
4305             }
4306             char op_str[2];
4307             sprintf(op_str, "%c", c);
4308             g_info << loc << ": op:" << op_str << " records:" << records << endl;
4309             opseq++;
4310             continue;
4311           }
4312           if (c == 'z')
4313           {
4314             CHECK(ops.clearTable(pNdb) == 0);
4315             continue;
4316           }
4317           require(false);
4318         }
4319         CHECK(send_msg(ctx, loc, 0, "o"));
4320         continue;
4321       }
4322       require(false);
4323     }
4324   } while (0);
4325 
4326   g_err << "ops: loc:" << loc << " exit:" << result << endl;
4327   if (result != NDBT_OK)
4328     ctx->stopTest();
4329   return result;
4330 }
4331 
4332 int
runBug54651(NDBT_Context * ctx,NDBT_Step * step)4333 runBug54651(NDBT_Context* ctx, NDBT_Step* step)
4334 {
4335   Ndb* pNdb = GETNDB(step);
4336   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4337 
4338   for (Uint32 j = 0; j< 2; j++)
4339   {
4340     pDic->createTable(* ctx->getTab());
4341 
4342     const NdbDictionary::Table * pTab =pDic->getTable(ctx->getTab()->getName());
4343     NdbDictionary::Table copy = * pTab;
4344     BaseString name;
4345     name.assfmt("%s_1", pTab->getName());
4346     copy.setName(name.c_str());
4347 
4348     if (pDic->createTable(copy))
4349     {
4350       ndbout_c("Failed to create table...");
4351       ndbout << pDic->getNdbError() << endl;
4352       return NDBT_FAILED;
4353     }
4354 
4355     NdbDictionary::Table alter = * pTab;
4356     alter.setName(name.c_str());
4357     for (Uint32 i = 0; i<2; i++)
4358     {
4359       // now rename org table to same name...
4360       if (pDic->alterTable(* pTab, alter) == 0)
4361       {
4362         ndbout << "Alter with duplicate name succeeded!!" << endl;
4363         return NDBT_FAILED;
4364       }
4365 
4366       ndbout << "Alter with duplicate name failed...good" << endl
4367              << pDic->getNdbError() << endl;
4368     }
4369 
4370     pDic->dropTable(copy.getName());
4371     pDic->dropTable(ctx->getTab()->getName());
4372   }
4373   return NDBT_OK;
4374 }
4375 
4376 /** telco-6.4 **/
4377 
4378 // begin schema trans
4379 
4380 #undef chk1
4381 #undef chk2
4382 
4383 static bool st_core_on_err = false;
4384 
4385 #define chk1(x) \
4386   do { \
4387     if (x) break; \
4388     g_err << "FAIL " << __LINE__ << " " << #x << endl; \
4389     if (st_core_on_err) abort(); \
4390     goto err; \
4391   } while (0)
4392 
4393 #define chk2(x, e) \
4394   do { \
4395     if (x) break; \
4396     g_err << "FAIL " << __LINE__ << " " << #x << ": " << e << endl; \
4397     if (st_core_on_err) abort(); \
4398     goto err; \
4399   } while (0)
4400 
4401 static uint
urandom(uint m)4402 urandom(uint m)
4403 {
4404   require(m != 0);
4405   uint n = (uint)ndb_rand();
4406   return n % m;
4407 }
4408 
4409 static bool
randomly(uint k,uint m)4410 randomly(uint k, uint m)
4411 {
4412   uint n = urandom(m);
4413   return n < k;
4414 }
4415 
4416 // structs
4417 
4418 struct ST_Obj;
4419 template class Vector<ST_Obj*>;
4420 typedef Vector<ST_Obj*> ST_Objlist;
4421 
4422 static ST_Objlist st_objlist;
4423 #ifndef NDEBUG
4424 static const ST_Obj* st_find_obj(const char* db, const char* name);
4425 #endif
4426 
4427 #define ST_MAX_NAME_SIZE  (MAX_TAB_NAME_SIZE + 100)
4428 
4429 struct ST_Obj {
4430   NdbDictionary::Object::Type type;
4431   char dbname[ST_MAX_NAME_SIZE];
4432   char name[ST_MAX_NAME_SIZE];
4433   int id;
4434   enum { Skip = 0xFFFF }; // mark ignored objects in List
4435   bool create; // true/false = create/drop prepared or committed
4436   bool commit;
existsST_Obj4437   bool exists() const { // visible to trans
4438     return !(!create && commit);
4439   }
is_triggerST_Obj4440   virtual bool is_trigger() const {
4441     return false;
4442   }
is_indexST_Obj4443   virtual bool is_index() const {
4444     return false;
4445   }
is_tableST_Obj4446   virtual bool is_table() const {
4447     return false;
4448   }
realnameST_Obj4449   virtual const char* realname() const {
4450     return name;
4451   }
ST_ObjST_Obj4452   ST_Obj(const char* a_dbname, const char* a_name) {
4453     type = NdbDictionary::Object::TypeUndefined;
4454     strcpy(dbname, a_dbname);
4455     strcpy(name, a_name);
4456     id = -1;
4457     create = false; // init as dropped
4458     commit = true;
4459     assert(st_find_obj(dbname, name) == 0);
4460     st_objlist.push_back(this);
4461   }
~ST_ObjST_Obj4462   virtual ~ST_Obj() {}
4463 };
4464 
4465 static NdbOut&
operator <<(NdbOut & out,const ST_Obj & obj)4466 operator<<(NdbOut& out, const ST_Obj& obj)
4467 {
4468   out << obj.name << "[" << obj.id << "]";
4469   return out;
4470 }
4471 
4472 struct ST_Trg : public ST_Obj {
4473   struct ST_Ind* ind;
4474   TriggerEvent::Value event;
4475   mutable char realname_buf[ST_MAX_NAME_SIZE];
is_triggerST_Trg4476   virtual bool is_trigger() const {
4477     return true;
4478   }
4479   virtual const char* realname() const;
ST_TrgST_Trg4480   ST_Trg(const char* a_db, const char* a_name) :
4481     ST_Obj(a_db, a_name) {
4482     ind = 0;
4483   }
~ST_TrgST_Trg4484   virtual ~ST_Trg() {};
4485 };
4486 
4487 template class Vector<ST_Trg*>;
4488 typedef Vector<ST_Trg*> ST_Trglist;
4489 
4490 struct ST_Ind : public ST_Obj {
4491   struct ST_Tab* tab;
4492   const NdbDictionary::Index* ind;
4493   const NdbDictionary::Index* ind_r; // retrieved
4494   BaseString colnames;
4495   ST_Trglist* trglist;
4496   int trgcount;
is_indexST_Ind4497   virtual bool is_index() const {
4498     return true;
4499   }
is_uniqueST_Ind4500   bool is_unique() const {
4501     return type == NdbDictionary::Object::UniqueHashIndex;
4502   }
trgST_Ind4503   const ST_Trg& trg(int k) const {
4504     return *((*trglist)[k]);
4505   }
trgST_Ind4506   ST_Trg& trg(int k) {
4507     return *((*trglist)[k]);
4508   }
ST_IndST_Ind4509   ST_Ind(const char* a_db, const char* a_name) :
4510     ST_Obj(a_db, a_name) {
4511     tab = 0;
4512     ind = 0;
4513     ind_r = 0;
4514     trglist = new ST_Trglist;
4515     trgcount = 0;
4516   };
~ST_IndST_Ind4517   virtual ~ST_Ind() {
4518     delete ind;
4519     delete trglist;
4520     ind = 0;
4521     trglist = 0;
4522   }
4523 };
4524 
4525 const char*
realname() const4526 ST_Trg::realname() const
4527 {
4528   if (!exists())
4529     return name;
4530   const char* p = name;
4531   const char* q = strchr(p, '<');
4532   const char* r = strchr(p, '>');
4533   require(q != 0 && r != 0 && q < r);
4534   require(ind->id != -1);
4535   sprintf(realname_buf, "%.*s%d%s", (int)(q - p), p, ind->id, r + 1);
4536   return realname_buf;
4537 }
4538 
4539 template class Vector<ST_Ind*>;
4540 typedef Vector<ST_Ind*> ST_Indlist;
4541 
4542 struct ST_Tab : public ST_Obj {
4543   const NdbDictionary::Table* tab;
4544   const NdbDictionary::Table* tab_r; // retrieved
4545   ST_Indlist* indlist;
4546   int indcount;
4547   int induniquecount;
4548   int indorderedcount;
is_tableST_Tab4549   virtual bool is_table() const {
4550     return true;
4551   }
indST_Tab4552   const ST_Ind& ind(int j) const {
4553     return *((*indlist)[j]);
4554   }
indST_Tab4555   ST_Ind& ind(int j) {
4556     return *((*indlist)[j]);
4557   }
ST_TabST_Tab4558   ST_Tab(const char* a_db, const char* a_name) :
4559     ST_Obj(a_db, a_name) {
4560     tab = 0;
4561     tab_r = 0;
4562     indlist = new ST_Indlist;
4563     indcount = 0;
4564     induniquecount = 0;
4565     indorderedcount = 0;
4566   }
~ST_TabST_Tab4567   virtual ~ST_Tab() {
4568     delete tab;
4569     delete indlist;
4570     tab = 0;
4571     indlist = 0;
4572   }
4573 };
4574 
4575 template class Vector<ST_Tab*>;
4576 typedef Vector<ST_Tab*> ST_Tablist;
4577 
4578 struct ST_Restarter : public NdbRestarter {
4579   int get_status();
4580   const ndb_mgm_node_state& get_state(int node_id);
ST_RestarterST_Restarter4581   ST_Restarter() {
4582     int i;
4583     for (i = 0; i < MAX_NODES; i++)
4584       state[i].node_type = NDB_MGM_NODE_TYPE_UNKNOWN;
4585     first_time = true;
4586   }
4587 protected:
4588   void set_state(const ndb_mgm_node_state& state);
4589   ndb_mgm_node_state state[MAX_NODES];
4590   bool first_time;
4591 };
4592 
4593 const ndb_mgm_node_state&
get_state(int node_id)4594 ST_Restarter::get_state(int node_id) {
4595   require(node_id > 0 && node_id < MAX_NODES);
4596   require(!first_time);
4597   return state[node_id];
4598 }
4599 
4600 void
set_state(const ndb_mgm_node_state & new_state)4601 ST_Restarter::set_state(const ndb_mgm_node_state& new_state)
4602 {
4603   int node_id = new_state.node_id;
4604   require(1 <= node_id && node_id < MAX_NODES);
4605 
4606   require(new_state.node_type == NDB_MGM_NODE_TYPE_MGM ||
4607           new_state.node_type == NDB_MGM_NODE_TYPE_NDB ||
4608           new_state.node_type == NDB_MGM_NODE_TYPE_API);
4609 
4610   ndb_mgm_node_state& old_state = state[node_id];
4611   if (!first_time)
4612     require(old_state.node_type == new_state.node_type);
4613   old_state = new_state;
4614 }
4615 
4616 int
get_status()4617 ST_Restarter::get_status()
4618 {
4619   if (getStatus() == -1)
4620     return -1;
4621   int i;
4622   for (i = 0; i < (int)mgmNodes.size(); i++)
4623     set_state(mgmNodes[i]);
4624   for (i = 0; i < (int)ndbNodes.size(); i++)
4625     set_state(ndbNodes[i]);
4626   for (i = 0; i < (int)apiNodes.size(); i++)
4627     set_state(apiNodes[i]);
4628   first_time = false;
4629   return 0;
4630 }
4631 
4632 struct ST_Con {
4633   Ndb_cluster_connection* ncc;
4634   Ndb* ndb;
4635   NdbDictionary::Dictionary* dic;
4636   ST_Restarter* restarter;
4637   int numdbnodes;
4638   char dbname[ST_MAX_NAME_SIZE];
4639   ST_Tablist* tablist;
4640   int tabcount;
4641   bool tx_on;
4642   bool tx_commit;
4643   bool is_xcon;
4644   ST_Con* xcon;
4645   int node_id;
4646   int loop;
tabST_Con4647   const ST_Tab& tab(int i) const {
4648     return *((*tablist)[i]);
4649   }
tabST_Con4650   ST_Tab& tab(int i) {
4651     return *((*tablist)[i]);
4652   }
ST_ConST_Con4653   ST_Con(Ndb_cluster_connection* a_ncc,
4654          Ndb* a_ndb,
4655          ST_Restarter* a_restarter) {
4656     ncc = a_ncc;
4657     ndb = a_ndb;
4658     dic = a_ndb->getDictionary();
4659     restarter = a_restarter;
4660     numdbnodes = restarter->getNumDbNodes();
4661     require(numdbnodes >= 1);
4662     sprintf(dbname, "%s", ndb->getDatabaseName());
4663     tablist = new ST_Tablist;
4664     tabcount = 0;
4665     tx_on = false;
4666     tx_commit = false;
4667     is_xcon = false;
4668     xcon = 0;
4669     node_id = ncc->node_id();
4670     {
4671       require(restarter->get_status() == 0);
4672       const ndb_mgm_node_state& state = restarter->get_state(node_id);
4673       require(state.node_type == NDB_MGM_NODE_TYPE_API);
4674       require(state.version != 0); // means "connected"
4675       g_info << "node_id:" << node_id << endl;
4676     }
4677     loop = -1;
4678   }
~ST_ConST_Con4679   ~ST_Con() {
4680     if (!is_xcon) {
4681       delete tablist;
4682     } else {
4683       delete ndb;
4684       delete ncc;
4685     }
4686     tablist = 0;
4687     ndb = 0;
4688     ncc = 0;
4689   }
4690 };
4691 
4692 // initialization
4693 
4694 static int
st_drop_all_tables(ST_Con & c)4695 st_drop_all_tables(ST_Con& c)
4696 {
4697   g_info << "st_drop_all_tables" << endl;
4698   NdbDictionary::Dictionary::List list;
4699   chk2(c.dic->listObjects(list) == 0, c.dic->getNdbError());
4700   int n;
4701   for (n = 0; n < (int)list.count; n++) {
4702     const NdbDictionary::Dictionary::List::Element& element =
4703       list.elements[n];
4704     if (element.type == NdbDictionary::Object::UserTable &&
4705         strcmp(element.database, "TEST_DB") == 0) {
4706       chk2(c.dic->dropTable(element.name) == 0, c.dic->getNdbError());
4707     }
4708   }
4709   return 0;
4710 err:
4711   return -1;
4712 }
4713 
4714 static void
st_init_objects(ST_Con & c,NDBT_Context * ctx)4715 st_init_objects(ST_Con& c, NDBT_Context* ctx)
4716 {
4717   int numTables = ctx->getNumTables();
4718   c.tabcount = 0;
4719   int i;
4720   for (i = 0; i < numTables; i++) {
4721     const NdbDictionary::Table* pTab = 0;
4722 #if ndb_test_ALL_TABLES_is_fixed
4723     const NdbDictionary::Table** tables = ctx->getTables();
4724     pTab = tables[i];
4725 #else
4726     const Vector<BaseString>& tables = ctx->getSuite()->m_tables_in_test;
4727     pTab = NDBT_Tables::getTable(tables[i].c_str());
4728 #endif
4729     require(pTab != 0 && pTab->getName() != 0);
4730 
4731     {
4732       bool ok = true;
4733       int n;
4734       for (n = 0; n < pTab->getNoOfColumns(); n++) {
4735         const NdbDictionary::Column* pCol = pTab->getColumn(n);
4736         require(pCol != 0);
4737         if (pCol->getStorageType() !=
4738             NdbDictionary::Column::StorageTypeMemory) {
4739           g_err << pTab->getName() << ": skip non-mem table for now" << endl;
4740           ok = false;
4741           break;
4742         }
4743       }
4744       if (!ok)
4745         continue;
4746     }
4747 
4748     c.tablist->push_back(new ST_Tab(c.dbname, pTab->getName()));
4749     c.tabcount++;
4750     ST_Tab& tab = *c.tablist->back();
4751     tab.type = NdbDictionary::Object::UserTable;
4752     tab.tab = new NdbDictionary::Table(*pTab);
4753 
4754     const char** indspec = NDBT_Tables::getIndexes(tab.name);
4755 
4756     while (indspec != 0 && *indspec != 0) {
4757       char ind_name[ST_MAX_NAME_SIZE];
4758       sprintf(ind_name, "%sX%d", tab.name, tab.indcount);
4759       tab.indlist->push_back(new ST_Ind("sys", ind_name));
4760       ST_Ind& ind = *tab.indlist->back();
4761       ind.tab = &tab;
4762 
4763       NdbDictionary::Index* pInd = new NdbDictionary::Index(ind.name);
4764       pInd->setTable(tab.name);
4765       pInd->setLogging(false);
4766 
4767       const char* type = *indspec++;
4768       if (strcmp(type, "UNIQUE") == 0) {
4769         ind.type = NdbDictionary::Object::UniqueHashIndex;
4770         pInd->setType((NdbDictionary::Index::Type)ind.type);
4771         tab.induniquecount++;
4772 
4773         { char trg_name[ST_MAX_NAME_SIZE];
4774           sprintf(trg_name, "NDB$INDEX_<%s>_UI", ind.name);
4775           ind.trglist->push_back(new ST_Trg("", trg_name));
4776           ST_Trg& trg = *ind.trglist->back();
4777           trg.ind = &ind;
4778           trg.type = NdbDictionary::Object::HashIndexTrigger;
4779           trg.event = TriggerEvent::TE_INSERT;
4780         }
4781         ind.trgcount = 1;
4782       }
4783       else if (strcmp(type, "ORDERED") == 0) {
4784         ind.type = NdbDictionary::Object::OrderedIndex;
4785         pInd->setType((NdbDictionary::Index::Type)ind.type);
4786         tab.indorderedcount++;
4787 
4788         { char trg_name[ST_MAX_NAME_SIZE];
4789           sprintf(trg_name, "NDB$INDEX_<%s>_CUSTOM", ind.name);
4790           ind.trglist->push_back(new ST_Trg("", trg_name));
4791           ST_Trg& trg = *ind.trglist->back();
4792           trg.ind = &ind;
4793           trg.type = NdbDictionary::Object::IndexTrigger;
4794           trg.event = TriggerEvent::TE_CUSTOM;
4795         }
4796         ind.trgcount = 1;
4797       }
4798       else
4799       {
4800         require(false);
4801       }
4802 
4803       const char* sep = "";
4804       const char* colname;
4805       while ((colname = *indspec++) != 0) {
4806         const NdbDictionary::Column* col = tab.tab->getColumn(colname);
4807         require(col != 0);
4808         pInd->addColumn(*col);
4809 
4810         ind.colnames.appfmt("%s%s", sep, colname);
4811         sep = ",";
4812       }
4813 
4814       ind.ind = pInd;
4815       tab.indcount++;
4816     }
4817   }
4818 }
4819 
4820 // node states
4821 
4822 static int
st_report_db_nodes(ST_Con & c,NdbOut & out)4823 st_report_db_nodes(ST_Con& c, NdbOut& out)
4824 {
4825   chk1(c.restarter->get_status() == 0);
4826   char r1[100]; // up
4827   char r2[100]; // down
4828   char r3[100]; // unknown
4829   r1[0] =r2[0] = r3[0] = 0;
4830   int i;
4831   for (i = 1; i < MAX_NODES; i++) {
4832     const ndb_mgm_node_state& state = c.restarter->get_state(i);
4833     if (state.node_type == NDB_MGM_NODE_TYPE_NDB) {
4834       char* r = 0;
4835       if (state.node_status == NDB_MGM_NODE_STATUS_STARTED)
4836         r = r1;
4837       else if (state.node_status == NDB_MGM_NODE_STATUS_NO_CONTACT)
4838         r = r2;
4839       else
4840         r = r3;
4841       sprintf(r + strlen(r), "%s%d", r[0] == 0 ? "" : ",", i);
4842     }
4843   }
4844   if (r2[0] != 0 || r3[0] != 0) {
4845     out << "nodes up:" << r1 << " down:" << r2 << " unknown:" << r3 << endl;
4846     goto err;
4847   }
4848   out << "nodes up:" << r1 << " (all)" << endl;
4849   return 0;
4850 err:
4851   return -1;
4852 }
4853 
4854 static int
st_check_db_nodes(ST_Con & c,int ignore_node_id=-1)4855 st_check_db_nodes(ST_Con& c, int ignore_node_id = -1)
4856 {
4857   chk1(c.restarter->get_status() == 0);
4858   int i;
4859   for (i = 1; i < MAX_NODES; i++) {
4860     const ndb_mgm_node_state& state = c.restarter->get_state(i);
4861     if (state.node_type == NDB_MGM_NODE_TYPE_NDB &&
4862         i != ignore_node_id) {
4863       chk2(state.node_status == NDB_MGM_NODE_STATUS_STARTED, " node:" << i);
4864     }
4865   }
4866   return 0;
4867 err:
4868   return -1;
4869 }
4870 
4871 #if 0
4872 static int
4873 st_wait_db_node_up(ST_Con& c, int node_id)
4874 {
4875   int count = 0;
4876   int max_count = 30;
4877   int milli_sleep = 2000;
4878   while (count++ < max_count) {
4879     // get status and check that other db nodes have not crashed
4880     chk1(st_check_db_nodes(c, node_id) == 0);
4881 
4882     const ndb_mgm_node_state& state = c.restarter->get_state(node_id);
4883     require(state.node_type == NDB_MGM_NODE_TYPE_NDB);
4884     if (state.node_status == NDB_MGM_NODE_STATUS_STARTED)
4885       break;
4886     g_info << "waiting count:" << count << "/" << max_count << endl;
4887     NdbSleep_MilliSleep(milli_sleep);
4888   }
4889   return 0;
4890 err:
4891   return -1;
4892 }
4893 #endif
4894 
4895 // extra connection (separate API node)
4896 
4897 static int
st_start_xcon(ST_Con & c)4898 st_start_xcon(ST_Con& c)
4899 {
4900   require(c.xcon == 0);
4901   g_info << "start extra connection" << endl;
4902 
4903   do {
4904     int ret;
4905     Ndb_cluster_connection* xncc = new Ndb_cluster_connection;
4906     chk2((ret = xncc->connect(30, 1, 0)) == 0, "ret:" << ret);
4907     chk2((ret = xncc->wait_until_ready(30, 10)) == 0, "ret:" << ret);
4908     Ndb* xndb = new Ndb(xncc, c.dbname);
4909     chk1(xndb->init() == 0);
4910     chk1(xndb->waitUntilReady(30) == 0);
4911     // share restarter
4912     c.xcon = new ST_Con(xncc, xndb, c.restarter);
4913     // share objects
4914     c.xcon->tablist = c.tablist;
4915     c.xcon->tabcount = c.tabcount;
4916     c.xcon->is_xcon = true;
4917   } while (0);
4918   return 0;
4919 err:
4920   return -1;
4921 }
4922 
4923 static int
st_stop_xcon(ST_Con & c)4924 st_stop_xcon(ST_Con& c)
4925 {
4926   require(c.xcon != 0);
4927   int node_id = c.xcon->node_id;
4928   g_info << "stop extra connection node_id:" << node_id << endl;
4929 
4930   c.xcon->restarter = 0;
4931   c.xcon->tablist = 0;
4932   c.xcon->tabcount = 0;
4933   delete c.xcon;
4934   c.xcon = 0;
4935   int count = 0;
4936   while (1) {
4937     chk1(c.restarter->get_status() == 0);
4938     const ndb_mgm_node_state& state = c.restarter->get_state(node_id);
4939     require(state.node_type == NDB_MGM_NODE_TYPE_API);
4940     if (state.version == 0) // means "disconnected"
4941       break;
4942     g_info << "waiting count:" << ++count << endl;
4943     NdbSleep_MilliSleep(10 * count);
4944   }
4945   return 0;
4946 err:
4947   return -1;
4948 }
4949 
4950 // error insert
4951 
4952 struct ST_Errins {
4953   int value;              // error value to insert
4954   int code;               // ndb error code to expect
4955   int master;             // insert on master / non-master (-1 = random)
4956   int node;               // insert on node id
4957   const ST_Errins* list;  // include another list
4958   bool ends;              // end list
ST_ErrinsST_Errins4959   ST_Errins() :
4960     value(0), code(0), master(-1), node(0), list(0), ends(true)
4961   {}
ST_ErrinsST_Errins4962   ST_Errins(const ST_Errins* l) :
4963     value(0), code(0), master(-1), node(0), list(l), ends(false)
4964   {}
ST_ErrinsST_Errins4965   ST_Errins(int v, int c, int m = -1) :
4966     value(v), code(c), master(m), node(0), list(0), ends(false)
4967   {}
4968 };
4969 
4970 static NdbOut&
operator <<(NdbOut & out,const ST_Errins & errins)4971 operator<<(NdbOut& out, const ST_Errins& errins)
4972 {
4973   out << "value:" << errins.value;
4974   out << " code:" << errins.code;
4975   out << " master:" << errins.master;
4976   out << " node:" << errins.node;
4977   return out;
4978 }
4979 
4980 static ST_Errins
st_get_errins(ST_Con & c,const ST_Errins * list)4981 st_get_errins(ST_Con& c, const ST_Errins* list)
4982 {
4983   uint size = 0;
4984   while (!list[size++].ends)
4985     ;
4986   require(size > 1);
4987   uint n = urandom(size - 1);
4988   const ST_Errins& errins = list[n];
4989   if (errins.list == 0) {
4990     require(errins.value != 0);
4991     return errins;
4992   }
4993   return st_get_errins(c, errins.list);
4994 }
4995 
4996 static int
st_do_errins(ST_Con & c,ST_Errins & errins)4997 st_do_errins(ST_Con& c, ST_Errins& errins)
4998 {
4999   require(errins.value != 0);
5000   if (c.numdbnodes < 2)
5001     errins.master = 1;
5002   else if (errins.master == -1)
5003     errins.master = randomly(1, 2);
5004   if (errins.master) {
5005     errins.node = c.restarter->getMasterNodeId();
5006   } else {
5007     uint rand = urandom(c.numdbnodes);
5008     errins.node = c.restarter->getRandomNotMasterNodeId(rand);
5009   }
5010   g_info << "errins: " << errins << endl;
5011   chk2(c.restarter->insertErrorInNode(errins.node, errins.value) == 0, errins);
5012   c.restarter->get_status(); // do sync call to ensure error has been inserted
5013   return 0;
5014 err:
5015   return -1;
5016 }
5017 
5018 // debug aid
5019 #ifndef NDEBUG
5020 static const ST_Obj*
st_find_obj(const char * dbname,const char * name)5021 st_find_obj(const char* dbname, const char* name)
5022 {
5023   const ST_Obj* ret_objp = 0;
5024   int i;
5025   for (i = 0; i < (int)st_objlist.size(); i++) {
5026     const ST_Obj* objp = st_objlist[i];
5027     if (strcmp(objp->dbname, dbname) == 0 &&
5028         strcmp(objp->name, name) == 0) {
5029       require(ret_objp == 0);
5030       ret_objp = objp;
5031     }
5032   }
5033   return ret_objp;
5034 }
5035 #endif
5036 
5037 #if 0
5038 static void
5039 st_print_obj(const char* dbname, const char* name, int line = 0)
5040 {
5041   const ST_Obj* objp = st_find_obj(dbname, name);
5042   g_info << name << ": by name:";
5043   if (objp != 0)
5044     g_info << " create:" << objp->create
5045            << " commit:" << objp->commit
5046            << " exists:" << objp->exists();
5047   else
5048     g_info << " not found";
5049   if (line != 0)
5050     g_info << " line:" << line;
5051   g_info << endl;
5052 }
5053 #endif
5054 
5055 // set object state
5056 
5057 static void
st_set_commit_obj(ST_Con & c,ST_Obj & obj)5058 st_set_commit_obj(ST_Con& c, ST_Obj& obj)
5059 {
5060   bool create_old = obj.create;
5061   bool commit_old = obj.commit;
5062   if (!c.tx_commit && !obj.commit)
5063     obj.create = !obj.create;
5064   obj.commit = true;
5065   if (create_old != obj.create || commit_old != obj.commit) {
5066     g_info << obj.name << ": set commit:"
5067            << " create:" << create_old << "->" << obj.create
5068            << " commit:" << commit_old << "->" << obj.commit << endl;
5069   }
5070 }
5071 
5072 #if 0
5073 static void
5074 st_set_commit_trg(ST_Con& c, ST_Trg& trg)
5075 {
5076   st_set_commit_obj(c, trg);
5077 }
5078 #endif
5079 
5080 static void
st_set_commit_ind(ST_Con & c,ST_Ind & ind)5081 st_set_commit_ind(ST_Con& c, ST_Ind& ind)
5082 {
5083   st_set_commit_obj(c, ind);
5084   int k;
5085   for (k = 0; k < ind.trgcount; k++) {
5086     ST_Trg& trg = ind.trg(k);
5087     st_set_commit_obj(c, trg);
5088   }
5089 }
5090 
5091 static void
st_set_commit_tab(ST_Con & c,ST_Tab & tab)5092 st_set_commit_tab(ST_Con& c, ST_Tab& tab)
5093 {
5094   st_set_commit_obj(c, tab);
5095   int j;
5096   for (j = 0; j < tab.indcount; j++) {
5097     ST_Ind& ind = tab.ind(j);
5098     st_set_commit_ind(c, ind);
5099   }
5100 }
5101 
5102 static void
st_set_commit_all(ST_Con & c)5103 st_set_commit_all(ST_Con& c)
5104 {
5105   int i;
5106   for (i = 0; i < c.tabcount; i++) {
5107     ST_Tab& tab = c.tab(i);
5108     st_set_commit_tab(c, tab);
5109   }
5110 }
5111 
5112 static void
st_set_create_obj(ST_Con & c,ST_Obj & obj,bool create)5113 st_set_create_obj(ST_Con& c, ST_Obj& obj, bool create)
5114 {
5115   bool create_old = obj.create;
5116   bool commit_old = obj.commit;
5117   obj.create = create;
5118   obj.commit = !c.tx_on;
5119   if (create_old != obj.create || commit_old != obj.commit) {
5120     g_info << obj.name << ": set create:"
5121            << " create:" << create_old << "->" << obj.create
5122            << " commit:" << commit_old << "->" << obj.commit << endl;
5123   }
5124 }
5125 
5126 static void
st_set_create_trg(ST_Con & c,ST_Trg & trg,bool create)5127 st_set_create_trg(ST_Con& c, ST_Trg& trg, bool create)
5128 {
5129   st_set_create_obj(c, trg, create);
5130 }
5131 
5132 static void
st_set_create_ind(ST_Con & c,ST_Ind & ind,bool create)5133 st_set_create_ind(ST_Con& c, ST_Ind& ind, bool create)
5134 {
5135   st_set_create_obj(c, ind, create);
5136   int k;
5137   for (k = 0; k < ind.trgcount; k++) {
5138     ST_Trg& trg = ind.trg(k);
5139     st_set_create_trg(c, trg, create);
5140   }
5141 }
5142 
5143 static void
st_set_create_tab(ST_Con & c,ST_Tab & tab,bool create)5144 st_set_create_tab(ST_Con& c, ST_Tab& tab, bool create)
5145 {
5146   st_set_create_obj(c, tab, create);
5147   int j;
5148   for (j = 0; j < tab.indcount; j++) {
5149     ST_Ind& ind = tab.ind(j);
5150     if (create == true)
5151       require(!ind.exists());
5152     else {
5153       if (ind.exists())
5154         st_set_create_ind(c, ind, false);
5155     }
5156   }
5157 }
5158 
5159 // verify against database listing
5160 
5161 static bool
st_known_type(const NdbDictionary::Dictionary::List::Element & element)5162 st_known_type(const NdbDictionary::Dictionary::List::Element& element)
5163 {
5164   return element.id != ST_Obj::Skip;
5165 }
5166 
5167 static int
st_find_object(const NdbDictionary::Dictionary::List & list,NdbDictionary::Object::Type type,int id)5168 st_find_object(const NdbDictionary::Dictionary::List& list,
5169                NdbDictionary::Object::Type type, int id)
5170 {
5171   int n;
5172   for (n = 0; n < (int)list.count; n++) {
5173     const NdbDictionary::Dictionary::List::Element& element =
5174       list.elements[n];
5175     if (element.type == type && (int)element.id == id)
5176       return n;
5177   }
5178   return -1;
5179 }
5180 
5181 // filter out irrelevant by whatever means (we need listObjects2)
5182 static int
st_list_objects(ST_Con & c,NdbDictionary::Dictionary::List & list)5183 st_list_objects(ST_Con& c, NdbDictionary::Dictionary::List& list)
5184 {
5185   g_info << "st_list_objects" << endl;
5186   int keep[256];
5187   memset(keep, 0, sizeof(keep));
5188   chk2(c.dic->listObjects(list) == 0, c.dic->getNdbError());
5189   int n;
5190   // tables
5191   for (n = 0; n < (int)list.count; n++) {
5192     const NdbDictionary::Dictionary::List::Element& element =
5193       list.elements[n];
5194     if (element.type == NdbDictionary::Object::UserTable) {
5195       int i;
5196       for (i = 0; i < c.tabcount; i++) {
5197         const ST_Tab& tab = c.tab(i);
5198         if (strcmp(element.name, tab.name) == 0)
5199           keep[n]++;
5200       }
5201     }
5202     require(keep[n] <= 1);
5203   }
5204   // indexes
5205   for (n = 0; n < (int)list.count; n++) {
5206     const NdbDictionary::Dictionary::List::Element& element =
5207       list.elements[n];
5208     if (element.type == NdbDictionary::Object::UniqueHashIndex ||
5209         element.type == NdbDictionary::Object::OrderedIndex) {
5210       int i, j;
5211       for (i = 0; i < c.tabcount; i++) {
5212         const ST_Tab& tab = c.tab(i);
5213         for (j = 0; j < tab.indcount; j++) {
5214           const ST_Ind& ind = tab.ind(j);
5215           if (strcmp(element.name, ind.name) == 0)
5216             keep[n]++;
5217         }
5218       }
5219     }
5220     require(keep[n] <= 1);
5221   }
5222   // triggers
5223   for (n = 0; n < (int)list.count; n++) {
5224     const NdbDictionary::Dictionary::List::Element& element =
5225       list.elements[n];
5226     if (element.type == NdbDictionary::Object::HashIndexTrigger) {
5227       int id, n2;
5228       chk2(sscanf(element.name, "NDB$INDEX_%d_UI", &id) == 1,
5229            element.name);
5230       n2 = st_find_object(list, NdbDictionary::Object::UniqueHashIndex, id);
5231       chk2(n2 >= 0, element.name);
5232       if (keep[n2])
5233         keep[n]++;
5234     }
5235     if (element.type == NdbDictionary::Object::IndexTrigger) {
5236       int id, n2;
5237       chk2(sscanf(element.name, "NDB$INDEX_%d_CUSTOM", &id) == 1,
5238            element.name);
5239       n2 = st_find_object(list, NdbDictionary::Object::OrderedIndex, id);
5240       chk2(n2 >= 0, element.name);
5241       if (keep[n2])
5242         keep[n]++;
5243     }
5244     require(keep[n] <= 1);
5245   }
5246   // mark ignored
5247   for (n = 0; n < (int)list.count; n++) {
5248     NdbDictionary::Dictionary::List::Element& element =
5249       list.elements[n];
5250     g_info << "id=" << element.id << " type=" << element.type
5251            << " name=" << element.name << " keep=" << keep[n] << endl;
5252     if (!keep[n]) {
5253       require(element.id != ST_Obj::Skip);
5254       element.id = ST_Obj::Skip;
5255     }
5256   }
5257   return 0;
5258 err:
5259   return -1;
5260 }
5261 
5262 static bool
st_match_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element)5263 st_match_obj(const ST_Obj& obj,
5264              const NdbDictionary::Dictionary::List::Element& element)
5265 {
5266   int veryverbose = 0;
5267   if (veryverbose) {
5268     g_info
5269       << "match:"
5270       << " " << obj.type << "-" << element.type
5271       << " " << obj.dbname << "-" << element.database
5272       << " " << obj.realname() << "-" << element.name << endl;
5273   }
5274   return
5275     obj.type == element.type &&
5276     strcmp(obj.dbname, element.database) == 0 &&
5277     strcmp(obj.realname(), element.name) == 0;
5278 }
5279 
5280 static int // check state
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element)5281 st_verify_obj(const ST_Obj& obj,
5282               const NdbDictionary::Dictionary::List::Element& element)
5283 {
5284   chk2(obj.exists(), obj.name);
5285 
5286   if (obj.commit)
5287     chk2(element.state == NdbDictionary::Object::StateOnline, obj.name);
5288 
5289   // other states are inconsistent
5290 
5291   else if (obj.create) {
5292     if (obj.is_table() || obj.is_index())
5293       chk2(element.state == NdbDictionary::Object::StateBuilding, obj.name);
5294     if (obj.is_trigger())
5295       chk2(element.state == NdbDictionary::Object::StateBuilding, obj.name);
5296   }
5297   else {
5298     if (obj.is_trigger())
5299       chk2(element.state == NdbDictionary::Object::StateOnline, obj.name);
5300     if (obj.is_table() || obj.is_index())
5301       chk2(element.state == NdbDictionary::Object::StateDropping, obj.name);
5302   }
5303   return 0;
5304 err:
5305   return -1;
5306 }
5307 
5308 static int // find on list
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List & list)5309 st_verify_obj(const ST_Obj& obj,
5310               const NdbDictionary::Dictionary::List& list)
5311 {
5312   int found = 0;
5313   int n;
5314   for (n = 0; n < (int)list.count; n++) {
5315     const NdbDictionary::Dictionary::List::Element& element =
5316       list.elements[n];
5317     if (!st_known_type(element))
5318       continue;
5319     if (st_match_obj(obj, element)) {
5320       chk1(st_verify_obj(obj, element) == 0);
5321       found += 1;
5322     }
5323   }
5324   if (obj.exists())
5325     chk2(found == 1, obj.name);
5326   else
5327     chk2(found == 0, obj.name);
5328   return 0;
5329 err:
5330   return -1;
5331 }
5332 
5333 static int // possible match
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element,int & found)5334 st_verify_obj(const ST_Obj& obj,
5335              const NdbDictionary::Dictionary::List::Element& element,
5336              int& found)
5337 {
5338   if (obj.exists()) {
5339     if (st_match_obj(obj, element)) {
5340       chk1(st_verify_obj(obj, element) == 0);
5341       found += 1;
5342     }
5343   }
5344   else {
5345     chk2(st_match_obj(obj, element) == false, obj.name);
5346   }
5347   return 0;
5348 err:
5349   return -1;
5350 }
5351 
5352 static int
st_verify_list(ST_Con & c)5353 st_verify_list(ST_Con& c)
5354 {
5355   NdbDictionary::Dictionary::List list;
5356   chk1(st_list_objects(c, list) == 0);
5357   int i, j, k, n;
5358   // us vs list
5359   for (i = 0; i < c.tabcount; i++) {
5360     const ST_Tab& tab = c.tab(i);
5361     chk1(st_verify_obj(tab, list) == 0);
5362     for (j = 0; j < tab.indcount; j++) {
5363       const ST_Ind& ind = tab.ind(j);
5364       chk1(st_verify_obj(ind, list) == 0);
5365       for (k = 0; k < ind.trgcount; k++) {
5366         const ST_Trg& trg = ind.trg(k);
5367         chk1(st_verify_obj(trg, list) == 0);
5368       }
5369     }
5370   }
5371   // list vs us
5372   for (n = 0; n < (int)list.count; n++) {
5373     const NdbDictionary::Dictionary::List::Element& element =
5374       list.elements[n];
5375     if (!st_known_type(element))
5376       continue;
5377     int found = 0;
5378     for (i = 0; i < c.tabcount; i++) {
5379       const ST_Tab& tab = c.tab(i);
5380       chk1(st_verify_obj(tab, element, found) == 0);
5381       for (j = 0; j < tab.indcount; j++) {
5382         const ST_Ind& ind = tab.ind(j);
5383         chk1(st_verify_obj(ind, element, found) == 0);
5384         for (k = 0; k < ind.trgcount; k++) {
5385           const ST_Trg& trg = ind.trg(k);
5386           chk1(st_verify_obj(trg, element, found) == 0);
5387         }
5388       }
5389     }
5390     const char* dot = element.database[0] != 0 ? "." : "";
5391     chk2(found == 1, element.database << dot << element.name);
5392   }
5393   return 0;
5394 err:
5395   return -1;
5396 }
5397 
5398 // wait for DICT to finish current trans
5399 
5400 static int
st_wait_idle(ST_Con & c)5401 st_wait_idle(ST_Con& c)
5402 {
5403   // todo: use try-lock when available
5404   g_info << "st_wait_idle" << endl;
5405   int count = 0;
5406   int max_count = 60;
5407   int milli_sleep = 1000;
5408   while (count++ < max_count) {
5409     NdbDictionary::Dictionary::List list;
5410     chk1(st_list_objects(c, list) == 0);
5411     bool ok = true;
5412     int n;
5413     for (n = 0; n < (int)list.count; n++) {
5414       const NdbDictionary::Dictionary::List::Element& element =
5415         list.elements[n];
5416       if (!st_known_type(element))
5417         continue;
5418       if (element.state != NdbDictionary::Object::StateOnline) {
5419         ok = false;
5420         break;
5421       }
5422     }
5423     if (ok)
5424       return 0;
5425     g_info << "waiting count:" << count << "/" << max_count << endl;
5426     NdbSleep_MilliSleep(milli_sleep);
5427   }
5428   g_err << "st_wait_idle: objects did not become Online" << endl;
5429 err:
5430   return -1;
5431 }
5432 
5433 // ndb dict comparisons (non-retrieved vs retrieved)
5434 
5435 static int
st_equal_column(const NdbDictionary::Column & c1,const NdbDictionary::Column & c2,NdbDictionary::Object::Type type)5436 st_equal_column(const NdbDictionary::Column& c1,
5437                 const NdbDictionary::Column& c2,
5438                 NdbDictionary::Object::Type type)
5439 {
5440   chk1(strcmp(c1.getName(), c2.getName()) == 0);
5441   chk1(c1.getNullable() == c2.getNullable());
5442   if (type == NdbDictionary::Object::UserTable) {
5443     chk1(c1.getPrimaryKey() == c2.getPrimaryKey());
5444   }
5445   if (0) { // should fix
5446     chk1(c1.getColumnNo() == c2.getColumnNo());
5447   }
5448   chk1(c1.getType() == c2.getType());
5449   if (c1.getType() == NdbDictionary::Column::Decimal ||
5450       c1.getType() == NdbDictionary::Column::Decimalunsigned) {
5451     chk1(c1.getPrecision() == c2.getPrecision());
5452     chk1(c1.getScale() == c2.getScale());
5453   }
5454   if (c1.getType() != NdbDictionary::Column::Blob &&
5455       c1.getType() != NdbDictionary::Column::Text) {
5456     chk1(c1.getLength() == c2.getLength());
5457   } else {
5458     chk1(c1.getInlineSize() == c2.getInlineSize());
5459     chk1(c1.getPartSize() == c2.getPartSize());
5460     chk1(c1.getStripeSize() == c2.getStripeSize());
5461   }
5462   chk1(c1.getCharset() == c2.getCharset());
5463   if (type == NdbDictionary::Object::UserTable) {
5464     chk1(c1.getPartitionKey() == c2.getPartitionKey());
5465   }
5466   chk1(c1.getArrayType() == c2.getArrayType());
5467   chk1(c1.getStorageType() == c2.getStorageType());
5468   chk1(c1.getDynamic() == c2.getDynamic());
5469   chk1(c1.getAutoIncrement() == c2.getAutoIncrement());
5470   return 0;
5471 err:
5472   return -1;
5473 }
5474 
5475 static int
st_equal_table(const NdbDictionary::Table & t1,const NdbDictionary::Table & t2)5476 st_equal_table(const NdbDictionary::Table& t1, const NdbDictionary::Table& t2)
5477 {
5478   chk1(strcmp(t1.getName(), t2.getName()) == 0);
5479   chk1(t1.getLogging() == t2.getLogging());
5480   chk1(t1.getFragmentType() == t2.getFragmentType());
5481   chk1(t1.getKValue() == t2.getKValue());
5482   chk1(t1.getMinLoadFactor() == t2.getMinLoadFactor());
5483   chk1(t1.getMaxLoadFactor() == t2.getMaxLoadFactor());
5484   chk1(t1.getNoOfColumns() == t2.getNoOfColumns());
5485   /*
5486    * There is no method to get type of table...
5487    * On the other hand SystemTable/UserTable should be just Table
5488    * and "System" should be an independent property.
5489    */
5490   NdbDictionary::Object::Type type;
5491   type = NdbDictionary::Object::UserTable;
5492   int n;
5493   for (n = 0; n < t1.getNoOfColumns(); n++) {
5494     const NdbDictionary::Column* c1 = t1.getColumn(n);
5495     const NdbDictionary::Column* c2 = t2.getColumn(n);
5496     require(c1 != 0 && c2 != 0);
5497     chk2(st_equal_column(*c1, *c2, type) == 0, "col:" << n);
5498   }
5499   chk1(t1.getNoOfPrimaryKeys() == t2.getNoOfPrimaryKeys());
5500   chk1(t1.getTemporary() == t2.getTemporary());
5501   chk1(t1.getForceVarPart() == t2.getForceVarPart());
5502   return 0;
5503 err:
5504   return -1;
5505 }
5506 
5507 static int
st_equal_index(const NdbDictionary::Index & i1,const NdbDictionary::Index & i2)5508 st_equal_index(const NdbDictionary::Index& i1, const NdbDictionary::Index& i2)
5509 {
5510   chk1(strcmp(i1.getName(), i2.getName()) == 0);
5511   require(i1.getTable() != 0 && i2.getTable() != 0);
5512   chk1(strcmp(i1.getTable(), i2.getTable()) == 0);
5513   chk1(i1.getNoOfColumns() == i2.getNoOfColumns());
5514   chk1(i1.getType() == i2.getType());
5515   NdbDictionary::Object::Type type;
5516   type = (NdbDictionary::Object::Type)i1.getType();
5517   int n;
5518   for (n = 0; n < (int)i1.getNoOfColumns(); n++) {
5519     const NdbDictionary::Column* c1 = i1.getColumn(n);
5520     const NdbDictionary::Column* c2 = i2.getColumn(n);
5521     require(c1 != 0 && c2 != 0);
5522     chk2(st_equal_column(*c1, *c2, type) == 0, "col:" << n);
5523   }
5524   chk1(i1.getLogging() == i2.getLogging());
5525   chk1(i1.getTemporary() == i2.getTemporary());
5526   return 0;
5527 err:
5528   return -1;
5529 }
5530 
5531 // verify against database objects (hits all nodes randomly)
5532 
5533 static int
st_verify_table(ST_Con & c,ST_Tab & tab)5534 st_verify_table(ST_Con& c, ST_Tab& tab)
5535 {
5536   c.dic->invalidateTable(tab.name);
5537   const NdbDictionary::Table* pTab = c.dic->getTable(tab.name);
5538   tab.tab_r = pTab;
5539   if (tab.exists()) {
5540     chk2(pTab != 0, c.dic->getNdbError());
5541     chk1(st_equal_table(*tab.tab, *pTab) == 0);
5542     tab.id = pTab->getObjectId();
5543     g_info << tab << ": verified exists tx_on:" << c.tx_on << endl;
5544   } else {
5545     chk2(pTab == 0, tab);
5546     chk2(c.dic->getNdbError().code == 723, c.dic->getNdbError());
5547     g_info << tab << ": verified not exists tx_on:" << c.tx_on << endl;
5548     tab.id = -1;
5549   }
5550   return 0;
5551 err:
5552   return -1;
5553 }
5554 
5555 static int
st_verify_index(ST_Con & c,ST_Ind & ind)5556 st_verify_index(ST_Con& c, ST_Ind& ind)
5557 {
5558   ST_Tab& tab = *ind.tab;
5559   c.dic->invalidateIndex(ind.name, tab.name);
5560   const NdbDictionary::Index* pInd = c.dic->getIndex(ind.name, tab.name);
5561   ind.ind_r = pInd;
5562   if (ind.exists()) {
5563     chk2(pInd != 0, c.dic->getNdbError());
5564     chk1(st_equal_index(*ind.ind, *pInd) == 0);
5565     ind.id = pInd->getObjectId();
5566     g_info << ind << ": verified exists tx_on:" << c.tx_on << endl;
5567   } else {
5568     chk2(pInd == 0, ind);
5569     chk2(c.dic->getNdbError().code == 4243, c.dic->getNdbError());
5570     g_info << ind << ": verified not exists tx_on:" << c.tx_on << endl;
5571     ind.id = -1;
5572   }
5573   return 0;
5574 err:
5575   return -1;
5576 }
5577 
5578 static int
st_verify_all(ST_Con & c)5579 st_verify_all(ST_Con& c)
5580 {
5581   chk1(st_verify_list(c) == 0);
5582   int i, j;
5583   for (i = 0; i < c.tabcount; i++) {
5584     ST_Tab& tab = c.tab(i);
5585     chk1(st_verify_table(c, tab) == 0);
5586     for (j = 0; j < tab.indcount; j++) {
5587       ST_Ind& ind = tab.ind(j);
5588       chk1(st_verify_index(c, ind) == 0);
5589     }
5590   }
5591   return 0;
5592 err:
5593   return -1;
5594 }
5595 
5596 // subroutines
5597 
5598 static const uint
5599 ST_CommitFlag = 0;
5600 
5601 static const uint
5602 ST_AbortFlag = NdbDictionary::Dictionary::SchemaTransAbort;
5603 
5604 static const uint
5605 ST_BackgroundFlag = NdbDictionary::Dictionary::SchemaTransBackground;
5606 
5607 struct ST_Retry {
5608   int max_tries;
5609   int sleep_ms;
5610 };
5611 
5612 static int
st_begin_trans(ST_Con & c,int code=0)5613 st_begin_trans(ST_Con& c, int code = 0)
5614 {
5615   g_info << "begin trans";
5616   if (code == 0) {
5617     g_info << endl;
5618     chk2(c.dic->beginSchemaTrans() == 0, c.dic->getNdbError());
5619     chk1(c.dic->hasSchemaTrans() == true);
5620     c.tx_on = true;
5621   } else {
5622     g_info << " - expect error " << code << endl;
5623     chk1(c.dic->beginSchemaTrans() == -1);
5624     const NdbError& error = c.dic->getNdbError();
5625     chk2(error.code == code, error << " wanted: " << code);
5626   }
5627   return 0;
5628 err:
5629   return -1;
5630 }
5631 
5632 static int
st_begin_trans(ST_Con & c,ST_Errins errins)5633 st_begin_trans(ST_Con& c, ST_Errins errins)
5634 {
5635   require(errins.code != 0);
5636   chk1(st_do_errins(c, errins) == 0);
5637   chk1(st_begin_trans(c, errins.code) == 0);
5638   return 0;
5639 err:
5640   return -1;
5641 }
5642 
5643 static int
st_begin_trans(ST_Con & c,ST_Retry retry)5644 st_begin_trans(ST_Con& c, ST_Retry retry)
5645 {
5646   int tries = 0;
5647   while (++tries <= retry.max_tries) {
5648     int code = 0;
5649     if (c.dic->beginSchemaTrans() == -1) {
5650       code = c.dic->getNdbError().code;
5651       require(code != 0);
5652     }
5653     chk2(code == 0 || code == 780 || code == 701, c.dic->getNdbError());
5654     if (code == 0) {
5655       chk1(c.dic->hasSchemaTrans() == true);
5656       g_info << "begin trans at try " << tries << endl;
5657       break;
5658     }
5659     NdbSleep_MilliSleep(retry.sleep_ms);
5660   }
5661   return 0;
5662 err:
5663   return -1;
5664 }
5665 
5666 static int
st_end_trans(ST_Con & c,uint flags)5667 st_end_trans(ST_Con& c, uint flags)
5668 {
5669   g_info << "end trans flags:" << hex << flags << endl;
5670   int res= c.dic->endSchemaTrans(flags);
5671   g_info << "end trans result:" << res << endl;
5672   chk2(res == 0, c.dic->getNdbError());
5673   c.tx_on = false;
5674   c.tx_commit = !(flags & ST_AbortFlag);
5675   st_set_commit_all(c);
5676   return 0;
5677 err:
5678   return -1;
5679 }
5680 
5681 static int
st_end_trans_aborted(ST_Con & c,uint flags)5682 st_end_trans_aborted(ST_Con& c, uint flags)
5683 {
5684   g_info << "end trans flags:" << hex << flags << endl;
5685   int res= c.dic->endSchemaTrans(flags);
5686   g_info << "end trans result:" << res << endl;
5687   if (flags & ST_AbortFlag)
5688     chk1(res == 0);
5689   else
5690     chk1(res != 0);
5691   c.tx_on = false;
5692   c.tx_commit = (flags & ST_AbortFlag);
5693   return 0;
5694 err:
5695   return -1;
5696 }
5697 
5698 static int
st_end_trans(ST_Con & c,ST_Errins errins,uint flags)5699 st_end_trans(ST_Con& c, ST_Errins errins, uint flags)
5700 {
5701   chk1(st_do_errins(c, errins) == 0);
5702   chk1(st_end_trans(c, flags) == 0);
5703   return 0;
5704 err:
5705   return -1;
5706 }
5707 
5708 static int
st_end_trans_aborted(ST_Con & c,ST_Errins errins,uint flags)5709 st_end_trans_aborted(ST_Con& c, ST_Errins errins, uint flags)
5710 {
5711   chk1(st_do_errins(c, errins) == 0);
5712   chk1(st_end_trans_aborted(c, flags) == 0);
5713   return 0;
5714 err:
5715   return -1;
5716 }
5717 
5718 static int
st_load_table(ST_Con & c,ST_Tab & tab,int rows=1000)5719 st_load_table(ST_Con& c, ST_Tab& tab, int rows = 1000)
5720 {
5721   g_info << tab.name << ": load data rows:" << rows << endl;
5722   chk1(tab.tab_r != NULL);
5723   {
5724     HugoTransactions ht(*tab.tab_r);
5725     chk1(ht.loadTable(c.ndb, rows) == 0);
5726   }
5727   return 0;
5728 err:
5729   return -1;
5730 }
5731 
5732 static int
st_create_table(ST_Con & c,ST_Tab & tab,int code=0)5733 st_create_table(ST_Con& c, ST_Tab& tab, int code = 0)
5734 {
5735   g_info << tab.name << ": create table";
5736   if (code == 0) {
5737     g_info << endl;
5738     require(!tab.exists());
5739     chk2(c.dic->createTable(*tab.tab) == 0, c.dic->getNdbError());
5740     g_info << tab.name << ": created" << endl;
5741     st_set_create_tab(c, tab, true);
5742   }
5743   else {
5744     g_info << " - expect error " << code << endl;
5745     chk1(c.dic->createTable(*tab.tab) == -1);
5746     const NdbError& error = c.dic->getNdbError();
5747     chk2(error.code == code, error << " wanted: " << code);
5748   }
5749   chk1(st_verify_table(c, tab) == 0);
5750   return 0;
5751 err:
5752   return -1;
5753 }
5754 
5755 static int
st_create_table(ST_Con & c,ST_Tab & tab,ST_Errins errins)5756 st_create_table(ST_Con& c, ST_Tab& tab, ST_Errins errins)
5757 {
5758   require(errins.code != 0);
5759   chk1(st_do_errins(c, errins) == 0);
5760   chk1(st_create_table(c, tab, errins.code) == 0);
5761   return 0;
5762 err:
5763   return -1;
5764 }
5765 
5766 static int
st_drop_table(ST_Con & c,ST_Tab & tab,int code=0)5767 st_drop_table(ST_Con& c, ST_Tab& tab, int code = 0)
5768 {
5769   g_info << tab.name << ": drop table";
5770   if (code == 0) {
5771     g_info << endl;
5772     require(tab.exists());
5773     c.dic->invalidateTable(tab.name);
5774     chk2(c.dic->dropTable(tab.name) == 0, c.dic->getNdbError());
5775     g_info << tab.name << ": dropped" << endl;
5776     st_set_create_tab(c, tab, false);
5777   } else {
5778     g_info << " - expect error " << code << endl;
5779     c.dic->invalidateTable(tab.name);
5780     chk1(c.dic->dropTable(tab.name) == -1);
5781     const NdbError& error = c.dic->getNdbError();
5782     chk2(error.code == code, error << " wanted: " << code);
5783   }
5784   chk1(st_verify_table(c, tab) == 0);
5785   return 0;
5786 err:
5787   return -1;
5788 }
5789 
5790 static int
st_drop_table(ST_Con & c,ST_Tab & tab,ST_Errins errins)5791 st_drop_table(ST_Con& c, ST_Tab& tab, ST_Errins errins)
5792 {
5793   require(errins.code != 0);
5794   chk1(st_do_errins(c, errins) == 0);
5795   chk1(st_drop_table(c, tab, errins.code) == 0);
5796   return 0;
5797 err:
5798   return -1;
5799 }
5800 
5801 static int
st_create_index(ST_Con & c,ST_Ind & ind,int code=0)5802 st_create_index(ST_Con& c, ST_Ind& ind, int code = 0)
5803 {
5804   ST_Tab& tab = *ind.tab;
5805   g_info << ind.name << ": create index on "
5806          << tab.name << "(" << ind.colnames.c_str() << ")";
5807   if (code == 0) {
5808     g_info << endl;
5809     require(!ind.exists());
5810     chk2(c.dic->createIndex(*ind.ind, *tab.tab_r) == 0, c.dic->getNdbError());
5811     st_set_create_ind(c, ind, true);
5812     g_info << ind.name << ": created" << endl;
5813   } else {
5814     g_info << " - expect error " << code << endl;
5815     chk1(c.dic->createIndex(*ind.ind, *tab.tab_r) == -1);
5816     const NdbError& error = c.dic->getNdbError();
5817     chk2(error.code == code, error << " wanted: " << code);
5818   }
5819   chk1(st_verify_index(c, ind) == 0);
5820   return 0;
5821 err:
5822   return -1;
5823 }
5824 
5825 static int
st_create_index(ST_Con & c,ST_Ind & ind,ST_Errins errins)5826 st_create_index(ST_Con& c, ST_Ind& ind, ST_Errins errins)
5827 {
5828   require(errins.code != 0);
5829   chk1(st_do_errins(c, errins) == 0);
5830   chk1(st_create_index(c, ind, errins.code) == 0);
5831   return 0;
5832 err:
5833   return -1;
5834 }
5835 
5836 static int
st_drop_index(ST_Con & c,ST_Ind & ind,int code=0)5837 st_drop_index(ST_Con& c, ST_Ind& ind, int code = 0)
5838 {
5839   ST_Tab& tab = *ind.tab;
5840   g_info << ind.name << ": drop index";
5841   if (code == 0) {
5842     g_info << endl;
5843     require(ind.exists());
5844     c.dic->invalidateIndex(ind.name, tab.name);
5845     chk2(c.dic->dropIndex(ind.name, tab.name) == 0, c.dic->getNdbError());
5846     g_info << ind.name << ": dropped" << endl;
5847     st_set_create_ind(c, ind, false);
5848   } else {
5849     g_info << " expect error " << code << endl;
5850     c.dic->invalidateIndex(ind.name, tab.name);
5851     chk1(c.dic->dropIndex(ind.name, tab.name) == -1);
5852     const NdbError& error = c.dic->getNdbError();
5853     chk2(error.code == code, error << " wanted: " << code);
5854   }
5855   chk1(st_verify_index(c, ind) == 0);
5856   return 0;
5857 err:
5858   return -1;
5859 }
5860 
5861 static int
st_drop_index(ST_Con & c,ST_Ind & ind,ST_Errins errins)5862 st_drop_index(ST_Con& c, ST_Ind& ind, ST_Errins errins)
5863 {
5864   require(errins.code != 0);
5865   chk1(st_do_errins(c, errins) == 0);
5866   chk1(st_drop_index(c, ind, errins.code) == 0);
5867   return 0;
5868 err:
5869   return -1;
5870 }
5871 
5872 static int
st_create_table_index(ST_Con & c,ST_Tab & tab)5873 st_create_table_index(ST_Con& c, ST_Tab& tab)
5874 {
5875   chk1(st_create_table(c, tab) == 0);
5876   int j;
5877   for (j = 0; j < tab.indcount; j++) {
5878     ST_Ind& ind = tab.ind(j);
5879     chk1(st_create_index(c, ind) == 0);
5880   }
5881   return 0;
5882 err:
5883   return -1;
5884 }
5885 
5886 // drop all
5887 
5888 static int
st_drop_test_tables(ST_Con & c)5889 st_drop_test_tables(ST_Con& c)
5890 {
5891   g_info << "st_drop_test_tables" << endl;
5892   int i;
5893   for (i = 0; i < c.tabcount; i++) {
5894     ST_Tab& tab = c.tab(i);
5895     if (tab.exists())
5896       chk1(st_drop_table(c, tab) == 0);
5897   }
5898   return 0;
5899 err:
5900   return -1;
5901 }
5902 
5903 // error insert values
5904 
5905 static const ST_Errins
5906 st_errins_begin_trans[] = {
5907   ST_Errins(6101, 780),
5908   ST_Errins()
5909 };
5910 
5911 static const ST_Errins
5912 st_errins_end_trans1[] = {
5913   ST_Errins(ERR_INSERT_MASTER_FAILURE1, 0, 1),
5914   ST_Errins()
5915 };
5916 
5917 static const ST_Errins
5918 st_errins_end_trans2[] = {
5919   ST_Errins(ERR_INSERT_MASTER_FAILURE2, 0, 1),
5920   ST_Errins()
5921 };
5922 
5923 static const ST_Errins
5924 st_errins_end_trans3[] = {
5925   ST_Errins(ERR_INSERT_MASTER_FAILURE3, 0, 1),
5926   ST_Errins()
5927 };
5928 
5929 static const ST_Errins
5930 st_errins_table[] = {
5931   ST_Errins(6111, 783),
5932   ST_Errins(6121, 9121),
5933   //ST_Errins(6131, 9131),
5934   ST_Errins()
5935 };
5936 
5937 static ST_Errins
5938 st_errins_index[] = {
5939   ST_Errins(st_errins_table),
5940   ST_Errins(6112, 783),
5941   ST_Errins(6113, 783),
5942   ST_Errins(6114, 783),
5943   ST_Errins(6122, 9122),
5944   ST_Errins(6123, 9123),
5945   ST_Errins(6124, 9124),
5946   //ST_Errins(6132, 9131),
5947   //ST_Errins(6133, 9131),
5948   //ST_Errins(6134, 9131),
5949   //ST_Errins(6135, 9131),
5950   ST_Errins()
5951 };
5952 
5953 static ST_Errins
5954 st_errins_index_create[] = {
5955   ST_Errins(st_errins_index),
5956   ST_Errins(6116, 783),
5957   ST_Errins(6126, 9126),
5958   //ST_Errins(6136, 9136),
5959   ST_Errins()
5960 };
5961 
5962 static ST_Errins
5963 st_errins_index_drop[] = {
5964   ST_Errins(st_errins_index),
5965   ST_Errins()
5966 };
5967 
5968 // specific test cases
5969 
5970 static int
st_test_create(ST_Con & c,int arg=-1)5971 st_test_create(ST_Con& c, int arg = -1)
5972 {
5973   int do_abort = (arg == 1);
5974   int i;
5975   chk1(st_begin_trans(c) == 0);
5976   for (i = 0; i < c.tabcount; i++) {
5977     ST_Tab& tab = c.tab(i);
5978     chk1(st_create_table_index(c, tab) == 0);
5979   }
5980   chk1(st_verify_list(c) == 0);
5981   if (!do_abort)
5982     chk1(st_end_trans(c, 0) == 0);
5983   else
5984     chk1(st_end_trans(c, ST_AbortFlag) == 0);
5985   chk1(st_verify_list(c) == 0);
5986   if (!do_abort)
5987     chk1(st_drop_test_tables(c) == 0);
5988   return NDBT_OK;
5989 err:
5990   return NDBT_FAILED;
5991 }
5992 
5993 static int
st_test_drop(ST_Con & c,int arg=-1)5994 st_test_drop(ST_Con& c, int arg = -1)
5995 {
5996   int do_abort = (arg == 1);
5997   int i;
5998   for (i = 0; i < c.tabcount; i++) {
5999     ST_Tab& tab = c.tab(i);
6000     chk1(st_create_table_index(c, tab) == 0);
6001   }
6002   chk1(st_begin_trans(c) == 0);
6003   for (i = 0; i < c.tabcount; i++) {
6004     ST_Tab& tab = c.tab(i);
6005     chk1(st_drop_table(c, tab) == 0);
6006   }
6007   chk1(st_verify_list(c) == 0);
6008   if (!do_abort)
6009     chk1(st_end_trans(c, 0) == 0);
6010   else
6011     chk1(st_end_trans(c, ST_AbortFlag) == 0);
6012   chk1(st_verify_list(c) == 0);
6013   return NDBT_OK;
6014 err:
6015   return NDBT_FAILED;
6016 }
6017 
6018 static int
st_test_rollback_create_table(ST_Con & c,int arg=-1)6019 st_test_rollback_create_table(ST_Con& c, int arg = -1)
6020 {
6021   int i;
6022   chk1(st_begin_trans(c) == 0);
6023   for (i = 0; i < c.tabcount; i++) {
6024     ST_Tab& tab = c.tab(i);
6025     if (i % 2 == 0) {
6026       ST_Errins errins(6111, 783, 0); // fail CTa seize op
6027       chk1(st_create_table(c, tab, errins) == 0);
6028     } else {
6029       chk1(st_create_table(c, tab) == 0);
6030     }
6031   }
6032   chk1(st_end_trans(c, 0) == 0);
6033   chk1(st_verify_list(c) == 0);
6034   for (i = 0; i < c.tabcount; i++) {
6035     ST_Tab& tab = c.tab(i);
6036     if (i % 2 == 0)
6037       require(!tab.exists());
6038     else {
6039       require(tab.exists());
6040       chk1(st_drop_table(c, tab) == 0);
6041     }
6042   }
6043   return NDBT_OK;
6044 err:
6045   return NDBT_FAILED;
6046 }
6047 
6048 static int
st_test_rollback_drop_table(ST_Con & c,int arg=-1)6049 st_test_rollback_drop_table(ST_Con& c, int arg = -1)
6050 {
6051   int i;
6052   for (i = 0; i < c.tabcount; i++) {
6053     ST_Tab& tab = c.tab(i);
6054     chk1(st_create_table(c, tab) == 0);
6055   }
6056   chk1(st_begin_trans(c) == 0);
6057   for (i = 0; i < c.tabcount; i++) {
6058     ST_Tab& tab = c.tab(i);
6059     if (i % 2 == 0) {
6060       ST_Errins errins(6111, 783, 0); // fail DTa seize op
6061       chk1(st_drop_table(c, tab, errins) == 0);
6062     } else {
6063       chk1(st_drop_table(c, tab) == 0);
6064     }
6065   }
6066   chk1(st_end_trans(c, 0) == 0);
6067   chk1(st_verify_list(c) == 0);
6068   for (i = 0; i < c.tabcount; i++) {
6069     ST_Tab& tab = c.tab(i);
6070     if (i % 2 == 0) {
6071       require(tab.exists());
6072       chk1(st_drop_table(c, tab) == 0);
6073     } else {
6074       require(!tab.exists());
6075     }
6076   }
6077   return NDBT_OK;
6078 err:
6079   return NDBT_FAILED;
6080 }
6081 
6082 static int
st_test_rollback_create_index(ST_Con & c,int arg=-1)6083 st_test_rollback_create_index(ST_Con& c, int arg = -1)
6084 {
6085   int i, j;
6086   for (i = 0; i < c.tabcount; i++) {
6087     ST_Tab& tab = c.tab(i);
6088     if (tab.indcount < 1)
6089       continue;
6090     chk1(st_create_table(c, tab) == 0);
6091     chk1(st_begin_trans(c) == 0);
6092     for (j = 0; j < tab.indcount; j++) {
6093       ST_Ind& ind = tab.ind(j);
6094       if (j % 2 == 0) {
6095         ST_Errins errins(6116, 783, 0); // fail BIn seize op
6096         chk1(st_create_index(c, ind, errins) == 0);
6097       } else {
6098         chk1(st_create_index(c, ind) == 0);
6099       }
6100     }
6101     chk1(st_end_trans(c, 0) == 0);
6102     chk1(st_verify_list(c) == 0);
6103     for (j = 0; j < tab.indcount; j++) {
6104       ST_Ind& ind = tab.ind(j);
6105       if (j % 2 == 0)
6106         require(!ind.exists());
6107       else {
6108         require(ind.exists());
6109         chk1(st_drop_index(c, ind) == 0);
6110       }
6111     }
6112     chk1(st_drop_table(c, tab) == 0);
6113   }
6114   return NDBT_OK;
6115 err:
6116   return NDBT_FAILED;
6117 }
6118 
6119 static int
st_test_rollback_drop_index(ST_Con & c,int arg=-1)6120 st_test_rollback_drop_index(ST_Con& c, int arg = -1)
6121 {
6122   int i, j;
6123   for (i = 0; i < c.tabcount; i++) {
6124     ST_Tab& tab = c.tab(i);
6125     if (tab.indcount < 1)
6126       continue;
6127     chk1(st_create_table_index(c, tab) == 0);
6128   }
6129   for (i = 0; i < c.tabcount; i++) {
6130     ST_Tab& tab = c.tab(i);
6131     if (tab.indcount < 1)
6132       continue;
6133     chk1(st_begin_trans(c) == 0);
6134     for (j = 0; j < tab.indcount; j++) {
6135       ST_Ind& ind = tab.ind(j);
6136       if (j % 2 == 0) {
6137         ST_Errins errins(6114, 783, 0); // fail ATr seize op
6138         chk1(st_drop_index(c, ind, errins) == 0);
6139       } else {
6140         chk1(st_drop_index(c, ind) == 0);
6141       }
6142     }
6143     chk1(st_end_trans(c, 0) == 0);
6144     chk1(st_verify_list(c) == 0);
6145     for (j = 0; j < tab.indcount; j++) {
6146       ST_Ind& ind = tab.ind(j);
6147       if (j % 2 == 0) {
6148         require(ind.exists());
6149         chk1(st_drop_index(c, ind) == 0);
6150       } else {
6151         require(!ind.exists());
6152       }
6153     }
6154   }
6155   return NDBT_OK;
6156 err:
6157   return NDBT_FAILED;
6158 }
6159 
6160 static int
st_test_dup_create_table(ST_Con & c,int arg=-1)6161 st_test_dup_create_table(ST_Con& c, int arg = -1)
6162 {
6163   int do_trans;
6164   int do_abort;
6165   int i;
6166   for (do_trans = 0; do_trans <= 1; do_trans++) {
6167     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6168       g_info << "trans:" << do_trans
6169              << " abort:" << do_abort << endl;
6170       for (i = 0; i < c.tabcount; i++) {
6171         ST_Tab& tab = c.tab(i);
6172         if (do_trans)
6173           chk1(st_begin_trans(c) == 0);
6174         chk1(st_create_table(c, tab) == 0);
6175         chk1(st_create_table(c, tab, 721) == 0);
6176         if (do_trans) {
6177           if (!do_abort)
6178             chk1(st_end_trans(c, 0) == 0);
6179           else
6180             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6181         }
6182         chk1(st_verify_list(c) == 0);
6183         if (tab.exists()) {
6184           chk1(st_drop_table(c, tab) == 0);
6185         }
6186       }
6187     }
6188   }
6189   return NDBT_OK;
6190 err:
6191   return NDBT_FAILED;
6192 }
6193 
6194 static int
st_test_dup_drop_table(ST_Con & c,int arg=-1)6195 st_test_dup_drop_table(ST_Con& c, int arg = -1)
6196 {
6197   int do_trans;
6198   int do_abort;
6199   int i;
6200   for (do_trans = 0; do_trans <= 1; do_trans++) {
6201     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6202       g_info << "trans:" << do_trans
6203              << " abort:" << do_abort << endl;
6204       for (i = 0; i < c.tabcount; i++) {
6205         ST_Tab& tab = c.tab(i);
6206         chk1(st_create_table(c, tab) == 0);
6207         if (do_trans)
6208           chk1(st_begin_trans(c) == 0);
6209         chk1(st_drop_table(c, tab) == 0);
6210         if (!do_trans)
6211           chk1(st_drop_table(c, tab, 723) == 0);
6212         else
6213           chk1(st_drop_table(c, tab, 785) == 0);
6214         if (do_trans) {
6215           if (!do_abort)
6216             chk1(st_end_trans(c, 0) == 0);
6217           else
6218             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6219         }
6220         chk1(st_verify_list(c) == 0);
6221         if (tab.exists()) {
6222           chk1(st_drop_table(c, tab) == 0);
6223         }
6224       }
6225     }
6226   }
6227   return NDBT_OK;
6228 err:
6229   return NDBT_FAILED;
6230 }
6231 
6232 static int
st_test_dup_create_index(ST_Con & c,int arg=-1)6233 st_test_dup_create_index(ST_Con& c, int arg = -1)
6234 {
6235   int do_trans;
6236   int do_abort;
6237   int i, j;
6238   for (do_trans = 0; do_trans <= 1; do_trans++) {
6239     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6240       g_info << "trans:" << do_trans
6241              << " abort:" << do_abort << endl;
6242       for (i = 0; i < c.tabcount; i++) {
6243         ST_Tab& tab = c.tab(i);
6244         if (tab.indcount < 1)
6245           continue;
6246         chk1(st_create_table(c, tab) == 0);
6247         for (j = 0; j < tab.indcount; j++) {
6248           ST_Ind& ind = tab.ind(j);
6249           if (do_trans)
6250             chk1(st_begin_trans(c) == 0);
6251           chk1(st_create_index(c, ind) == 0);
6252           chk1(st_create_index(c, ind, 721) == 0);
6253           if (do_trans) {
6254             if (!do_abort)
6255               chk1(st_end_trans(c, 0) == 0);
6256             else
6257               chk1(st_end_trans(c, ST_AbortFlag) == 0);
6258           }
6259           chk1(st_verify_list(c) == 0);
6260         }
6261         chk1(st_drop_table(c, tab) == 0);
6262       }
6263     }
6264   }
6265   return NDBT_OK;
6266 err:
6267   return NDBT_FAILED;
6268 }
6269 
6270 static int
st_test_dup_drop_index(ST_Con & c,int arg=-1)6271 st_test_dup_drop_index(ST_Con& c, int arg = -1)
6272 {
6273   int do_trans;
6274   int do_abort;
6275   int i, j;
6276   for (do_trans = 0; do_trans <= 1; do_trans++) {
6277     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6278       g_info << "trans:" << do_trans
6279              << " abort:" << do_abort << endl;
6280       for (i = 0; i < c.tabcount; i++) {
6281         ST_Tab& tab = c.tab(i);
6282         if (tab.indcount < 1)
6283           continue;
6284         chk1(st_create_table(c, tab) == 0);
6285         for (j = 0; j < tab.indcount; j++) {
6286           ST_Ind& ind = tab.ind(j);
6287           chk1(st_create_index(c, ind) == 0);
6288           if (do_trans)
6289             chk1(st_begin_trans(c) == 0);
6290           chk1(st_drop_index(c, ind) == 0);
6291           if (!do_trans)
6292             chk1(st_drop_index(c, ind, 4243) == 0);
6293           else
6294             chk1(st_drop_index(c, ind, 785) == 0);
6295           if (do_trans) {
6296             if (!do_abort)
6297               chk1(st_end_trans(c, 0) == 0);
6298             else
6299               chk1(st_end_trans(c, ST_AbortFlag) == 0);
6300           }
6301           chk1(st_verify_list(c) == 0);
6302         }
6303         chk1(st_drop_table(c, tab) == 0);
6304       }
6305     }
6306   }
6307   return NDBT_OK;
6308 err:
6309   return NDBT_FAILED;
6310 }
6311 
6312 static int
st_test_build_index(ST_Con & c,int arg=-1)6313 st_test_build_index(ST_Con& c, int arg = -1)
6314 {
6315   int i, j;
6316   for (i = 0; i < c.tabcount; i++) {
6317     ST_Tab& tab = c.tab(i);
6318     if (tab.indcount < 1)
6319       continue;
6320     chk1(st_create_table(c, tab) == 0);
6321     chk1(st_load_table(c, tab) == 0);
6322     for (j = 0; j < tab.indcount; j++) {
6323       ST_Ind& ind = tab.ind(j);
6324       chk1(st_create_index(c, ind) == 0);
6325       chk1(st_verify_list(c) == 0);
6326     }
6327     chk1(st_drop_table(c, tab) == 0);
6328   }
6329   return NDBT_OK;
6330 err:
6331   return NDBT_FAILED;
6332 }
6333 
6334 static ST_Errins
6335 st_test_local_create_list[] = {
6336   ST_Errins(8033, 293, 1),    // TC trigger
6337   ST_Errins(8033, 293, 0),
6338   ST_Errins(4003, 4237, 1),   // TUP trigger
6339   ST_Errins(4003, 4237, 0),
6340   ST_Errins(8034, 292, 1),    // TC index
6341   ST_Errins(8034, 292, 0)
6342 };
6343 
6344 static int
st_test_local_create(ST_Con & c,int arg=-1)6345 st_test_local_create(ST_Con& c, int arg = -1)
6346 {
6347   const int n = arg;
6348   ST_Errins *list = st_test_local_create_list;
6349   const int listlen =
6350     sizeof(st_test_local_create_list)/sizeof(st_test_local_create_list[0]);
6351   require(0 <= n && n < listlen);
6352   const bool only_unique = (n == 0 || n == 1 || n == 4 || n == 5);
6353   int i, j;
6354   for (i = 0; i < c.tabcount; i++) {
6355     ST_Tab& tab = c.tab(i);
6356     bool tabdone = false;
6357     for (j = 0; j < tab.indcount; j++) {
6358       ST_Ind& ind = tab.ind(j);
6359       if (only_unique && !ind.is_unique())
6360         continue;
6361       if (!tabdone) {
6362         chk1(st_create_table(c, tab) == 0);
6363         chk1(st_load_table(c, tab) == 0);
6364         tabdone = true;
6365       }
6366       ST_Errins errins = list[n];
6367       chk1(st_create_index(c, ind, errins) == 0);
6368       chk1(st_verify_list(c) == 0);
6369     }
6370     if (tabdone)
6371       chk1(st_drop_table(c, tab) == 0);
6372   }
6373   return NDBT_OK;
6374 err:
6375   return NDBT_FAILED;
6376 }
6377 
6378 // random test cases
6379 
6380 static const uint ST_AllowAbort = 1;
6381 static const uint ST_AllowErrins = 2;
6382 
6383 static int
st_test_trans(ST_Con & c,int arg=-1)6384 st_test_trans(ST_Con& c, int arg = -1)
6385 {
6386   if ((arg & ST_AllowErrins) && randomly(2, 3)) {
6387     ST_Errins errins = st_get_errins(c, st_errins_begin_trans);
6388     chk1(st_begin_trans(c, errins) == 0);
6389   } else {
6390     chk1(st_begin_trans(c) == 0);
6391     if (randomly(1, 5)) {
6392       g_info << "try duplicate begin trans" << endl;
6393       chk1(st_begin_trans(c, 4410) == 0);
6394       chk1(c.dic->hasSchemaTrans() == true);
6395     }
6396     if ((arg & ST_AllowAbort) && randomly(1, 3)) {
6397       chk1(st_end_trans(c, ST_AbortFlag) == 0);
6398     } else {
6399       chk1(st_end_trans(c, 0) == 0);
6400     }
6401   }
6402   return NDBT_OK;
6403 err:
6404   return NDBT_FAILED;
6405 }
6406 
6407 static int
st_test_create_table(ST_Con & c,int arg=-1)6408 st_test_create_table(ST_Con& c, int arg = -1)
6409 {
6410   bool trans = randomly(3, 4);
6411   bool simpletrans = !trans && randomly(1, 2);
6412   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
6413   if (trans) {
6414     chk1(st_begin_trans(c) == 0);
6415   }
6416   int i;
6417   for (i = 0; i < c.tabcount; i++) {
6418     ST_Tab& tab = c.tab(i);
6419     if (tab.exists()) {
6420       g_info << tab.name << ": skip existing" << endl;
6421       continue;
6422     }
6423     g_info << tab.name << ": to create" << endl;
6424     if (simpletrans) {
6425       chk1(st_begin_trans(c) == 0);
6426     }
6427     if ((arg & ST_AllowErrins) && randomly(1, 3)) {
6428       ST_Errins errins = st_get_errins(c, st_errins_table);
6429       chk1(st_create_table(c, tab, errins) == 0);
6430       if (simpletrans) {
6431         if (randomly(1, 2))
6432           chk1(st_end_trans(c, 0) == 0);
6433         else
6434           chk1(st_end_trans(c, ST_AbortFlag) == 0);
6435       }
6436     } else {
6437       chk1(st_create_table(c, tab) == 0);
6438       if (simpletrans) {
6439         uint flags = 0;
6440         if ((arg & ST_AllowAbort) && randomly(4, 5))
6441           flags |= ST_AbortFlag;
6442         chk1(st_end_trans(c, flags) == 0);
6443       }
6444     }
6445     if (tab.exists() && randomly(1, 3)) {
6446       g_info << tab.name << ": try duplicate create" << endl;
6447       chk1(st_create_table(c, tab, 721) == 0);
6448     }
6449   }
6450   if (trans) {
6451     uint flags = 0;
6452     if ((arg & ST_AllowAbort) && randomly(4, 5))
6453       flags |= ST_AbortFlag;
6454     chk1(st_end_trans(c, flags) == 0);
6455   }
6456   return NDBT_OK;
6457 err:
6458   return NDBT_FAILED;
6459 }
6460 
6461 static int
st_test_drop_table(ST_Con & c,int arg=-1)6462 st_test_drop_table(ST_Con& c, int arg = -1)
6463 {
6464   bool trans = randomly(3, 4);
6465   bool simpletrans = !trans && randomly(1, 2);
6466   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
6467   if (trans) {
6468     chk1(st_begin_trans(c) == 0);
6469   }
6470   int i;
6471   for (i = 0; i < c.tabcount; i++) {
6472     ST_Tab& tab = c.tab(i);
6473     if (!tab.exists()) {
6474       g_info << tab.name << ": skip not existing" << endl;
6475       continue;
6476     }
6477     g_info << tab.name << ": to drop" << endl;
6478     if (simpletrans) {
6479       chk1(st_begin_trans(c) == 0);
6480     }
6481     if ((arg & ST_AllowErrins) && randomly(1, 3)) {
6482       ST_Errins errins = st_get_errins(c, st_errins_table);
6483       chk1(st_drop_table(c, tab, errins) == 0);
6484       if (simpletrans) {
6485         if (randomly(1, 2))
6486           chk1(st_end_trans(c, 0) == 0);
6487         else
6488           chk1(st_end_trans(c, ST_AbortFlag) == 0);
6489       }
6490     } else {
6491       chk1(st_drop_table(c, tab) == 0);
6492       if (simpletrans) {
6493         uint flags = 0;
6494         if ((arg & ST_AllowAbort) && randomly(4, 5))
6495           flags |= ST_AbortFlag;
6496         chk1(st_end_trans(c, flags) == 0);
6497       }
6498     }
6499     if (!tab.exists() && randomly(1, 3)) {
6500       g_info << tab.name << ": try duplicate drop" << endl;
6501       chk1(st_drop_table(c, tab, 723) == 0);
6502     }
6503   }
6504   if (trans) {
6505     uint flags = 0;
6506     if ((arg & ST_AllowAbort) && randomly(4, 5))
6507       flags |= ST_AbortFlag;
6508     chk1(st_end_trans(c, flags) == 0);
6509   }
6510   return NDBT_OK;
6511 err:
6512   return NDBT_FAILED;
6513 }
6514 
6515 static int
st_test_table(ST_Con & c,int arg=-1)6516 st_test_table(ST_Con& c, int arg = -1)
6517 {
6518   chk1(st_test_create_table(c) == NDBT_OK);
6519   chk1(st_test_drop_table(c) == NDBT_OK);
6520   return NDBT_OK;
6521 err:
6522   return NDBT_FAILED;
6523 }
6524 
6525 static int
st_test_create_index(ST_Con & c,int arg=-1)6526 st_test_create_index(ST_Con& c, int arg = -1)
6527 {
6528   bool trans = randomly(3, 4);
6529   bool simpletrans = !trans && randomly(1, 2);
6530   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
6531   if (trans) {
6532     chk1(st_begin_trans(c) == 0);
6533   }
6534   int i, j;
6535   for (i = 0; i < c.tabcount; i++) {
6536     ST_Tab& tab = c.tab(i);
6537     if (tab.indcount == 0)
6538       continue;
6539     if (!tab.exists()) {
6540       g_info << tab.name << ": to create" << endl;
6541       chk1(st_create_table(c, tab) == 0);
6542     }
6543     for (j = 0; j < tab.indcount; j++) {
6544       ST_Ind& ind = tab.ind(j);
6545       if (ind.exists()) {
6546         g_info << ind.name << ": skip existing" << endl;
6547         continue;
6548       }
6549       g_info << ind.name << ": to create" << endl;
6550       if (simpletrans) {
6551         chk1(st_begin_trans(c) == 0);
6552       }
6553       if ((arg & ST_AllowErrins) && randomly(1, 3)) {
6554         const ST_Errins* list = st_errins_index_create;
6555         ST_Errins errins = st_get_errins(c, list);
6556         chk1(st_create_index(c, ind, errins) == 0);
6557         if (simpletrans) {
6558           if (randomly(1, 2))
6559             chk1(st_end_trans(c, 0) == 0);
6560           else
6561             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6562         }
6563       } else {
6564         chk1(st_create_index(c, ind) == 0);
6565         if (simpletrans) {
6566           uint flags = 0;
6567           if ((arg & ST_AllowAbort) && randomly(4, 5))
6568             flags |= ST_AbortFlag;
6569           chk1(st_end_trans(c, flags) == 0);
6570         }
6571       }
6572       if (ind.exists() && randomly(1, 3)) {
6573         g_info << ind.name << ": try duplicate create" << endl;
6574         chk1(st_create_index(c, ind, 721) == 0);
6575       }
6576     }
6577   }
6578   if (trans) {
6579     uint flags = 0;
6580     if ((arg & ST_AllowAbort) && randomly(4, 5))
6581       flags |= ST_AbortFlag;
6582     chk1(st_end_trans(c, flags) == 0);
6583   }
6584   return NDBT_OK;
6585 err:
6586   return NDBT_FAILED;
6587 }
6588 
6589 static int
st_test_drop_index(ST_Con & c,int arg=-1)6590 st_test_drop_index(ST_Con& c, int arg = -1)
6591 {
6592   bool trans = randomly(3, 4);
6593   bool simpletrans = !trans && randomly(1, 2);
6594   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
6595   if (trans) {
6596     chk1(st_begin_trans(c) == 0);
6597   }
6598   int i, j;
6599   for (i = 0; i < c.tabcount; i++) {
6600     ST_Tab& tab = c.tab(i);
6601     if (tab.indcount == 0)
6602       continue;
6603     if (!tab.exists()) {
6604       g_info << tab.name << ": skip not existing" << endl;
6605       continue;
6606     }
6607     for (j = 0; j < tab.indcount; j++) {
6608       ST_Ind& ind = tab.ind(j);
6609       if (!ind.exists()) {
6610         g_info << ind.name << ": skip not existing" << endl;
6611         continue;
6612       }
6613       g_info << ind.name << ": to drop" << endl;
6614       if (simpletrans) {
6615         chk1(st_begin_trans(c) == 0);
6616       }
6617       if ((arg & ST_AllowErrins) && randomly(1, 3)) {
6618         const ST_Errins* list = st_errins_index_drop;
6619         ST_Errins errins = st_get_errins(c, list);
6620         chk1(st_drop_index(c, ind, errins) == 0);
6621         if (simpletrans) {
6622           if (randomly(1, 2))
6623             chk1(st_end_trans(c, 0) == 0);
6624           else
6625             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6626         }
6627       } else {
6628         chk1(st_drop_index(c, ind) == 0);
6629         if (simpletrans) {
6630           uint flags = 0;
6631           if ((arg & ST_AllowAbort) && randomly(4, 5))
6632             flags |= ST_AbortFlag;
6633           chk1(st_end_trans(c, flags) == 0);
6634         }
6635       }
6636       if (!ind.exists() && randomly(1, 3)) {
6637         g_info << ind.name << ": try duplicate drop" << endl;
6638         chk1(st_drop_index(c, ind, 4243) == 0);
6639       }
6640     }
6641   }
6642   if (trans) {
6643     uint flags = 0;
6644     if ((arg & ST_AllowAbort) && randomly(4, 5))
6645       flags |= ST_AbortFlag;
6646     chk1(st_end_trans(c, flags) == 0);
6647   }
6648   return NDBT_OK;
6649 err:
6650   return NDBT_FAILED;
6651 }
6652 
6653 static int
st_test_index(ST_Con & c,int arg=-1)6654 st_test_index(ST_Con& c, int arg = -1)
6655 {
6656   chk1(st_test_create_index(c) == NDBT_OK);
6657   chk1(st_test_drop_index(c) == NDBT_OK);
6658   return NDBT_OK;
6659 err:
6660   return NDBT_FAILED;
6661 }
6662 
6663 // node failure and system restart
6664 
6665 static int
st_test_anf_parse(ST_Con & c,int arg=-1)6666 st_test_anf_parse(ST_Con& c, int arg = -1)
6667 {
6668   int i;
6669   chk1(st_start_xcon(c) == 0);
6670   {
6671     ST_Con& xc = *c.xcon;
6672     chk1(st_begin_trans(xc) == 0);
6673     for (i = 0; i < c.tabcount; i++) {
6674       ST_Tab& tab = c.tab(i);
6675       chk1(st_create_table_index(xc, tab) == 0);
6676     }
6677     // DICT aborts the trans
6678     xc.tx_on = false;
6679     xc.tx_commit = false;
6680     st_set_commit_all(xc);
6681     chk1(st_stop_xcon(c) == 0);
6682     chk1(st_wait_idle(c) == 0);
6683     chk1(st_verify_list(c) == 0);
6684   }
6685   return NDBT_OK;
6686 err:
6687   return NDBT_FAILED;
6688 }
6689 
6690 static int
st_test_anf_background(ST_Con & c,int arg=-1)6691 st_test_anf_background(ST_Con& c, int arg = -1)
6692 {
6693   int i;
6694   chk1(st_start_xcon(c) == 0);
6695   {
6696     ST_Con& xc = *c.xcon;
6697     chk1(st_begin_trans(xc) == 0);
6698     for (i = 0; i < c.tabcount; i++) {
6699       ST_Tab& tab = c.tab(i);
6700       chk1(st_create_table(xc, tab) == 0);
6701     }
6702     // DICT takes over and completes the trans
6703     st_end_trans(xc, ST_BackgroundFlag);
6704     chk1(st_stop_xcon(c) == 0);
6705     chk1(st_wait_idle(c) == 0);
6706     chk1(st_verify_list(c) == 0);
6707   }
6708   return NDBT_OK;
6709 err:
6710   return NDBT_FAILED;
6711 }
6712 
6713 static int
st_test_anf_fail_begin(ST_Con & c,int arg=-1)6714 st_test_anf_fail_begin(ST_Con& c, int arg = -1)
6715 {
6716   chk1(st_start_xcon(c) == 0);
6717   {
6718     ST_Con& xc = *c.xcon;
6719 
6720     ST_Errins errins1(6102, -1, 1); // master kills us at begin
6721     ST_Errins errins2(6103, -1, 0); // slave delays conf
6722     chk1(st_do_errins(xc, errins1) == 0);
6723     chk1(st_do_errins(xc, errins2) == 0);
6724 
6725     chk1(st_begin_trans(xc, 4009) == 0);
6726 
6727     // DICT aborts the trans
6728     xc.tx_on = false;
6729     xc.tx_commit = false;
6730     st_set_commit_all(xc);
6731     chk1(st_stop_xcon(c) == 0);
6732 
6733     // xc may get 4009 before takeover is ready (5000 ms delay)
6734     ST_Retry retry = { 100, 100 }; // 100 * 100ms = 10000ms
6735     chk1(st_begin_trans(c, retry) == 0);
6736     chk1(st_wait_idle(c) == 0);
6737     chk1(st_verify_list(c) == 0);
6738   }
6739   return NDBT_OK;
6740 err:
6741   return NDBT_FAILED;
6742 }
6743 
6744 static int
st_test_snf_parse(ST_Con & c,int arg=-1)6745 st_test_snf_parse(ST_Con& c, int arg = -1)
6746 {
6747   bool do_abort = (arg == 1);
6748   chk1(st_begin_trans(c) == 0);
6749   int node_id;
6750   node_id = -1;
6751   int i;
6752   int midcount;
6753   midcount = c.tabcount / 2;
6754 
6755   for (i = 0; i < c.tabcount; i++) {
6756     ST_Tab& tab = c.tab(i);
6757     if (i == midcount) {
6758       require(c.numdbnodes > 1);
6759       uint rand = urandom(c.numdbnodes);
6760       node_id = c.restarter->getRandomNotMasterNodeId(rand);
6761       g_info << "restart node " << node_id << " (async)" << endl;
6762       const int flags = NdbRestarter::NRRF_NOSTART;
6763       chk1(c.restarter->restartOneDbNode2(node_id, flags) == 0);
6764       chk1(c.restarter->waitNodesNoStart(&node_id, 1) == 0);
6765       chk1(c.restarter->startNodes(&node_id, 1) == 0);
6766     }
6767     chk1(st_create_table_index(c, tab) == 0);
6768   }
6769   if (!do_abort)
6770     chk1(st_end_trans(c, 0) == 0);
6771   else
6772     chk1(st_end_trans(c, ST_AbortFlag) == 0);
6773 
6774   g_info << "wait for node " << node_id << " to come up" << endl;
6775   chk1(c.restarter->waitClusterStarted() == 0);
6776   g_info << "verify all" << endl;
6777   chk1(st_verify_all(c) == 0);
6778   return NDBT_OK;
6779 err:
6780   return NDBT_FAILED;
6781 }
6782 
6783 static int
st_test_mnf_parse(ST_Con & c,int arg=-1)6784 st_test_mnf_parse(ST_Con& c, int arg = -1)
6785 {
6786   const NdbDictionary::Table* pTab;
6787   bool do_abort = (arg == 1);
6788   chk1(st_begin_trans(c) == 0);
6789   int node_id;
6790   node_id = -1;
6791   int i;
6792   int midcount;
6793   midcount = c.tabcount / 2;
6794 
6795   for (i = 0; i < c.tabcount; i++) {
6796     ST_Tab& tab = c.tab(i);
6797     chk1(st_create_table_index(c, tab) == 0);
6798     if (i == midcount) {
6799       require(c.numdbnodes > 1);
6800       node_id = c.restarter->getMasterNodeId();
6801       g_info << "restart node " << node_id << " (async)" << endl;
6802       const int flags = NdbRestarter::NRRF_NOSTART;
6803       chk1(c.restarter->restartOneDbNode2(node_id, flags) == 0);
6804       chk1(c.restarter->waitNodesNoStart(&node_id, 1) == 0);
6805       chk1(c.restarter->startNodes(&node_id, 1) == 0);
6806       break;
6807     }
6808   }
6809   if (!do_abort)
6810     chk1(st_end_trans_aborted(c, ST_CommitFlag) == 0);
6811   else
6812     chk1(st_end_trans_aborted(c, ST_AbortFlag) == 0);
6813 
6814   g_info << "wait for node " << node_id << " to come up" << endl;
6815   chk1(c.restarter->waitClusterStarted() == 0);
6816   g_info << "verify all" << endl;
6817   for (i = 0; i < c.tabcount; i++) {
6818     ST_Tab& tab = c.tab(i);
6819     // Verify that table is not in db
6820     c.dic->invalidateTable(tab.name);
6821     pTab =
6822       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
6823     chk1(pTab == NULL);
6824   }
6825 /*
6826   chk1(st_verify_all(c) == 0);
6827 */
6828   return NDBT_OK;
6829 err:
6830   return NDBT_FAILED;
6831 }
6832 
6833 static int
st_test_mnf_prepare(ST_Con & c,int arg=-1)6834 st_test_mnf_prepare(ST_Con& c, int arg = -1)
6835 {
6836   NdbRestarter restarter;
6837   //int master = restarter.getMasterNodeId();
6838   ST_Errins errins = st_get_errins(c, st_errins_end_trans1);
6839   int i;
6840 
6841   chk1(st_begin_trans(c) == 0);
6842   for (i = 0; i < c.tabcount; i++) {
6843     ST_Tab& tab = c.tab(i);
6844     chk1(st_create_table_index(c, tab) == 0);
6845   }
6846   if (arg == 1)
6847   {
6848     chk1(st_end_trans_aborted(c, errins, ST_BackgroundFlag) == 0);
6849     chk1(st_wait_idle(c) == 0);
6850   }
6851   else
6852     chk1(st_end_trans_aborted(c, errins, ST_CommitFlag) == 0);
6853   chk1(c.restarter->waitClusterStarted() == 0);
6854   //st_wait_db_node_up(c, master);
6855   for (i = 0; i < c.tabcount; i++) {
6856     ST_Tab& tab = c.tab(i);
6857     // Verify that table is not in db
6858     c.dic->invalidateTable(tab.name);
6859     const NdbDictionary::Table* pTab =
6860       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
6861     chk1(pTab == NULL);
6862   }
6863   return NDBT_OK;
6864 err:
6865   return NDBT_FAILED;
6866 }
6867 
6868 static int
st_test_mnf_commit1(ST_Con & c,int arg=-1)6869 st_test_mnf_commit1(ST_Con& c, int arg = -1)
6870 {
6871   NdbRestarter restarter;
6872   //int master = restarter.getMasterNodeId();
6873   ST_Errins errins = st_get_errins(c, st_errins_end_trans2);
6874   int i;
6875 
6876   chk1(st_begin_trans(c) == 0);
6877   for (i = 0; i < c.tabcount; i++) {
6878     ST_Tab& tab = c.tab(i);
6879     chk1(st_create_table_index(c, tab) == 0);
6880   }
6881   if (arg == 1)
6882   {
6883     chk1(st_end_trans(c, errins, ST_BackgroundFlag) == 0);
6884     chk1(st_wait_idle(c) == 0);
6885   }
6886   else
6887     chk1(st_end_trans(c, errins, ST_CommitFlag) == 0);
6888   chk1(c.restarter->waitClusterStarted() == 0);
6889   //st_wait_db_node_up(c, master);
6890   for (i = 0; i < c.tabcount; i++) {
6891     ST_Tab& tab = c.tab(i);
6892     chk1(st_verify_table(c, tab) == 0);
6893   }
6894   chk1(st_drop_test_tables(c) == 0);
6895   return NDBT_OK;
6896 err:
6897   return NDBT_FAILED;
6898 }
6899 
6900 static int
st_test_mnf_commit2(ST_Con & c,int arg=-1)6901 st_test_mnf_commit2(ST_Con& c, int arg = -1)
6902 {
6903   NdbRestarter restarter;
6904   //int master = restarter.getMasterNodeId();
6905   ST_Errins errins = st_get_errins(c, st_errins_end_trans3);
6906   int i;
6907 
6908   chk1(st_begin_trans(c) == 0);
6909   for (i = 0; i < c.tabcount; i++) {
6910     ST_Tab& tab = c.tab(i);
6911     chk1(st_create_table_index(c, tab) == 0);
6912   }
6913   if (arg == 1)
6914   {
6915     chk1(st_end_trans(c, errins, ST_BackgroundFlag) == 0);
6916     chk1(st_wait_idle(c) == 0);
6917   }
6918   else
6919     chk1(st_end_trans(c, errins, ST_CommitFlag) == 0);
6920   chk1(c.restarter->waitClusterStarted() == 0);
6921   //st_wait_db_node_up(c, master);
6922   chk1(st_verify_all(c) == 0);
6923   for (i = 0; i < c.tabcount; i++) {
6924     ST_Tab& tab = c.tab(i);
6925     chk1(st_load_table(c, tab) == 0);
6926   }
6927   chk1(st_drop_test_tables(c) == 0);
6928   return NDBT_OK;
6929 err:
6930   return NDBT_FAILED;
6931 }
6932 
6933 static int
st_test_mnf_run_commit(ST_Con & c,int arg=-1)6934 st_test_mnf_run_commit(ST_Con& c, int arg = -1)
6935 {
6936   const NdbDictionary::Table* pTab;
6937   NdbRestarter restarter;
6938   //int master = restarter.getMasterNodeId();
6939   int i;
6940 
6941   if (arg == FAIL_BEGIN)
6942   {
6943     // No transaction to be found if only one node left
6944     if (restarter.getNumDbNodes() < 3)
6945       return NDBT_OK;
6946     chk1(st_begin_trans(c) == -1);
6947     goto verify;
6948   }
6949   else
6950     chk1(st_begin_trans(c) == 0);
6951   for (i = 0; i < c.tabcount; i++) {
6952     ST_Tab& tab = c.tab(i);
6953     if (arg == FAIL_CREATE)
6954     {
6955       chk1(st_create_table_index(c, tab) == -1);
6956       goto verify;
6957     }
6958     else
6959       chk1(st_create_table_index(c, tab) == 0);
6960   }
6961   if (arg == FAIL_END)
6962   {
6963     chk1(st_end_trans(c, ST_CommitFlag) == -1);
6964   }
6965   else // if (arg == SUCCEED_COMMIT)
6966     chk1(st_end_trans(c, ST_CommitFlag) == 0);
6967 
6968 verify:
6969   g_info << "wait for master node to come up" << endl;
6970   chk1(c.restarter->waitClusterStarted() == 0);
6971   //st_wait_db_node_up(c, master);
6972   g_info << "verify all" << endl;
6973   for (i = 0; i < c.tabcount; i++) {
6974     ST_Tab& tab = c.tab(i);
6975     switch (arg) {
6976     case FAIL_BEGIN:
6977     case FAIL_CREATE:
6978     case FAIL_END:
6979     {
6980       // Verify that table is not in db
6981       c.dic->invalidateTable(tab.name);
6982       pTab =
6983         NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
6984       chk1(pTab == NULL);
6985       break;
6986     }
6987     default:
6988       chk1(st_verify_table(c, tab) == 0);
6989     }
6990   }
6991 
6992   return NDBT_OK;
6993 err:
6994   return NDBT_FAILED;
6995 }
6996 
6997 static int
st_test_mnf_run_abort(ST_Con & c,int arg=-1)6998 st_test_mnf_run_abort(ST_Con& c, int arg = -1)
6999 {
7000   NdbRestarter restarter;
7001   //int master = restarter.getMasterNodeId();
7002   const NdbDictionary::Table* pTab;
7003   bool do_abort = (arg == SUCCEED_ABORT);
7004   int i;
7005 
7006   chk1(st_begin_trans(c) == 0);
7007   for (i = 0; i < c.tabcount; i++) {
7008     ST_Tab& tab = c.tab(i);
7009     chk1(st_create_table_index(c, tab) == 0);
7010   }
7011   if (!do_abort)
7012     chk1(st_end_trans(c, ST_CommitFlag) == -1);
7013   else
7014     chk1(st_end_trans_aborted(c, ST_AbortFlag) == 0);
7015 
7016   g_info << "wait for master node to come up" << endl;
7017   chk1(c.restarter->waitClusterStarted() == 0);
7018   //st_wait_db_node_up(c, master);
7019   g_info << "verify all" << endl;
7020   for (i = 0; i < c.tabcount; i++) {
7021     ST_Tab& tab = c.tab(i);
7022     // Verify that table is not in db
7023     c.dic->invalidateTable(tab.name);
7024     pTab =
7025       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
7026     chk1(pTab == NULL);
7027   }
7028 
7029   return NDBT_OK;
7030 err:
7031   return NDBT_FAILED;
7032 }
7033 
7034 static int
st_test_mnf_start_partial(ST_Con & c,int arg=-1)7035 st_test_mnf_start_partial(ST_Con& c, int arg = -1)
7036 {
7037   ST_Errins errins(ERR_INSERT_PARTIAL_START_FAIL, 0, 1); // slave skips start
7038   chk1(st_do_errins(c, errins) == 0);
7039   return st_test_mnf_run_commit(c, arg);
7040 err:
7041   return -1;
7042 }
7043 
7044 static int
st_test_mnf_parse_partial(ST_Con & c,int arg=-1)7045 st_test_mnf_parse_partial(ST_Con& c, int arg = -1)
7046 {
7047   ST_Errins errins(ERR_INSERT_PARTIAL_PARSE_FAIL, 0, 1); // slave skips parse
7048   chk1(st_do_errins(c, errins) == 0);
7049   return st_test_mnf_run_commit(c, arg);
7050 err:
7051   return -1;
7052 }
7053 
7054 static int
st_test_mnf_flush_prepare_partial(ST_Con & c,int arg=-1)7055 st_test_mnf_flush_prepare_partial(ST_Con& c, int arg = -1)
7056 {
7057   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_PREPARE_FAIL, 0, 1); // slave skips flush prepare
7058   chk1(st_do_errins(c, errins) == 0);
7059   return st_test_mnf_run_commit(c, arg);
7060 err:
7061   return -1;
7062 }
7063 
7064 static int
st_test_mnf_prepare_partial(ST_Con & c,int arg=-1)7065 st_test_mnf_prepare_partial(ST_Con& c, int arg = -1)
7066 {
7067   ST_Errins errins(ERR_INSERT_PARTIAL_PREPARE_FAIL, 0, 1); // slave skips prepare
7068   chk1(st_do_errins(c, errins) == 0);
7069   return st_test_mnf_run_commit(c, arg);
7070 err:
7071   return -1;
7072 }
7073 
7074 static int
st_test_mnf_abort_parse_partial(ST_Con & c,int arg=-1)7075 st_test_mnf_abort_parse_partial(ST_Con& c, int arg = -1)
7076 {
7077   ST_Errins errins(ERR_INSERT_PARTIAL_ABORT_PARSE_FAIL, 0, 1); // slave skips abort parse
7078   chk1(st_do_errins(c, errins) == 0);
7079   return st_test_mnf_run_abort(c, arg);
7080 err:
7081   return -1;
7082 }
7083 
7084 static int
st_test_mnf_abort_prepare_partial(ST_Con & c,int arg=-1)7085 st_test_mnf_abort_prepare_partial(ST_Con& c, int arg = -1)
7086 {
7087   ST_Errins errins(ERR_INSERT_PARTIAL_ABORT_PREPARE_FAIL, 0, 1); // slave skips abort prepare
7088   chk1(st_do_errins(c, errins) == 0);
7089   return st_test_mnf_run_abort(c, arg);
7090 err:
7091   return -1;
7092 }
7093 
7094 static int
st_test_mnf_flush_commit_partial(ST_Con & c,int arg=-1)7095 st_test_mnf_flush_commit_partial(ST_Con& c, int arg = -1)
7096 {
7097   NdbRestarter restarter;
7098   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_COMMIT_FAIL, 0, 1); // slave skips flush commit
7099   chk1(st_do_errins(c, errins) == 0);
7100   if (restarter.getNumDbNodes() < 3)
7101     // If new master is only node and it hasn't flush commit, we abort
7102     return st_test_mnf_run_commit(c, FAIL_END);
7103   else
7104     return st_test_mnf_run_commit(c, arg);
7105 err:
7106   return -1;
7107 }
7108 
7109 static int
st_test_mnf_commit_partial(ST_Con & c,int arg=-1)7110 st_test_mnf_commit_partial(ST_Con& c, int arg = -1)
7111 {
7112   ST_Errins errins(ERR_INSERT_PARTIAL_COMMIT_FAIL, 0, 1); // slave skips commit
7113   chk1(st_do_errins(c, errins) == 0);
7114   return st_test_mnf_run_commit(c, arg);
7115 err:
7116   return -1;
7117 }
7118 
7119 static int
st_test_mnf_flush_complete_partial(ST_Con & c,int arg=-1)7120 st_test_mnf_flush_complete_partial(ST_Con& c, int arg = -1)
7121 {
7122   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_COMPLETE_FAIL, 0, 1); // slave skips flush complete
7123   chk1(st_do_errins(c, errins) == 0);
7124   return st_test_mnf_run_commit(c, arg);
7125 err:
7126   return -1;
7127 }
7128 
7129 static int
st_test_mnf_complete_partial(ST_Con & c,int arg=-1)7130 st_test_mnf_complete_partial(ST_Con& c, int arg = -1)
7131 {
7132   ST_Errins errins(ERR_INSERT_PARTIAL_COMPLETE_FAIL, 0, 1); // slave skips complete
7133   chk1(st_do_errins(c, errins) == 0);
7134   return st_test_mnf_run_commit(c, arg);
7135 err:
7136   return -1;
7137 }
7138 
7139 static int
st_test_mnf_end_partial(ST_Con & c,int arg=-1)7140 st_test_mnf_end_partial(ST_Con& c, int arg = -1)
7141 {
7142   ST_Errins errins(ERR_INSERT_PARTIAL_END_FAIL, 0, 1); // slave skips end
7143   chk1(st_do_errins(c, errins) == 0);
7144   return st_test_mnf_run_commit(c, arg);
7145 err:
7146   return -1;
7147 }
7148 
7149 static int
st_test_sr_parse(ST_Con & c,int arg=-1)7150 st_test_sr_parse(ST_Con& c, int arg = -1)
7151 {
7152   bool do_abort = (arg == 1);
7153   chk1(st_begin_trans(c) == 0);
7154   int i;
7155   for (i = 0; i < c.tabcount; i++) {
7156     ST_Tab& tab = c.tab(i);
7157     chk1(st_create_table_index(c, tab) == 0);
7158   }
7159   if (!do_abort)
7160     chk1(st_end_trans(c, 0) == 0);
7161   else
7162     chk1(st_end_trans(c, ST_AbortFlag) == 0);
7163 
7164   g_info << "restart all" << endl;
7165   int flags;
7166   flags = NdbRestarter::NRRF_NOSTART;
7167   chk1(c.restarter->restartAll2(flags) == 0);
7168   g_info << "wait for cluster started" << endl;
7169   chk1(c.restarter->waitClusterNoStart() == 0);
7170   chk1(c.restarter->startAll() == 0);
7171   chk1(c.restarter->waitClusterStarted() == 0);
7172   g_info << "verify all" << endl;
7173   chk1(st_verify_all(c) == 0);
7174   return NDBT_OK;
7175 err:
7176   return NDBT_FAILED;
7177 }
7178 
7179 #if 0
7180 static int
7181 st_test_sr_commit(ST_Con& c, int arg = -1)
7182 {
7183   g_info << "not yet" << endl;
7184   return NDBT_OK;
7185 }
7186 #endif
7187 
7188 // run test cases
7189 
7190 struct ST_Test {
7191   const char* key;
7192   int mindbnodes;
7193   int arg;
7194   int (*func)(ST_Con& c, int arg);
7195   const char* name;
7196   const char* desc;
7197 };
7198 
7199 static NdbOut&
operator <<(NdbOut & out,const ST_Test & test)7200 operator<<(NdbOut& out, const ST_Test& test)
7201 {
7202   out << "CASE " << test.key;
7203   out << " " << test.name;
7204   if (test.arg != -1)
7205     out << "+" << test.arg;
7206   out << " - " << test.desc;
7207   return out;
7208 }
7209 
7210 static const ST_Test
7211 st_test_list[] = {
7212 #define func(f) f, #f
7213   // specific ops
7214   { "a1", 1, 0,
7215      func(st_test_create),
7216      "create all within trans, commit" },
7217   { "a2", 1, 1,
7218      func(st_test_create),
7219      "create all within trans, abort" },
7220   { "a3", 1, 0,
7221      func(st_test_drop),
7222      "drop all within trans, commit" },
7223   { "a4", 1, 1,
7224      func(st_test_drop),
7225      "drop all within trans, abort" },
7226   { "b1", 1, -1,
7227     func(st_test_rollback_create_table),
7228     "partial rollback of create table ops" },
7229   { "b2", 1, -1,
7230     func(st_test_rollback_drop_table),
7231     "partial rollback of drop table ops" },
7232   { "b3", 1, -1,
7233     func(st_test_rollback_create_index),
7234     "partial rollback of create index ops" },
7235   { "b4", 1, -1,
7236     func(st_test_rollback_drop_index),
7237     "partial rollback of drop index ops" },
7238   { "c1", 1, -1,
7239     func(st_test_dup_create_table),
7240     "try to create same table twice" },
7241   { "c2", 1, -1,
7242     func(st_test_dup_drop_table),
7243     "try to drop same table twice" },
7244   { "c3", 1, -1,
7245     func(st_test_dup_create_index),
7246     "try to create same index twice" },
7247   { "c4", 1, -1,
7248     func(st_test_dup_drop_index),
7249     "try to drop same index twice" },
7250   { "d1", 1, -1,
7251     func(st_test_build_index),
7252     "build index on non-empty table" },
7253   { "e1", 1, 0,
7254     func(st_test_local_create),
7255     "fail trigger create in TC, master errins 8033" },
7256   { "e2", 2, 1,
7257     func(st_test_local_create),
7258     "fail trigger create in TC, slave errins 8033" },
7259   { "e3", 1, 2,
7260     func(st_test_local_create),
7261     "fail trigger create in TUP, master errins 4003" },
7262   { "e4", 2, 3,
7263     func(st_test_local_create),
7264     "fail trigger create in TUP, slave errins 4003" },
7265   { "e5", 1, 4,
7266     func(st_test_local_create),
7267     "fail index create in TC, master errins 8034" },
7268   { "e6", 2, 5,
7269     func(st_test_local_create),
7270     "fail index create in TC, slave errins 8034" },
7271   // random ops
7272   { "o1", 1, 0,
7273     func(st_test_trans),
7274     "start and stop schema trans" },
7275   { "o2", 1, ST_AllowAbort,
7276     func(st_test_trans),
7277     "start and stop schema trans, allow abort" },
7278   { "o3", 1, ST_AllowAbort | ST_AllowErrins,
7279     func(st_test_trans),
7280     "start and stop schema trans, allow abort errins" },
7281   //
7282   { "p1", 1, 0,
7283     func(st_test_create_table),
7284     "create tables at random" },
7285   { "p2", 1, ST_AllowAbort,
7286     func(st_test_create_table),
7287     "create tables at random, allow abort" },
7288   { "p3", 1, ST_AllowAbort | ST_AllowErrins,
7289     func(st_test_create_table),
7290     "create tables at random, allow abort errins" },
7291   //
7292   { "p4", 1, 0,
7293     func(st_test_table),
7294     "create and drop tables at random" },
7295   { "p5", 1, ST_AllowAbort,
7296     func(st_test_table),
7297     "create and drop tables at random, allow abort" },
7298   { "p6", 1, ST_AllowAbort | ST_AllowErrins,
7299     func(st_test_table),
7300     "create and drop tables at random, allow abort errins" },
7301   //
7302   { "q1", 1, 0,
7303     func(st_test_create_index),
7304     "create indexes at random" },
7305   { "q2", 1, ST_AllowAbort,
7306     func(st_test_create_index),
7307     "create indexes at random, allow abort" },
7308   { "q3", 1, ST_AllowAbort | ST_AllowErrins,
7309     func(st_test_create_index),
7310     "create indexes at random, allow abort errins" },
7311   //
7312   { "q4", 1, 0,
7313     func(st_test_index),
7314     "create and drop indexes at random" },
7315   { "q5", 1, ST_AllowAbort,
7316     func(st_test_index),
7317     "create and drop indexes at random, allow abort" },
7318   { "q6", 1, ST_AllowAbort | ST_AllowErrins,
7319     func(st_test_index),
7320     "create and drop indexes at random, allow abort errins" },
7321   // node failure and system restart
7322   { "u1", 1, -1,
7323     func(st_test_anf_parse),
7324     "api node fail in parse phase" },
7325   { "u2", 1, -1,
7326     func(st_test_anf_background),
7327     "api node fail after background trans" },
7328   { "u3", 2, -1,
7329     func(st_test_anf_fail_begin),
7330     "api node fail in middle of kernel begin trans" },
7331   //
7332   { "v1", 2, 0,
7333     func(st_test_snf_parse),
7334     "slave node fail in parse phase, commit" },
7335   { "v2", 2, 1,
7336     func(st_test_snf_parse),
7337     "slave node fail in parse phase, abort" },
7338   { "w1", 1, 0,
7339     func(st_test_sr_parse),
7340     "system restart in parse phase, commit" },
7341   { "w2", 1, 1,
7342     func(st_test_sr_parse),
7343     "system restart in parse phase, abort" },
7344 #ifdef ndb_master_failure
7345   { "x1", 2, 0,
7346     func(st_test_mnf_parse),
7347     "master node fail in parse phase, commit" },
7348   { "x2", 2, 1,
7349     func(st_test_mnf_parse),
7350     "master node fail in parse phase, abort" },
7351   { "x3", 2, 0,
7352     func(st_test_mnf_prepare),
7353     "master node fail in prepare phase" },
7354   { "x4", 2, 0,
7355     func(st_test_mnf_commit1),
7356     "master node fail in start of commit phase" },
7357   { "x5", 2, 0,
7358     func(st_test_mnf_commit2),
7359     "master node fail in end of commit phase" },
7360   { "y1", 2, SUCCEED_COMMIT,
7361     func(st_test_mnf_start_partial),
7362     "master node fail in start phase, retry will succeed" },
7363   { "y2", 2, FAIL_CREATE,
7364     func(st_test_mnf_parse_partial),
7365     "master node fail in parse phase, partial rollback" },
7366   { "y3", 2, FAIL_END,
7367     func(st_test_mnf_flush_prepare_partial),
7368     "master node fail in flush prepare phase, partial rollback" },
7369   { "y4", 2, FAIL_END,
7370     func(st_test_mnf_prepare_partial),
7371     "master node fail in prepare phase, partial rollback" },
7372   { "y5", 2, SUCCEED_COMMIT,
7373     func(st_test_mnf_flush_commit_partial),
7374     "master node fail in flush commit phase, partial rollback" },
7375   { "y6", 2, SUCCEED_COMMIT,
7376     func(st_test_mnf_commit_partial),
7377     "master node fail in commit phase, commit, partial rollforward" },
7378   { "y7", 2, SUCCEED_COMMIT,
7379     func(st_test_mnf_flush_complete_partial),
7380     "master node fail in flush complete phase, commit, partial rollforward" },
7381   { "y8", 2, SUCCEED_COMMIT,
7382     func(st_test_mnf_complete_partial),
7383     "master node fail in complete phase, commit, partial rollforward" },
7384   { "y9", 2, SUCCEED_COMMIT,
7385     func(st_test_mnf_end_partial),
7386     "master node fail in end phase, commit, partial rollforward" },
7387   { "z1", 2, SUCCEED_ABORT,
7388     func(st_test_mnf_abort_parse_partial),
7389     "master node fail in abort parse phase, partial rollback" },
7390   { "z2", 2, FAIL_END,
7391     func(st_test_mnf_abort_prepare_partial),
7392     "master node fail in abort prepare phase, partial rollback" },
7393   { "z3", 2, 1,
7394     func(st_test_mnf_prepare),
7395     "master node fail in prepare phase in background" },
7396   { "z4", 2, 1,
7397     func(st_test_mnf_commit1),
7398     "master node fail in start of commit phase in background" },
7399   { "z5", 2, 1,
7400     func(st_test_mnf_commit2),
7401     "master node fail in end of commit phase in background" },
7402 
7403 #endif
7404 #undef func
7405 };
7406 
7407 static const int
7408 st_test_count = sizeof(st_test_list)/sizeof(st_test_list[0]);
7409 
7410 static const char* st_test_case = 0;
7411 static const char* st_test_skip = 0;
7412 
7413 static bool
st_test_match(const ST_Test & test)7414 st_test_match(const ST_Test& test)
7415 {
7416   const char* p = 0;
7417   if (st_test_case == 0)
7418     goto skip;
7419   if (strstr(st_test_case, test.key) != 0)
7420     goto skip;
7421   p = strchr(st_test_case, test.key[0]);
7422   if (p != 0 && (p[1] < '0' || p[1] > '9'))
7423     goto skip;
7424   return false;
7425 skip:
7426   if (st_test_skip == 0)
7427     return true;
7428   if (strstr(st_test_skip, test.key) != 0)
7429     return false;
7430   p = strchr(st_test_skip, test.key[0]);
7431   if (p != 0 && (p[1] < '0' || p[1] > '9'))
7432     return false;
7433   return true;
7434 }
7435 
7436 static int
st_test(ST_Con & c,const ST_Test & test)7437 st_test(ST_Con& c, const ST_Test& test)
7438 {
7439   chk1(st_end_trans(c, ST_AbortFlag) == 0);
7440   chk1(st_drop_test_tables(c) == 0);
7441   chk1(st_check_db_nodes(c) == 0);
7442 
7443   g_err << test << endl;
7444   if (c.numdbnodes < test.mindbnodes) {
7445     g_err << "skip, too few db nodes" << endl;
7446     return NDBT_OK;
7447   }
7448 
7449   chk1((*test.func)(c, test.arg) == NDBT_OK);
7450   chk1(st_check_db_nodes(c) == 0);
7451   //chk1(st_verify_list(c) == 0);
7452 
7453   return NDBT_OK;
7454 err:
7455   return NDBT_FAILED;
7456 }
7457 
7458 static int st_random_seed = -1;
7459 
7460 int
runSchemaTrans(NDBT_Context * ctx,NDBT_Step * step)7461 runSchemaTrans(NDBT_Context* ctx, NDBT_Step* step)
7462 {
7463 #ifdef NDB_USE_GET_ENV
7464   { const char* env = NdbEnv_GetEnv("NDB_TEST_DBUG", 0, 0);
7465     if (env != 0 && env[0] != 0) // e.g. d:t:L:F:o,ndb_test.log
7466       DBUG_PUSH(env);
7467   }
7468   { const char* env = NdbEnv_GetEnv("NDB_TEST_CORE", 0, 0);
7469     if (env != 0 && env[0] != 0 && env[0] != '0' && env[0] != 'N')
7470       st_core_on_err = true;
7471   }
7472   { const char* env = NdbEnv_GetEnv("NDB_TEST_CASE", 0, 0);
7473     st_test_case = env;
7474   }
7475   { const char* env = NdbEnv_GetEnv("NDB_TEST_SKIP", 0, 0);
7476     st_test_skip = env;
7477   }
7478   { const char* env = NdbEnv_GetEnv("NDB_TEST_SEED", 0, 0);
7479     if (env != 0)
7480       st_random_seed = atoi(env);
7481   }
7482 #endif
7483   if (st_test_case != 0 && strcmp(st_test_case, "?") == 0) {
7484     int i;
7485     ndbout << "case func+arg desc" << endl;
7486     for (i = 0; i < st_test_count; i++) {
7487       const ST_Test& test = st_test_list[i];
7488       ndbout << test << endl;
7489     }
7490     return NDBT_WRONGARGS;
7491   }
7492 
7493   if (st_random_seed == -1)
7494     st_random_seed = (short)getpid();
7495   if (st_random_seed != 0) {
7496     g_err << "random seed: " << st_random_seed << endl;
7497     ndb_srand(st_random_seed);
7498   } else {
7499     g_err << "random seed: loop number" << endl;
7500   }
7501 
7502   Ndb_cluster_connection* ncc = &ctx->m_cluster_connection;
7503   Ndb* ndb = GETNDB(step);
7504   ST_Restarter* restarter = new ST_Restarter;
7505   ST_Con c(ncc, ndb, restarter);
7506 
7507   chk1(st_drop_all_tables(c) == 0);
7508   st_init_objects(c, ctx);
7509 
7510   int numloops;
7511   numloops = ctx->getNumLoops();
7512 
7513   for (c.loop = 0; numloops == 0 || c.loop < numloops; c.loop++) {
7514     g_err << "LOOP " << c.loop << endl;
7515     if (st_random_seed == 0)
7516       ndb_srand(c.loop);
7517     int i;
7518     for (i = 0; i < st_test_count; i++) {
7519       const ST_Test& test = st_test_list[i];
7520       if (st_test_match(test)) {
7521         chk1(st_test(c, test) == NDBT_OK);
7522       }
7523     }
7524   }
7525 
7526   st_report_db_nodes(c, g_err);
7527   return NDBT_OK;
7528 err:
7529   st_report_db_nodes(c, g_err);
7530   return NDBT_FAILED;
7531 }
7532 
7533 // end schema trans
7534 
7535 int
runFailCreateHashmap(NDBT_Context * ctx,NDBT_Step * step)7536 runFailCreateHashmap(NDBT_Context* ctx, NDBT_Step* step)
7537 {
7538   static int lst[] = { 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 0 };
7539 
7540   NdbRestarter restarter;
7541   int nodeId = restarter.getMasterNodeId();
7542   Ndb* pNdb = GETNDB(step);
7543   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
7544 
7545   int errNo = 0;
7546 #ifdef NDB_USE_GET_ENV
7547   char buf[100];
7548   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
7549   {
7550     errNo = atoi(buf);
7551     ndbout_c("Using errno: %u", errNo);
7552   }
7553 #endif
7554   const int loops = ctx->getNumLoops();
7555   int result = NDBT_OK;
7556 
7557   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
7558   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
7559 
7560   NdbDictionary::HashMap hm;
7561   pDic->initDefaultHashMap(hm, 1);
7562 
7563 loop:
7564   if (pDic->getHashMap(hm, hm.getName()) != -1)
7565   {
7566     pDic->initDefaultHashMap(hm, rand() % 64);
7567     goto loop;
7568   }
7569 
7570   for (int l = 0; l < loops; l++)
7571   {
7572     for (unsigned i0 = 0; lst[i0]; i0++)
7573     {
7574       unsigned j = (l == 0 ? i0 : myRandom48(i0 + l));
7575       int errval = lst[j];
7576       if (errNo != 0 && errNo != errval)
7577         continue;
7578       g_info << "insert error node=" << nodeId << " value=" << errval << endl;
7579       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
7580              "failed to set error insert");
7581       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
7582 
7583       int res = pDic->createHashMap(hm);
7584       CHECK2(res != 0, "create hashmap failed to fail");
7585 
7586       NdbDictionary::HashMap check;
7587       CHECK2(res != 0, "create hashmap existed");
7588 
7589       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
7590              "failed to clear error insert");
7591       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
7592     }
7593   }
7594 end:
7595   return result;
7596 }
7597 // end FAIL create hashmap
7598 
7599 int
runCreateHashmaps(NDBT_Context * ctx,NDBT_Step * step)7600 runCreateHashmaps(NDBT_Context* ctx, NDBT_Step* step)
7601 {
7602   NdbRestarter restarter;
7603   // int nodeId = restarter.getMasterNodeId();
7604   Ndb* pNdb = GETNDB(step);
7605   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
7606 
7607   const int loops = ctx->getNumLoops();
7608   int result = NDBT_OK;
7609 
7610   NdbDictionary::HashMap hm;
7611 
7612   int created = 0;
7613   for (int i = 1; i <= NDB_DEFAULT_HASHMAP_BUCKETS && created < loops ; i++)
7614   {
7615     pDic->initDefaultHashMap(hm, i);
7616     int res = pDic->getHashMap(hm, hm.getName());
7617     if (res == -1)
7618     {
7619       const NdbError err = pDic->getNdbError();
7620       if (err.code != 723)
7621       {
7622         g_err << "getHashMap: " << hm.getName() << ": " << err << endl;
7623         result = NDBT_FAILED;
7624         break;
7625       }
7626       int res = pDic->createHashMap(hm);
7627       if (res == -1)
7628       {
7629         const NdbError err = pDic->getNdbError();
7630         if (err.code != 707 && err.code != 712)
7631         {
7632           g_err << "createHashMap: " << hm.getName() << ": " << err << endl;
7633           result = NDBT_FAILED;
7634         }
7635         break;
7636       }
7637       created++;
7638     }
7639   }
7640 
7641   // Drop all hashmaps (and everything else) with initial restart
7642   ndbout << "Restarting cluster" << endl;
7643   restarter.restartAll(/* initial */ true);
7644   restarter.waitClusterStarted();
7645 
7646   return result;
7647 }
7648 // end FAIL create hashmap
7649 
7650 int
runFailAddPartition(NDBT_Context * ctx,NDBT_Step * step)7651 runFailAddPartition(NDBT_Context* ctx, NDBT_Step* step)
7652 {
7653   static int lst[] = { 7211, 7212, 4050, 12008, 6212, 6124, 6213, 6214, 0 };
7654 
7655   Ndb* pNdb = GETNDB(step);
7656   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
7657   NdbDictionary::Table tab(*ctx->getTab());
7658   NdbRestarter restarter;
7659   int nodeId = restarter.getMasterNodeId();
7660 
7661   int errNo = 0;
7662 #ifdef NDB_USE_GET_ENV
7663   char buf[100];
7664   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
7665   {
7666     errNo = atoi(buf);
7667     ndbout_c("Using errno: %u", errNo);
7668   }
7669 #endif
7670   // ordered index on first few columns
7671   NdbDictionary::Index idx("X");
7672   idx.setTable(tab.getName());
7673   idx.setType(NdbDictionary::Index::OrderedIndex);
7674   idx.setLogging(false);
7675   for (int cnt = 0, i_hate_broken_compilers = 0;
7676        cnt < 3 &&
7677        i_hate_broken_compilers < tab.getNoOfColumns();
7678        i_hate_broken_compilers++) {
7679     if (NdbSqlUtil::check_column_for_ordered_index
7680         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
7681         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
7682         NdbDictionary::Column::StorageTypeDisk)
7683     {
7684       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
7685       cnt++;
7686     }
7687   }
7688 
7689   for (int i = 0; i<tab.getNoOfColumns(); i++)
7690   {
7691     if (tab.getColumn(i)->getStorageType() ==
7692         NdbDictionary::Column::StorageTypeDisk)
7693     {
7694       NDBT_Tables::create_default_tablespace(pNdb);
7695       break;
7696     }
7697   }
7698 
7699   const int loops = ctx->getNumLoops();
7700   int result = NDBT_OK;
7701   (void)pDic->dropTable(tab.getName());
7702   if (pDic->createTable(tab) != 0)
7703   {
7704     ndbout << "FAIL: " << pDic->getNdbError() << endl;
7705     return NDBT_FAILED;
7706   }
7707 
7708   if (pDic->createIndex(idx) != 0)
7709   {
7710     ndbout << "FAIL: " << pDic->getNdbError() << endl;
7711     return NDBT_FAILED;
7712   }
7713 
7714   const NdbDictionary::Table * org = pDic->getTable(tab.getName());
7715   NdbDictionary::Table altered = * org;
7716   altered.setFragmentCount(org->getFragmentCount() +
7717                            restarter.getNumDbNodes());
7718 
7719   if (pDic->beginSchemaTrans())
7720   {
7721     ndbout << "Failed to beginSchemaTrans()" << pDic->getNdbError() << endl;
7722     return NDBT_FAILED;
7723   }
7724 
7725   if (pDic->prepareHashMap(*org, altered) == -1)
7726   {
7727     ndbout << "Failed to create hashmap: " << pDic->getNdbError() << endl;
7728     return NDBT_FAILED;
7729   }
7730 
7731   if (pDic->endSchemaTrans())
7732   {
7733     ndbout << "Failed to endSchemaTrans()" << pDic->getNdbError() << endl;
7734     return NDBT_FAILED;
7735   }
7736 
7737   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
7738   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
7739 
7740   for (int l = 0; l < loops; l++)
7741   {
7742     for (unsigned i0 = 0; lst[i0]; i0++)
7743     {
7744       unsigned j = (l == 0 ? i0 : myRandom48(sizeof(lst)/sizeof(lst[0]) - 1));
7745       int errval = lst[j];
7746       if (errNo != 0 && errNo != errval)
7747         continue;
7748       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
7749       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
7750       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
7751              "failed to set error insert");
7752 
7753       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
7754 
7755       int res = pDic->alterTable(*org, altered);
7756       if (res)
7757       {
7758         ndbout << pDic->getNdbError() << endl;
7759       }
7760       CHECK2(res != 0,
7761              "failed to fail after error insert " << errval);
7762       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
7763              "failed to clear error insert");
7764       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
7765       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
7766 
7767       int dump3[] = {DumpStateOrd::DihAddFragFailCleanedUp, org->getTableId()};
7768       CHECK(restarter.dumpStateAllNodes(dump3, 2) == 0);
7769 
7770       const NdbDictionary::Table* check = pDic->getTable(tab.getName());
7771 
7772       CHECK2((check->getObjectId() == org->getObjectId() &&
7773               check->getObjectVersion() == org->getObjectVersion()),
7774              "table has been altered!");
7775     }
7776   }
7777 
7778 end:
7779   (void)pDic->dropTable(tab.getName());
7780   return result;
7781 }
7782 // fail add partition
7783 
7784 int
runTableAddPartition(NDBT_Context * ctx,NDBT_Step * step)7785 runTableAddPartition(NDBT_Context* ctx, NDBT_Step* step){
7786 
7787   int result = NDBT_OK;
7788 
7789   Ndb* pNdb = GETNDB(step);
7790   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
7791   int records = ctx->getNumRecords();
7792   const int loops = ctx->getNumLoops();
7793 
7794   ndbout << "|- " << ctx->getTab()->getName() << endl;
7795 
7796   NdbDictionary::Table myTab= *(ctx->getTab());
7797   myTab.setFragmentType(NdbDictionary::Object::HashMapPartition);
7798 
7799   for (int l = 0; l < loops && result == NDBT_OK ; l++)
7800   {
7801     // Try to create table in db
7802     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
7803       return NDBT_FAILED;
7804     }
7805 
7806     // Verify that table is in db
7807     const NdbDictionary::Table* pTab2 =
7808       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
7809     if (pTab2 == NULL){
7810       ndbout << myTab.getName() << " was not found in DB"<< endl;
7811       return NDBT_FAILED;
7812     }
7813     ctx->setTab(pTab2);
7814 
7815 #if 1
7816     // Load table
7817     const NdbDictionary::Table* pTab;
7818     CHECK((pTab = ctx->getTab()) != NULL);
7819     HugoTransactions beforeTrans(*pTab);
7820     if (beforeTrans.loadTable(pNdb, records) != 0){
7821       return NDBT_FAILED;
7822     }
7823 #endif
7824 
7825     // Add attributes to table.
7826     BaseString pTabName(pTab2->getName());
7827     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
7828 
7829     NdbDictionary::Table newTable= *oldTable;
7830 
7831     newTable.setFragmentCount(2 * oldTable->getFragmentCount());
7832     CHECK2(dict->alterTable(*oldTable, newTable) == 0,
7833            "TableAddAttrs failed");
7834 
7835     /* Need to purge old version and reload new version after alter table. */
7836     dict->invalidateTable(pTabName.c_str());
7837 
7838 #if 0
7839     {
7840       HugoTransactions afterTrans(* dict->getTable(pTabName.c_str()));
7841 
7842       ndbout << "delete...";
7843       if (afterTrans.clearTable(pNdb) != 0)
7844       {
7845         return NDBT_FAILED;
7846       }
7847       ndbout << endl;
7848 
7849       ndbout << "insert...";
7850       if (afterTrans.loadTable(pNdb, records) != 0){
7851         return NDBT_FAILED;
7852       }
7853       ndbout << endl;
7854 
7855       ndbout << "update...";
7856       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
7857       {
7858         return NDBT_FAILED;
7859       }
7860       ndbout << endl;
7861 
7862       ndbout << "delete...";
7863       if (afterTrans.clearTable(pNdb) != 0)
7864       {
7865         return NDBT_FAILED;
7866       }
7867       ndbout << endl;
7868     }
7869 #endif
7870     abort();
7871     // Drop table.
7872     dict->dropTable(pTabName.c_str());
7873   }
7874 end:
7875 
7876   return result;
7877 }
7878 
7879 int
runBug41905(NDBT_Context * ctx,NDBT_Step * step)7880 runBug41905(NDBT_Context* ctx, NDBT_Step* step)
7881 {
7882   const NdbDictionary::Table* pTab = ctx->getTab();
7883   BaseString tabName(pTab->getName());
7884   Ndb* pNdb = GETNDB(step);
7885   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
7886 
7887   NdbDictionary::Table creTab = *pTab;
7888   creTab.setForceVarPart(true);
7889   int ret = NDBT_OK;
7890 
7891   (void)pDic->dropTable(tabName.c_str());
7892   if (pDic->createTable(creTab)) {
7893     g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
7894     ret = NDBT_FAILED;
7895   }
7896 
7897   Uint32 cols = creTab.getNoOfColumns();
7898   Uint32 vers = 0;
7899   while (ret == NDBT_OK) {
7900     const NdbDictionary::Table* pOldTab = pDic->getTableGlobal(tabName.c_str());
7901     require(pOldTab != 0);
7902 
7903     const Uint32 old_st = pOldTab->getObjectStatus();
7904     const Uint32 old_cols = pOldTab->getNoOfColumns();
7905     const Uint32 old_vers = pOldTab->getObjectVersion() >> 24;
7906 
7907     if (old_st != NdbDictionary::Object::Retrieved) {
7908       g_err << __LINE__ << ": " << "got status " << old_st << endl;
7909       ret = NDBT_FAILED;
7910       break;
7911     }
7912     // bug#41905 or related: other thread causes us to get old version
7913     if (old_cols != cols || old_vers != vers) {
7914       g_err << __LINE__ << ": "
7915             << "got cols,vers " << old_cols << "," << old_vers
7916             << " expected " << cols << "," << vers << endl;
7917       ret = NDBT_FAILED;
7918       break;
7919     }
7920     if (old_cols >= 100)
7921       break;
7922     const NdbDictionary::Table& oldTab = *pOldTab;
7923 
7924     NdbDictionary::Table newTab = oldTab;
7925     char colName[100];
7926     sprintf(colName, "COL41905_%02d", cols);
7927     g_info << "add " << colName << endl;
7928     NDBT_Attribute newCol(colName, NdbDictionary::Column::Unsigned, 1,
7929                           false, true, (CHARSET_INFO*)0,
7930                           NdbDictionary::Column::StorageTypeMemory, true);
7931     newTab.addColumn(newCol);
7932 
7933     ctx->setProperty("Bug41905", 1);
7934     NdbSleep_MilliSleep(10);
7935 
7936     const bool removeEarly = (uint)rand() % 2;
7937     g_info << "removeEarly = " << removeEarly << endl;
7938 
7939     if (pDic->beginSchemaTrans() != 0) {
7940       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
7941       ret = NDBT_FAILED;
7942       break;
7943     }
7944     if (pDic->alterTable(oldTab, newTab) != 0) {
7945       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
7946       ret = NDBT_FAILED;
7947       break;
7948     }
7949 
7950     if (removeEarly)
7951       pDic->removeTableGlobal(*pOldTab, 0);
7952 
7953     if (pDic->endSchemaTrans() != 0) {
7954       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
7955       ret = NDBT_FAILED;
7956       break;
7957     }
7958 
7959     cols++;
7960     vers++;
7961     if (!removeEarly)
7962       pDic->removeTableGlobal(*pOldTab, 0);
7963     ctx->setProperty("Bug41905", 2);
7964     NdbSleep_MilliSleep(10);
7965   }
7966 
7967   ctx->setProperty("Bug41905", 3);
7968   return ret;
7969 }
7970 
7971 int
runBug41905getTable(NDBT_Context * ctx,NDBT_Step * step)7972 runBug41905getTable(NDBT_Context* ctx, NDBT_Step* step)
7973 {
7974   const NdbDictionary::Table* pTab = ctx->getTab();
7975   BaseString tabName(pTab->getName());
7976   Ndb* pNdb = GETNDB(step);
7977   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
7978 
7979   while (1) {
7980     while (1) {
7981       if (ctx->getProperty("Bug41905") == 1)
7982         break;
7983       if (ctx->getProperty("Bug41905") == 3)
7984         goto out;
7985       NdbSleep_MilliSleep(10);
7986     }
7987 
7988     uint ms = (uint)rand() % 1000;
7989     NdbSleep_MilliSleep(ms);
7990     g_info << "get begin ms=" << ms << endl;
7991 
7992     Uint32 count = 0;
7993     Uint32 oldstatus = 0;
7994     while (1) {
7995       count++;
7996       const NdbDictionary::Table* pTmp = pDic->getTableGlobal(tabName.c_str());
7997       require(pTmp != 0);
7998       Uint32 code = pDic->getNdbError().code;
7999       Uint32 status = pTmp->getObjectStatus();
8000       if (oldstatus == 2 && status == 3)
8001         g_info << "code=" << code << " status=" << status << endl;
8002       oldstatus = status;
8003       pDic->removeTableGlobal(*pTmp, 0);
8004       if (ctx->getProperty("Bug41905") != 1)
8005         break;
8006       NdbSleep_MilliSleep(10);
8007     }
8008     g_info << "get end count=" << count << endl;
8009   }
8010 
8011 out:
8012   (void)pDic->dropTable(tabName.c_str());
8013   return NDBT_OK;
8014 }
8015 
8016 static
8017 int
createIndexes(NdbDictionary::Dictionary * pDic,const NdbDictionary::Table & tab,int cnt)8018 createIndexes(NdbDictionary::Dictionary* pDic,
8019               const NdbDictionary::Table & tab, int cnt)
8020 {
8021   for (int i = 0; i<cnt && i < tab.getNoOfColumns(); i++)
8022   {
8023     char buf[256];
8024     NdbDictionary::Index idx0;
8025     BaseString::snprintf(buf, sizeof(buf), "%s-idx-%u", tab.getName(), i);
8026     idx0.setName(buf);
8027     idx0.setType(NdbDictionary::Index::OrderedIndex);
8028     idx0.setTable(tab.getName());
8029     idx0.setStoredIndex(false);
8030     idx0.addIndexColumn(tab.getColumn(i)->getName());
8031 
8032     if (pDic->createIndex(idx0))
8033     {
8034       ndbout << pDic->getNdbError() << endl;
8035       return NDBT_FAILED;
8036     }
8037   }
8038 
8039   return 0;
8040 }
8041 
8042 int
runBug46552(NDBT_Context * ctx,NDBT_Step * step)8043 runBug46552(NDBT_Context* ctx, NDBT_Step* step)
8044 {
8045   Ndb* pNdb = GETNDB(step);
8046   const NdbDictionary::Table* pTab = ctx->getTab();
8047   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8048 
8049   NdbRestarter res;
8050   if (res.getNumDbNodes() < 2)
8051     return NDBT_OK;
8052 
8053   NdbDictionary::Table tab0 = *pTab;
8054   NdbDictionary::Table tab1 = *pTab;
8055 
8056   BaseString name;
8057   name.assfmt("%s_0", tab0.getName());
8058   tab0.setName(name.c_str());
8059   name.assfmt("%s_1", tab1.getName());
8060   tab1.setName(name.c_str());
8061 
8062   pDic->dropTable(tab0.getName());
8063   pDic->dropTable(tab1.getName());
8064 
8065   if (pDic->createTable(tab0))
8066   {
8067     ndbout << pDic->getNdbError() << endl;
8068     return NDBT_FAILED;
8069   }
8070 
8071   if (pDic->createTable(tab1))
8072   {
8073     ndbout << pDic->getNdbError() << endl;
8074     return NDBT_FAILED;
8075   }
8076 
8077   if (createIndexes(pDic, tab1, 4))
8078     return NDBT_FAILED;
8079 
8080   Vector<int> group1;
8081   Vector<int> group2;
8082   Bitmask<256/32> nodeGroupMap;
8083   for (int j = 0; j<res.getNumDbNodes(); j++)
8084   {
8085     int node = res.getDbNodeId(j);
8086     int ng = res.getNodeGroup(node);
8087     if (nodeGroupMap.get(ng))
8088     {
8089       group2.push_back(node);
8090     }
8091     else
8092     {
8093       group1.push_back(node);
8094       nodeGroupMap.set(ng);
8095     }
8096   }
8097 
8098   res.restartNodes(group1.getBase(), (int)group1.size(),
8099                    NdbRestarter::NRRF_NOSTART |
8100                    NdbRestarter::NRRF_ABORT);
8101 
8102   res.waitNodesNoStart(group1.getBase(), (int)group1.size());
8103   res.startNodes(group1.getBase(), (int)group1.size());
8104   res.waitClusterStarted();
8105 
8106   res.restartNodes(group2.getBase(), (int)group2.size(),
8107                    NdbRestarter::NRRF_NOSTART |
8108                    NdbRestarter::NRRF_ABORT);
8109   res.waitNodesNoStart(group2.getBase(), (int)group2.size());
8110   res.startNodes(group2.getBase(), (int)group2.size());
8111   res.waitClusterStarted();
8112 
8113   if (pDic->dropTable(tab0.getName()))
8114   {
8115     ndbout << pDic->getNdbError() << endl;
8116     return NDBT_FAILED;
8117   }
8118 
8119   if (pDic->createTable(tab0))
8120   {
8121     ndbout << pDic->getNdbError() << endl;
8122     return NDBT_FAILED;
8123   }
8124 
8125   if (createIndexes(pDic, tab0, 4))
8126     return NDBT_FAILED;
8127 
8128   res.restartAll2(NdbRestarter::NRRF_NOSTART | NdbRestarter::NRRF_ABORT);
8129   res.waitClusterNoStart();
8130   res.startAll();
8131   res.waitClusterStarted();
8132 
8133   if (pDic->dropTable(tab0.getName()))
8134   {
8135     ndbout << pDic->getNdbError() << endl;
8136     return NDBT_FAILED;
8137   }
8138 
8139   if (pDic->dropTable(tab1.getName()))
8140   {
8141     ndbout << pDic->getNdbError() << endl;
8142     return NDBT_FAILED;
8143   }
8144 
8145   return NDBT_OK;
8146 }
8147 
8148 int
runBug46585(NDBT_Context * ctx,NDBT_Step * step)8149 runBug46585(NDBT_Context* ctx, NDBT_Step* step)
8150 {
8151   Ndb* pNdb = GETNDB(step);
8152   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8153   NdbDictionary::Table tab(*ctx->getTab());
8154   NdbRestarter res;
8155   int records = ctx->getNumRecords();
8156 
8157   // ordered index on first few columns
8158   NdbDictionary::Index idx("X");
8159   idx.setTable(tab.getName());
8160   idx.setType(NdbDictionary::Index::OrderedIndex);
8161   idx.setLogging(false);
8162   for (int cnt = 0, i_hate_broken_compilers = 0;
8163        cnt < 3 &&
8164        i_hate_broken_compilers < tab.getNoOfColumns();
8165        i_hate_broken_compilers++) {
8166     if (NdbSqlUtil::check_column_for_ordered_index
8167         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
8168         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
8169         NdbDictionary::Column::StorageTypeDisk)
8170     {
8171       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
8172       cnt++;
8173     }
8174   }
8175 
8176   for (int i = 0; i<tab.getNoOfColumns(); i++)
8177   {
8178     if (tab.getColumn(i)->getStorageType() ==
8179         NdbDictionary::Column::StorageTypeDisk)
8180     {
8181       NDBT_Tables::create_default_tablespace(pNdb);
8182       break;
8183     }
8184   }
8185 
8186   const int loops = ctx->getNumLoops();
8187   int result = NDBT_OK;
8188   (void)pDic->dropTable(tab.getName());
8189   if (pDic->createTable(tab) != 0)
8190   {
8191     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8192     return NDBT_FAILED;
8193   }
8194 
8195   if (pDic->createIndex(idx) != 0)
8196   {
8197     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8198     return NDBT_FAILED;
8199   }
8200 
8201   for (int i = 0; i<loops; i++)
8202   {
8203     const NdbDictionary::Table * org = pDic->getTable(tab.getName());
8204     {
8205       CHECK(org != NULL);
8206       HugoTransactions trans(* org);
8207       CHECK2(trans.loadTable(pNdb, records) == 0,
8208            "load table failed");
8209     }
8210 
8211     NdbDictionary::Table altered = * org;
8212     altered.setFragmentCount(org->getFragmentCount() + 1);
8213     ndbout_c("alter from %u to %u partitions",
8214              org->getFragmentCount(),
8215              altered.getFragmentCount());
8216 
8217     if (pDic->beginSchemaTrans())
8218     {
8219       ndbout << "Failed to beginSchemaTrans()" << pDic->getNdbError() << endl;
8220       return NDBT_FAILED;
8221     }
8222 
8223     if (pDic->prepareHashMap(*org, altered) == -1)
8224     {
8225       ndbout << "Failed to create hashmap: " << pDic->getNdbError() << endl;
8226       return NDBT_FAILED;
8227     }
8228 
8229     if (pDic->endSchemaTrans())
8230     {
8231       ndbout << "Failed to endSchemaTrans()" << pDic->getNdbError() << endl;
8232       return NDBT_FAILED;
8233     }
8234 
8235     result = pDic->alterTable(*org, altered);
8236     if (result)
8237     {
8238       ndbout << pDic->getNdbError() << endl;
8239     }
8240     if (pDic->getNdbError().code == 1224)
8241     {
8242       /**
8243        * To many fragments is an acceptable error
8244        *   depending on configuration used for test-case
8245        */
8246       result = NDBT_OK;
8247       goto end;
8248     }
8249     CHECK2(result == 0,
8250            "failed to alter");
8251 
8252     pDic->invalidateTable(tab.getName());
8253     {
8254       const NdbDictionary::Table * alteredP = pDic->getTable(tab.getName());
8255       CHECK2(alteredP->getFragmentCount() == altered.getFragmentCount(),
8256              "altered table does not have correct frag count");
8257 
8258       HugoTransactions trans(* alteredP);
8259 
8260       CHECK2(trans.scanUpdateRecords(pNdb, records) == 0,
8261              "scan update failed");
8262       trans.startTransaction(pNdb);
8263       trans.pkUpdateRecord(pNdb, 0);
8264       trans.execute_Commit(pNdb);
8265       ndbout_c("before restart, gci: %d", trans.getRecordGci(0));
8266       trans.closeTransaction(pNdb);
8267     }
8268 
8269     switch(i % 2){
8270     case 0:
8271       if (res.getNumDbNodes() > 1)
8272       {
8273         int nodeId = res.getNode(NdbRestarter::NS_RANDOM);
8274         ndbout_c("performing node-restart of node %d", nodeId);
8275         CHECK2(res.restartOneDbNode(nodeId,
8276                                     false,
8277                                     true,
8278                                     true) == 0,
8279                "restart one node failed");
8280         CHECK2(res.waitNodesNoStart(&nodeId, 1) == 0,
8281                "wait node started failed");
8282         CHECK2(res.startNodes(&nodeId, 1) == 0,
8283                "start node failed");
8284         break;
8285       }
8286     case 1:
8287     {
8288       ndbout_c("performing system restart");
8289       CHECK2(res.restartAll(false, true, false) == 0,
8290              "restart all failed");
8291       CHECK2(res.waitClusterNoStart() == 0,
8292              "waitClusterNoStart failed");
8293       CHECK2(res.startAll() == 0,
8294              "startAll failed");
8295       break;
8296     }
8297     }
8298     CHECK2(res.waitClusterStarted() == 0,
8299            "wait cluster started failed");
8300 
8301     Uint32 restartGCI = 0;
8302     CHECK2(pDic->getRestartGCI(&restartGCI) == 0,
8303            "getRestartGCI failed");
8304     ndbout_c("restartGCI: %u", restartGCI);
8305 
8306     pDic->invalidateTable(tab.getName());
8307     {
8308       const NdbDictionary::Table * alteredP = pDic->getTable(tab.getName());
8309       CHECK(alteredP != NULL);
8310       HugoTransactions trans(* alteredP);
8311 
8312       int cnt;
8313       CHECK2(trans.selectCount(pNdb, 0, &cnt) == 0,
8314              "select count failed");
8315 
8316       CHECK2(cnt == records,
8317              "table does not have correct record count: "
8318              << cnt << " != " << records);
8319 
8320       CHECK2(alteredP->getFragmentCount() == altered.getFragmentCount(),
8321              "altered table does not have correct frag count");
8322 
8323       CHECK2(trans.scanUpdateRecords(pNdb, records) == 0,
8324              "scan update failed");
8325       CHECK2(trans.pkUpdateRecords(pNdb, records) == 0,
8326              "pkUpdateRecords failed");
8327       CHECK2(trans.clearTable(pNdb) == 0,
8328              "clear table failed");
8329     }
8330   }
8331 
8332 end:
8333   (void)pDic->dropTable(tab.getName());
8334   return result;
8335 }
8336 
8337 int
runBug53944(NDBT_Context * ctx,NDBT_Step * step)8338 runBug53944(NDBT_Context* ctx, NDBT_Step* step)
8339 {
8340   Ndb* pNdb = GETNDB(step);
8341   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8342   NdbDictionary::Table tab(*ctx->getTab());
8343   NdbRestarter res;
8344 
8345   Vector<int> ids;
8346   for (unsigned i = 0; i< 25; i++)
8347   {
8348     NdbDictionary::Table copy = tab;
8349     BaseString name;
8350     name.appfmt("%s_%u", copy.getName(), i);
8351     copy.setName(name.c_str());
8352     int res = pDic->createTable(copy);
8353     if (res)
8354     {
8355       g_err << "Failed to create table" << copy.getName() << "\n"
8356             << pDic->getNdbError() << endl;
8357       return NDBT_FAILED;
8358     }
8359     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
8360     if (tab == 0)
8361     {
8362       g_err << "Failed to retreive table" << copy.getName() << endl;
8363       return NDBT_FAILED;
8364 
8365     }
8366     ids.push_back(tab->getObjectId());
8367   }
8368 
8369   res.restartAll2(NdbRestarter::NRRF_ABORT | NdbRestarter::NRRF_NOSTART);
8370   res.waitClusterNoStart();
8371   res.startAll();
8372   res.waitClusterStarted();
8373 
8374   for (unsigned i = 0; i< 25; i++)
8375   {
8376     NdbDictionary::Table copy = tab;
8377     BaseString name;
8378     name.appfmt("%s_%u", copy.getName(), i);
8379     copy.setName(name.c_str());
8380     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
8381     if (tab == 0)
8382     {
8383       g_err << "Failed to retreive table" << copy.getName() << endl;
8384       return NDBT_FAILED;
8385 
8386     }
8387     int res = pDic->dropTable(copy.getName());
8388     if (res)
8389     {
8390       g_err << "Failed to drop table" << copy.getName() << "\n"
8391             << pDic->getNdbError() << endl;
8392       return NDBT_FAILED;
8393     }
8394   }
8395 
8396   Vector<int> ids2;
8397   for (unsigned i = 0; i< 25; i++)
8398   {
8399     NdbDictionary::Table copy = tab;
8400     BaseString name;
8401     name.appfmt("%s_%u", copy.getName(), i);
8402     copy.setName(name.c_str());
8403     int res = pDic->createTable(copy);
8404     if (res)
8405     {
8406       g_err << "Failed to create table" << copy.getName() << "\n"
8407             << pDic->getNdbError() << endl;
8408       return NDBT_FAILED;
8409     }
8410     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
8411     if (tab == 0)
8412     {
8413       g_err << "Failed to retreive table" << copy.getName() << endl;
8414       return NDBT_FAILED;
8415 
8416     }
8417     ids2.push_back(tab->getObjectId());
8418   }
8419 
8420   for (unsigned i = 0; i< 25; i++)
8421   {
8422     NdbDictionary::Table copy = tab;
8423     BaseString name;
8424     name.appfmt("%s_%u", copy.getName(), i);
8425     copy.setName(name.c_str());
8426     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
8427     if (tab == 0)
8428     {
8429       g_err << "Failed to retreive table" << copy.getName() << endl;
8430       return NDBT_FAILED;
8431 
8432     }
8433     int res = pDic->dropTable(copy.getName());
8434     if (res)
8435     {
8436       g_err << "Failed to drop table" << copy.getName() << "\n"
8437             << pDic->getNdbError() << endl;
8438       return NDBT_FAILED;
8439     }
8440   }
8441 
8442   /**
8443    * With Bug53944 - none of the table-id have been reused in this scenario
8444    *   check that atleast 15 of the 25 have been to return OK
8445    */
8446   unsigned reused = 0;
8447   for (unsigned i = 0; i<ids.size(); i++)
8448   {
8449     int id = ids[i];
8450     for (unsigned j = 0; j<ids2.size(); j++)
8451     {
8452       if (ids2[j] == id)
8453       {
8454         reused++;
8455         break;
8456       }
8457     }
8458   }
8459 
8460   ndbout_c("reused %u table-ids out of %u",
8461            (unsigned)reused, (unsigned)ids.size());
8462 
8463   if (reused >= (ids.size() >> 2))
8464   {
8465     return NDBT_OK;
8466   }
8467   else
8468   {
8469     return NDBT_FAILED;
8470   }
8471 }
8472 
8473 // Bug58277 + Bug57057
8474 
8475 #define CHK2(b, e) \
8476   if (!(b)) { \
8477     g_err << "ERR: " << #b << " failed at line " << __LINE__ \
8478           << ": " << e << endl; \
8479     result = NDBT_FAILED; \
8480     break; \
8481   }
8482 
8483 // allow list of expected error codes which do not cause NDBT_FAILED
8484 #define CHK3(b, e, x) \
8485   if (!(b)) { \
8486     int n = sizeof(x)/sizeof(x[0]); \
8487     int i; \
8488     for (i = 0; i < n; i++) { \
8489       int s = (x[i] >= 0 ? +1 : -1); \
8490       if (e.code == s * x[i]) { \
8491         if (s == +1) \
8492           g_info << "OK: " << #b << " failed at line " << __LINE__ \
8493                 << ": " << e << endl; \
8494         break; \
8495       } \
8496     } \
8497     if (i == n) { \
8498       g_err << "ERR: " << #b << " failed at line " << __LINE__ \
8499             << ": " << e << endl; \
8500       result = NDBT_FAILED; \
8501     } \
8502     break; \
8503   }
8504 
8505 const char* tabName_Bug58277 = "TBug58277";
8506 const char* indName_Bug58277 = "TBug58277X1";
8507 
8508 static void
sync_main_step(NDBT_Context * ctx,NDBT_Step * step,const char * state)8509 sync_main_step(NDBT_Context* ctx, NDBT_Step* step, const char* state)
8510 {
8511   // total sub-steps
8512   Uint32 sub_steps = ctx->getProperty("SubSteps", (Uint32)0);
8513   require(sub_steps != 0);
8514   // count has been reset before
8515   require(ctx->getProperty("SubCount", (Uint32)0) == 0);
8516   // set the state
8517   g_info << "step main: set " << state << endl;
8518   require(ctx->getProperty(state, (Uint32)0) == 0);
8519   ctx->setProperty(state, (Uint32)1);
8520   // wait for sub-steps
8521   ctx->getPropertyWait("SubCount", sub_steps);
8522   if (ctx->isTestStopped())
8523     return;
8524   g_info << "step main: sub-steps got " << state << endl;
8525   // reset count and state
8526   ctx->setProperty("SubCount", (Uint32)0);
8527   ctx->setProperty(state, (Uint32)0);
8528 }
8529 
8530 static void
sync_sub_step(NDBT_Context * ctx,NDBT_Step * step,const char * state)8531 sync_sub_step(NDBT_Context* ctx, NDBT_Step* step, const char* state)
8532 {
8533   // wait for main step to set state
8534   g_info << "step " << step->getStepNo() << ": wait for " << state << endl;
8535   ctx->getPropertyWait(state, (Uint32)1);
8536   if (ctx->isTestStopped())
8537     return;
8538   // add to sub-step counter
8539   ctx->incProperty("SubCount");
8540   g_info << "step " << step->getStepNo() << ": got " << state << endl;
8541   // continue to run until next sync
8542 }
8543 
8544 static int
runBug58277createtable(NDBT_Context * ctx,NDBT_Step * step)8545 runBug58277createtable(NDBT_Context* ctx, NDBT_Step* step)
8546 {
8547   Ndb* pNdb = GETNDB(step);
8548   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8549   int result = NDBT_OK;
8550   const int rows = ctx->getNumRecords();
8551   const char* tabname = tabName_Bug58277;
8552 
8553   do
8554   {
8555     CHK2(rows > 0, "cannot use --records=0"); // others require this
8556     g_info << "create table " << tabname << endl;
8557     NdbDictionary::Table tab(tabname);
8558     const char* name[] = { "a", "b" };
8559     for (int i = 0; i <= 1; i++)
8560     {
8561       NdbDictionary::Column c(name[i]);
8562       c.setType(NdbDictionary::Column::Unsigned);
8563       c.setPrimaryKey(i == 0);
8564       c.setNullable(false);
8565       tab.addColumn(c);
8566     }
8567     if (rand() % 3 != 0)
8568     {
8569       g_info << "set FragAllLarge" << endl;
8570       tab.setFragmentType(NdbDictionary::Object::FragAllLarge);
8571     }
8572     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
8573   }
8574   while (0);
8575   return result;
8576 }
8577 
8578 static int
runBug58277loadtable(NDBT_Context * ctx,NDBT_Step * step)8579 runBug58277loadtable(NDBT_Context* ctx, NDBT_Step* step)
8580 {
8581   Ndb* pNdb = GETNDB(step);
8582   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8583   int result = NDBT_OK;
8584   const int rows = ctx->getNumRecords();
8585   const char* tabname = tabName_Bug58277;
8586 
8587   do
8588   {
8589     g_info << "load table" << endl;
8590     const NdbDictionary::Table* pTab = 0;
8591     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
8592 
8593     int cnt = 0;
8594     for (int i = 0; i < rows; i++)
8595     {
8596       int retries = 10;
8597   retry:
8598       NdbTransaction* pTx = 0;
8599       CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
8600 
8601       NdbOperation* pOp = 0;
8602       CHK2((pOp = pTx->getNdbOperation(pTab)) != 0, pTx->getNdbError());
8603       CHK2(pOp->insertTuple() == 0, pOp->getNdbError());
8604       Uint32 aVal = i;
8605       Uint32 bVal = rand() % rows;
8606       CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
8607       CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
8608 
8609       do
8610       {
8611         int x[] = {
8612          -630
8613         };
8614         int res = pTx->execute(Commit);
8615         if (res != 0 &&
8616             pTx->getNdbError().status == NdbError::TemporaryError)
8617         {
8618           retries--;
8619           if (retries >= 0)
8620           {
8621             pTx->close();
8622             NdbSleep_MilliSleep(10);
8623             goto retry;
8624           }
8625         }
8626         CHK3(res == 0, pTx->getNdbError(), x);
8627         cnt++;
8628       }
8629       while (0);
8630       CHK2(result == NDBT_OK, "load failed");
8631       pNdb->closeTransaction(pTx);
8632     }
8633     CHK2(result == NDBT_OK, "load failed");
8634     g_info << "load " << cnt << " rows" << endl;
8635   }
8636   while (0);
8637   return result;
8638 }
8639 
8640 static int
runBug58277createindex(NDBT_Context * ctx,NDBT_Step * step)8641 runBug58277createindex(NDBT_Context* ctx, NDBT_Step* step)
8642 {
8643   Ndb* pNdb = GETNDB(step);
8644   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8645   int result = NDBT_OK;
8646   const char* tabname = tabName_Bug58277;
8647   const char* indname = indName_Bug58277;
8648 
8649   do
8650   {
8651     g_info << "create index " << indname << endl;
8652     NdbDictionary::Index ind(indname);
8653     ind.setTable(tabname);
8654     ind.setType(NdbDictionary::Index::OrderedIndex);
8655     ind.setLogging(false);
8656     ind.addColumn("b");
8657     CHK2(pDic->createIndex(ind) == 0, pDic->getNdbError());
8658 
8659     const NdbDictionary::Index* pInd = 0;
8660     CHK2((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError());
8661   }
8662   while (0);
8663   return result;
8664 }
8665 
8666 // separate error handling test
8667 int
runBug58277errtest(NDBT_Context * ctx,NDBT_Step * step)8668 runBug58277errtest(NDBT_Context* ctx, NDBT_Step* step)
8669 {
8670   Ndb* pNdb = GETNDB(step);
8671   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8672   const int loops = ctx->getNumLoops();
8673   int result = NDBT_OK;
8674   //const int rows = ctx->getNumRecords();
8675   NdbRestarter restarter;
8676   const char* tabname = tabName_Bug58277;
8677   const char* indname = indName_Bug58277;
8678   (void)pDic->dropTable(tabname);
8679 
8680   const int errloops = loops < 5 ? loops : 5;
8681   int errloop = 0;
8682   while (!ctx->isTestStopped() && errloop < errloops)
8683   {
8684     g_info << "===== errloop " << errloop << " =====" << endl;
8685 
8686     if (errloop == 0)
8687     {
8688       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
8689       CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
8690       CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
8691     }
8692     const NdbDictionary::Index* pInd = 0;
8693     CHK2((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError());
8694 
8695     int errins[] = {
8696       12008, 909,  // TuxNoFreeScanOp
8697       12009, 4259  // InvalidBounds
8698     };
8699     const int errcnt = (int)(sizeof(errins)/sizeof(errins[0]));
8700     for (int i = 0; i < errcnt; i += 2)
8701     {
8702       const int ei = errins[i + 0];
8703       const int ec = errins[i + 1];
8704       CHK2(restarter.insertErrorInAllNodes(ei) == 0, "value " << ei);
8705 
8706       NdbTransaction* pSTx = 0;
8707       CHK2((pSTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
8708       NdbIndexScanOperation* pSOp = 0;
8709       CHK2((pSOp = pSTx->getNdbIndexScanOperation(pInd)) != 0, pSTx->getNdbError());
8710 
8711       NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
8712       Uint32 flags = 0;
8713       CHK2(pSOp->readTuples(lm, flags) == 0, pSOp->getNdbError());
8714 
8715       Uint32 aVal = 0;
8716       CHK2(pSOp->getValue("a", (char*)&aVal) != 0, pSOp->getNdbError());
8717       CHK2(pSTx->execute(NoCommit) == 0, pSTx->getNdbError());
8718       // before fixes 12009 failed to fail at once here
8719       CHK2(pSOp->nextResult(true) == -1, "failed to fail on " << ei);
8720       CHK2(pSOp->getNdbError().code == ec, "expect " << ec << " got " << pSOp->getNdbError());
8721       pNdb->closeTransaction(pSTx);
8722 
8723       g_info << "error " << ei << " " << ec << " ok" << endl;
8724       CHK2(restarter.insertErrorInAllNodes(0) == 0, "value " << 0);
8725     }
8726     CHK2(result == NDBT_OK, "test error handling failed");
8727 
8728     errloop++;
8729     if (errloop == errloops)
8730     {
8731       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
8732       g_info << "table " << tabname << " dropped" << endl;
8733     }
8734   }
8735   if (result != NDBT_OK)
8736   {
8737     g_info << "stop test at line " << __LINE__ << endl;
8738     ctx->stopTest();
8739   }
8740   return result;
8741 }
8742 
8743 int
runBug58277drop(NDBT_Context * ctx,NDBT_Step * step)8744 runBug58277drop(NDBT_Context* ctx, NDBT_Step* step)
8745 {
8746   Ndb* pNdb = GETNDB(step);
8747   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8748   int result = NDBT_OK;
8749   const char* tabname = tabName_Bug58277;
8750   const char* indname = indName_Bug58277;
8751   int dropms = 0;
8752 
8753   while (!ctx->isTestStopped())
8754   {
8755     sync_sub_step(ctx, step, "Start");
8756     if (ctx->isTestStopped())
8757       break;
8758     dropms = ctx->getProperty("DropMs", (Uint32)0);
8759     NdbSleep_MilliSleep(dropms);
8760 
8761     g_info << "drop index " << indname << endl;
8762     CHK2(pDic->dropIndex(indname, tabname) == 0, pDic->getNdbError());
8763     pDic->invalidateIndex(indname, tabname);
8764     CHK2(pDic->getIndex(indname, tabname) == 0, "failed");
8765     g_info << "drop index done" << endl;
8766 
8767     sync_sub_step(ctx, step, "Stop");
8768     if (ctx->isTestStopped())
8769       break;
8770   }
8771   if (result != NDBT_OK)
8772   {
8773     g_info << "stop test at line " << __LINE__ << endl;
8774     ctx->stopTest();
8775   }
8776   return result;
8777 }
8778 
8779 static int
runBug58277scanop(NDBT_Context * ctx,NDBT_Step * step,int cnt[1+3])8780 runBug58277scanop(NDBT_Context* ctx, NDBT_Step* step, int cnt[1+3])
8781 {
8782   Ndb* pNdb = GETNDB(step);
8783   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8784   int result = NDBT_OK;
8785   const int rows = ctx->getNumRecords();
8786   const char* tabname = tabName_Bug58277;
8787   const char* indname = indName_Bug58277;
8788   const int range_max = ctx->getProperty("RANGE_MAX", (Uint32)0);
8789   require(range_max > 0);
8790   const bool scan_delete = ctx->getProperty("SCAN_DELETE", (Uint32)0);
8791 
8792   do
8793   {
8794     const NdbDictionary::Index* pInd = 0;
8795     {
8796       int x[] = {
8797         4243  // Index not found
8798       };
8799       pDic->invalidateIndex(indname, tabname);
8800       CHK3((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError(), x);
8801     }
8802 
8803     NdbTransaction* pSTx = 0;
8804     CHK2((pSTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
8805     NdbIndexScanOperation* pSOp = 0;
8806     CHK2((pSOp = pSTx->getNdbIndexScanOperation(pInd)) != 0, pSTx->getNdbError());
8807     NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
8808     Uint32 flags = 0;
8809     int range_cnt = rand() % range_max;
8810     if (range_cnt > 1 || rand() % 5 == 0)
8811       flags |= NdbIndexScanOperation::SF_MultiRange;
8812     CHK2(pSOp->readTuples(lm, flags) == 0, pSOp->getNdbError());
8813     g_info << "range cnt " << range_cnt << endl;
8814     for (int i = 0; i < range_cnt; )
8815     {
8816       int tlo = -1;
8817       int thi = -1;
8818       if (rand() % 5 == 0)
8819       {
8820         if (rand() % 5 != 0)
8821           tlo = 0 + rand() % 2;
8822         if (rand() % 5 != 0)
8823           thi = 2 + rand() % 2;
8824       }
8825       else
8826         tlo = 4;
8827       // apparently no bounds is not allowed (see also bug#57396)
8828       if (tlo == -1 && thi == -1)
8829         continue;
8830       Uint32 blo = 0;
8831       Uint32 bhi = 0;
8832       if (tlo != -1)
8833       {
8834         blo = rand() % rows;
8835         CHK2(pSOp->setBound("b", tlo, &blo) == 0, pSOp->getNdbError());
8836       }
8837       if (thi != -1)
8838       {
8839         bhi = rand() % (rows + 1);
8840         if (bhi < blo)
8841           bhi = rand() % (rows + 1);
8842         CHK2(pSOp->setBound("b", thi, &bhi) == 0, pSOp->getNdbError());
8843       }
8844       CHK2(pSOp->end_of_bound() == 0, pSOp->getNdbError());
8845       i++;
8846     }
8847     CHK2(result == NDBT_OK, "set bound ranges failed");
8848 
8849     Uint32 aVal = 0;
8850     CHK2(pSOp->getValue("a", (char*)&aVal) != 0, pSOp->getNdbError());
8851     CHK2(pSTx->execute(NoCommit) == 0, pSTx->getNdbError());
8852 
8853     while (1)
8854     {
8855       int ret;
8856       {
8857         int x[] = {
8858           241,  // Invalid schema object version
8859           274,  // Time-out in NDB, probably caused by deadlock
8860           283,  // Table is being dropped
8861           284,  // Table not defined in transaction coordinator
8862           910,  // Index is being dropped
8863           1226  // Table is being dropped
8864         };
8865         CHK3((ret = pSOp->nextResult(true)) != -1, pSOp->getNdbError(), x);
8866       }
8867       require(ret == 0 || ret == 1);
8868       if (ret == 1)
8869         break;
8870 
8871       NdbTransaction* pTx = 0;
8872       CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
8873 
8874       while (1)
8875       {
8876         int type = 1 + rand() % 3;
8877         if (type == 2) // insert->update
8878           type = 1;
8879         if (scan_delete)
8880           type = 3;
8881         do
8882         {
8883           if (type == 1)
8884           {
8885             NdbOperation* pOp = 0;
8886             CHK2((pOp = pSOp->updateCurrentTuple(pTx)) != 0, pSOp->getNdbError());
8887             Uint32 bVal = (Uint32)(rand() % rows);
8888             CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
8889             break;
8890           }
8891           if (type == 3)
8892           {
8893             CHK2(pSOp->deleteCurrentTuple(pTx) == 0, pSOp->getNdbError());
8894             break;
8895           }
8896           require(false);
8897         }
8898         while (0);
8899         CHK2(result == NDBT_OK, "scan takeover error");
8900         cnt[type]++;
8901         {
8902           int x[] = {
8903             266,  // Time-out in NDB, probably caused by deadlock
8904             499,  // Scan take over error
8905             631,  // 631
8906             4350  // Transaction already aborted
8907           };
8908           CHK3(pTx->execute(NoCommit) == 0, pTx->getNdbError(), x);
8909         }
8910 
8911         CHK2((ret = pSOp->nextResult(false)) != -1, pSOp->getNdbError());
8912         require(ret == 0 || ret == 2);
8913         if (ret == 2)
8914           break;
8915       }
8916       CHK2(result == NDBT_OK, "batch failed");
8917 
8918       {
8919         int x[] = {
8920           266,  // Time-out in NDB, probably caused by deadlock
8921           4350  // Transaction already aborted
8922         };
8923         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
8924       }
8925       pNdb->closeTransaction(pTx);
8926     }
8927     CHK2(result == NDBT_OK, "batch failed");
8928     pNdb->closeTransaction(pSTx);
8929   }
8930   while (0);
8931   return result;
8932 }
8933 
8934 int
runBug58277scan(NDBT_Context * ctx,NDBT_Step * step)8935 runBug58277scan(NDBT_Context* ctx, NDBT_Step* step)
8936 {
8937   int result = NDBT_OK;
8938 
8939   while (!ctx->isTestStopped())
8940   {
8941     sync_sub_step(ctx, step, "Start");
8942     if (ctx->isTestStopped())
8943       break;
8944     g_info << "start scan loop" << endl;
8945     while (!ctx->isTestStopped())
8946     {
8947       g_info << "start scan" << endl;
8948       int cnt[1+3] = { 0, 0, 0, 0 };
8949       CHK2(runBug58277scanop(ctx, step, cnt) == NDBT_OK, "scan failed");
8950       g_info << "scan ops " << cnt[1] << "/-/" << cnt[3] << endl;
8951 
8952       if (ctx->getProperty("Stop", (Uint32)0) == 1)
8953       {
8954         sync_sub_step(ctx, step, "Stop");
8955         break;
8956       }
8957     }
8958     CHK2(result == NDBT_OK, "scan loop failed");
8959   }
8960   if (result != NDBT_OK)
8961   {
8962     g_info << "stop test at line " << __LINE__ << endl;
8963     ctx->stopTest();
8964   }
8965   return result;
8966 }
8967 
8968 static int
runBug58277pkop(NDBT_Context * ctx,NDBT_Step * step,int cnt[1+3])8969 runBug58277pkop(NDBT_Context* ctx, NDBT_Step* step, int cnt[1+3])
8970 {
8971   Ndb* pNdb = GETNDB(step);
8972   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8973   int result = NDBT_OK;
8974   const int rows = ctx->getNumRecords();
8975   const char* tabname = tabName_Bug58277;
8976 
8977   do
8978   {
8979     const NdbDictionary::Table* pTab = 0;
8980     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
8981 
8982     NdbTransaction* pTx = 0;
8983     CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
8984     NdbOperation* pOp = 0;
8985     CHK2((pOp = pTx->getNdbOperation(pTab)) != 0, pTx->getNdbError());
8986     int type = 1 + rand() % 3;
8987     Uint32 aVal = rand() % rows;
8988     Uint32 bVal = rand() % rows;
8989 
8990     do
8991     {
8992       if (type == 1)
8993       {
8994         CHK2(pOp->updateTuple() == 0, pOp->getNdbError());
8995         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
8996         CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
8997         int x[] = {
8998           266,  // Time-out in NDB, probably caused by deadlock
8999          -626   // Tuple did not exist
9000         };
9001         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9002         break;
9003       }
9004       if (type == 2)
9005       {
9006         CHK2(pOp->insertTuple() == 0, pOp->getNdbError());
9007         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9008         CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
9009         int x[] = {
9010           266,  // Time-out in NDB, probably caused by deadlock
9011          -630   // Tuple already existed when attempting to insert
9012         };
9013         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9014         break;
9015       }
9016       if (type == 3)
9017       {
9018         CHK2(pOp->deleteTuple() == 0, pOp->getNdbError());
9019         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9020         int x[] = {
9021           266,  // Time-out in NDB, probably caused by deadlock
9022          -626   // Tuple did not exist
9023         };
9024         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9025         break;
9026       }
9027       require(false);
9028     }
9029     while (0);
9030     CHK2(result == NDBT_OK, "pk op failed");
9031 
9032     pNdb->closeTransaction(pTx);
9033     cnt[type]++;
9034   }
9035   while (0);
9036   return result;
9037 }
9038 
9039 int
runBug58277pk(NDBT_Context * ctx,NDBT_Step * step)9040 runBug58277pk(NDBT_Context* ctx, NDBT_Step* step)
9041 {
9042   int result = NDBT_OK;
9043 
9044   while (!ctx->isTestStopped())
9045   {
9046     sync_sub_step(ctx, step, "Start");
9047     if (ctx->isTestStopped())
9048       break;
9049 
9050     g_info << "start pk loop" << endl;
9051     int cnt[1+3] = { 0, 0, 0, 0 };
9052     while (!ctx->isTestStopped())
9053     {
9054       CHK2(runBug58277pkop(ctx, step, cnt) == NDBT_OK, "pk op failed");
9055 
9056       if (ctx->getProperty("Stop", (Uint32)0) == 1)
9057       {
9058         sync_sub_step(ctx, step, "Stop");
9059         break;
9060       }
9061     }
9062     CHK2(result == NDBT_OK, "pk loop failed");
9063     g_info << "pk ops " << cnt[1] << "/" << cnt[2] << "/" << cnt[3] << endl;
9064   }
9065   if (result != NDBT_OK)
9066   {
9067     g_info << "stop test at line " << __LINE__ << endl;
9068     ctx->stopTest();
9069   }
9070   return result;
9071 }
9072 
9073 int
runBug58277rand(NDBT_Context * ctx,NDBT_Step * step)9074 runBug58277rand(NDBT_Context* ctx, NDBT_Step* step)
9075 {
9076   int result = NDBT_OK;
9077   NdbRestarter restarter;
9078 
9079   while (!ctx->isTestStopped())
9080   {
9081     int sleepms = rand() % 5000;
9082     g_info << "rand sleep " << sleepms << " ms" << endl;
9083     NdbSleep_MilliSleep(sleepms);
9084     if (rand() % 5 == 0)
9085     {
9086       g_info << "rand force LCP" << endl;
9087       int dump1[] = { DumpStateOrd::DihStartLcpImmediately };
9088       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9089     }
9090   }
9091   if (result != NDBT_OK)
9092   {
9093     g_info << "stop test at line " << __LINE__ << endl;
9094     ctx->stopTest();
9095   }
9096   g_info << "rand exit" << endl;
9097   return result;
9098 }
9099 
9100 int
runBug58277(NDBT_Context * ctx,NDBT_Step * step)9101 runBug58277(NDBT_Context* ctx, NDBT_Step* step)
9102 {
9103   Ndb* pNdb = GETNDB(step);
9104   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9105   const int loops = ctx->getNumLoops();
9106   int result = NDBT_OK;
9107   const bool rss_check = ctx->getProperty("RSS_CHECK", (Uint32)0);
9108   NdbRestarter restarter;
9109   const char* tabname = tabName_Bug58277;
9110   const char* indname = indName_Bug58277;
9111   (void)pDic->dropTable(tabname);
9112 
9113   int loop = 0;
9114   while (!ctx->isTestStopped())
9115   {
9116     g_info << "===== loop " << loop << " =====" << endl;
9117 
9118     if (loop == 0)
9119     {
9120       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
9121       CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
9122     }
9123 
9124     if (rss_check)
9125     {
9126       g_info << "save all resource usage" << endl;
9127       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
9128       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9129     }
9130 
9131     CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
9132 
9133     int dropmin = 1000;
9134     int dropmax = 9000;
9135     int dropms = dropmin + rand() % (dropmax - dropmin + 1);
9136     g_info << "drop in " << dropms << " ms" << endl;
9137     ctx->setProperty("DropMs", dropms);
9138 
9139     sync_main_step(ctx, step, "Start");
9140     if (ctx->isTestStopped())
9141       break;
9142 
9143     // vary Stop time a bit in either direction
9144     int stopvar = rand() % 100;
9145     int stopsgn = (rand() % 2 == 0 ? +1 : -1);
9146     int stopms = dropms + stopsgn * stopvar;
9147     NdbSleep_MilliSleep(stopms);
9148 
9149     sync_main_step(ctx, step, "Stop");
9150     if (ctx->isTestStopped())
9151       break;
9152 
9153     // index must have been dropped
9154     pDic->invalidateIndex(indname, tabname);
9155     CHK2(pDic->getIndex(indname, tabname) == 0, "failed");
9156 
9157     if (rss_check)
9158     {
9159       g_info << "check all resource usage" << endl;
9160       int dump2[] = { DumpStateOrd::SchemaResourceCheckLeak };
9161       CHK2(restarter.dumpStateAllNodes(dump2, 1) == 0, "failed");
9162 
9163       g_info << "check cluster is up" << endl;
9164       CHK2(restarter.waitClusterStarted() == 0, "failed");
9165     }
9166 
9167     if (++loop == loops)
9168     {
9169       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9170       g_info << "table " << tabname << " dropped" << endl;
9171       break;
9172     }
9173   }
9174 
9175   g_info << "stop test at line " << __LINE__ << endl;
9176   ctx->stopTest();
9177   return result;
9178 }
9179 
9180 int
runBug57057(NDBT_Context * ctx,NDBT_Step * step)9181 runBug57057(NDBT_Context* ctx, NDBT_Step* step)
9182 {
9183   Ndb* pNdb = GETNDB(step);
9184   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9185   const int loops = ctx->getNumLoops();
9186   int result = NDBT_OK;
9187   const bool rss_check = ctx->getProperty("RSS_CHECK", (Uint32)0);
9188   NdbRestarter restarter;
9189   const char* tabname = tabName_Bug58277;
9190   //const char* indname = indName_Bug58277;
9191   (void)pDic->dropTable(tabname);
9192 
9193   int loop = 0;
9194   while (!ctx->isTestStopped())
9195   {
9196     g_info << "===== loop " << loop << " =====" << endl;
9197 
9198     if (loop == 0)
9199     {
9200       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
9201       CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
9202     }
9203 
9204     CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
9205 
9206     if (rss_check)
9207     {
9208       g_info << "save all resource usage" << endl;
9209       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
9210       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9211     }
9212 
9213     int dropmin = 1000;
9214     int dropmax = 2000;
9215     int dropms = dropmin + rand() % (dropmax - dropmin + 1);
9216     int stopms = dropms;
9217 
9218     sync_main_step(ctx, step, "Start");
9219     if (ctx->isTestStopped())
9220       break;
9221 
9222     g_info << "stop in " << stopms << " ms" << endl;
9223     NdbSleep_MilliSleep(stopms);
9224 
9225     sync_main_step(ctx, step, "Stop");
9226     if (ctx->isTestStopped())
9227       break;
9228 
9229     if (rss_check)
9230     {
9231       g_info << "check all resource usage" << endl;
9232       int dump2[] = { DumpStateOrd::SchemaResourceCheckLeak };
9233       CHK2(restarter.dumpStateAllNodes(dump2, 1) == 0, "failed");
9234 
9235       g_info << "check cluster is up" << endl;
9236       CHK2(restarter.waitClusterStarted() == 0, "failed");
9237     }
9238 
9239     if (++loop == loops)
9240     {
9241       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9242       g_info << "table " << tabname << " dropped" << endl;
9243       break;
9244     }
9245   }
9246 
9247   g_info << "stop test at line " << __LINE__ << endl;
9248   ctx->stopTest();
9249   return result;
9250 }
9251 
9252 /**
9253  * This is a regression test for Bug #14647210 "CAN CRASH ALL NODES EASILY
9254  * WHEN RESTARTING MORE THAN 6 NODES SIMULTANEOUSLY". The cause of this bug
9255  * was that DICT did not handle GET_TABINFOREF signals.
9256  */
9257 static int
runGetTabInfoRef(NDBT_Context * ctx,NDBT_Step * step)9258 runGetTabInfoRef(NDBT_Context* ctx, NDBT_Step* step)
9259 {
9260   NdbRestarter restarter;
9261   if (restarter.getNumDbNodes() == 1)
9262   {
9263     g_info << "Cannot do this test with just one datanode." << endl;
9264     return NDBT_OK;
9265   }
9266 
9267   /**
9268    * This error insert makes DICT respond with GET_TABINFOREF where
9269    * error==busy when receiving the next GET_TABINFOREQ signal.
9270    */
9271   restarter.insertErrorInAllNodes(6026);
9272 
9273   /* Find a node in each nodegroup to restart. */
9274   Vector<int> nodeSet;
9275   Bitmask<MAX_NDB_NODES/32> nodeGroupMap;
9276   for (int i = 0; i < restarter.getNumDbNodes(); i++)
9277   {
9278     const int node = restarter.getDbNodeId(i);
9279     const int ng = restarter.getNodeGroup(node);
9280     if (!nodeGroupMap.get(ng))
9281     {
9282       g_info << "Node " << node << " will be stopped." << endl;
9283       nodeSet.push_back(node);
9284       nodeGroupMap.set(ng);
9285     }
9286   }
9287 
9288   if (restarter.restartNodes(nodeSet.getBase(), (int)nodeSet.size(),
9289                              NdbRestarter::NRRF_NOSTART |
9290                              NdbRestarter::NRRF_ABORT))
9291   {
9292     g_err << "Failed to stop nodes" << endl;
9293     restarter.insertErrorInAllNodes(0);
9294     return NDBT_FAILED;
9295   }
9296 
9297   g_info << "Waiting for nodes to stop." << endl;
9298   if (restarter.waitNodesNoStart(nodeSet.getBase(), (int)nodeSet.size()))
9299   {
9300     g_err << "Failed to wait for nodes to stop" << endl;
9301     restarter.insertErrorInAllNodes(0);
9302     return NDBT_FAILED;
9303   }
9304 
9305   if (restarter.startNodes(nodeSet.getBase(), (int)nodeSet.size()))
9306   {
9307     g_err << "Failed to restart nodes" << endl;
9308     restarter.insertErrorInAllNodes(0);
9309     return NDBT_FAILED;
9310   }
9311 
9312   g_info << "Waiting for nodes to start again." << endl;
9313   if (restarter.waitClusterStarted() != 0)
9314   {
9315     g_err << "Failed to restart cluster " << endl;
9316     restarter.insertErrorInAllNodes(0);
9317     return NDBT_FAILED;
9318   }
9319 
9320   restarter.insertErrorInAllNodes(0);
9321   return NDBT_OK;
9322 } // runGetTabInfoRef()
9323 
9324 int
runBug13416603(NDBT_Context * ctx,NDBT_Step * step)9325 runBug13416603(NDBT_Context* ctx, NDBT_Step* step)
9326 {
9327   Ndb* pNdb = GETNDB(step);
9328   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9329   NdbIndexStat is;
9330   NdbRestarter res;
9331 
9332   int elist[] = { 18026, 0 };
9333   const NdbDictionary::Table *pTab = pDic->getTable(ctx->getTab()->getName());
9334   const NdbDictionary::Index *pIdx = 0;
9335   NdbDictionary::Dictionary::List indexes;
9336   pDic->listIndexes(indexes, * pTab);
9337   for (unsigned i = 0; i < indexes.count; i++)
9338   {
9339     if ((pIdx = pDic->getIndex(indexes.elements[i].name, pTab->getName())) != 0)
9340       break;
9341   }
9342 
9343   if (pIdx == 0)
9344   {
9345     return NDBT_OK;
9346   }
9347 
9348   bool has_created_stat_tables = false;
9349   bool has_created_stat_events = false;
9350   pNdb->setDatabaseName("mysql");
9351   if (is.create_systables(pNdb) == 0)
9352   {
9353     has_created_stat_tables = true;
9354   }
9355 
9356   if (is.create_sysevents(pNdb) == 0)
9357   {
9358     has_created_stat_events = true;
9359   }
9360 
9361   chk2(is.create_listener(pNdb) == 0, is.getNdbError());
9362   chk2(is.execute_listener(pNdb) == 0, is.getNdbError());
9363 
9364   is.set_index(* pIdx, * pTab);
9365 
9366   {
9367     ndbout_c("%u - update_stat", __LINE__);
9368     chk2(is.update_stat(pNdb) == 0, is.getNdbError());
9369     int ret;
9370     ndbout_c("%u - poll_listener", __LINE__);
9371     chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
9372     chk1(ret == 1);
9373     // one event is expected
9374     ndbout_c("%u - next_listener", __LINE__);
9375     chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
9376     chk1(ret == 1);
9377     ndbout_c("%u - next_listener", __LINE__);
9378     chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
9379     chk1(ret == 0);
9380   }
9381 
9382   {
9383     Vector<Vector<int> > partitions = res.splitNodes();
9384     if (partitions.size() == 1)
9385       goto cleanup;
9386 
9387     for (unsigned i = 0; i < partitions.size(); i++)
9388     {
9389       printf("stopping: ");
9390       for (unsigned j = 0; j < partitions[i].size(); j++)
9391         printf("%d ", partitions[i][j]);
9392       printf("\n");
9393 
9394       res.restartNodes(partitions[i].getBase(),
9395                        partitions[i].size(),
9396                        NdbRestarter::NRRF_NOSTART | NdbRestarter::NRRF_ABORT);
9397       res.waitNodesNoStart(partitions[i].getBase(),
9398                            partitions[i].size());
9399 
9400       {
9401         ndbout_c("%u - update_stat", __LINE__);
9402         chk2(is.update_stat(pNdb) == 0, is.getNdbError());
9403         int ret;
9404         ndbout_c("%u - poll_listener", __LINE__);
9405         chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
9406         chk1(ret == 1);
9407         // one event is expected
9408         ndbout_c("%u - next_listener", __LINE__);
9409         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
9410         chk1(ret == 1);
9411         ndbout_c("%u - next_listener", __LINE__);
9412         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
9413         chk1(ret == 0);
9414       }
9415 
9416       res.startNodes(partitions[i].getBase(),
9417                      partitions[i].size());
9418       res.waitClusterStarted();
9419     }
9420   }
9421 
9422   for (int i = 0; elist[i] != 0; i++)
9423   {
9424     ndbout_c("testing errno: %u", elist[i]);
9425     res.insertErrorInAllNodes(elist[i]);
9426     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
9427     res.dumpStateAllNodes(val2, 2);
9428 
9429     {
9430       ndbout_c("%u - update_stat", __LINE__);
9431       int ret = is.update_stat(pNdb);
9432       ndbout_c("%u - update_stat => %d", __LINE__, ret);
9433       chk1(ret == -1);
9434       ndbout << is.getNdbError() << endl;
9435       ndbout_c("%u - poll_listener", __LINE__);
9436       chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
9437       if (ret == 1)
9438       {
9439         /* After the new api is introduced, pollEvents() (old api version)
9440          * returns 1 when empty epoch is at the head of the event queue.
9441          * pollEvents2() (new api version) returns 1 when exceptional
9442          * epoch is at the head of the event queue.
9443          * So next_listener() must be called to handle them.
9444          */
9445         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
9446       }
9447       // Check that the event queue is empty
9448       chk1(ret == 0);
9449     }
9450 
9451     /**
9452      * Wait for one of the nodes to have died...
9453      */
9454     int count_started = 0;
9455     int count_not_started = 0;
9456     int count_nok = 0;
9457     int down = 0;
9458     do
9459     {
9460       NdbSleep_MilliSleep(100);
9461       count_started = count_not_started = count_nok = 0;
9462       for (int i = 0; i < res.getNumDbNodes(); i++)
9463       {
9464         int n = res.getDbNodeId(i);
9465         if (res.getNodeStatus(n) == NDB_MGM_NODE_STATUS_NOT_STARTED)
9466         {
9467           count_not_started++;
9468           down = n;
9469         }
9470         else if (res.getNodeStatus(n) == NDB_MGM_NODE_STATUS_STARTED)
9471           count_started++;
9472         else
9473           count_nok ++;
9474       }
9475     } while (count_not_started != 1);
9476 
9477     res.startNodes(&down, 1);
9478     res.waitClusterStarted();
9479     res.insertErrorInAllNodes(0);
9480   }
9481 
9482 cleanup:
9483   // cleanup
9484   is.drop_listener(pNdb);
9485   if (has_created_stat_events)
9486   {
9487     is.drop_sysevents(pNdb);
9488   }
9489   if (has_created_stat_tables)
9490   {
9491     is.drop_systables(pNdb);
9492   }
9493 
9494   // Ensure that nodes will start after error inserts again.
9495   {
9496     const int restartState[] =
9497       { DumpStateOrd::CmvmiSetRestartOnErrorInsert, NRT_DoStart_Restart };
9498 
9499     require(res.dumpStateAllNodes(restartState,
9500                                   sizeof restartState/sizeof restartState[0])
9501             == 0);
9502   }
9503 
9504   return NDBT_OK;
9505 
9506 err:
9507   return NDBT_FAILED;
9508 }
9509 
9510 int
runIndexStatCreate(NDBT_Context * ctx,NDBT_Step * step)9511 runIndexStatCreate(NDBT_Context* ctx, NDBT_Step* step)
9512 {
9513   Ndb* pNdb = GETNDB(step);
9514   NdbIndexStat is;
9515 
9516   const int loops = ctx->getNumLoops();
9517 
9518   pNdb->setDatabaseName("mysql");
9519 
9520   Uint64 end = NdbTick_CurrentMillisecond() + 1000 * loops;
9521   do
9522   {
9523     if (is.create_systables(pNdb) == 0)
9524     {
9525       /**
9526        * OK
9527        */
9528     }
9529     else if (! (is.getNdbError().code == 701  || // timeout
9530                 is.getNdbError().code == 721  || // already exists
9531                 is.getNdbError().code == 4244 || // already exists
9532                 is.getNdbError().code == 4009))  // no connection
9533     {
9534       ndbout << is.getNdbError() << endl;
9535       return NDBT_FAILED;
9536     }
9537 
9538     is.drop_systables(pNdb);
9539   } while (!ctx->isTestStopped() && NdbTick_CurrentMillisecond() < end);
9540 
9541   return NDBT_OK;
9542 }
9543 
9544 int
runWL946(NDBT_Context * ctx,NDBT_Step * step)9545 runWL946(NDBT_Context* ctx, NDBT_Step* step)
9546 {
9547   Ndb* pNdb = GETNDB(step);
9548   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9549   const int loops = ctx->getNumLoops();
9550   const int records = ctx->getNumRecords();
9551   bool keep_table = false; // keep table and data
9552 #ifdef VM_TRACE
9553 #ifdef NDB_USE_GET_ENV
9554   {
9555     const char* p = NdbEnv_GetEnv("KEEP_TABLE_WL946", (char*)0, 0);
9556     if (p != 0 && strchr("1Y", p[0]) != 0)
9557       keep_table = true;
9558   }
9559 #endif
9560 #endif
9561   int result = NDBT_OK;
9562 
9563   const char* tabname = "T_WL946";
9564   (void)pDic->dropTable(tabname);
9565 
9566   for (int loop = 0; loop < loops; loop++)
9567   {
9568     g_info << "loop " << loop << "(" << loops << ")" << endl;
9569 
9570     NdbDictionary::Table tab;
9571     tab.setName(tabname);
9572 
9573     struct Coldef {
9574       const char* name;
9575       NdbDictionary::Column::Type type;
9576       int prec; // fractional precision 0-6
9577       int flag; // 1-pk 2-nullable 4-fractional 8-create index
9578       const char* indname;
9579     } coldef[] = {
9580       // primary key
9581       { "pk", NdbDictionary::Column::Unsigned, 0, 1, 0 },
9582       // deprecated
9583       { "a0", NdbDictionary::Column::Time, 0, 2|8, "x0" },
9584       { "a1", NdbDictionary::Column::Datetime, 0, 2|8, "x1" },
9585       { "a2", NdbDictionary::Column::Timestamp, 0, 2|8, "x2" },
9586       // fractional
9587       { "b0", NdbDictionary::Column::Time2, 0, 2|4|8, "y0" },
9588       { "b1", NdbDictionary::Column::Datetime2, 0, 2|4|8, "y1" },
9589       { "b2", NdbDictionary::Column::Timestamp2, 0, 2|4|8, "y2" },
9590       // update key
9591       { "uk", NdbDictionary::Column::Unsigned, 0, 0, 0 }
9592     };
9593     const int Colcnt = sizeof(coldef)/sizeof(coldef[0]);
9594 
9595     NdbDictionary::Column col[Colcnt];
9596     for (int i = 0; i < Colcnt; i++)
9597     {
9598       Coldef& d = coldef[i];
9599       NdbDictionary::Column& c = col[i];
9600       c.setName(d.name);
9601       c.setType(d.type);
9602       if (d.flag & 4)
9603       {
9604         d.prec = myRandom48(7);
9605         require(d.prec >= 0 && d.prec <= 6);
9606         c.setPrecision(d.prec);
9607       }
9608       c.setPrimaryKey(d.flag & 1);
9609       c.setNullable(d.flag & 2);
9610       tab.addColumn(c);
9611     }
9612 
9613     g_info << "create table " << tabname << endl;
9614     const NdbDictionary::Table* pTab = 0;
9615     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
9616     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
9617 
9618     const NdbDictionary::Column* pCol[Colcnt];
9619     for (int i = 0; i < Colcnt; i++)
9620     {
9621       const Coldef& d = coldef[i];
9622       const NdbDictionary::Column* pc = 0;
9623       CHK2((pc = tab.getColumn(i)) != 0, pDic->getNdbError());
9624       CHK2(strcmp(pc->getName(), d.name) == 0, "name");
9625       CHK2(pc->getType() == d.type, "type");
9626       CHK2(pc->getPrecision() == d.prec, "prec");
9627       pCol[i] = pc;
9628     }
9629     CHK2(result == NDBT_OK, "verify columns");
9630 
9631     g_info << "create indexes" << endl;
9632     NdbDictionary::Index ind[Colcnt];
9633     const NdbDictionary::Index* pInd[Colcnt];
9634     for (int i = 0; i < Colcnt; i++)
9635     {
9636       Coldef& d = coldef[i];
9637       pInd[i] = 0;
9638       if (d.flag & 8)
9639       {
9640         NdbDictionary::Index& x = ind[i];
9641         x.setName(d.indname);
9642         x.setTable(tabname);
9643         x.setType(NdbDictionary::Index::OrderedIndex);
9644         x.setLogging(false);
9645         x.addColumn(d.name);
9646         const NdbDictionary::Index* px = 0;
9647         CHK2(pDic->createIndex(x) == 0, pDic->getNdbError());
9648         CHK2((px = pDic->getIndex(d.indname, tabname)) != 0, pDic->getNdbError());
9649         pInd[i] = px;
9650       }
9651     }
9652     CHK2(result == NDBT_OK, "create indexes");
9653 
9654     HugoTransactions trans(*pTab);
9655 
9656     g_info << "load records" << endl;
9657     CHK2(trans.loadTable(pNdb, records) == 0, trans.getNdbError());
9658 
9659     const int scanloops = 5;
9660     for (int j = 0; j < scanloops; j++)
9661     {
9662       g_info << "scan table " << j << "(" << scanloops << ")" << endl;
9663       CHK2(trans.scanReadRecords(pNdb, records) == 0, trans.getNdbError());
9664 
9665       for (int i = 0; i < Colcnt; i++)
9666       {
9667         Coldef& d = coldef[i];
9668         if (d.flag & 8)
9669         {
9670           g_info << "scan index " << d.indname << endl;
9671           const NdbDictionary::Index* px = pInd[i];
9672           CHK2(trans.scanReadRecords(pNdb, px, records) == 0, trans.getNdbError());
9673         }
9674       }
9675       CHK2(result == NDBT_OK, "index scan");
9676 
9677       g_info << "update records" << endl;
9678       CHK2(trans.scanUpdateRecords(pNdb, records) == 0, trans.getNdbError());
9679     }
9680     CHK2(result == NDBT_OK, "scans");
9681 
9682     if (loop + 1 < loops || !keep_table)
9683     {
9684       g_info << "delete records" << endl;
9685       CHK2(trans.clearTable(pNdb) == 0, trans.getNdbError());
9686 
9687       g_info << "drop table" << endl;
9688       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9689     }
9690   }
9691 
9692   if (result != NDBT_OK && !keep_table)
9693   {
9694     g_info << "drop table after error" << endl;
9695     (void)pDic->dropTable(tabname);
9696   }
9697   return result;
9698 }
9699 
9700 int
getOrCreateDefaultHashMap(NdbDictionary::Dictionary & dict,NdbDictionary::HashMap & hm,Uint32 buckets,Uint32 fragments)9701 getOrCreateDefaultHashMap(NdbDictionary::Dictionary& dict, NdbDictionary::HashMap& hm, Uint32 buckets, Uint32 fragments)
9702 {
9703   if (dict.getDefaultHashMap(hm, buckets, fragments) == 0)
9704   {
9705     return 0;
9706   }
9707 
9708   dict.initDefaultHashMap(hm, buckets, fragments);
9709   if (dict.createHashMap(hm, NULL) == -1)
9710   {
9711     return -1;
9712   }
9713 
9714   if (dict.getDefaultHashMap(hm, buckets, fragments) == 0)
9715   {
9716     return 0;
9717   }
9718 
9719   return -1;
9720 }
9721 
9722 struct Bug14645319_createTable_args
9723 {
9724   char const* template_name;
9725   char const* name;
9726   Uint32 buckets;
9727   Uint32 fragments;
9728 };
9729 
Bug14645319_createTable(Ndb * pNdb,NdbDictionary::Table & tab,int when,void * arg)9730 int Bug14645319_createTable(Ndb* pNdb, NdbDictionary::Table& tab, int when,
9731                                     void* arg)
9732 {
9733   Bug14645319_createTable_args& args = *static_cast<Bug14645319_createTable_args*>(arg);
9734   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9735   if (when == 0)
9736   {
9737     tab.setName(args.name);
9738     tab.setFragmentCount(args.fragments);
9739     if (args.fragments == 0)
9740     {
9741       tab.setFragmentData(0, 0);
9742     }
9743     NdbDictionary::HashMap hm;
9744     getOrCreateDefaultHashMap(*pDic, hm, args.buckets, args.fragments);
9745     tab.setHashMap(hm);
9746   }
9747   return 0;
9748 }
9749 
9750 int
runBug14645319(NDBT_Context * ctx,NDBT_Step * step)9751 runBug14645319(NDBT_Context* ctx, NDBT_Step* step)
9752 {
9753   Ndb* pNdb = GETNDB(step);
9754   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9755   int failures = 0;
9756 
9757   struct test_case {
9758     char const* description;
9759     int old_fragments;
9760     int old_buckets;
9761     int new_fragments;
9762     int new_buckets;
9763     int expected_buckets;
9764   };
9765 
9766   STATIC_ASSERT(NDB_DEFAULT_HASHMAP_BUCKETS % 240 == 0);
9767   STATIC_ASSERT(NDB_DEFAULT_HASHMAP_BUCKETS % 260 != 0);
9768   test_case test_cases[] = {
9769     { "Simulate online reorg, may or may not change hashmap depending on default fragment count",
9770       3, 120, 0, NDB_DEFAULT_HASHMAP_BUCKETS, 0 },
9771     { "Keep old hashmap since no new fragments",
9772       3, 120, 3, NDB_DEFAULT_HASHMAP_BUCKETS, 120 },
9773     { "Keep old hashmap size since old size a multiple of new fragment count",
9774       3, 120, 6, NDB_DEFAULT_HASHMAP_BUCKETS, 120 },
9775     { "Keep old hashmap size since new size not a multiple of old",
9776       3, 130, 6, NDB_DEFAULT_HASHMAP_BUCKETS, 130 },
9777     { "Extend hashmap",
9778       3, 120, 7, NDB_DEFAULT_HASHMAP_BUCKETS, NDB_DEFAULT_HASHMAP_BUCKETS },
9779     { "Keep old hashmap size since old size not multiple of old fragment count",
9780       5, 84, 7, 42, 84 },
9781     { "Shrink hashmap",
9782       3, 120, 6, 60, 60 },
9783   };
9784 
9785   Bug14645319_createTable_args args;
9786   args.template_name = ctx->getTab()->getName();
9787   args.name = "Bug14645319";
9788 
9789   for (size_t testi = 0; testi < NDB_ARRAY_SIZE(test_cases); testi++)
9790   {
9791     test_case const& test = test_cases[testi];
9792     int result = NDBT_FAILED;
9793 
9794     int old_fragments = 0;
9795     int old_buckets = 0;
9796     int new_fragments = 0;
9797     int new_buckets = 0;
9798 
9799     do {
9800       /* setup old table */
9801       args.buckets = test.old_buckets;
9802       args.fragments = test.old_fragments;
9803       result = NDBT_Tables::createTable(pNdb, args.template_name, false, false, Bug14645319_createTable, &args);
9804       if (result != 0) break;
9805 
9806       NdbDictionary::Table const& old_tab = *pDic->getTable(args.name);
9807 
9808       /* check old table properties */
9809       NdbDictionary::HashMap old_hm;
9810       result = pDic->getHashMap(old_hm, &old_tab);
9811       if (result != 0) break;
9812 
9813       old_fragments = old_tab.getFragmentCount();
9814       old_buckets = old_hm.getMapLen();
9815       if (old_fragments != test.old_fragments)
9816       {
9817         result = NDBT_FAILED;
9818         break;
9819       }
9820       if (old_buckets != test.old_buckets)
9821       {
9822         result = NDBT_FAILED;
9823         break;
9824       }
9825 
9826       /* alter table */
9827       NdbDictionary::Table new_tab = old_tab;
9828       new_tab.setFragmentCount(test.new_fragments);
9829       if (test.new_fragments == 0)
9830         new_tab.setFragmentData(0, 0);
9831 
9832       result = pDic->beginSchemaTrans();
9833       if (result != 0) break;
9834 
9835       result = pDic->prepareHashMap(old_tab, new_tab, test.new_buckets);
9836 
9837       result |= pDic->endSchemaTrans();
9838       if (result != 0) break;
9839 
9840       result = pDic->alterTable(old_tab, new_tab);
9841       if (result != 0) break;
9842 
9843       /* check */
9844       NdbDictionary::HashMap new_hm;
9845       result = pDic->getHashMap(new_hm, &new_tab);
9846       if (result != 0) break;
9847 
9848       new_fragments = new_tab.getFragmentCount();
9849       new_buckets = new_hm.getMapLen();
9850 
9851       if (test.expected_buckets > 0 &&
9852           new_buckets != test.expected_buckets)
9853       {
9854         result = NDBT_FAILED;
9855         break;
9856       }
9857       result = 0;
9858     } while (false);
9859 
9860     result |= pDic->dropTable(args.name);
9861 
9862     if (result == 0)
9863     {
9864       ndbout << "Test#" << (testi + 1) << " '" << test_cases[testi].description << "' passed" <<
9865         " (" << old_buckets << " => " << test_cases[testi].new_buckets << " => " << test_cases[testi].expected_buckets << ")" << endl;
9866     }
9867     else
9868     {
9869       ndbout << "Test#" << (testi + 1) << " '" << test_cases[testi].description << "' failed" <<
9870         " (" << old_buckets << " => " << test_cases[testi].new_buckets << " => " << new_buckets << " expected: " << test_cases[testi].expected_buckets << ")" << endl;
9871       failures++;
9872     }
9873   }
9874 
9875   return failures > 0 ? NDBT_FAILED : NDBT_OK;
9876 }
9877 
9878 // FK SR/NR
9879 
9880 #define CHK1(b) CHK2(b, "-");
9881 
9882 // myRandom48 seems too non-random
9883 #define myRandom48(x) (unsigned(ndb_rand()) % (x))
9884 #define myRandom48Init(x) (ndb_srand(x))
9885 
9886 // used for create and verify
9887 struct Fkdef {
9888   static const int tabmax = 5;
9889   static const int colmax = 5;
9890   static const int indmax = 5;
9891   static const int keymax = tabmax * 5;
9892   static const int strmax = 10;
9893   struct Ob {
9894     bool retrieved;
9895     int id;
9896     int version;
9897   };
9898   struct Col {
9899     char colname[strmax];
9900     bool pk;
9901     bool nullable; // false
9902     int icol; // pos in table columns
9903   };
9904   struct Ind : Ob {
9905     char indname[strmax];
9906     Col col[colmax];
9907     int ncol;
9908     bool pk;
9909     bool unique;
9910     const NdbDictionary::Index* pInd;
9911   };
9912   struct Tab : Ob {
9913     char tabname[strmax];
9914     Col col[colmax];
9915     int ncol;
9916     Ind ind[indmax]; // first "index" is primary key
9917     int nind;
9918     const NdbDictionary::Table* pTab;
9919   };
9920   struct Key : Ob {
9921     char keyname[strmax];
9922     char fullname[20 + strmax]; // bug#19122346
9923     // 0-parent 1-child
9924     const Tab* tab0;
9925     const Tab* tab1;
9926     const Ind* ind0;
9927     const Ind* ind1;
9928     NdbDictionary::ForeignKey::FkAction updateAction;
9929     NdbDictionary::ForeignKey::FkAction deleteAction;
9930   };
9931   struct List {
9932     NdbDictionary::Dictionary::List* list;
9933     int keystart; // FK stuff sorted to end of list starts here
ListFkdef::List9934     List() { list = 0; }
~ListFkdef::List9935     ~List() { delete list; }
9936   };
9937   Tab tab[tabmax];
9938   int ntab;
9939   Key key[keymax];
9940   int nkey;
9941   List list;
9942   bool nokeys;
9943   bool nodrop;
9944   int testcase;
9945 };
9946 
9947 static int
fk_compare_icol(const void * p1,const void * p2)9948 fk_compare_icol(const void* p1, const void* p2)
9949 {
9950   const Fkdef::Col& col1 = *(const Fkdef::Col*)p1;
9951   const Fkdef::Col& col2 = *(const Fkdef::Col*)p2;
9952   return col1.icol - col2.icol;
9953 }
9954 
9955 static int
fk_type(int t)9956 fk_type(int t)
9957 {
9958   if (
9959     t ==  NdbDictionary::Object::ForeignKey ||
9960     t ==  NdbDictionary::Object::FKParentTrigger ||
9961     t ==  NdbDictionary::Object::FKChildTrigger
9962   )
9963     return 1;
9964   return 0;
9965 }
9966 
9967 static int
fk_compare_element(const void * p1,const void * p2)9968 fk_compare_element(const void* p1, const void* p2)
9969 {
9970   const NdbDictionary::Dictionary::List::Element& e1 =
9971     *(const NdbDictionary::Dictionary::List::Element*)p1;
9972   const NdbDictionary::Dictionary::List::Element& e2 =
9973     *(const NdbDictionary::Dictionary::List::Element*)p2;
9974   int k = 0;
9975   if ((k = fk_type(e1.type) - fk_type(e2.type)) != 0)
9976     return k;
9977   if ((k = e1.type - e2.type) != 0)
9978     return k;
9979   if ((k = (int)e1.id - (int)e2.id) != 0)
9980     return k;
9981   return 0;
9982 }
9983 
9984 static bool
fk_find_element(const Fkdef::List & list,int type,const char * database,const char * name)9985 fk_find_element(const Fkdef::List& list, int type,
9986                 const char* database, const char* name)
9987 {
9988   int found = 0;
9989   for (int i = 0; i < (int)list.list->count; i++)
9990   {
9991     const NdbDictionary::Dictionary::List::Element& e =
9992       list.list->elements[i];
9993     if (e.type == type &&
9994         strcmp(e.database, database) == 0 &&
9995         strcmp(e.name, name) == 0)
9996     {
9997       found++;
9998     }
9999   }
10000   require(found == 0 || found == 1);
10001   return found;
10002 }
10003 
10004 // testcase 1: t0 (a0 pk, b0 key), t1 (a1 pk, b1 key), fk b1->a0
10005 
10006 static void
fk_define_tables1(Fkdef & d)10007 fk_define_tables1(Fkdef& d)
10008 {
10009   d.ntab = 2;
10010   for (int i = 0; i < d.ntab; i++)
10011   {
10012     Fkdef::Tab& dt = d.tab[i];
10013     sprintf(dt.tabname, "t%d", i);
10014     dt.ncol = 2;
10015     for (int j = 0; j < dt.ncol; j++)
10016     {
10017       Fkdef::Col& dc = dt.col[j];
10018       sprintf(dc.colname, "%c%d", 'a' + j, i);
10019       dc.pk = (j == 0);
10020       dc.nullable = false;
10021       dc.icol = j;
10022     }
10023     dt.nind = 2;
10024     dt.pTab = 0;
10025     dt.retrieved = false;
10026     {
10027       Fkdef::Ind& di = dt.ind[0];
10028       sprintf(di.indname, "%s", "pk");
10029       di.ncol = 1;
10030       di.col[0] = dt.col[0];
10031       di.pk = true;
10032       di.unique = true;
10033       di.pInd = 0;
10034       di.retrieved = false;
10035     }
10036     {
10037       Fkdef::Ind& di = dt.ind[1];
10038       sprintf(di.indname, "t%dx%d", i, 1);
10039       di.ncol = 1;
10040       di.col[0] = dt.col[1];
10041       di.pk = false;
10042       di.unique = false;
10043       di.pInd = 0;
10044       di.retrieved = false;
10045     }
10046   }
10047   g_info << "defined " << d.ntab << " tables" << endl;
10048 }
10049 
10050 static void
fk_define_keys1(Fkdef & d)10051 fk_define_keys1(Fkdef& d)
10052 {
10053   d.nkey = 1;
10054   Fkdef::Key& dk = d.key[0];
10055   sprintf(dk.keyname, "fk%d", 0);
10056   dk.tab0 = &d.tab[0];
10057   dk.tab1 = &d.tab[1];
10058   dk.ind0 = &dk.tab0->ind[0];
10059   dk.ind1 = &dk.tab1->ind[1];
10060   dk.updateAction = NdbDictionary::ForeignKey::NoAction;
10061   dk.deleteAction = NdbDictionary::ForeignKey::NoAction;
10062   dk.retrieved = false;
10063   g_info << "defined " << d.nkey << " keys" << endl;
10064 }
10065 
10066 // testcase 2: random
10067 
10068 static void
fk_define_tables2(Fkdef & d)10069 fk_define_tables2(Fkdef& d)
10070 {
10071   d.ntab = 1 + myRandom48(d.tabmax);
10072   for (int i = 0; i < d.ntab; i++)
10073   {
10074     Fkdef::Tab& dt = d.tab[i];
10075     sprintf(dt.tabname, "t%d", i);
10076     dt.ncol = 2 + myRandom48(d.colmax - 1);
10077     for (int j = 0; j < dt.ncol; j++)
10078     {
10079       Fkdef::Col& dc = dt.col[j];
10080       sprintf(dc.colname, "%c%d", 'a' + j, i);
10081       dc.pk = (j == 0 || myRandom48(d.colmax) == 0);
10082       dc.nullable = false;
10083       dc.icol = j;
10084     }
10085     dt.nind = 1 + myRandom48(d.indmax);
10086     dt.pTab = 0;
10087     dt.retrieved = false;
10088     for (int k = 0; k < dt.nind; k++)
10089     {
10090       Fkdef::Ind& di = dt.ind[k];
10091       if (k == 0)
10092       {
10093         sprintf(di.indname, "%s", "pk");
10094         di.ncol = 0;
10095         for (int j = 0; j < dt.ncol; j++)
10096         {
10097           Fkdef::Col& dc = dt.col[j];
10098           if (dc.pk)
10099             di.col[di.ncol++] = dc;
10100         }
10101         di.pk = true;
10102         di.unique = true;
10103       }
10104       else
10105       {
10106         di.unique = (myRandom48(3) != 0);
10107         sprintf(di.indname, "t%dx%d", i, k);
10108         di.ncol = 1 + myRandom48(dt.ncol);
10109         uint mask = 0;
10110         int n = 0;
10111         while (n < di.ncol)
10112         {
10113           int j = myRandom48(dt.ncol);
10114           Fkdef::Col& dc = dt.col[j];
10115           if ((mask & (1 << j)) == 0)
10116           {
10117             di.col[n++] = dc;
10118             mask |= (1 << j);
10119           }
10120         }
10121         if (di.unique)
10122           qsort(&di.col, di.ncol, sizeof(di.col[0]), fk_compare_icol);
10123       }
10124       di.pInd = 0;
10125       di.retrieved = false;
10126     }
10127   }
10128   g_info << "defined " << d.ntab << " tables" << endl;
10129 }
10130 
10131 static void
fk_define_keys2(Fkdef & d)10132 fk_define_keys2(Fkdef& d)
10133 {
10134   int nkey = 1 + myRandom48(d.ntab * 5);
10135   int k = 0;
10136   int ntrymax = nkey * 100;
10137   int ntry = 0;
10138   while (k < nkey && ntry++ < ntrymax)
10139   {
10140     Fkdef::Key& dk = d.key[k];
10141     new (&dk) Fkdef::Key;
10142     int i0 = myRandom48(d.ntab);
10143     int i1 = myRandom48(d.ntab);
10144     Fkdef::Tab& dt0 = d.tab[i0];
10145     Fkdef::Tab& dt1 = d.tab[i1];
10146     int k0 = myRandom48(dt0.nind);
10147     int k1 = myRandom48(dt1.nind);
10148     Fkdef::Ind& di0 = dt0.ind[k0];
10149     Fkdef::Ind& di1 = dt1.ind[k1];
10150     if (!di0.unique || di0.ncol != di1.ncol)
10151       continue;
10152     if (i0 == i1 && k0 == k1)
10153       if (myRandom48(10) != 0) // allowed but try to avoid
10154         continue;
10155     sprintf(dk.keyname, "fk%d", k);
10156     dk.tab0 = &dt0;
10157     dk.tab1 = &dt1;
10158     dk.ind0 = &di0;
10159     dk.ind1 = &di1;
10160     dk.updateAction = NdbDictionary::ForeignKey::NoAction;
10161     dk.deleteAction = NdbDictionary::ForeignKey::NoAction;
10162     dk.retrieved = false;
10163     k++;
10164   }
10165   d.nkey = k;
10166   g_info << "defined " << d.nkey << " keys tries:" << ntry << endl;
10167 }
10168 
10169 static void
fk_define_tables(Fkdef & d)10170 fk_define_tables(Fkdef& d)
10171 {
10172   if (d.testcase == 1)
10173     fk_define_tables1(d);
10174   else if (d.testcase == 2)
10175     fk_define_tables2(d);
10176   else
10177     require(false);
10178 }
10179 
10180 static void
fk_define_keys(Fkdef & d)10181 fk_define_keys(Fkdef& d)
10182 {
10183   if (d.nokeys)
10184   {
10185     d.nkey = 0;
10186     return;
10187   }
10188   if (d.testcase == 1)
10189     fk_define_keys1(d);
10190   else if (d.testcase == 2)
10191     fk_define_keys2(d);
10192   else
10193     require(false);
10194 }
10195 
10196 static void
fk_undefine_keys(Fkdef & d)10197 fk_undefine_keys(Fkdef& d)
10198 {
10199   d.nkey = 0;
10200 }
10201 
10202 static void
fk_define_all(Fkdef & d)10203 fk_define_all(Fkdef& d)
10204 {
10205   fk_define_tables(d);
10206   fk_define_keys(d);
10207 }
10208 
10209 static int
fk_create_table(Fkdef & d,Ndb * pNdb,int i)10210 fk_create_table(Fkdef& d, Ndb* pNdb, int i)
10211 {
10212   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10213   int result = NDBT_OK;
10214   do
10215   {
10216     Fkdef::Tab& dt = d.tab[i];
10217     NdbDictionary::Table tab;
10218     tab.setName(dt.tabname);
10219     for (int j = 0; j < dt.ncol; j++)
10220     {
10221       Fkdef::Col& dc = dt.col[j];
10222       NdbDictionary::Column col;
10223       col.setName(dc.colname);
10224       col.setType(NdbDictionary::Column::Unsigned);
10225       col.setPrimaryKey(dc.pk);
10226       col.setNullable(dc.nullable);
10227       tab.addColumn(col);
10228     }
10229     g_info << "create table " << dt.tabname << endl;
10230     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
10231     const NdbDictionary::Table* pTab = 0;
10232     CHK2((pTab = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
10233     require(!dt.retrieved);
10234     dt.retrieved = true;
10235     dt.id = pTab->getObjectId();
10236     dt.version = pTab->getObjectVersion();
10237     dt.pTab = pTab;
10238     for (int k = 1; k < dt.nind; k++) // skip pk
10239     {
10240       Fkdef::Ind& di = dt.ind[k];
10241       NdbDictionary::Index ind;
10242       ind.setName(di.indname);
10243       ind.setTable(dt.tabname);
10244       if (di.unique)
10245       {
10246         ind.setType(NdbDictionary::Index::UniqueHashIndex);
10247         ind.setLogging(true);
10248       }
10249       else
10250       {
10251         ind.setType(NdbDictionary::Index::OrderedIndex);
10252         ind.setLogging(false);
10253       }
10254       for (int j = 0; j < di.ncol; j++)
10255       {
10256         const Fkdef::Col& dc = di.col[j];
10257         ind.addColumn(dc.colname);
10258       }
10259       g_info << "create index " << di.indname << endl;
10260       CHK2(pDic->createIndex(ind) == 0, pDic->getNdbError());
10261       const NdbDictionary::Index* pInd = 0;
10262       CHK2((pInd = pDic->getIndex(di.indname, dt.tabname)) != 0, pDic->getNdbError());
10263       require(!di.retrieved);
10264       di.retrieved = true;
10265       di.id = pInd->getObjectId();
10266       di.version = pInd->getObjectVersion();
10267       di.pInd = pInd;
10268     }
10269   }
10270   while (0);
10271   return result;
10272 }
10273 
10274 static int
fk_create_tables(Fkdef & d,Ndb * pNdb)10275 fk_create_tables(Fkdef& d, Ndb* pNdb)
10276 {
10277   int result = NDBT_OK;
10278   for (int i = 0; i < d.ntab; i++)
10279   {
10280     CHK1(fk_create_table(d, pNdb, i) == NDBT_OK);
10281   }
10282   return result;
10283 }
10284 
10285 static int
fk_create_key(Fkdef & d,Ndb * pNdb,int k)10286 fk_create_key(Fkdef& d, Ndb* pNdb, int k)
10287 {
10288   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10289   int result = NDBT_OK;
10290   do
10291   {
10292     Fkdef::Key& dk = d.key[k];
10293     NdbDictionary::ForeignKey key;
10294     key.setName(dk.keyname);
10295     const Fkdef::Tab& dt0 = *dk.tab0;
10296     const Fkdef::Tab& dt1 = *dk.tab1;
10297     const Fkdef::Ind& di0 = *dk.ind0;
10298     const Fkdef::Ind& di1 = *dk.ind1;
10299     const NdbDictionary::Table* pTab0 = dt0.pTab;
10300     const NdbDictionary::Table* pTab1 = dt1.pTab;
10301     const NdbDictionary::Index* pInd0 = di0.pInd;
10302     const NdbDictionary::Index* pInd1 = di1.pInd;
10303     key.setParent(*pTab0, pInd0);
10304     key.setChild(*pTab1, pInd1);
10305     g_info << "create key " << dk.keyname << endl;
10306     CHK2(pDic->createForeignKey(key) == 0, pDic->getNdbError());
10307     {
10308       NdbDictionary::ForeignKey key;
10309       sprintf(dk.fullname, "%d/%d/%s", dt0.id, dt1.id, dk.keyname);
10310       CHK2(pDic->getForeignKey(key, dk.fullname) == 0, pDic->getNdbError());
10311       require(!dk.retrieved);
10312       dk.retrieved = true;
10313       dk.id = key.getObjectId();
10314       dk.version = key.getObjectVersion();
10315     }
10316   }
10317   while (0);
10318   return result;
10319 }
10320 
10321 static int
fk_create_keys(Fkdef & d,Ndb * pNdb)10322 fk_create_keys(Fkdef& d, Ndb* pNdb)
10323 {
10324   int result = NDBT_OK;
10325   for (int k = 0; k < d.nkey; k++)
10326   {
10327     CHK1(fk_create_key(d, pNdb, k) == NDBT_OK);
10328   }
10329   return result;
10330 }
10331 
10332 static int
fk_alter_table(Fkdef & d,Ndb * pNdb,int i)10333 fk_alter_table(Fkdef& d, Ndb* pNdb, int i)
10334 {
10335   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10336   int result = NDBT_OK;
10337   do
10338   {
10339     Fkdef::Tab& dt = d.tab[i];
10340     const NdbDictionary::Table* pTab1 = 0;
10341     CHK2((pTab1 = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
10342     g_info << "alter table " << dt.tabname << endl;
10343     int id1 = pTab1->getObjectId();
10344     int version1 = pTab1->getObjectVersion();
10345     g_info << "old: id=" << id1 << " version=" << hex << version1 << endl;
10346     CHK2(pDic->alterTable(*pTab1, *pTab1) == 0, pDic->getNdbError());
10347     pDic->invalidateTable(dt.tabname);
10348     const NdbDictionary::Table* pTab2 = 0;
10349     CHK2((pTab2 = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
10350     int id2 = pTab2->getObjectId();
10351     int version2 = pTab2->getObjectVersion();
10352     g_info << "old: id=" << id2 << " version=" << hex << version2 << endl;
10353     CHK2(id1 == id2, id1 << " != " << id2);
10354     CHK2(version1 != version2, version1 << " == " << version2);
10355     dt.id = id2;
10356     dt.version = version2;
10357   }
10358   while (0);
10359   return result;
10360 }
10361 
10362 static int
fk_alter_tables(Fkdef & d,Ndb * pNdb,bool atrandom)10363 fk_alter_tables(Fkdef& d, Ndb* pNdb, bool atrandom)
10364 {
10365   int result = NDBT_OK;
10366   for (int i = 0; i < d.ntab; i++)
10367   {
10368     if (!atrandom || myRandom48(2) == 0)
10369     {
10370       CHK1(fk_alter_table(d, pNdb, i) == NDBT_OK);
10371     }
10372   }
10373   return result;
10374 }
10375 
10376 static int
fk_create_all(Fkdef & d,Ndb * pNdb)10377 fk_create_all(Fkdef& d, Ndb* pNdb)
10378 {
10379   int result = NDBT_OK;
10380   do
10381   {
10382     CHK1(fk_create_tables(d, pNdb) == 0);
10383     CHK1(fk_create_keys(d, pNdb) == NDBT_OK);
10384     // imitate mysqld by doing an alter table afterwards
10385     CHK1(fk_alter_tables(d, pNdb, true) == NDBT_OK);
10386   }
10387   while (0);
10388   return result;
10389 }
10390 
10391 static int
fk_verify_table(const Fkdef & d,Ndb * pNdb,int i)10392 fk_verify_table(const Fkdef& d, Ndb* pNdb, int i)
10393 {
10394   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10395   int result = NDBT_OK;
10396   do
10397   {
10398     const Fkdef::Tab& dt = d.tab[i];
10399     g_info << "verify table " << dt.tabname << endl;
10400     const NdbDictionary::Table* pTab = 0;
10401     CHK2((pTab = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
10402     int id = pTab->getObjectId();
10403     int version = pTab->getObjectVersion();
10404     require(dt.retrieved);
10405     CHK2(dt.id == id, dt.id << " != " << id);
10406     CHK2(dt.version == version, dt.version << " != " << version);
10407     for (int k = 1; k < dt.nind; k++) // skip pk
10408     {
10409       const Fkdef::Ind& di = dt.ind[k];
10410       g_info << "verify index " << di.indname << endl;
10411       const NdbDictionary::Index* pInd = 0;
10412       CHK2((pInd = pDic->getIndex(di.indname, dt.tabname)) != 0, pDic->getNdbError());
10413       int id = pInd->getObjectId();
10414       int version = pInd->getObjectVersion();
10415       require(di.retrieved);
10416       CHK2(di.id == id, di.id << " != " << id);
10417       CHK2(di.version == version, di.version << " != " << version);
10418     }
10419     CHK1(result == NDBT_OK);
10420   }
10421   while (0);
10422   return result;
10423 }
10424 
10425 static int
fk_verify_tables(const Fkdef & d,Ndb * pNdb)10426 fk_verify_tables(const Fkdef& d, Ndb* pNdb)
10427 {
10428   int result = NDBT_OK;
10429   for (int i = 0; i < d.ntab; i++)
10430   {
10431     CHK1(fk_verify_table(d, pNdb, i) == 0);
10432   }
10433   return result;
10434 }
10435 
10436 static int
fk_verify_key(const Fkdef & d,Ndb * pNdb,int k)10437 fk_verify_key(const Fkdef& d, Ndb* pNdb, int k)
10438 {
10439   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10440   int result = NDBT_OK;
10441   do
10442   {
10443     const Fkdef::Key& dk = d.key[k];
10444     g_info << "verify key " << dk.fullname << endl;
10445     NdbDictionary::ForeignKey key;
10446     CHK2(pDic->getForeignKey(key, dk.fullname) == 0, pDic->getNdbError());
10447     int id = key.getObjectId();
10448     int version = key.getObjectVersion();
10449     require(dk.retrieved);
10450     CHK2(dk.id == id, dk.id << " != " << id);
10451     CHK2(dk.version == version, dk.version << " != " << version);
10452     CHK2(strcmp(dk.fullname, key.getName()) == 0, dk.fullname << " != " << key.getName());
10453 #if 0 // can add more checks
10454     const Fkdef::Tab& dt0 = *dk.tab0;
10455     const Fkdef::Tab& dt1 = *dk.tab1;
10456     const Fkdef::Ind& di0 = *dk.ind0;
10457     const Fkdef::Ind& di1 = *dk.ind1;
10458 #endif
10459   }
10460   while (0);
10461   return result;
10462 }
10463 
10464 static int
fk_verify_keys(const Fkdef & d,Ndb * pNdb)10465 fk_verify_keys(const Fkdef& d, Ndb* pNdb)
10466 {
10467   int result = NDBT_OK;
10468   for (int k = 0; k < d.nkey; k++)
10469   {
10470     CHK1(fk_verify_key(d, pNdb, k) == 0);
10471   }
10472   return result;
10473 }
10474 
10475 static int
fk_verify_ddl(const Fkdef & d,Ndb * pNdb)10476 fk_verify_ddl(const Fkdef& d, Ndb* pNdb)
10477 {
10478   int result = NDBT_OK;
10479   do
10480   {
10481     g_info << "verify ddl" << endl;
10482     CHK1(fk_verify_tables(d, pNdb) == 0);
10483     CHK1(fk_verify_keys(d, pNdb) == 0);
10484   }
10485   while (0);
10486   return result;
10487 }
10488 
10489 static int
fk_verify_dml(const Fkdef & d,Ndb * pNdb,int records)10490 fk_verify_dml(const Fkdef& d, Ndb* pNdb, int records)
10491 {
10492   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10493   int result = NDBT_OK;
10494   const int batch = 1;
10495   const bool allowCV = false;
10496   const int errNoParent = 255;
10497   const int errHasChild = 256;
10498   do
10499   {
10500     if (!(d.testcase == 1 && records > 0))
10501       break;
10502     g_info << "verify dml" << endl;
10503     const Fkdef::Tab& dt0 = d.tab[0];
10504     const Fkdef::Tab& dt1 = d.tab[1];
10505     const NdbDictionary::Table* pTab0 = 0;
10506     const NdbDictionary::Table* pTab1 = 0;
10507     CHK2((pTab0 = pDic->getTable(dt0.tabname)) != 0, pDic->getNdbError());
10508     CHK2((pTab1 = pDic->getTable(dt1.tabname)) != 0, pDic->getNdbError());
10509     HugoTransactions tx0(*pTab0);
10510     HugoTransactions tx1(*pTab1);
10511     // insert into child t1 - not ok
10512     g_err << "expect error " << errNoParent << endl;
10513     CHK1(tx1.loadTable(pNdb, records, batch, allowCV) != 0);
10514     CHK2(tx1.getNdbError().code == errNoParent, tx1.getNdbError());
10515     // insert into parent t0 - ok
10516     CHK2(tx0.loadTable(pNdb, records, batch, allowCV) == 0,
10517          tx0.getNdbError());
10518     // insert into child t1 - ok (b1 is 0, a0 is 0,1,2,..)
10519     CHK2(tx1.loadTable(pNdb, records, batch, allowCV) == 0,
10520          tx1.getNdbError());
10521     // delete from parent - not ok
10522     g_err << "expect error " << errHasChild << endl;
10523     CHK1(tx0.pkDelRecords(pNdb, records, batch, allowCV) != 0);
10524     CHK2(tx0.getNdbError().code == errHasChild, tx0.getNdbError());
10525     // delete from child t1 - ok
10526     CHK2(tx1.pkDelRecords(pNdb, records, batch, allowCV) == 0,
10527          tx1.getNdbError());
10528     // delete from parent to - ok
10529     CHK2(tx0.pkDelRecords(pNdb, records, batch, allowCV) == 0,
10530          tx0.getNdbError());
10531   }
10532   while (0);
10533   return result;
10534 }
10535 
10536 static int
fk_retrieve_list(Fkdef & d,Ndb * pNdb,Fkdef::List & list)10537 fk_retrieve_list(Fkdef& d, Ndb* pNdb, Fkdef::List& list)
10538 {
10539   (void)d;
10540   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10541   int result = NDBT_OK;
10542   do
10543   {
10544     g_info << "list objects" << endl;
10545     require(list.list == 0);
10546     list.list = new NdbDictionary::Dictionary::List;
10547     CHK2(pDic->listObjects(*list.list) == 0, pDic->getNdbError());
10548     qsort(list.list->elements, list.list->count, sizeof(list.list->elements[0]),
10549           fk_compare_element);
10550     list.keystart = 0;
10551     for (int i = 0; i < (int)list.list->count; i++)
10552     {
10553       NdbDictionary::Dictionary::List::Element& e =
10554         list.list->elements[i];
10555       if (e.database == 0)
10556       {
10557         e.database = new char [1];
10558         e.database[0] = 0;
10559       }
10560       if (!fk_type(e.type))
10561         list.keystart++;
10562       g_info << "ob " << i << ":"
10563              << " type=" << e.type << " id=" << e.id
10564              << " db=" << e.database << " name=" << e.name << endl;
10565       if (i > 0)
10566       {
10567         const NdbDictionary::Dictionary::List::Element& e2 =
10568           list.list->elements[i - 1];
10569         CHK1(e.type != e2.type || e.id != e2.id);
10570       }
10571     }
10572     g_info << "list count=" << list.list->count
10573            << " keystart=" << list.keystart << endl;
10574   }
10575   while (0);
10576   return result;
10577 }
10578 
10579 static int
fk_verify_list(Fkdef & d,Ndb * pNdb,bool ignore_keys)10580 fk_verify_list(Fkdef& d, Ndb* pNdb, bool ignore_keys)
10581 {
10582   int result = NDBT_OK;
10583   do
10584   {
10585     Fkdef::List& list1 = d.list;
10586     if (list1.list == 0)
10587     {
10588       g_info << "retrieve first object list" << endl;
10589       CHK1(fk_retrieve_list(d, pNdb, list1) == 0);
10590     }
10591     else
10592     {
10593       g_info << "verify object list old vs new"
10594                 " ignore_keys=" << ignore_keys << endl;
10595       Fkdef::List list2;
10596       CHK1(fk_retrieve_list(d, pNdb, list2) == NDBT_OK);
10597       // optionally ignore FK stuff in either list
10598       int count1 = !ignore_keys ? list1.list->count : list1.keystart;
10599       int count2 = !ignore_keys ? list2.list->count : list2.keystart;
10600       CHK1(count1 == count2);
10601       for (int i = 0; i < count1; i++)
10602       {
10603         const NdbDictionary::Dictionary::List::Element& e1 =
10604           list1.list->elements[i];
10605         const NdbDictionary::Dictionary::List::Element& e2 =
10606           list2.list->elements[i];
10607         CHK2(e1.type == e2.type,
10608              i << ": " << e1.type << " != " << e2.type);
10609         CHK2(e1.id == e2.id,
10610              i << ": " << e1.id << " != " << e2.id);
10611         CHK2(strcmp(e1.database, e2.database) == 0,
10612              i << ": " << e1.database << " != " << e2.database);
10613         CHK2(strcmp(e1.name, e2.name) == 0,
10614              i << ": " << e1.name << " != " << e2.name);
10615       }
10616       CHK1(result == NDBT_OK);
10617       // replace old by new
10618       delete list1.list;
10619       list1.list = list2.list;
10620       list1.keystart = list2.keystart;
10621       list2.list = 0;
10622     }
10623     // verify objects vs list
10624     for (int i = 0; i < d.ntab; i++)
10625     {
10626       const Fkdef::Tab& dt = d.tab[i];
10627       CHK2(fk_find_element(list1, NdbDictionary::Object::UserTable,
10628            "TEST_DB", dt.tabname), dt.tabname);
10629       for (int k = 1; k < dt.nind; k++)
10630       {
10631         const Fkdef::Ind& di = dt.ind[k];
10632         if (di.unique)
10633         {
10634           CHK2(fk_find_element(list1, NdbDictionary::Object::UniqueHashIndex,
10635                "sys", di.indname), di.indname);
10636         }
10637         else
10638         {
10639           CHK2(fk_find_element(list1, NdbDictionary::Object::OrderedIndex,
10640                "sys", di.indname), di.indname);
10641         }
10642       }
10643       CHK1(result == NDBT_OK);
10644     }
10645     for (int k = 0; k < d.nkey; k++) {
10646       const Fkdef::Key& dk = d.key[k];
10647       CHK2(fk_find_element(list1, NdbDictionary::Object::ForeignKey,
10648            "", dk.fullname), dk.fullname);
10649       // could also check FK triggers..
10650     }
10651     CHK1(result == NDBT_OK);
10652   }
10653   while (0);
10654   return result;
10655 }
10656 
10657 static int
fk_drop_table(Fkdef & d,Ndb * pNdb,int i,bool force)10658 fk_drop_table(Fkdef& d, Ndb* pNdb, int i, bool force)
10659 {
10660   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10661   int result = NDBT_OK;
10662   do
10663   {
10664     Fkdef::Tab& dt = d.tab[i];
10665     g_info << "drop table " << dt.tabname
10666            << (force ? " (force)" : "") << endl;
10667     if (pDic->dropTable(dt.tabname) != 0)
10668     {
10669       const NdbError& err = pDic->getNdbError();
10670       CHK2(force, err);
10671       CHK2(err.code == 709 || err.code == 723, err);
10672       break;
10673     }
10674     // all indexes are dropped by ndb api
10675     // all related FKs child/parent are dropped by ndb api
10676   }
10677   while (0);
10678   return result;
10679 }
10680 
10681 static int
fk_drop_tables(Fkdef & d,Ndb * pNdb,bool force)10682 fk_drop_tables(Fkdef& d, Ndb* pNdb, bool force)
10683 {
10684   int result = NDBT_OK;
10685   for (int i = 0; i < d.ntab; i++)
10686   {
10687     CHK1(fk_drop_table(d, pNdb, i, force) == NDBT_OK);
10688   }
10689   return result;
10690 }
10691 
10692 static int
fk_drop_key(Fkdef & d,Ndb * pNdb,int k,bool force)10693 fk_drop_key(Fkdef& d, Ndb* pNdb, int k, bool force)
10694 {
10695   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10696   int result = NDBT_OK;
10697   do
10698   {
10699     Fkdef::Key& dk = d.key[k];
10700     g_info << "drop key " << dk.fullname
10701            << (force ? " (force)" : "") << endl;
10702     NdbDictionary::ForeignKey key;
10703     if (pDic->getForeignKey(key, dk.fullname) != 0)
10704     {
10705       const NdbError& err = pDic->getNdbError();
10706       CHK2(force, err);
10707       CHK2(err.code == 709 || err.code == 723 || err.code == 21040, err);
10708       break;
10709     }
10710     CHK2(pDic->dropForeignKey(key) == 0, pDic->getNdbError());
10711   }
10712   while (0);
10713   return result;
10714 }
10715 
10716 static int
fk_drop_keys(Fkdef & d,Ndb * pNdb,bool force)10717 fk_drop_keys(Fkdef& d, Ndb* pNdb, bool force)
10718 {
10719   int result = NDBT_OK;
10720   for (int k = 0; k < d.nkey; k++)
10721   {
10722     CHK1(fk_drop_key(d, pNdb, k, force) == NDBT_OK);
10723   }
10724   return result;
10725 }
10726 
10727 static int
fk_drop_all(Fkdef & d,Ndb * pNdb,bool force)10728 fk_drop_all(Fkdef& d, Ndb* pNdb, bool force)
10729 {
10730   int result = NDBT_OK;
10731   do
10732   {
10733     CHK1(fk_drop_keys(d, pNdb, force) == NDBT_OK);
10734     CHK1(fk_drop_tables(d, pNdb, force) == NDBT_OK);
10735   }
10736   while (0);
10737   return result;
10738 }
10739 
10740 // commit drop
10741 
10742 // just reset all retrieved
10743 static void
fk_dropped_all(Fkdef & d)10744 fk_dropped_all(Fkdef& d)
10745 {
10746   for (int i = 0; i < d.ntab; i++)
10747   {
10748     Fkdef::Tab& dt = d.tab[i];
10749     dt.retrieved = false;
10750     for (int k = 0; k < dt.nind; k++)
10751     {
10752       Fkdef::Ind& di = dt.ind[k];
10753       di.retrieved = false;
10754     }
10755   }
10756   for (int k = 0; k < d.nkey; k++)
10757   {
10758     Fkdef::Key& dk = d.key[k];
10759     dk.retrieved = false;
10760   }
10761 }
10762 
10763 // for FK_Bug18069680
10764 
10765 static int
fk_create_all_random(Fkdef & d,Ndb * pNdb)10766 fk_create_all_random(Fkdef& d, Ndb* pNdb)
10767 {
10768   int result = NDBT_OK;
10769   int ntab = 0;
10770   int nkey = 0;
10771   do
10772   {
10773     for (int i = 0; i < d.ntab; i++)
10774     {
10775       Fkdef::Tab& dt = d.tab[i];
10776       if (!dt.retrieved && myRandom48(3) == 0)
10777       {
10778         CHK1(fk_create_table(d, pNdb, i) == 0);
10779         require(dt.retrieved);
10780         ntab++;
10781       }
10782     }
10783     CHK1(result == NDBT_OK);
10784     for (int k = 0; k < d.nkey; k++)
10785     {
10786       Fkdef::Key& dk = d.key[k];
10787       if (!dk.retrieved && myRandom48(3) == 0 &&
10788           dk.tab0->retrieved && dk.tab1->retrieved)
10789       {
10790         CHK1(fk_create_key(d, pNdb, k) == 0);
10791         require(dk.retrieved);
10792         nkey++;
10793       }
10794     }
10795     CHK1(result == NDBT_OK);
10796     require(ntab <= d.ntab && nkey <= d.nkey);
10797   }
10798   while (ntab < d.ntab || nkey < d.nkey);
10799   return result;
10800 }
10801 
10802 static int
fk_drop_indexes_under(const Fkdef & d,Ndb * pNdb)10803 fk_drop_indexes_under(const Fkdef& d, Ndb* pNdb)
10804 {
10805   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10806   int result = NDBT_OK;
10807   do
10808   {
10809     for (int i = 0; i < d.ntab; i++)
10810     {
10811       const Fkdef::Tab& dt = d.tab[i];
10812       for (int k = 1; k < dt.nind; k++) // skip pk
10813       {
10814         const Fkdef::Ind& di = dt.ind[k];
10815         int parent = 0;
10816         int child = 0;
10817         for (int m = 0; m < d.nkey; m++)
10818         {
10819           const Fkdef::Key& dk = d.key[m];
10820           if (dk.ind0 == &di)
10821             parent++;
10822           if (dk.ind1 == &di)
10823             child++;
10824         }
10825         if (parent != 0 || child != 0)
10826         {
10827           // drop must fail
10828           g_info << "try to drop index under " << di.indname
10829                  << " parent:" << parent << " child:" << child << endl;
10830           int ret = pDic->dropIndex(di.indname, dt.tabname);
10831           CHK2(ret != 0, "no error on drop underlying index");
10832           const NdbError& err = pDic->getNdbError();
10833           // could be either error code depending on check order
10834           CHK2(err.code == 21081 || err.code == 21082, pDic->getNdbError());
10835         }
10836       }
10837       CHK1(result == NDBT_OK);
10838     }
10839     CHK1(result == NDBT_OK);
10840   }
10841   while (0);
10842   return result;
10843 }
10844 
10845 // for manual testing
10846 static void
fk_env_options(Fkdef & d)10847 fk_env_options(Fkdef& d)
10848 {
10849   // random seed
10850   int seed = (int)getpid();
10851 #ifdef NDB_USE_GET_ENV
10852   {
10853     const char* p = NdbEnv_GetEnv("RANDOM_SEED", (char*)0, 0);
10854     if (p != 0)
10855       seed = atoi(p);
10856   }
10857 #endif
10858   myRandom48Init(seed);
10859   g_err << "random seed: " << seed << endl;
10860   // create no FKs at all
10861   d.nokeys = false;
10862 #ifdef NDB_USE_GET_ENV
10863   {
10864     const char* p = NdbEnv_GetEnv("FK_NOKEYS", (char*)0, 0);
10865     if (p != 0 && strchr("1Y", p[0]) != 0)
10866       d.nokeys = true;
10867   }
10868 #endif
10869   // do not drop objects at end
10870   d.nodrop = false;
10871 #ifdef NDB_USE_GET_ENV
10872   {
10873     const char* p = NdbEnv_GetEnv("FK_NODROP", (char*)0, 0);
10874     if (p != 0 && strchr("1Y", p[0]) != 0)
10875       d.nodrop = true;
10876   }
10877 #endif
10878 }
10879 
10880 int
runFK_SRNR(NDBT_Context * ctx,NDBT_Step * step)10881 runFK_SRNR(NDBT_Context* ctx, NDBT_Step* step)
10882 {
10883   Ndb* pNdb = GETNDB(step);
10884   const int loops = ctx->getNumLoops();
10885   const int records = ctx->getNumRecords();
10886   int result = NDBT_OK;
10887 
10888   NdbRestarter restarter;
10889   const int numdbnodes = restarter.getNumDbNodes();
10890 
10891   Fkdef d;
10892   d.testcase = ctx->getProperty("testcase", (Uint32)0);
10893   fk_env_options(d);
10894   fk_define_all(d);
10895 
10896   do
10897   {
10898     (void)fk_drop_all(d, pNdb, true);
10899     CHK1(fk_create_all(d, pNdb) == NDBT_OK);
10900     CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
10901     CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
10902     CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
10903 
10904     for (int loop = 0; loop < loops; loop++)
10905     {
10906       g_info << "loop " << loop << "<" << loops << endl;
10907 
10908       bool rs = (numdbnodes == 1 || myRandom48(2) == 0);
10909       if (rs)
10910       {
10911         g_info << "restart all" << endl;
10912         CHK1(restarter.restartAll() == 0);
10913       }
10914       else
10915       {
10916         int i = myRandom48(numdbnodes);
10917         int nodeid = restarter.getDbNodeId(i);
10918         bool initial = (bool)myRandom48(2);
10919         bool nostart = true;
10920         g_info << "restart node " << nodeid << " initial=" << initial << endl;
10921 
10922         CHK1(restarter.restartOneDbNode(nodeid, initial, nostart) == 0);
10923         CHK1(restarter.waitNodesNoStart(&nodeid, 1) == 0);
10924         g_info << "nostart node " << nodeid << endl;
10925 
10926         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
10927         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
10928         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
10929 
10930         g_info << "start node " << nodeid << endl;
10931         CHK1(restarter.startNodes(&nodeid, 1) == 0);
10932       }
10933 
10934       CHK1(restarter.waitClusterStarted() == 0);
10935       g_info << "cluster is started" << endl;
10936 
10937       CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
10938       CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
10939       CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
10940     }
10941     CHK1(result == NDBT_OK);
10942 
10943     if (!d.nodrop)
10944     {
10945       CHK1(fk_drop_all(d, pNdb, false) == NDBT_OK);
10946     }
10947   }
10948   while (0);
10949 
10950   if (result != NDBT_OK)
10951   {
10952     if (!d.nodrop)
10953       (void)fk_drop_all(d, pNdb, true);
10954   }
10955   return result;
10956 }
10957 
10958 int
runFK_TRANS(NDBT_Context * ctx,NDBT_Step * step)10959 runFK_TRANS(NDBT_Context* ctx, NDBT_Step* step)
10960 {
10961   Ndb* pNdb = GETNDB(step);
10962   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10963   const int loops = ctx->getNumLoops();
10964   const int records = ctx->getNumRecords();
10965   int result = NDBT_OK;
10966   const int abort_flag = NdbDictionary::Dictionary::SchemaTransAbort;
10967 
10968   Fkdef d;
10969   d.testcase = ctx->getProperty("testcase", (Uint32)0);
10970   fk_env_options(d);
10971   fk_define_tables(d);
10972   fk_undefine_keys(d);
10973 
10974   do
10975   {
10976     (void)fk_drop_all(d, pNdb, true);
10977     CHK1(fk_create_tables(d, pNdb) == NDBT_OK);
10978     CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
10979     CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
10980 
10981     // what to do on loop % 3
10982     const int abort_loop[3][2] = { { 1, -1 }, { 0, 1 }, { 0, 0 } };
10983 
10984     for (int loop = 0; loop < loops; loop++)
10985     {
10986       g_info << "loop " << loop << "<" << loops << endl;
10987 
10988       int abort_create = abort_loop[loop % 3][0];
10989       require(abort_create == 0 || abort_create == 1);
10990       g_info << "abort create: " << abort_create << endl;
10991 
10992       fk_define_keys(d);
10993       CHK2(pDic->beginSchemaTrans() == 0, pDic->getNdbError());
10994       CHK1(fk_create_keys(d, pNdb) == 0);
10995       if (!abort_create)
10996       {
10997         g_info << "commit schema trans" << endl;
10998         CHK2(pDic->endSchemaTrans(0) == 0, pDic->getNdbError());
10999         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11000         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11001         CHK1(fk_verify_list(d, pNdb, true) == NDBT_OK);
11002       }
11003       else
11004       {
11005         g_info << "abort schema trans" << endl;
11006         CHK2(pDic->endSchemaTrans(abort_flag) == 0, pDic->getNdbError());
11007         fk_undefine_keys(d);
11008         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11009         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11010         continue; // nothing to drop
11011       }
11012 
11013       int abort_drop = abort_loop[loop % 3][1];
11014       require(abort_drop == 0 || abort_drop == 1);
11015       g_info << "abort drop: " << abort_drop << endl;
11016 
11017       CHK2(pDic->beginSchemaTrans() == 0, pDic->getNdbError());
11018       CHK1(fk_drop_keys(d, pNdb, false) == 0);
11019       if (!abort_drop)
11020       {
11021         g_info << "commit schema trans" << endl;
11022         CHK2(pDic->endSchemaTrans(0) == 0, pDic->getNdbError());
11023         fk_undefine_keys(d);
11024         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11025         CHK1(fk_verify_list(d, pNdb, true) == NDBT_OK);
11026       }
11027       else
11028       {
11029         g_info << "abort schema trans" << endl;
11030         CHK2(pDic->endSchemaTrans(abort_flag) == 0, pDic->getNdbError());
11031         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11032         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11033         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11034         // prepare for next round
11035         CHK1(fk_drop_keys(d, pNdb, false) == NDBT_OK);
11036         fk_undefine_keys(d);
11037       }
11038     }
11039     CHK1(result == NDBT_OK);
11040 
11041     if (!d.nodrop)
11042     {
11043       CHK1(fk_drop_all(d, pNdb, false) == NDBT_OK);
11044     }
11045   }
11046   while (0);
11047 
11048   if (result != NDBT_OK)
11049   {
11050     (void)pDic->endSchemaTrans(abort_flag);
11051     if (!d.nodrop)
11052       (void)fk_drop_all(d, pNdb, true);
11053   }
11054   return result;
11055 }
11056 
11057 int
runFK_Bug18069680(NDBT_Context * ctx,NDBT_Step * step)11058 runFK_Bug18069680(NDBT_Context* ctx, NDBT_Step* step)
11059 {
11060   Ndb* pNdb = GETNDB(step);
11061   const int loops = ctx->getNumLoops();
11062   const int records = ctx->getNumRecords();
11063   int result = NDBT_OK;
11064 
11065   Fkdef d;
11066   d.testcase = ctx->getProperty("testcase", (Uint32)0);
11067   fk_env_options(d);
11068   fk_define_all(d);
11069 
11070   do
11071   {
11072     (void)fk_drop_all(d, pNdb, true);
11073 
11074     for (int loop = 0; loop < loops; loop++)
11075     {
11076       g_info << "loop " << loop << "<" << loops << endl;
11077 
11078       CHK1(fk_create_all_random(d, pNdb) == NDBT_OK);
11079       CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11080       CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11081 
11082       CHK1(fk_drop_indexes_under(d, pNdb) == NDBT_OK);
11083       CHK1(fk_drop_tables(d, pNdb, false) == NDBT_OK);
11084 
11085       fk_dropped_all(d);
11086     }
11087     CHK1(result == NDBT_OK);
11088   }
11089   while (0);
11090 
11091   if (result != NDBT_OK)
11092   {
11093     if (!d.nodrop)
11094       (void)fk_drop_all(d, pNdb, true);
11095   }
11096   return result;
11097 }
11098 
11099 #undef myRandom48
11100 #undef myRandom48Init
11101 
11102 int
runDictTO_1(NDBT_Context * ctx,NDBT_Step * step)11103 runDictTO_1(NDBT_Context* ctx, NDBT_Step* step)
11104 {
11105   Ndb* pNdb = GETNDB(step);
11106   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11107   NdbRestarter restarter;
11108 
11109   if (restarter.getNumDbNodes() < 3)
11110     return NDBT_OK;
11111 
11112   for (int i = 0; i < ctx->getNumLoops(); i++)
11113   {
11114     int master = restarter.getMasterNodeId();
11115     int next = restarter.getNextMasterNodeId(master);
11116     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
11117 
11118     restarter.dumpStateOneNode(master, val2, 2);
11119     restarter.insertError2InNode(master, 6050, next);
11120 
11121     ndbout_c("master: %d next: %d", master, next);
11122     {
11123       g_info << "save all resource usage" << endl;
11124       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
11125       restarter.dumpStateAllNodes(dump1, 1);
11126     }
11127 
11128 
11129     {
11130       if (pDic->beginSchemaTrans() != 0)
11131       {
11132         ndbout << "ERROR: line: " << __LINE__ << endl;
11133         ndbout << pDic->getNdbError();
11134         return NDBT_FAILED;
11135       }
11136       for (int j = 0; j < (i + 1); j++)
11137       {
11138         NdbDictionary::Table pTab(* ctx->getTab());
11139         pTab.setName(BaseString(pTab.getName()).appfmt("_EXTRA_%u", j).c_str());
11140 
11141         if (pDic->createTable(pTab) != 0)
11142         {
11143           ndbout << "ERROR: line: " << __LINE__ << endl;
11144           ndbout << pDic->getNdbError();
11145           return NDBT_FAILED;
11146         }
11147       }
11148 
11149       // this should give master failuer...but trans should rollforward
11150       if (pDic->endSchemaTrans() != 0)
11151       {
11152         ndbout << "ERROR: line: " << __LINE__ << endl;
11153         ndbout << pDic->getNdbError();
11154         return NDBT_FAILED;
11155       }
11156     }
11157 
11158     for (int j = 0; j < (i + 1); j++)
11159     {
11160       pDic->dropTable(BaseString(ctx->getTab()->getName()).appfmt("_EXTRA_%u", j).c_str());
11161     }
11162 
11163     {
11164       g_info << "check all resource usage" << endl;
11165       for (int j = 0; j < restarter.getNumDbNodes(); j++)
11166       {
11167         if (restarter.getDbNodeId(j) == master)
11168           continue;
11169 
11170         int dump1[] = { DumpStateOrd::SchemaResourceCheckLeak };
11171         restarter.dumpStateOneNode(restarter.getDbNodeId(j), dump1, 1);
11172       }
11173     }
11174 
11175     restarter.waitNodesNoStart(&master, 1);
11176     restarter.startNodes(&master, 1);
11177     restarter.waitClusterStarted();
11178   }
11179 
11180   return NDBT_OK;
11181 }
11182 
11183 NDBT_TESTSUITE(testDict);
11184 TESTCASE("testDropDDObjects",
11185          "* 1. start cluster\n"
11186          "* 2. Create LFG\n"
11187          "* 3. create TS\n"
11188          "* 4. run DropDDObjects\n"
11189          "* 5. Verify DropDDObjectsRestart worked\n"){
11190 INITIALIZER(runWaitStarted);
11191 INITIALIZER(runDropDDObjects);
11192 INITIALIZER(testDropDDObjectsSetup);
11193 STEP(runDropDDObjects);
11194 FINALIZER(DropDDObjectsVerify);
11195 }
11196 
11197 TESTCASE("Bug29501",
11198          "* 1. start cluster\n"
11199          "* 2. Restart 1 node -abort -nostart\n"
11200          "* 3. create LFG\n"
11201          "* 4. Restart data node\n"
11202          "* 5. Restart 1 node -nostart\n"
11203          "* 6. Drop LFG\n"){
11204 INITIALIZER(runWaitStarted);
11205 INITIALIZER(runDropDDObjects);
11206 STEP(runBug29501);
11207 FINALIZER(runDropDDObjects);
11208 }
11209 TESTCASE("CreateAndDrop",
11210 	 "Try to create and drop the table loop number of times\n"){
11211   INITIALIZER(runCreateAndDrop);
11212 }
11213 TESTCASE("CreateAndDropAtRandom",
11214 	 "Try to create and drop table at random loop number of times\n"
11215          "Uses all available tables\n"
11216          "Uses error insert 4013 to make TUP verify table descriptor"){
11217   INITIALIZER(runCreateAndDropAtRandom);
11218 }
11219 TESTCASE("CreateAndDropIndexes",
11220 	 "Like CreateAndDropAtRandom but also creates random ordered\n"
11221          "indexes and loads data as a simple check of index operation"){
11222   TC_PROPERTY("CreateIndexes", 1);
11223   TC_PROPERTY("LoadData", 1);
11224   INITIALIZER(runCreateAndDropAtRandom);
11225 }
11226 TESTCASE("CreateAndDropWithData",
11227 	 "Try to create and drop the table when it's filled with data\n"
11228 	 "do this loop number of times\n"){
11229   INITIALIZER(runCreateAndDropWithData);
11230 }
11231 TESTCASE("CreateAndDropDuring",
11232 	 "Try to create and drop the table when other thread is using it\n"
11233 	 "do this loop number of times\n"){
11234   STEP(runCreateAndDropDuring);
11235   STEP(runUseTableUntilStopped);
11236 }
11237 TESTCASE("DropWithTakeover","bug 14190114"){
11238   INITIALIZER(runDropTakeoverTest);
11239 }
11240 TESTCASE("CreateInvalidTables",
11241 	 "Try to create the invalid tables we have defined\n"){
11242   INITIALIZER(runCreateInvalidTables);
11243 }
11244 TESTCASE("DropTableConcurrentLCP",
11245          "Drop a table while LCP is ongoing\n")
11246 {
11247   INITIALIZER(runCreateTheTable);
11248   INITIALIZER(runFillTable);
11249   INITIALIZER(runSetMinTimeBetweenLCP);
11250   INITIALIZER(runSetDropTableConcurrentLCP);
11251   INITIALIZER(runDropTheTable);
11252   FINALIZER(runResetMinTimeBetweenLCP);
11253 }
11254 TESTCASE("DropTableConcurrentLCP2",
11255          "Drop a table while LCP is ongoing\n")
11256 {
11257   INITIALIZER(runCreateTheTable);
11258   INITIALIZER(runFillTable);
11259   INITIALIZER(runSetMinTimeBetweenLCP);
11260   INITIALIZER(runSetDropTableConcurrentLCP2);
11261   INITIALIZER(runDropTheTable);
11262   FINALIZER(runResetMinTimeBetweenLCP);
11263 }
11264 TESTCASE("CreateTableWhenDbIsFull",
11265 	 "Try to create a new table when db already is full\n"){
11266   INITIALIZER(runCreateTheTable);
11267   INITIALIZER(runFillTable);
11268   INITIALIZER(runCreateTableWhenDbIsFull);
11269   INITIALIZER(runDropTableWhenDbIsFull);
11270   FINALIZER(runDropTheTable);
11271 }
11272 TESTCASE("FragmentTypeSingle",
11273 	 "Create the table with fragment type Single\n"){
11274   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragSingle);
11275   INITIALIZER(runTestFragmentTypes);
11276 }
11277 TESTCASE("FragmentTypeAllSmall",
11278 	 "Create the table with fragment type AllSmall\n"){
11279   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllSmall);
11280   INITIALIZER(runTestFragmentTypes);
11281 }
11282 TESTCASE("FragmentTypeAllMedium",
11283 	 "Create the table with fragment type AllMedium\n"){
11284   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllMedium);
11285   INITIALIZER(runTestFragmentTypes);
11286 }
11287 TESTCASE("FragmentTypeAllLarge",
11288 	 "Create the table with fragment type AllLarge\n"){
11289   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllLarge);
11290   INITIALIZER(runTestFragmentTypes);
11291 }
11292 TESTCASE("TemporaryTables",
11293 	 "Create the table as temporary and make sure it doesn't\n"
11294 	 "contain any data when system is restarted\n"){
11295   INITIALIZER(runTestTemporaryTables);
11296 }
11297 TESTCASE("CreateMaxTables",
11298 	 "Create tables until db says that it can't create any more\n"){
11299   TC_PROPERTY("tables", 1000);
11300   INITIALIZER(runCreateMaxTables);
11301   INITIALIZER(runDropMaxTables);
11302 }
11303 TESTCASE("PkSizes",
11304 	 "Create tables with all different primary key sizes.\n"\
11305 	 "Test all data operations insert, update, delete etc.\n"\
11306 	 "Drop table."){
11307   INITIALIZER(runPkSizes);
11308 }
11309 TESTCASE("StoreFrm",
11310 	 "Test that a frm file can be properly stored as part of the\n"
11311 	 "data in Dict."){
11312   INITIALIZER(runStoreFrm);
11313 }
11314 TESTCASE("GetPrimaryKey",
11315 	 "Test the function NdbDictionary::Column::getPrimaryKey\n"
11316 	 "It should return true only if the column is part of \n"
11317 	 "the primary key in the table"){
11318   INITIALIZER(runGetPrimaryKey);
11319 }
11320 TESTCASE("StoreFrmError",
11321 	 "Test that a frm file with too long length can't be stored."){
11322   INITIALIZER(runStoreFrmError);
11323 }
11324 TESTCASE("TableRename",
11325 	 "Test basic table rename"){
11326   INITIALIZER(runTableRename);
11327 }
11328 TESTCASE("TableRenameSR",
11329 	 "Test that table rename can handle system restart"){
11330   INITIALIZER(runTableRenameSR);
11331 }
11332 TESTCASE("DictionaryPerf",
11333 	 ""){
11334   INITIALIZER(runTestDictionaryPerf);
11335 }
11336 TESTCASE("CreateLogfileGroup", ""){
11337   INITIALIZER(runCreateLogfileGroup);
11338 }
11339 TESTCASE("CreateTablespace", ""){
11340   INITIALIZER(runCreateTablespace);
11341 }
11342 TESTCASE("CreateDiskTable", ""){
11343   INITIALIZER(runCreateDiskTable);
11344 }
11345 TESTCASE("FailAddFragment",
11346          "Fail add fragment or attribute in ACC or TUP or TUX\n"){
11347   INITIALIZER(runFailAddFragment);
11348 }
11349 TESTCASE("Restart_NF1",
11350          "DICT ops during node graceful shutdown (not master)"){
11351   TC_PROPERTY("Restart_NF_ops", 1);
11352   TC_PROPERTY("Restart_NF_type", 1);
11353   STEP(runRestarts);
11354   STEP(runDictOps);
11355 }
11356 TESTCASE("Restart_NF2",
11357          "DICT ops during node shutdown abort (not master)"){
11358   TC_PROPERTY("Restart_NF_ops", 1);
11359   TC_PROPERTY("Restart_NF_type", 2);
11360   STEP(runRestarts);
11361   STEP(runDictOps);
11362 }
11363 TESTCASE("Restart_NR1",
11364          "DICT ops during node startup (not master)"){
11365   TC_PROPERTY("Restart_NR_ops", 1);
11366   STEP(runRestarts);
11367   STEP(runDictOps);
11368 }
11369 TESTCASE("Restart_NR2",
11370          "DICT ops during node startup with crash inserts (not master)"){
11371   TC_PROPERTY("Restart_NR_ops", 1);
11372   TC_PROPERTY("Restart_NR_error", 1);
11373   STEP(runRestarts);
11374   STEP(runDictOps);
11375 }
11376 TESTCASE("TableAddAttrs",
11377 	 "Add attributes to an existing table using alterTable()"){
11378   INITIALIZER(runTableAddAttrs);
11379 }
11380 TESTCASE("TableAddAttrsDuring",
11381 	 "Try to add attributes to the table when other thread is using it\n"
11382 	 "do this loop number of times\n"){
11383   INITIALIZER(runCreateTheTable);
11384   STEP(runTableAddAttrsDuring);
11385   STEP(runUseTableUntilStopped2);
11386   STEP(runUseTableUntilStopped3);
11387   FINALIZER(runDropTheTable);
11388 }
11389 TESTCASE("TableAddAttrsDuringError",
11390 	 "Try to add attributes to the table when other thread is using it\n"
11391 	 "do this loop number of times\n"){
11392   TC_PROPERTY("AbortAlter", 1);
11393   INITIALIZER(runCreateTheTable);
11394   STEP(runTableAddAttrsDuring);
11395   STEP(runUseTableUntilStopped2);
11396   STEP(runUseTableUntilStopped3);
11397   FINALIZER(runDropTheTable);
11398 }
11399 TESTCASE("Bug21755",
11400          ""){
11401   INITIALIZER(runBug21755);
11402 }
11403 TESTCASE("DictRestart",
11404          ""){
11405   INITIALIZER(runDictRestart);
11406 }
11407 TESTCASE("Bug24631",
11408          ""){
11409   INITIALIZER(runBug24631);
11410 }
11411 TESTCASE("Bug36702", "")
11412 {
11413   INITIALIZER(runDropDDObjects);
11414   INITIALIZER(runBug36072);
11415   FINALIZER(restartClusterInitial);
11416 }
11417 TESTCASE("Bug29186",
11418          ""){
11419   INITIALIZER(runBug29186);
11420 }
11421 TESTCASE("Bug48604",
11422          "Online ordered index build.\n"
11423          "Complements testOIBasic -case f"){
11424   STEP(runBug48604);
11425   STEP(runBug48604ops);
11426 #if 0 // for future MT test
11427   STEP(runBug48604ops);
11428   STEP(runBug48604ops);
11429   STEP(runBug48604ops);
11430 #endif
11431 }
11432 TESTCASE("Bug54651", ""){
11433   INITIALIZER(runBug54651);
11434 }
11435 /** telco-6.4 **/
11436 TESTCASE("SchemaTrans",
11437          "Schema transactions"){
11438   ALL_TABLES();
11439   STEP(runSchemaTrans);
11440 }
11441 TESTCASE("FailCreateHashmap",
11442          "Fail create hashmap")
11443 {
11444   INITIALIZER(runFailCreateHashmap);
11445 }
11446 TESTCASE("FailAddPartition",
11447          "Fail add partition")
11448 {
11449   INITIALIZER(runFailAddPartition);
11450 }
11451 TESTCASE("TableAddPartitions",
11452 	 "Add partitions to an existing table using alterTable()"){
11453   INITIALIZER(runTableAddPartition);
11454 }
11455 TESTCASE("Bug41905",
11456 	 ""){
11457   STEP(runBug41905);
11458   STEP(runBug41905getTable);
11459 }
11460 TESTCASE("Bug46552", "")
11461 {
11462   INITIALIZER(runBug46552);
11463 }
11464 TESTCASE("Bug46585", "")
11465 {
11466   INITIALIZER(runWaitStarted);
11467   INITIALIZER(runBug46585);
11468 }
11469 TESTCASE("Bug53944", "")
11470 {
11471   INITIALIZER(runBug53944);
11472 }
11473 TESTCASE("Bug58277",
11474          "Dropping busy ordered index can crash data node.\n"
11475          "Give any tablename as argument (T1)"){
11476   TC_PROPERTY("RSS_CHECK", (Uint32)true);
11477   TC_PROPERTY("RANGE_MAX", (Uint32)5);
11478   INITIALIZER(runBug58277errtest);
11479   STEP(runBug58277);
11480   // sub-steps 2-8 synced with main step
11481   TC_PROPERTY("SubSteps", 7);
11482   STEP(runBug58277drop);
11483   /*
11484    * A single scan update can show the bug but this is not likely.
11485    * Add more scan updates.  Also add PK ops for other asserts.
11486    */
11487   STEP(runBug58277scan);
11488   STEP(runBug58277scan);
11489   STEP(runBug58277scan);
11490   STEP(runBug58277scan);
11491   STEP(runBug58277pk);
11492   STEP(runBug58277pk);
11493   // kernel side scans (eg. LCP) for resource usage check
11494   STEP(runBug58277rand);
11495 }
11496 TESTCASE("Bug57057",
11497          "MRR + delete leaks stored procs (fixed under Bug58277).\n"
11498          "Give any tablename as argument (T1)"){
11499   TC_PROPERTY("RSS_CHECK", (Uint32)true);
11500   TC_PROPERTY("RANGE_MAX", (Uint32)100);
11501   TC_PROPERTY("SCAN_DELETE", (Uint32)1);
11502   STEP(runBug57057);
11503   TC_PROPERTY("SubSteps", 1);
11504   STEP(runBug58277scan);
11505 }
11506 TESTCASE("GetTabInfoRef", "Regression test for bug #14647210 'CAN CRASH ALL "
11507          "NODES EASILY WHEN RESTARTING MORE THAN 6 NODES SIMULTANEOUSLY'"
11508          " (missing handling of GET_TABINFOREF signal).")
11509 {
11510   INITIALIZER(runGetTabInfoRef);
11511 }
11512 TESTCASE("Bug13416603", "")
11513 {
11514   INITIALIZER(runCreateTheTable);
11515   INITIALIZER(runLoadTable);
11516   INITIALIZER(runBug13416603);
11517   FINALIZER(runDropTheTable);
11518 }
11519 TESTCASE("IndexStatCreate", "")
11520 {
11521   STEPS(runIndexStatCreate, 10);
11522 }
11523 TESTCASE("WL946",
11524          "Time types with fractional seconds.\n"
11525          "Give any tablename as argument (T1)"){
11526   INITIALIZER(runWL946);
11527 }
11528 TESTCASE("Bug14645319", "")
11529 {
11530   STEP(runBug14645319);
11531 }
11532 TESTCASE("FK_SRNR1",
11533          "Foreign keys SR/NR, simple case with DDL and DML checks.\n"
11534          "Give any tablename as argument (T1)"){
11535   TC_PROPERTY("testcase", 1);
11536   INITIALIZER(runFK_SRNR);
11537 }
11538 TESTCASE("FK_SRNR2",
11539          "Foreign keys SR/NR, complex case with DDL checks .\n"
11540          "Give any tablename as argument (T1)"){
11541   TC_PROPERTY("testcase", 2);
11542   INITIALIZER(runFK_SRNR);
11543 }
11544 TESTCASE("FK_TRANS1",
11545          "Foreign keys schema trans, simple case with DDL and DML checks.\n"
11546          "Give any tablename as argument (T1)"){
11547   TC_PROPERTY("testcase", 1);
11548   INITIALIZER(runFK_TRANS);
11549 }
11550 TESTCASE("FK_TRANS2",
11551          "Foreign keys schema trans, complex case with DDL checks.\n"
11552          "Give any tablename as argument (T1)"){
11553   TC_PROPERTY("testcase", 2);
11554   INITIALIZER(runFK_TRANS);
11555 }
11556 TESTCASE("FK_Bug18069680",
11557          "NDB API drop table with foreign keys.\n"
11558          "Give any tablename as argument (T1)"){
11559   TC_PROPERTY("testcase", 2);
11560   INITIALIZER(runFK_Bug18069680);
11561 }
11562 TESTCASE("CreateHashmaps",
11563          "Create (default) hashmaps")
11564 {
11565   INITIALIZER(runCreateHashmaps);
11566 }
11567 TESTCASE("DictTakeOver_1", "")
11568 {
11569   INITIALIZER(runDictTO_1);
11570 }
11571 NDBT_TESTSUITE_END(testDict);
11572 
main(int argc,const char ** argv)11573 int main(int argc, const char** argv){
11574   ndb_init();
11575   NDBT_TESTSUITE_INSTANCE(testDict);
11576   // Tables should not be auto created
11577   testDict.setCreateTable(false);
11578   myRandom48Init((long)NdbTick_CurrentMillisecond());
11579   return testDict.execute(argc, argv);
11580 }
11581