1 /*
2    Copyright (c) 2003, 2020 Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <NDBT.hpp>
26 #include <NDBT_Test.hpp>
27 #include <HugoTransactions.hpp>
28 #include <UtilTransactions.hpp>
29 #include <NdbRestarter.hpp>
30 #include <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 <NdbBackup.hpp>
39 #include <NdbSqlUtil.hpp>
40 #include <NdbEnv.h>
41 #include <NdbHost.h>
42 #include <ndb_rand.h>
43 #include <Bitmask.hpp>
44 #include <../src/kernel/ndbd.hpp>
45 #include <NdbMgmd.hpp>
46 
47 #define ERR_INSERT_MASTER_FAILURE1 6013
48 #define ERR_INSERT_MASTER_FAILURE2 6014
49 #define ERR_INSERT_MASTER_FAILURE3 6015
50 
51 #define ERR_INSERT_PARTIAL_START_FAIL 6140
52 #define ERR_INSERT_PARTIAL_PARSE_FAIL 6141
53 #define ERR_INSERT_PARTIAL_FLUSH_PREPARE_FAIL 6142
54 #define ERR_INSERT_PARTIAL_PREPARE_FAIL 6143
55 #define ERR_INSERT_PARTIAL_ABORT_PARSE_FAIL 6144
56 #define ERR_INSERT_PARTIAL_ABORT_PREPARE_FAIL 6145
57 #define ERR_INSERT_PARTIAL_FLUSH_COMMIT_FAIL 6146
58 #define ERR_INSERT_PARTIAL_COMMIT_FAIL 6147
59 #define ERR_INSERT_PARTIAL_FLUSH_COMPLETE_FAIL 6148
60 #define ERR_INSERT_PARTIAL_COMPLETE_FAIL 6149
61 #define ERR_INSERT_PARTIAL_END_FAIL 6150
62 
63 #define FAIL_BEGIN 0
64 #define FAIL_CREATE 1
65 #define FAIL_END 2
66 #define SUCCEED_COMMIT 3
67 #define SUCCEED_ABORT 4
68 
69 #define ndb_master_failure 1
70 #define NO_NODE_GROUP int(-1)
71 #define FREE_NODE_GROUP 65535
72 
73 #define TEST_FRM_DATA_SIZE 14000
74 
75 static int numNodeGroups;
76 static int numNoNodeGroups;
77 static int nodeGroup[MAX_NDB_NODE_GROUPS];
78 static int nodeGroupIds[MAX_NDB_NODE_GROUPS];
79 
getNodeGroups(NdbRestarter & restarter)80 void getNodeGroups(NdbRestarter & restarter)
81 {
82   Uint32 nextFreeNodeGroup = 0;
83 
84   numNoNodeGroups = 0;
85   for (Uint32 i = 0; i < MAX_NDB_NODE_GROUPS; i++)
86   {
87     nodeGroup[i] = NO_NODE_GROUP;
88     nodeGroupIds[i] = NO_NODE_GROUP;
89   }
90 
91   int numDbNodes = restarter.getNumDbNodes();
92   for (int i = 0; i < numDbNodes; i++)
93   {
94     int nodeId = restarter.getDbNodeId(i);
95     ndbout_c("nodeId: %d", nodeId);
96     require(nodeId != -1);
97     int nodeGroupId = restarter.getNodeGroup(nodeId);
98     ndbout_c("nodeGroupId: %d", nodeGroupId);
99     require(nodeGroupId != -1);
100     nodeGroup[nodeId] = nodeGroupId;
101     if (nodeGroupId == FREE_NODE_GROUP)
102     {
103       numNoNodeGroups++;
104     }
105     else
106     {
107       bool found = false;
108       for (Uint32 i = 0; i < nextFreeNodeGroup; i++)
109       {
110         if (nodeGroupIds[i] == nodeGroupId)
111         {
112           found = true;
113           break;
114         }
115       }
116       if (!found)
117       {
118         nodeGroupIds[nextFreeNodeGroup++] = nodeGroupId;
119       }
120     }
121   }
122   numNodeGroups = nextFreeNodeGroup;
123 }
124 
125 char f_tablename[256];
126 
127 #define CHECK(b) if (!(b)) { \
128   g_err << "ERR: "<< step->getName() \
129          << " failed on line " << __LINE__ << endl; \
130   result = NDBT_FAILED; \
131   break; }
132 
133 #define CHECK2(b, c) if (!(b)) { \
134   g_err << "ERR: "<< step->getName() \
135          << " failed on line " << __LINE__ << ": " << c << endl; \
136   result = NDBT_FAILED; \
137   goto end; }
138 
139 #define CHECK3(b, c) if (!(b)) { \
140   g_err << "ERR: "<< step->getName() \
141          << " failed on line " << __LINE__ << ": " << c << endl; \
142   return NDBT_FAILED; }
143 
144 
runLoadTable(NDBT_Context * ctx,NDBT_Step * step)145 int runLoadTable(NDBT_Context* ctx, NDBT_Step* step){
146   Ndb* pNdb = GETNDB(step);
147   int records = ctx->getNumRecords();
148   HugoTransactions hugoTrans(*ctx->getTab());
149   if (hugoTrans.loadTable(pNdb, records) != 0){
150     return NDBT_FAILED;
151   }
152   return NDBT_OK;
153 }
154 
runCreateInvalidTables(NDBT_Context * ctx,NDBT_Step * step)155 int runCreateInvalidTables(NDBT_Context* ctx, NDBT_Step* step){
156   Ndb* pNdb = GETNDB(step);
157   int result = NDBT_OK;
158 
159   char failTabName[256];
160 
161   const int expectedDictErrors[6]= {720,
162                                     4317,
163                                     737,
164                                     739,
165                                     736,
166                                     740 };
167 
168   for (int i = 0; i < 10; i++){
169     BaseString::snprintf(failTabName, 256, "F%d", i);
170 
171     const NdbDictionary::Table* pFailTab = NDBT_Tables::getTable(failTabName);
172     if (pFailTab != NULL){
173       ndbout << "|- " << failTabName << endl;
174 
175       // Try to create table in db
176       if (pFailTab->createTableInDb(pNdb) == 0){
177         ndbout << failTabName << " created, this was not expected"<< endl;
178         result = NDBT_FAILED;
179       }
180 
181       // Ensure any error is roughly as expected
182       int errorCode=pNdb->getDictionary()->getNdbError().code;
183       bool errorOk= false;
184       for (int e=0; e < 6; e++)
185         errorOk |= (errorCode == expectedDictErrors[e]);
186 
187       if (!errorOk)
188       {
189         ndbout << "Failure, got dict error : " << pNdb->getDictionary()->
190           getNdbError().code << endl;
191         return NDBT_FAILED;
192       }
193 
194       // Verify that table is not in db
195       const NdbDictionary::Table* pTab2 =
196 	NDBT_Table::discoverTableFromDb(pNdb, failTabName) ;
197       if (pTab2 != NULL){
198         ndbout << failTabName << " was found in DB, this was not expected"<< endl;
199         result = NDBT_FAILED;
200 	if (pFailTab->equal(*pTab2) == true){
201 	  ndbout << "It was equal" << endl;
202 	} else {
203 	  ndbout << "It was not equal" << endl;
204 	}
205 	int records = 1000;
206 	HugoTransactions hugoTrans(*pTab2);
207 	if (hugoTrans.loadTable(pNdb, records) != 0){
208 	  ndbout << "It can NOT be loaded" << endl;
209 	} else{
210 	  ndbout << "It can be loaded" << endl;
211 
212 	  UtilTransactions utilTrans(*pTab2);
213 	  if (utilTrans.clearTable(pNdb, records, 64) != 0){
214 	    ndbout << "It can NOT be cleared" << endl;
215 	  } else{
216 	    ndbout << "It can be cleared" << endl;
217 	  }
218 	}
219 
220 	if (pNdb->getDictionary()->dropTable(pTab2->getName()) == -1){
221 	  ndbout << "It can NOT be dropped" << endl;
222 	} else {
223 	  ndbout << "It can be dropped" << endl;
224 	}
225       }
226     }
227   }
228   return result;
229 }
230 
runCreateTheTable(NDBT_Context * ctx,NDBT_Step * step)231 int runCreateTheTable(NDBT_Context* ctx, NDBT_Step* step){
232   Ndb* pNdb = GETNDB(step);
233   const NdbDictionary::Table* pTab = ctx->getTab();
234 
235   // Try to create table in db
236   if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
237     return NDBT_FAILED;
238   }
239 
240   // Verify that table is in db
241   const NdbDictionary::Table* pTab2 =
242     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
243   if (pTab2 == NULL){
244     ndbout << pTab->getName() << " was not found in DB"<< endl;
245     return NDBT_FAILED;
246   }
247   ctx->setTab(pTab2);
248 
249   BaseString::snprintf(f_tablename, sizeof(f_tablename),
250                        "%s", pTab->getName());
251 
252   return NDBT_OK;
253 }
254 
runDropTheTable(NDBT_Context * ctx,NDBT_Step * step)255 int runDropTheTable(NDBT_Context* ctx, NDBT_Step* step){
256   Ndb* pNdb = GETNDB(step);
257 
258   // Drop table
259   pNdb->getDictionary()->dropTable(f_tablename);
260 
261   return NDBT_OK;
262 }
263 
runCreateTheIndex(NDBT_Context * ctx,NDBT_Step * step)264 int runCreateTheIndex(NDBT_Context* ctx, NDBT_Step* step){
265   Ndb* pNdb = GETNDB(step);
266   const NdbDictionary::Table* pTab = ctx->getTab();
267   char idxname[20];
268   sprintf(idxname, "%s_idx", pTab->getName());
269   NdbDictionary::Index idx(idxname);
270   idx.setTable(pTab->getName());
271   idx.setType(NdbDictionary::Index::OrderedIndex);
272   idx.setLogging(false);
273   for (int c = 0; c< pTab->getNoOfColumns(); c++)
274   {
275     const NdbDictionary::Column * col = pTab->getColumn(c);
276     if (col->getPrimaryKey())
277       idx.addIndexColumn(col->getName());
278   }
279 
280   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
281   if(pDict->createIndex(idx) != 0)
282   {
283     ndbout << "Failed to create index" << endl;
284     return NDBT_FAILED;
285   }
286   return NDBT_OK;
287 }
288 
runDropTheIndex(NDBT_Context * ctx,NDBT_Step * step)289 int runDropTheIndex(NDBT_Context* ctx, NDBT_Step* step){
290   Ndb* pNdb = GETNDB(step);
291   const NdbDictionary::Table* pTab = ctx->getTab();
292   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
293   char idxname[20];
294   sprintf(idxname, "%s_idx", pTab->getName());
295   if(pDict->dropIndex(idxname, pTab->getName()) != 0)
296   {
297     ndbout << "Failed to drop index" << endl;
298     return NDBT_FAILED;
299   }
300   return NDBT_OK;
301 }
302 
runSetDropTableConcurrentLCP(NDBT_Context * ctx,NDBT_Step * step)303 int runSetDropTableConcurrentLCP(NDBT_Context *ctx, NDBT_Step *step)
304 {
305   NdbRestarter restarter;
306   if(restarter.insertErrorInAllNodes(5088) != 0)
307   {
308     g_err << "failed to set error insert"<< endl;
309     return NDBT_FAILED;
310   }
311   return NDBT_OK;
312 }
313 
runSetMinTimeBetweenLCP(NDBT_Context * ctx,NDBT_Step * step)314 int runSetMinTimeBetweenLCP(NDBT_Context *ctx, NDBT_Step *step)
315 {
316   NdbRestarter restarter;
317   int result;
318   int val = DumpStateOrd::DihMinTimeBetweenLCP;
319   if (restarter.dumpStateAllNodes(&val, 1) != 0)
320   {
321     do { CHECK(0); } while(0);
322     g_err << "Failed to set LCP to min value" << endl;
323     return NDBT_FAILED;
324   }
325   return NDBT_OK;
326 }
327 
runResetMinTimeBetweenLCP(NDBT_Context * ctx,NDBT_Step * step)328 int runResetMinTimeBetweenLCP(NDBT_Context *ctx, NDBT_Step *step)
329 {
330   NdbRestarter restarter;
331   int result;
332   int val2[] = { DumpStateOrd::DihMinTimeBetweenLCP, 0 };
333   if (restarter.dumpStateAllNodes(val2, 2) != 0)
334   {
335     do { CHECK(0); } while(0);
336     g_err << "Failed to set LCP to min value" << endl;
337     return NDBT_FAILED;
338   }
339   return NDBT_OK;
340 }
341 
runSetDropTableConcurrentLCP2(NDBT_Context * ctx,NDBT_Step * step)342 int runSetDropTableConcurrentLCP2(NDBT_Context *ctx, NDBT_Step *step)
343 {
344   NdbRestarter restarter;
345   if(restarter.insertErrorInAllNodes(5089) != 0)
346   {
347     g_err << "failed to set error insert"<< endl;
348     return NDBT_FAILED;
349   }
350   return NDBT_OK;
351 }
352 
353 /*******
354  * Precondition:
355  *    'DataMemory' has been filled until insertion failed
356  *    due to 'DbIsFull'. The table 'TRANSACTION' should
357  *    not exist in the DB
358  *
359  * Test:
360  *    Creation of the (empty) table 'TRANSACTION'
361  *    should succeed even if 'DbIsFull'. Or it could fail
362  *    due to memory for hash index.  If succeed however,
363  *    insertion of the first row should fail.
364  *
365  * Postcond:
366  *    The created table 'TRANSACTION is removed.
367  *    DataMemory is still full.
368  */
runCreateTableWhenDbIsFull(NDBT_Context * ctx,NDBT_Step * step)369 int runCreateTableWhenDbIsFull(NDBT_Context* ctx, NDBT_Step* step){
370   Ndb* pNdb = GETNDB(step);
371   int result = NDBT_OK;
372   const char* tabName = "TRANSACTION"; //Use a util table
373 
374   // Precondition is that 'DataMemory' filled to max.
375   // So we skip test if a DiskStorage table was filled
376   for (Uint32 i = 0; i<(Uint32)ctx->getTab()->getNoOfColumns(); i++)
377   {
378     if (ctx->getTab()->getColumn(i)->getStorageType() ==
379         NdbDictionary::Column::StorageTypeDisk)
380     {
381       ndbout << "Skip test for *disk* tables" << endl;
382       return NDBT_OK;
383     }
384   }
385 
386   const NdbDictionary::Table* pTab = NDBT_Tables::getTable(tabName);
387   while (pTab != NULL){ //Always 'break' without looping
388     ndbout << "|- " << tabName << endl;
389 
390     // Verify that table is not in db
391     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) != NULL){
392       ndbout << tabName << " was found in DB"<< endl;
393       result = NDBT_FAILED;
394       break;
395     }
396 
397     /*
398      * Create (empty) table in db, should succeed even if 'DbIsFull' or fail
399      * with 625:
400      * Out of memory in Ndb Kernel, hash index part (increase DataMemory).
401      */
402     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0)
403     {
404       if (pNdb->getDictionary()->getNdbError().code == 625)
405       {
406         /*
407          * Fail due to really out of data memory, not even a hash index page
408          * available.
409          */
410         result = NDBT_OK;
411         break;
412       }
413 
414       ndbout << tabName << " was not created when DB is full" << endl;
415       result = NDBT_FAILED;
416       break;
417     }
418 
419     // Verify that table is now in db
420     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) == NULL){
421       ndbout << tabName << " was not visible in DB"<< endl;
422       result = NDBT_FAILED;
423       break;
424     }
425 
426     // As 'DbIsFull', insert of a single record should fail
427     HugoOperations hugoOps(*pTab);
428     CHECK(hugoOps.startTransaction(pNdb) == 0);
429     CHECK(hugoOps.pkInsertRecord(pNdb, 1) == 0);
430     CHECK(hugoOps.execute_Commit(pNdb) != 0); //Should fail
431     CHECK(hugoOps.closeTransaction(pNdb) == 0);
432 
433     break;
434   }
435 
436   // Drop table (if exist, so we dont care about errors)
437   pNdb->getDictionary()->dropTable(tabName);
438   return result;
439 }
440 
runDropTableWhenDbIsFull(NDBT_Context * ctx,NDBT_Step * step)441 int runDropTableWhenDbIsFull(NDBT_Context* ctx, NDBT_Step* step){
442   Ndb* pNdb = GETNDB(step);
443   int result = NDBT_OK;
444   const char* tabName = "TRANSACTION"; //Use a util table
445 
446   const NdbDictionary::Table* pTab = NDBT_Table::discoverTableFromDb(pNdb, tabName);
447   if (pTab != NULL){
448     ndbout << "|- TRANSACTION" << endl;
449 
450     // Try to drop table in db
451     if (pNdb->getDictionary()->dropTable(pTab->getName()) == -1){
452       result = NDBT_FAILED;
453     }
454 
455     // Verify that table is not in db
456     if (NDBT_Table::discoverTableFromDb(pNdb, tabName) != NULL){
457       ndbout << tabName << " was found in DB"<< endl;
458       result = NDBT_FAILED;
459     }
460   }
461 
462   return result;
463 
464 }
465 
466 
runCreateAndDrop(NDBT_Context * ctx,NDBT_Step * step)467 int runCreateAndDrop(NDBT_Context* ctx, NDBT_Step* step){
468   Ndb* pNdb = GETNDB(step);
469   int loops = ctx->getNumLoops();
470   int i = 0;
471 
472   const NdbDictionary::Table* pTab = ctx->getTab();
473   ndbout << "|- " << pTab->getName() << endl;
474 
475   while (i < loops){
476 
477     ndbout << i << ": ";
478     // Try to create table in db
479     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
480       return NDBT_FAILED;
481     }
482 
483     // Verify that table is in db
484     const NdbDictionary::Table* pTab2 =
485       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
486     if (pTab2 == NULL){
487       ndbout << pTab->getName() << " was not found in DB"<< endl;
488       return NDBT_FAILED;
489     }
490 
491     if (pNdb->getDictionary()->dropTable(pTab2->getName())){
492       ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
493       return NDBT_FAILED;
494     }
495 
496     // Verify that table is not in db
497     const NdbDictionary::Table* pTab3 =
498       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
499     if (pTab3 != NULL){
500       ndbout << pTab3->getName() << " was found in DB"<< endl;
501       return NDBT_FAILED;
502     }
503     i++;
504   }
505 
506   return NDBT_OK;
507 }
508 
runCreateAndDropAtRandom(NDBT_Context * ctx,NDBT_Step * step)509 int runCreateAndDropAtRandom(NDBT_Context* ctx, NDBT_Step* step)
510 {
511   myRandom48Init((long)NdbTick_CurrentMillisecond());
512   Ndb* pNdb = GETNDB(step);
513   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
514   int loops = ctx->getNumLoops();
515   int records = ctx->getNumRecords();
516 
517   int numAllTables = NDBT_Tables::getNumTables();
518   struct TabList {
519     int exists; // -1 = skip, 0 = no, 1 = yes
520     const NdbDictionary::Table* pTab; // retrieved
521     TabList() { exists = -1; pTab = 0; }
522   };
523   TabList* tabList = new TabList [ numAllTables ];
524   int numTables = 0;
525   int num;
526   for (num = 0; num < numAllTables; num++) {
527     const NdbDictionary::Table* pTab = NDBT_Tables::getTable(num);
528     if (pTab->checkColumns(0, 0) & 2) // skip disk
529       continue;
530     tabList[num].exists = 0;
531     (void)pDic->dropTable(pTab->getName());
532     numTables++;
533   }
534   int numExists = 0;
535 
536   const bool createIndexes = ctx->getProperty("CreateIndexes");
537   const bool loadData = ctx->getProperty("LoadData");
538 
539   NdbRestarter restarter;
540   int result = NDBT_OK;
541   int bias = 1; // 0-less 1-more
542   int i = 0;
543 
544   while (i < loops && result == NDBT_OK) {
545     num = myRandom48(numAllTables);
546     if (tabList[num].exists == -1)
547       continue;
548     g_info << "loop " << i << " tabs " << numExists << "/" << numTables << endl;
549     const NdbDictionary::Table* pTab = NDBT_Tables::getTable(num);
550     char tabName[200];
551     strcpy(tabName, pTab->getName());
552 
553     if (tabList[num].exists == 0) {
554       if (bias == 0 && myRandom48(100) < 80)
555         continue;
556       g_info << tabName << ": create" << endl;
557       if (pDic->createTable(*pTab) != 0) {
558         const NdbError err = pDic->getNdbError();
559         g_err << tabName << ": create failed: " << err << endl;
560         result = NDBT_FAILED;
561         break;
562       }
563       const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
564       if (pTab2 == NULL) {
565         const NdbError err = pDic->getNdbError();
566         g_err << tabName << ": verify create failed: " << err << endl;
567         result = NDBT_FAILED;
568         break;
569       }
570       tabList[num].pTab = pTab2;
571       if (loadData) {
572         g_info << tabName << ": load data" << endl;
573         HugoTransactions hugoTrans(*pTab2);
574         if (hugoTrans.loadTable(pNdb, records) != 0) {
575           g_err << tabName << ": loadTable failed" << endl;
576           result = NDBT_FAILED;
577           break;
578         }
579       }
580       if (createIndexes) {
581         int icount = myRandom48(10);
582         int inum;
583         for (inum = 0; inum < icount; inum++) {
584           const int tcols = pTab2->getNoOfColumns();
585           require(tcols != 0);
586           int icols = 1 + myRandom48(tcols);
587           if (icols > NDB_MAX_ATTRIBUTES_IN_INDEX)
588             icols = NDB_MAX_ATTRIBUTES_IN_INDEX;
589           char indName[256];
590           sprintf(indName, "%s_X%d", tabName, inum);
591           NdbDictionary::Index ind(indName);
592           ind.setTable(tabName);
593           ind.setType(NdbDictionary::Index::OrderedIndex);
594           ind.setLogging(false);
595           Bitmask<MAX_ATTRIBUTES_IN_TABLE> mask;
596           char ilist[200];
597           ilist[0] = 0;
598           int ic;
599           for (ic = 0; ic < icols; ic++) {
600             int tc = myRandom48(tcols);
601             const NdbDictionary::Column* c = pTab2->getColumn(tc);
602             require(c != 0);
603             if (mask.get(tc) ||
604                 c->getType() == NdbDictionary::Column::Blob ||
605                 c->getType() == NdbDictionary::Column::Text ||
606                 c->getType() == NdbDictionary::Column::Bit ||
607                 c->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
608               continue;
609             ind.addColumn(*c);
610             mask.set(tc);
611             sprintf(ilist + strlen(ilist), " %d", tc);
612           }
613           if (mask.isclear())
614             continue;
615           g_info << indName << ": columns:" << ilist << endl;
616           if (pDic->createIndex(ind) == 0) {
617             g_info << indName << ": created" << endl;
618           } else {
619             const NdbError err = pDic->getNdbError();
620             g_err << indName << ": create index failed: " << err << endl;
621             if (err.code != 826 && // Too many tables and attributes..
622                 err.code != 903 && // Too many ordered indexes..
623                 err.code != 904 && // Out of fragment records..
624                 err.code != 905 && // Out of attribute records..
625                 err.code != 707 && // No more table metadata records..
626                 err.code != 708)   // No more attribute metadata records..
627             {
628               result = NDBT_FAILED;
629               break;
630             }
631           }
632         }
633       }
634       if (loadData) {
635         // first update a random table to flush global variables
636         int num3 = 0;
637         while (1) {
638           num3 = myRandom48(numAllTables);
639           if (num == num3 || tabList[num3].exists == 1)
640             break;
641         }
642         const NdbDictionary::Table* pTab3 = tabList[num3].pTab;
643         require(pTab3 != 0);
644         char tabName3[200];
645         strcpy(tabName3, pTab3->getName());
646         HugoTransactions hugoTrans(*pTab3);
647         g_info << tabName3 << ": update data" << endl;
648         if (hugoTrans.pkUpdateRecords(pNdb, records) != 0) {
649           g_err << tabName3 << ": pkUpdateRecords failed" << endl;
650           result = NDBT_FAILED;
651           break;
652         }
653       }
654       if (loadData) {
655         HugoTransactions hugoTrans(*pTab2);
656         g_info << tabName << ": update data" << endl;
657         if (hugoTrans.pkUpdateRecords(pNdb, records) != 0) {
658           g_err << "pkUpdateRecords failed" << endl;
659           result = NDBT_FAILED;
660           break;
661         }
662       }
663       tabList[num].exists = 1;
664       require(numExists < numTables);
665       numExists++;
666       if (numExists == numTables)
667         bias = 0;
668     }
669     else if (tabList[num].exists == 1) {
670       if (bias == 1 && myRandom48(100) < 80)
671         continue;
672       g_info << tabName << ": drop" << endl;
673       if (restarter.insertErrorInAllNodes(4013) != 0) {
674         g_err << "error insert failed" << endl;
675         result = NDBT_FAILED;
676         break;
677       }
678       if (pDic->dropTable(tabName) != 0) {
679         const NdbError err = pDic->getNdbError();
680         g_err << tabName << ": drop failed: " << err << endl;
681         result = NDBT_FAILED;
682         break;
683       }
684       const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
685       if (pTab2 != NULL) {
686         g_err << tabName << ": verify drop: table exists" << endl;
687         result = NDBT_FAILED;
688         break;
689       }
690       if (pDic->getNdbError().code != 709 &&
691           pDic->getNdbError().code != 723) {
692         const NdbError err = pDic->getNdbError();
693         g_err << tabName << ": verify drop: " << err << endl;
694         result = NDBT_FAILED;
695         break;
696       }
697       tabList[num].exists = 0;
698       require(numExists > 0);
699       numExists--;
700       if (numExists == 0)
701         bias = 1;
702     }
703     i++;
704   }
705 
706   for (num = 0; num < numAllTables; num++)
707     if (tabList[num].exists == 1)
708       pDic->dropTable(NDBT_Tables::getTable(num)->getName());
709 
710   delete [] tabList;
711   return result;
712 }
713 
714 
runCreateAndDropWithData(NDBT_Context * ctx,NDBT_Step * step)715 int runCreateAndDropWithData(NDBT_Context* ctx, NDBT_Step* step){
716   Ndb* pNdb = GETNDB(step);
717   int loops = ctx->getNumLoops();
718   int records = ctx->getNumRecords();
719   int i = 0;
720 
721   NdbRestarter restarter;
722   int val = DumpStateOrd::DihMinTimeBetweenLCP;
723   if(restarter.dumpStateAllNodes(&val, 1) != 0){
724     int result;
725     do { CHECK(0); } while (0);
726     g_err << "Unable to change timebetween LCP" << endl;
727     return NDBT_FAILED;
728   }
729 
730   const NdbDictionary::Table* pTab = ctx->getTab();
731   ndbout << "|- " << pTab->getName() << endl;
732 
733   while (i < loops){
734     ndbout << i << ": ";
735     // Try to create table in db
736 
737     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
738       return NDBT_FAILED;
739     }
740 
741     // Verify that table is in db
742     const NdbDictionary::Table* pTab2 =
743       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
744     if (pTab2 == NULL){
745       ndbout << pTab->getName() << " was not found in DB"<< endl;
746       return NDBT_FAILED;
747     }
748 
749     HugoTransactions hugoTrans(*pTab2);
750     if (hugoTrans.loadTable(pNdb, records) != 0){
751       return NDBT_FAILED;
752     }
753 
754     int count = 0;
755     UtilTransactions utilTrans(*pTab2);
756     if (utilTrans.selectCount(pNdb, 64, &count) != 0){
757       return NDBT_FAILED;
758     }
759     if (count != records){
760       ndbout << count <<" != "<<records << endl;
761       return NDBT_FAILED;
762     }
763 
764     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
765       ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
766       return NDBT_FAILED;
767     }
768 
769     // Verify that table is not in db
770     const NdbDictionary::Table* pTab3 =
771       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
772     if (pTab3 != NULL){
773       ndbout << pTab3->getName() << " was found in DB"<< endl;
774       return NDBT_FAILED;
775     }
776 
777 
778     i++;
779   }
780 
781   return NDBT_OK;
782 }
783 
runFillTable(NDBT_Context * ctx,NDBT_Step * step)784 int runFillTable(NDBT_Context* ctx, NDBT_Step* step){
785   Ndb* pNdb = GETNDB(step);
786   HugoTransactions hugoTrans(*ctx->getTab());
787   if (hugoTrans.fillTable(pNdb) != 0){
788     return NDBT_FAILED;
789   }
790   return NDBT_OK;
791 }
792 
runClearTable(NDBT_Context * ctx,NDBT_Step * step)793 int runClearTable(NDBT_Context* ctx, NDBT_Step* step){
794   Ndb* pNdb = GETNDB(step);
795   int records = ctx->getNumRecords();
796 
797   UtilTransactions utilTrans(*ctx->getTab());
798   if (utilTrans.clearTable(pNdb,  records) != 0){
799     return NDBT_FAILED;
800   }
801   return NDBT_OK;
802 }
803 
runCreateAndDropDuring(NDBT_Context * ctx,NDBT_Step * step)804 int runCreateAndDropDuring(NDBT_Context* ctx, NDBT_Step* step){
805   int result = NDBT_OK;
806   int loops = ctx->getNumLoops();
807   int i = 0;
808 
809   const NdbDictionary::Table* pTab = ctx->getTab();
810   ndbout << "|- " << pTab->getName() << endl;
811 
812   while (i < loops && result == NDBT_OK){
813     ndbout << i << ": " << endl;
814     // Try to create table in db
815 
816     Ndb* pNdb = GETNDB(step);
817     g_debug << "Creating table" << endl;
818 
819     if (NDBT_Tables::createTable(pNdb, pTab->getName()) != 0){
820       g_err << "createTableInDb failed" << endl;
821       result =  NDBT_FAILED;
822       continue;
823     }
824 
825     g_debug << "Verifying creation of table" << endl;
826 
827     // Verify that table is in db
828     const NdbDictionary::Table* pTab2 =
829       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
830     if (pTab2 == NULL){
831       g_err << pTab->getName() << " was not found in DB"<< endl;
832       result =  NDBT_FAILED;
833       continue;
834     }
835 
836     NdbSleep_MilliSleep(3000);
837 
838     g_debug << "Dropping table" << endl;
839 
840     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
841       g_err << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
842       result =  NDBT_FAILED;
843       continue;
844     }
845 
846     g_debug << "Verifying dropping of table" << endl;
847 
848     // Verify that table is not in db
849     const NdbDictionary::Table* pTab3 =
850       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
851     if (pTab3 != NULL){
852       g_err << pTab3->getName() << " was found in DB"<< endl;
853       result =  NDBT_FAILED;
854       continue;
855     }
856     i++;
857   }
858   ctx->stopTest();
859 
860   return result;
861 }
862 
863 
runUseTableUntilStopped(NDBT_Context * ctx,NDBT_Step * step)864 int runUseTableUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
865   int records = ctx->getNumRecords();
866 
867   const NdbDictionary::Table* pTab = ctx->getTab();
868 
869   while (ctx->isTestStopped() == false) {
870     // g_info << i++ << ": ";
871 
872 
873     // Delete and recreate Ndb object
874     // Otherwise you always get Invalid Schema Version
875     // It would be a nice feature to remove this two lines
876     //step->tearDown();
877     //step->setUp();
878 
879     Ndb* pNdb = GETNDB(step);
880 
881     const NdbDictionary::Table* pTab2 =
882       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
883     if (pTab2 == NULL)
884       continue;
885 
886     int res;
887     HugoTransactions hugoTrans(*pTab2);
888     if ((res = hugoTrans.loadTable(pNdb, records)) != 0){
889       NdbError err = pNdb->getNdbError(res);
890       if(err.classification == NdbError::SchemaError){
891 	pNdb->getDictionary()->invalidateTable(pTab->getName());
892       }
893       continue;
894     }
895 
896     if ((res = hugoTrans.clearTable(pNdb,  records)) != 0){
897       NdbError err = pNdb->getNdbError(res);
898       if(err.classification == NdbError::SchemaError){
899 	pNdb->getDictionary()->invalidateTable(pTab->getName());
900       }
901       continue;
902     }
903   }
904   g_info << endl;
905   return NDBT_OK;
906 }
907 
runUseTableUntilStopped2(NDBT_Context * ctx,NDBT_Step * step)908 int runUseTableUntilStopped2(NDBT_Context* ctx, NDBT_Step* step){
909   int records = ctx->getNumRecords();
910 
911   Ndb* pNdb = GETNDB(step);
912   const NdbDictionary::Table* pTab = ctx->getTab();
913   const NdbDictionary::Table* pTab2 =
914     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
915 
916   if (pTab2 == NULL) {
917     g_err << "Table: " << pTab->getName()
918           << ", not 'discovered' on line " << __LINE__
919           << endl;
920     return NDBT_FAILED;
921   }
922   HugoTransactions hugoTrans(*pTab2);
923 
924   int i = 0;
925   while (ctx->isTestStopped() == false)
926   {
927     ndbout_c("loop: %u", i++);
928 
929 
930     // Delete and recreate Ndb object
931     // Otherwise you always get Invalid Schema Version
932     // It would be a nice feature to remove this two lines
933     //step->tearDown();
934     //step->setUp();
935 
936 
937     int res;
938     if ((res = hugoTrans.loadTable(pNdb, records)) != 0){
939       NdbError err = pNdb->getNdbError(res);
940       if(err.classification == NdbError::SchemaError){
941 	pNdb->getDictionary()->invalidateTable(pTab->getName());
942       }
943       continue;
944     }
945 
946     if ((res = hugoTrans.scanUpdateRecords(pNdb, records)) != 0)
947     {
948       NdbError err = pNdb->getNdbError(res);
949       if(err.classification == NdbError::SchemaError){
950 	pNdb->getDictionary()->invalidateTable(pTab->getName());
951       }
952       continue;
953     }
954 
955     if ((res = hugoTrans.clearTable(pNdb,  records)) != 0){
956       NdbError err = pNdb->getNdbError(res);
957       if(err.classification == NdbError::SchemaError){
958 	pNdb->getDictionary()->invalidateTable(pTab->getName());
959       }
960       continue;
961     }
962   }
963   g_info << endl;
964   return NDBT_OK;
965 }
966 
runUseTableUntilStopped3(NDBT_Context * ctx,NDBT_Step * step)967 int runUseTableUntilStopped3(NDBT_Context* ctx, NDBT_Step* step){
968   int records = ctx->getNumRecords();
969 
970   Ndb* pNdb = GETNDB(step);
971   const NdbDictionary::Table* pTab = ctx->getTab();
972   const NdbDictionary::Table* pTab2 =
973     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
974   if (pTab2 == NULL) {
975     g_err << "Table : " << pTab->getName()
976           << ", not 'discovered' on line " << __LINE__
977           << endl;
978     return NDBT_FAILED;
979   }
980   HugoTransactions hugoTrans(*pTab2);
981 
982   int i = 0;
983   while (ctx->isTestStopped() == false)
984   {
985     ndbout_c("loop: %u", i++);
986 
987 
988     // Delete and recreate Ndb object
989     // Otherwise you always get Invalid Schema Version
990     // It would be a nice feature to remove this two lines
991     //step->tearDown();
992     //step->setUp();
993 
994 
995     int res;
996     if ((res = hugoTrans.scanUpdateRecords(pNdb, records)) != 0)
997     {
998       NdbError err = pNdb->getNdbError(res);
999       if(err.classification == NdbError::SchemaError){
1000 	pNdb->getDictionary()->invalidateTable(pTab->getName());
1001       }
1002       continue;
1003     }
1004   }
1005   g_info << endl;
1006   return NDBT_OK;
1007 }
1008 
1009 /**
1010  * This is a regression test for bug 14190114
1011  * "CLUSTER CRASH DUE TO NDBREQUIRE IN ./LOCALPROXY.HPP DBLQH (LINE: 234)".
1012  * This bug occurs if there is a takeover (i.e. the master node crashes)
1013  * while an LQH block is executing a DROP_TAB_REQ signal. It only affects
1014  * multi-threaded ndb.
1015  */
1016 static int
runDropTakeoverTest(NDBT_Context * ctx,NDBT_Step * step)1017 runDropTakeoverTest(NDBT_Context* ctx, NDBT_Step* step)
1018 {
1019   NdbRestarter restarter;
1020   if (restarter.getNumDbNodes() == 1)
1021   {
1022     g_info << "Cannot do this test with just one datanode." << endl;
1023     return NDBT_OK;
1024   }
1025 
1026   Ndb* const ndb = GETNDB(step);
1027   NdbDictionary::Dictionary* const dict = ndb->getDictionary();
1028 
1029   // First we create a table that is a copy of ctx->getTab().
1030   NdbDictionary::Table copyTab(*ctx->getTab());
1031   const char* copyName = "copyTab";
1032 
1033   copyTab.setName(copyName);
1034   if (dict->createTable(copyTab) != 0)
1035   {
1036     g_err << "Failed to create table " << copyName << endl
1037           << dict->getNdbError() << endl;
1038     return NDBT_FAILED;
1039   }
1040 
1041   /**
1042    * Find the node id of the master node and another data node that is not
1043    * the master.
1044    */
1045   const int masterNodeId = restarter.getMasterNodeId();
1046   const int nonMasterNodeId =
1047     masterNodeId == restarter.getDbNodeId(0) ?
1048     restarter.getDbNodeId(1) :
1049     restarter.getDbNodeId(0);
1050 
1051   /**
1052    * This error insert makes LQH resend the DROP_TAB_REQ to itself (with a
1053    * long delay) rather than executing it.
1054    * This makes it appear as if though the LQH block spends a long time
1055    * executing the DROP_TAB_REQ signal.
1056    */
1057   g_info << "Insert error 5076 in node " << nonMasterNodeId << endl;
1058   restarter.insertErrorInNode(nonMasterNodeId, 5076);
1059   /**
1060    * This error insert makes the master node crash when one of its LQH
1061    * blocks tries to execute a DROP_TAB_REQ signal. This will then trigger
1062    * a takeover.
1063    */
1064   g_info << "Insert error 5077 in node " << masterNodeId << endl;
1065   restarter.insertErrorInNode(masterNodeId, 5077);
1066 
1067   // dropTable should succeed with the new master.
1068   g_info << "Trying to drop table " << copyName << endl;
1069   if (dict->dropTable(copyName))
1070   {
1071     g_err << "Unexpectedly failed to drop table " << copyName << endl;
1072     return NDBT_FAILED;
1073   }
1074 
1075   /**
1076    * Check that only old master is dead. Bug 14190114 would cause other nodes
1077    * to die as well.
1078    */
1079   const int deadNodeId = restarter.checkClusterAlive(&masterNodeId, 1);
1080   if (deadNodeId != 0)
1081   {
1082     g_err << "NodeId " << deadNodeId << " is down." << endl;
1083     return NDBT_FAILED;
1084   }
1085 
1086   // Verify that old master comes back up, and that no other node crashed.
1087   g_info << "Waiting for all nodes to be up." << endl;
1088   if (restarter.waitClusterStarted() != 0)
1089   {
1090     g_err << "One or more cluster nodes are not up." << endl;
1091     return NDBT_FAILED;
1092   }
1093   CHK_NDB_READY(ndb);
1094 
1095   /**
1096    * The 'drop table' operation should have been rolled forward, since the
1097    * node crash happened in the complete phase. Verify that the table is
1098    * gone.
1099    */
1100   g_info << "Verifying that table " << copyName << " was deleted." << endl;
1101   if (dict->getTable(copyName) == NULL)
1102   {
1103     if (dict->getNdbError().code != 723) // 723 = no such table existed.
1104     {
1105       g_err << "dict->getTable() for " << copyName
1106             << " failed in unexpedted way:" << endl
1107             << dict->getNdbError() << endl;
1108       return NDBT_FAILED;
1109     }
1110   }
1111   else
1112   {
1113     g_err << "Transaction dropping " << copyName << " was not rolled forward"
1114           << endl;
1115     return NDBT_FAILED;
1116   }
1117 
1118   /**
1119    * Do another dictionary transaction, to verify that the cluster allows that.
1120    */
1121   NdbDictionary::Table extraTab(*ctx->getTab());
1122   const char* extraName = "extraTab";
1123 
1124   extraTab.setName(extraName);
1125   g_info << "Trying to create table " << extraName << endl;
1126   if (dict->createTable(extraTab) != 0)
1127   {
1128     g_err << "Failed to create table " << extraName << endl
1129           << dict->getNdbError() << endl;
1130     return NDBT_FAILED;
1131   }
1132 
1133   // Clean up by dropping extraTab.
1134   g_info << "Trying to drop table " << extraName << endl;
1135   if (dict->dropTable(extraName) != 0)
1136   {
1137     g_err << "Failed to drop table " << extraName << endl
1138           << dict->getNdbError() << endl;
1139     return NDBT_FAILED;
1140   }
1141 
1142   return NDBT_OK;
1143 }
1144 
1145 int
runBackup(NDBT_Context * ctx,NDBT_Step * step)1146 runBackup(NDBT_Context* ctx, NDBT_Step* step)
1147 {
1148   NdbBackup backup;
1149   Uint32 backupId = 0;
1150   backup.clearOldBackups();
1151   if (backup.start(backupId) == -1)
1152   {
1153     return NDBT_FAILED;
1154   }
1155   return NDBT_OK;
1156 }
1157 
1158 int
runCreateMaxTables(NDBT_Context * ctx,NDBT_Step * step)1159 runCreateMaxTables(NDBT_Context* ctx, NDBT_Step* step)
1160 {
1161   char tabName[256];
1162   int numTables = ctx->getProperty("tables", 1000);
1163   Ndb* pNdb = GETNDB(step);
1164   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
1165   int i = 0;
1166   for (i = 0; i < numTables; i++) {
1167     BaseString::snprintf(tabName, 256, "MAXTAB%d", i);
1168     if (pNdb->waitUntilReady(30) != 0) {
1169       // Db is not ready, return with failure
1170       return NDBT_FAILED;
1171     }
1172     const NdbDictionary::Table* pTab = ctx->getTab();
1173     //ndbout << "|- " << tabName << endl;
1174     // Set new name for T1
1175     NdbDictionary::Table newTab(* pTab);
1176     newTab.setName(tabName);
1177     // Drop any old (or try to)
1178     (void)pDic->dropTable(newTab.getName());
1179     // Try to create table in db
1180     if (newTab.createTableInDb(pNdb) != 0) {
1181       ndbout << tabName << " could not be created: "
1182              << pDic->getNdbError() << endl;
1183       if (pDic->getNdbError().code == 625 ||
1184           pDic->getNdbError().code == 707 ||
1185           pDic->getNdbError().code == 708 ||
1186           pDic->getNdbError().code == 826 ||
1187           pDic->getNdbError().code == 827 ||
1188           pDic->getNdbError().code == 921)
1189         break;
1190       return NDBT_FAILED;
1191     }
1192     // Verify that table exists in db
1193     const NdbDictionary::Table* pTab3 =
1194       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1195     if (pTab3 == NULL){
1196       ndbout << tabName << " was not found in DB: "
1197              << pDic->getNdbError() << endl;
1198       return NDBT_FAILED;
1199     }
1200     if (! newTab.equal(*pTab3)) {
1201       ndbout << "It was not equal" << endl; abort();
1202       return NDBT_FAILED;
1203     }
1204     int records = ctx->getNumRecords();
1205     HugoTransactions hugoTrans(*pTab3);
1206     if (hugoTrans.loadTable(pNdb, records) != 0) {
1207       ndbout << "It can NOT be loaded" << endl;
1208       return NDBT_FAILED;
1209     }
1210     UtilTransactions utilTrans(*pTab3);
1211     if (utilTrans.clearTable(pNdb, records, 64) != 0) {
1212       ndbout << "It can NOT be cleared" << endl;
1213       return NDBT_FAILED;
1214     }
1215   }
1216   if (pNdb->waitUntilReady(30) != 0) {
1217     // Db is not ready, return with failure
1218     return NDBT_FAILED;
1219   }
1220   ctx->setProperty("maxtables", i);
1221   // HURRAAA!
1222   return NDBT_OK;
1223 }
1224 
runDropMaxTables(NDBT_Context * ctx,NDBT_Step * step)1225 int runDropMaxTables(NDBT_Context* ctx, NDBT_Step* step)
1226 {
1227   char tabName[256];
1228   int numTables = ctx->getProperty("maxtables", (Uint32)0);
1229   Ndb* pNdb = GETNDB(step);
1230   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
1231   for (int i = 0; i < numTables; i++) {
1232     BaseString::snprintf(tabName, 256, "MAXTAB%d", i);
1233     if (pNdb->waitUntilReady(30) != 0) {
1234       // Db is not ready, return with failure
1235       return NDBT_FAILED;
1236     }
1237     // Verify that table exists in db
1238     const NdbDictionary::Table* pTab3 =
1239       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1240     if (pTab3 == NULL) {
1241       ndbout << tabName << " was not found in DB: "
1242              << pDic->getNdbError() << endl;
1243       return NDBT_FAILED;
1244     }
1245     // Try to drop table in db
1246     if (pDic->dropTable(pTab3->getName()) != 0) {
1247       ndbout << tabName << " could not be dropped: "
1248              << pDic->getNdbError() << endl;
1249       return NDBT_FAILED;
1250     }
1251   }
1252   return NDBT_OK;
1253 }
1254 
runTestFragmentTypes(NDBT_Context * ctx,NDBT_Step * step)1255 int runTestFragmentTypes(NDBT_Context* ctx, NDBT_Step* step){
1256   int records = ctx->getNumRecords();
1257   int fragTtype = ctx->getProperty("FragmentType");
1258   Ndb* pNdb = GETNDB(step);
1259   int result = NDBT_OK;
1260   NdbRestarter restarter;
1261 
1262   if (pNdb->waitUntilReady(30) != 0){
1263     // Db is not ready, return with failure
1264     return NDBT_FAILED;
1265   }
1266 
1267   const NdbDictionary::Table* pTab = ctx->getTab();
1268   pNdb->getDictionary()->dropTable(pTab->getName());
1269 
1270   NdbDictionary::Table newTab(* pTab);
1271   // Set fragment type for table
1272   newTab.setFragmentType((NdbDictionary::Object::FragmentType)fragTtype);
1273 
1274   // Try to create table in db
1275   if (newTab.createTableInDb(pNdb) != 0){
1276     ndbout << newTab.getName() << " could not be created"
1277 	   << ", fragmentType = "<<fragTtype <<endl;
1278     ndbout << pNdb->getDictionary()->getNdbError() << endl;
1279     return NDBT_FAILED;
1280   }
1281 
1282   // Verify that table exists in db
1283   const NdbDictionary::Table* pTab3 =
1284     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName()) ;
1285   if (pTab3 == NULL){
1286     ndbout << pTab->getName() << " was not found in DB"<< endl;
1287     return NDBT_FAILED;
1288 
1289   }
1290 
1291   if (pTab3->getFragmentType() != fragTtype){
1292     ndbout << pTab->getName() << " fragmentType error "<< endl;
1293     result = NDBT_FAILED;
1294     goto drop_the_tab;
1295   }
1296 /**
1297    This test does not work since fragmentation is
1298    decided by the kernel, hence the fragementation
1299    attribute on the column will differ
1300 
1301   if (newTab.equal(*pTab3) == false){
1302     ndbout << "It was not equal" << endl;
1303     result = NDBT_FAILED;
1304     goto drop_the_tab;
1305   }
1306 */
1307   do {
1308 
1309     HugoTransactions hugoTrans(*pTab3);
1310     UtilTransactions utilTrans(*pTab3);
1311     int count;
1312     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1313     CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1314     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1315     CHECK(count == records);
1316     CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0);
1317     CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0);
1318     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1319     CHECK(count == (records/2));
1320 
1321     // restart all
1322     ndbout << "Restarting cluster" << endl;
1323     CHECK(restarter.restartAll() == 0);
1324     int timeout = 120;
1325     CHECK(restarter.waitClusterStarted(timeout) == 0);
1326     CHECK(pNdb->waitUntilReady(timeout) == 0);
1327 
1328     // Verify content
1329     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1330     CHECK(count == (records/2));
1331 
1332     CHECK(utilTrans.clearTable(pNdb, records) == 0);
1333     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1334     CHECK(utilTrans.clearTable(pNdb, records) == 0);
1335     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1336     CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1337     CHECK(utilTrans.clearTable(pNdb, records, 64) == 0);
1338 
1339   } while(false);
1340 
1341  drop_the_tab:
1342 
1343   // Try to drop table in db
1344   if (pNdb->getDictionary()->dropTable(pTab3->getName()) != 0){
1345     ndbout << pTab3->getName()  << " could not be dropped"<< endl;
1346     result =  NDBT_FAILED;
1347   }
1348 
1349   return result;
1350 }
1351 
1352 
runTestTemporaryTables(NDBT_Context * ctx,NDBT_Step * step)1353 int runTestTemporaryTables(NDBT_Context* ctx, NDBT_Step* step){
1354   int result = NDBT_OK;
1355   int loops = ctx->getNumLoops();
1356   int records = ctx->getNumRecords();
1357   Ndb* pNdb = GETNDB(step);
1358   int i = 0;
1359   NdbRestarter restarter;
1360 
1361   const NdbDictionary::Table* pTab = ctx->getTab();
1362   ndbout << "|- " << pTab->getName() << endl;
1363 
1364   NdbDictionary::Table newTab(* pTab);
1365   // Set table as temporary
1366   newTab.setStoredTable(false);
1367 
1368   // Try to create table in db
1369   if (newTab.createTableInDb(pNdb) != 0){
1370     return NDBT_FAILED;
1371   }
1372 
1373   // Verify that table is in db
1374   const NdbDictionary::Table* pTab2 =
1375     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1376   if (pTab2 == NULL){
1377     ndbout << pTab->getName() << " was not found in DB"<< endl;
1378     return NDBT_FAILED;
1379   }
1380 
1381   if (pTab2->getStoredTable() != false){
1382     ndbout << pTab->getName() << " was not temporary in DB"<< endl;
1383     result = NDBT_FAILED;
1384     goto drop_the_tab;
1385   }
1386 
1387 
1388   while (i < loops && result == NDBT_OK){
1389     ndbout << i << ": ";
1390 
1391     HugoTransactions hugoTrans(*pTab2);
1392     CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1393 
1394     int count = 0;
1395     UtilTransactions utilTrans(*pTab2);
1396     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1397     CHECK(count == records);
1398 
1399     // restart all
1400     ndbout << "Restarting cluster" << endl;
1401     CHECK(restarter.restartAll() == 0);
1402     int timeout = 120;
1403     CHECK(restarter.waitClusterStarted(timeout) == 0);
1404     CHECK(pNdb->waitUntilReady(timeout) == 0);
1405 
1406     ndbout << "Verifying records..." << endl;
1407     CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1408     CHECK(count == 0);
1409 
1410     i++;
1411   }
1412 
1413  drop_the_tab:
1414 
1415 
1416   if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1417     ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
1418     result = NDBT_FAILED;
1419   }
1420 
1421   // Verify that table is not in db
1422   const NdbDictionary::Table* pTab3 =
1423     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1424   if (pTab3 != NULL){
1425     ndbout << pTab3->getName() << " was found in DB"<< endl;
1426     result = NDBT_FAILED;
1427   }
1428 
1429   return result;
1430 }
1431 
runPkSizes(NDBT_Context * ctx,NDBT_Step * step)1432 int runPkSizes(NDBT_Context* ctx, NDBT_Step* step){
1433   int result = NDBT_OK;
1434   char tabName[256];
1435   int minPkSize = 1;
1436   ndbout << "minPkSize=" <<minPkSize<<endl;
1437   int maxPkSize = MAX_KEY_SIZE_IN_WORDS * 4;
1438   ndbout << "maxPkSize=" <<maxPkSize<<endl;
1439   Ndb* pNdb = GETNDB(step);
1440   int numRecords = ctx->getNumRecords();
1441 
1442   for (int i = minPkSize; i < maxPkSize; i++){
1443     BaseString::snprintf(tabName, 256, "TPK_%d", i);
1444 
1445     int records = numRecords;
1446     int max = ~0;
1447     // Limit num records for small PKs
1448     if (i == 1)
1449       max = 99;
1450     if (i == 2)
1451       max = 999;
1452     if (i == 3)
1453       max = 9999;
1454     if (records > max)
1455       records = max;
1456     ndbout << "records =" << records << endl;
1457 
1458     if (pNdb->waitUntilReady(30) != 0){
1459       // Db is not ready, return with failure
1460       return NDBT_FAILED;
1461     }
1462 
1463     ndbout << "|- " << tabName << endl;
1464 
1465     if (NDBT_Tables::createTable(pNdb, tabName) != 0){
1466       ndbout << tabName << " could not be created"<< endl;
1467       return NDBT_FAILED;
1468     }
1469 
1470     // Verify that table exists in db
1471     const NdbDictionary::Table* pTab3 =
1472       NDBT_Table::discoverTableFromDb(pNdb, tabName) ;
1473     if (pTab3 == NULL){
1474       g_err << tabName << " was not found in DB"<< endl;
1475       return NDBT_FAILED;
1476     }
1477 
1478     //    ndbout << *pTab3 << endl;
1479 
1480     if (pTab3->equal(*NDBT_Tables::getTable(tabName)) == false){
1481       g_err << "It was not equal" << endl;
1482       return NDBT_FAILED;
1483     }
1484 
1485     do {
1486       // Do it all
1487       HugoTransactions hugoTrans(*pTab3);
1488       UtilTransactions utilTrans(*pTab3);
1489       int count;
1490       CHECK(hugoTrans.loadTable(pNdb, records) == 0);
1491       CHECK(hugoTrans.pkUpdateRecords(pNdb, records) == 0);
1492       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1493       CHECK(count == records);
1494       CHECK(hugoTrans.pkDelRecords(pNdb, records/2) == 0);
1495       CHECK(hugoTrans.scanUpdateRecords(pNdb, records/2) == 0);
1496       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1497       CHECK(count == (records/2));
1498       CHECK(utilTrans.clearTable(pNdb, records) == 0);
1499 
1500 #if 0
1501       // Fill table
1502       CHECK(hugoTrans.fillTable(pNdb) == 0);
1503       CHECK(utilTrans.clearTable2(pNdb, records) == 0);
1504       CHECK(utilTrans.selectCount(pNdb, 64, &count) == 0);
1505       CHECK(count == 0);
1506 #endif
1507     } while(false);
1508 
1509     // Drop table
1510     if (pNdb->getDictionary()->dropTable(pTab3->getName()) != 0){
1511       ndbout << "Failed to drop "<<pTab3->getName()<<" in db" << endl;
1512       return NDBT_FAILED;
1513     }
1514   }
1515   return result;
1516 }
1517 
runStoreFrm(NDBT_Context * ctx,NDBT_Step * step)1518 int runStoreFrm(NDBT_Context* ctx, NDBT_Step* step){
1519   Ndb* pNdb = GETNDB(step);
1520   const NdbDictionary::Table* pTab = ctx->getTab();
1521   int result = NDBT_OK;
1522   int loops = ctx->getNumLoops();
1523 
1524   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1525 
1526     Uint32 dataLen = (Uint32)myRandom48(TEST_FRM_DATA_SIZE);
1527     // size_t dataLen = 10;
1528     unsigned char data[TEST_FRM_DATA_SIZE];
1529 
1530     char start = l + 248;
1531     for(Uint32 i = 0; i < dataLen; i++){
1532       data[i] = start;
1533       start++;
1534     }
1535 #if 0
1536     ndbout << "dataLen="<<dataLen<<endl;
1537     for (Uint32 i = 0; i < dataLen; i++){
1538       unsigned char c = data[i];
1539       ndbout << hex << c << ", ";
1540     }
1541     ndbout << endl;
1542 #endif
1543 
1544     NdbDictionary::Table newTab(* pTab);
1545     void* pData = &data;
1546     newTab.setFrm(pData, dataLen);
1547 
1548     // Try to create table in db
1549     if (newTab.createTableInDb(pNdb) != 0){
1550       result = NDBT_FAILED;
1551       continue;
1552     }
1553 
1554     // Verify that table is in db
1555     const NdbDictionary::Table* pTab2 =
1556       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1557     if (pTab2 == NULL){
1558       g_err << pTab->getName() << " was not found in DB"<< endl;
1559       result = NDBT_FAILED;
1560       continue;
1561     }
1562 
1563     const void* pData2 = pTab2->getFrmData();
1564     Uint32 resultLen = pTab2->getFrmLength();
1565     if (dataLen != resultLen){
1566       g_err << "Length of data failure" << endl
1567 	    << " expected = " << dataLen << endl
1568 	    << " got = " << resultLen << endl;
1569       result = NDBT_FAILED;
1570     }
1571 
1572     // Verfiy the frm data
1573     if (memcmp(pData, pData2, resultLen) != 0){
1574       g_err << "Wrong data received" << endl;
1575       for (size_t i = 0; i < dataLen; i++){
1576 	unsigned char c = ((unsigned char*)pData2)[i];
1577 	g_err << hex << c << ", ";
1578       }
1579       g_err << endl;
1580       result = NDBT_FAILED;
1581     }
1582 
1583     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1584       g_err << "It can NOT be dropped" << endl;
1585       result = NDBT_FAILED;
1586     }
1587   }
1588 
1589   return result;
1590 }
1591 
runStoreExtraMetada(NDBT_Context * ctx,NDBT_Step * step)1592 int runStoreExtraMetada(NDBT_Context* ctx, NDBT_Step* step)
1593 {
1594   Ndb* pNdb = GETNDB(step);
1595   const NdbDictionary::Table* pTab = ctx->getTab();
1596   int result = NDBT_OK;
1597 
1598   static constexpr Uint32 testBufferLenInWords = (TEST_FRM_DATA_SIZE + 3) / 4;
1599   Int32 data[testBufferLenInWords];
1600 
1601   for (int l = 0; l < ctx->getNumLoops() && result == NDBT_OK ; l++)
1602   {
1603     /* LENGTH OF DATA: The data fills 75% to 100% of the test buffer. */
1604     const Uint32 dataLen = (testBufferLenInWords * 3) +
1605                            myRandom48(testBufferLenInWords);
1606     const Uint32 dataLenInWords = (dataLen + 3)  / 4;
1607 
1608     /* Fill the buffer with (almost) random data. We use random data to defeat
1609        the zlib compression that will be applied to ExtraMetadata.
1610        Actually myRandom48() returns a signed long int >= 0, so for every 32
1611        bits stored we only get 31 bits of randomness, but this is good enough.
1612     */
1613     for(Uint32 i = 0; i < dataLenInWords; i++)
1614     {
1615       data[i] = myRandom48(INT32_MAX);
1616     }
1617 
1618     NdbDictionary::Table newTab(* pTab);
1619     // Using loop counter for version since any version should be supported
1620     const Uint32 version = l;
1621     if (newTab.setExtraMetadata(version,
1622                                 &data, dataLen))
1623     {
1624       g_err << "table.setExtraMetadata() failed. length:" << dataLen << endl;
1625       result = NDBT_FAILED;
1626       continue;
1627     }
1628 
1629     // Try to create table in db
1630     if (newTab.createTableInDb(pNdb) != 0){
1631       g_err << "createTableInDb() failed" << endl;
1632       result = NDBT_FAILED;
1633       continue;
1634     }
1635 
1636     // Verify that table is in db
1637     const NdbDictionary::Table* pTab2 =
1638       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1639     if (pTab2 == NULL){
1640       g_err << pTab->getName() << " was not found in DB"<< endl;
1641       result = NDBT_FAILED;
1642       continue;
1643     }
1644 
1645     Uint32 version2;
1646     void* data2;
1647     Uint32 dataLen2;
1648     if (pTab2->getExtraMetadata(version2,
1649                                 &data2, &dataLen2))
1650     {
1651       result = NDBT_FAILED;
1652     }
1653 
1654     if (version != version2)
1655     {
1656       g_err << "Wrong version received" << endl
1657             << " expected = " << version << endl
1658             << " got = " << version2 << endl;
1659       result = NDBT_FAILED;
1660     }
1661 
1662     if (dataLen != dataLen2){
1663       g_err << "Length of data failure" << endl
1664             << " expected = " << dataLen << endl
1665             << " got = " << dataLen2 << endl;
1666       result = NDBT_FAILED;
1667     }
1668 
1669     // Verify the frm data
1670     if (memcmp(data, data2, dataLen2) != 0)
1671     {
1672       g_err << "Wrong data received" << endl;
1673       for (size_t i = 0; i < dataLen; i++){
1674         unsigned char c = ((unsigned char*)data2)[i];
1675         g_err << hex << c << ", ";
1676       }
1677       g_err << endl;
1678       result = NDBT_FAILED;
1679     }
1680     free(data2);
1681 
1682     if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1683       g_err << "It can NOT be dropped" << endl;
1684       result = NDBT_FAILED;
1685     }
1686   }
1687 
1688   return result;
1689 }
1690 
1691 /* After wl#10665, the limit on the size of ExtraMetadata is
1692    defined by MAX_WORDS_META_FILE.
1693 */
runStoreExtraMetadataError(NDBT_Context * ctx,NDBT_Step * step)1694 int runStoreExtraMetadataError(NDBT_Context* ctx, NDBT_Step* step)
1695 {
1696   Ndb* pNdb = GETNDB(step);
1697   const NdbDictionary::Table* pTab = ctx->getTab();
1698   int result = NDBT_OK;
1699 
1700   static constexpr Uint32 dataLenInWords = MAX_WORDS_META_FILE;
1701   static constexpr Uint32 dataLen = dataLenInWords * 4;
1702   Int32 data[dataLenInWords];
1703 
1704   for (int l = 0; l < ctx->getNumLoops() && result == NDBT_OK ; l++)
1705   {
1706     // The whole dictionary entry must fit in MAX_WORDS_META_FILE.
1707     // Create a table where the ExtraMetadata alone is too long
1708     // (and cannot be effectively compressed).
1709 
1710     for(Uint32 i = 0; i < dataLenInWords; i++)
1711     {
1712       data[i] = myRandom48(INT32_MAX);
1713     }
1714 
1715     // It should be possible to set the extra metadata
1716     // even though it later will not work to create the table
1717     NdbDictionary::Table newTab(* pTab);
1718     if (newTab.setExtraMetadata(37, // version
1719                                 data, dataLen))
1720     {
1721       g_err << "Failed to set the extra metadata, length: " << dataLen << endl;
1722       result = NDBT_FAILED;
1723       continue;
1724     }
1725 
1726     // Try to create table in db, should fail!
1727     if (newTab.createTableInDb(pNdb) == 0){
1728       g_err << "Table created, that was unexpected" << endl;
1729       result = NDBT_FAILED;
1730       continue;
1731     }
1732 
1733     const NdbDictionary::Table* pTab2 =
1734       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1735     if (pTab2 != NULL){
1736       g_err << pTab->getName() << " was found in DB"<< endl;
1737       result = NDBT_FAILED;
1738       if (pNdb->getDictionary()->dropTable(pTab2->getName()) != 0){
1739         g_err << "It can NOT be dropped" << endl;
1740         result = NDBT_FAILED;
1741       }
1742 
1743       continue;
1744     }
1745 
1746   }
1747 
1748   return result;
1749 }
1750 
verifyTablesAreEqual(const NdbDictionary::Table * pTab,const NdbDictionary::Table * pTab2)1751 int verifyTablesAreEqual(const NdbDictionary::Table* pTab, const NdbDictionary::Table* pTab2){
1752   // Verify that getPrimaryKey only returned true for primary keys
1753   for (int i = 0; i < pTab2->getNoOfColumns(); i++){
1754     const NdbDictionary::Column* col = pTab->getColumn(i);
1755     const NdbDictionary::Column* col2 = pTab2->getColumn(i);
1756     if (col->getPrimaryKey() != col2->getPrimaryKey()){
1757       g_err << "col->getPrimaryKey() != col2->getPrimaryKey()" << endl;
1758       return NDBT_FAILED;
1759     }
1760   }
1761 
1762   if (!pTab->equal(*pTab2)){
1763     g_err << "equal failed" << endl;
1764     g_info << *(NDBT_Table*)pTab; // gcc-4.1.2
1765     g_info << *(NDBT_Table*)pTab2;
1766     return NDBT_FAILED;
1767   }
1768   return NDBT_OK;
1769 }
1770 
runGetPrimaryKey(NDBT_Context * ctx,NDBT_Step * step)1771 int runGetPrimaryKey(NDBT_Context* ctx, NDBT_Step* step){
1772   Ndb* pNdb = GETNDB(step);
1773   const NdbDictionary::Table* pTab = ctx->getTab();
1774   ndbout << "|- " << pTab->getName() << endl;
1775   g_info << *(NDBT_Table*)pTab;
1776   // Try to create table in db
1777   if (pTab->createTableInDb(pNdb) != 0){
1778     return NDBT_FAILED;
1779   }
1780 
1781   const NdbDictionary::Table* pTab2 =
1782     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1783   if (pTab2 == NULL){
1784     ndbout << pTab->getName() << " was not found in DB"<< endl;
1785     return NDBT_FAILED;
1786   }
1787 
1788   int result = NDBT_OK;
1789   if (verifyTablesAreEqual(pTab, pTab2) != NDBT_OK)
1790     result = NDBT_FAILED;
1791 
1792 
1793 #if 0
1794   // Create an index on the table and see what
1795   // the function returns now
1796   char name[200];
1797   sprintf(name, "%s_X007", pTab->getName());
1798   NDBT_Index* pInd = new NDBT_Index(name);
1799   pInd->setTable(pTab->getName());
1800   pInd->setType(NdbDictionary::Index::UniqueHashIndex);
1801   //  pInd->setLogging(false);
1802   for (int i = 0; i < 2; i++){
1803     const NDBT_Attribute* pAttr = pTab->getAttribute(i);
1804     pInd->addAttribute(*pAttr);
1805   }
1806   g_info << "Create index:" << endl << *pInd;
1807   if (pInd->createIndexInDb(pNdb, false) != 0){
1808     result = NDBT_FAILED;
1809   }
1810   delete pInd;
1811 
1812   const NdbDictionary::Table* pTab3 =
1813     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1814   if (pTab3 == NULL){
1815     ndbout << pTab->getName() << " was not found in DB"<< endl;
1816     return NDBT_FAILED;
1817   }
1818 
1819   if (verifyTablesAreEqual(pTab, pTab3) != NDBT_OK)
1820     result = NDBT_FAILED;
1821   if (verifyTablesAreEqual(pTab2, pTab3) != NDBT_OK)
1822     result = NDBT_FAILED;
1823 #endif
1824 
1825 #if 0
1826   if (pTab2->getDictionary()->dropTable(pNdb) != 0){
1827     ndbout << "Failed to drop "<<pTab2->getName()<<" in db" << endl;
1828     return NDBT_FAILED;
1829   }
1830 
1831   // Verify that table is not in db
1832   const NdbDictionary::Table* pTab4 =
1833     NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1834   if (pTab4 != NULL){
1835     ndbout << pTab4->getName() << " was found in DB"<< endl;
1836     return NDBT_FAILED;
1837   }
1838 #endif
1839 
1840   return result;
1841 }
1842 
1843 #define APIERROR(error) \
1844   { g_err << "Error in " << __FILE__ << ", line:" << __LINE__ << ", code:" \
1845               << error.code << ", msg: " << error.message << "." << endl; \
1846   }
1847 
1848 int
runCreateAutoincrementTable(NDBT_Context * ctx,NDBT_Step * step)1849 runCreateAutoincrementTable(NDBT_Context* ctx, NDBT_Step* step){
1850 
1851   Uint32 startvalues[5] = {256-2, 0, 256*256-2, ~Uint32(0), 256*256*256-2};
1852 
1853   int ret = NDBT_OK;
1854 
1855   for (int jj = 0; jj < 5 && ret == NDBT_OK; jj++) {
1856     char tabname[] = "AUTOINCTAB";
1857     Uint32 startvalue = startvalues[jj];
1858 
1859     NdbDictionary::Table myTable;
1860     NdbDictionary::Column myColumn;
1861 
1862     Ndb* myNdb = GETNDB(step);
1863     NdbDictionary::Dictionary* myDict = myNdb->getDictionary();
1864 
1865 
1866     if (myDict->getTable(tabname) != NULL) {
1867       g_err << "NDB already has example table: " << tabname << endl;
1868       APIERROR(myNdb->getNdbError());
1869       return NDBT_FAILED;
1870     }
1871 
1872     myTable.setName(tabname);
1873 
1874     myColumn.setName("ATTR1");
1875     myColumn.setType(NdbDictionary::Column::Unsigned);
1876     myColumn.setLength(1);
1877     myColumn.setPrimaryKey(true);
1878     myColumn.setNullable(false);
1879     myColumn.setAutoIncrement(true);
1880     if (startvalue != ~Uint32(0)) // check that default value starts with 1
1881       myColumn.setAutoIncrementInitialValue(startvalue);
1882     myTable.addColumn(myColumn);
1883 
1884     if (myDict->createTable(myTable) == -1) {
1885       g_err << "Failed to create table " << tabname << endl;
1886       APIERROR(myNdb->getNdbError());
1887       return NDBT_FAILED;
1888     }
1889 
1890 
1891     if (startvalue == ~Uint32(0)) // check that default value starts with 1
1892       startvalue = 1;
1893 
1894     for (int i = 0; i < 16; i++) {
1895 
1896       Uint64 value;
1897       if (myNdb->getAutoIncrementValue(tabname, value, 1) == -1) {
1898         g_err << "getAutoIncrementValue failed on " << tabname << endl;
1899         APIERROR(myNdb->getNdbError());
1900         return NDBT_FAILED;
1901       }
1902       else if (value != (startvalue+i)) {
1903         g_err << "value = " << value << " expected " << startvalue+i << endl;;
1904         APIERROR(myNdb->getNdbError());
1905         //      ret = NDBT_FAILED;
1906         //      break;
1907       }
1908     }
1909 
1910     if (myDict->dropTable(tabname) == -1) {
1911       g_err << "Failed to drop table " << tabname << endl;
1912       APIERROR(myNdb->getNdbError());
1913       ret = NDBT_FAILED;
1914     }
1915   }
1916 
1917   return ret;
1918 }
1919 
1920 int
runTableRename(NDBT_Context * ctx,NDBT_Step * step)1921 runTableRename(NDBT_Context* ctx, NDBT_Step* step){
1922 
1923   int result = NDBT_OK;
1924 
1925   Ndb* pNdb = GETNDB(step);
1926   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
1927   int records = ctx->getNumRecords();
1928   const int loops = ctx->getNumLoops();
1929 
1930   ndbout << "|- " << ctx->getTab()->getName() << endl;
1931 
1932   for (int l = 0; l < loops && result == NDBT_OK ; l++){
1933     const NdbDictionary::Table* pTab = ctx->getTab();
1934 
1935     // Try to create table in db
1936     if (pTab->createTableInDb(pNdb) != 0){
1937       return NDBT_FAILED;
1938     }
1939 
1940     // Verify that table is in db
1941     const NdbDictionary::Table* pTab2 =
1942       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
1943     if (pTab2 == NULL){
1944       ndbout << pTab->getName() << " was not found in DB"<< endl;
1945       return NDBT_FAILED;
1946     }
1947     ctx->setTab(pTab2);
1948 
1949     // Load table
1950     HugoTransactions hugoTrans(*ctx->getTab());
1951     if (hugoTrans.loadTable(pNdb, records) != 0){
1952       return NDBT_FAILED;
1953     }
1954 
1955     // Rename table
1956     BaseString pTabName(pTab->getName());
1957     BaseString pTabNewName(pTabName);
1958     pTabNewName.append("xx");
1959 
1960     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
1961     if (oldTable) {
1962       NdbDictionary::Table newTable = *oldTable;
1963       newTable.setName(pTabNewName.c_str());
1964       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
1965 	     "TableRename failed");
1966     }
1967     else {
1968       result = NDBT_FAILED;
1969     }
1970 
1971     // Verify table contents
1972     NdbDictionary::Table pNewTab(pTabNewName.c_str());
1973 
1974     UtilTransactions utilTrans(pNewTab);
1975     if (utilTrans.clearTable(pNdb,  records) != 0){
1976       continue;
1977     }
1978 
1979     // Drop table
1980     dict->dropTable(pNewTab.getName());
1981   }
1982  end:
1983 
1984   return result;
1985 }
1986 
1987 int
runTableRenameSR(NDBT_Context * ctx,NDBT_Step * step)1988 runTableRenameSR(NDBT_Context* ctx, NDBT_Step* step){
1989   NdbRestarter restarter;
1990   if(restarter.getNumDbNodes() < 2)
1991     return NDBT_OK;
1992 
1993   int result = NDBT_OK;
1994 
1995   Ndb* pNdb = GETNDB(step);
1996   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
1997   int records = ctx->getNumRecords();
1998   const int loops = ctx->getNumLoops();
1999 
2000   ndbout << "|- " << ctx->getTab()->getName() << endl;
2001 
2002   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2003     // Rename table
2004     const NdbDictionary::Table* pTab = ctx->getTab();
2005 
2006     // Try to create table in db
2007     if (pTab->createTableInDb(pNdb) != 0){
2008       return NDBT_FAILED;
2009     }
2010 
2011     // Verify that table is in db
2012     const NdbDictionary::Table* pTab2 =
2013       NDBT_Table::discoverTableFromDb(pNdb, pTab->getName());
2014     if (pTab2 == NULL){
2015       ndbout << pTab->getName() << " was not found in DB"<< endl;
2016       return NDBT_FAILED;
2017     }
2018     ctx->setTab(pTab2);
2019 
2020     // Load table
2021     HugoTransactions hugoTrans(*ctx->getTab());
2022     if (hugoTrans.loadTable(pNdb, records) != 0){
2023       return NDBT_FAILED;
2024     }
2025 
2026     BaseString pTabName(pTab->getName());
2027     BaseString pTabNewName(pTabName);
2028     pTabNewName.append("xx");
2029 
2030     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
2031     if (oldTable) {
2032       NdbDictionary::Table newTable = *oldTable;
2033       newTable.setName(pTabNewName.c_str());
2034       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2035 	     "TableRename failed");
2036     }
2037     else {
2038       result = NDBT_FAILED;
2039     }
2040 
2041     // Restart cluster
2042 
2043     /**
2044      * Need to run LCP at high rate otherwise
2045      * packed replicas become "to many"
2046      */
2047     int val = DumpStateOrd::DihMinTimeBetweenLCP;
2048     if(restarter.dumpStateAllNodes(&val, 1) != 0){
2049       do { CHECK(0); } while(0);
2050       g_err << "Failed to set LCP to min value" << endl;
2051       return NDBT_FAILED;
2052     }
2053 
2054     CHECK2(restarter.restartAll() == 0,
2055 	   "failed to set restartOneDbNode");
2056 
2057     CHECK2(restarter.waitClusterStarted() == 0,
2058 	   "waitClusterStarted failed");
2059     CHK_NDB_READY(pNdb);
2060 
2061     // Verify table contents
2062     NdbDictionary::Table pNewTab(pTabNewName.c_str());
2063 
2064     UtilTransactions utilTrans(pNewTab);
2065     if (utilTrans.clearTable(pNdb,  records) != 0){
2066       continue;
2067     }
2068 
2069     // Drop table
2070     dict->dropTable(pTabNewName.c_str());
2071   }
2072  end:
2073   return result;
2074 }
2075 
2076 /*
2077   Run rename column
2078 */
2079 int
runColumnRename(NDBT_Context * ctx,NDBT_Step * step)2080 runColumnRename(NDBT_Context* ctx, NDBT_Step* step){
2081   int result = NDBT_OK;
2082 
2083   Ndb* pNdb = GETNDB(step);
2084   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
2085   int records = ctx->getNumRecords();
2086   const int loops = ctx->getNumLoops();
2087 
2088   ndbout << "|- " << ctx->getTab()->getName() << endl;
2089 
2090   NdbDictionary::Table myTab= *(ctx->getTab());
2091 
2092   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2093     // Try to create table in db
2094 
2095     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
2096       return NDBT_FAILED;
2097     }
2098 
2099     // Verify that table is in db
2100     const NdbDictionary::Table* pTab2 =
2101       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
2102     if (pTab2 == NULL){
2103       ndbout << myTab.getName() << " was not found in DB"<< endl;
2104       return NDBT_FAILED;
2105     }
2106     ctx->setTab(pTab2);
2107 
2108     /*
2109       Check that table already has a varpart, otherwise add attr is
2110       not possible.
2111     */
2112     if (pTab2->getForceVarPart() == false)
2113     {
2114       const NdbDictionary::Column *col;
2115       for (Uint32 i= 0; (col= pTab2->getColumn(i)) != 0; i++)
2116       {
2117         if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
2118             (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
2119           break;
2120       }
2121       if (col == 0)
2122       {
2123         /* Alter table add attribute not applicable, just mark success. */
2124         dict->dropTable(pTab2->getName());
2125         break;
2126       }
2127     }
2128 
2129     ndbout << "Load table" << endl;
2130     // Load table
2131     HugoTransactions beforeTrans(*ctx->getTab());
2132     if (beforeTrans.loadTable(pNdb, records) != 0){
2133       return NDBT_FAILED;
2134     }
2135     ndbout << "Load table completed" << endl;
2136 
2137         // Add attributes to table.
2138     BaseString pTabName(pTab2->getName());
2139 
2140     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
2141     if (oldTable) {
2142       NdbDictionary::Table newTable= *oldTable;
2143 
2144       NDBT_Attribute newcol1("NEWKOL1", NdbDictionary::Column::Unsigned, 1,
2145                             false, true, 0,
2146                             NdbDictionary::Column::StorageTypeMemory, true);
2147       newTable.addColumn(newcol1);
2148       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2149 	     "runColumnRename failed");
2150       /* Need to purge old version and reload new version after alter table. */
2151       dict->invalidateTable(pTabName.c_str());
2152     }
2153     else {
2154       result = NDBT_FAILED;
2155     }
2156     ndbout << "Added column completed" << endl;
2157     {
2158       const NdbDictionary::Table* oldTable = dict->getTable(pTabName.c_str());
2159       if (oldTable) {
2160         NdbDictionary::Table newTable= *oldTable;
2161         int colNum= newTable.getNoOfColumns()-1;
2162         NdbDictionary::Column* addedCol= newTable.getColumn(colNum);
2163         addedCol->setName("renamed_NEWKOL1");
2164         CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2165                "runColumnRename failed");
2166         /* Need to purge old version and reload new version after alter table. */
2167         dict->invalidateTable(pTabName.c_str());
2168       }
2169       else {
2170         result = NDBT_FAILED;
2171         break;
2172       }
2173     }
2174 
2175     ndbout << "Column rename completed" << endl;
2176     {
2177       const NdbDictionary::Table* pTab = dict->getTable(pTabName.c_str());
2178       CHECK2(pTab != NULL, "Table not found");
2179       HugoTransactions afterTrans(*pTab);
2180 
2181       ndbout << "Checking renamed column" << endl;
2182       const NdbDictionary::Column* addedCol= pTab->getColumn("renamed_NEWKOL1");
2183       CHECK2((addedCol) && addedCol->getColumnNo() == pTab->getNoOfColumns()-1,
2184              "runColumnRename failed");
2185 
2186       ndbout << "delete...";
2187       if (afterTrans.clearTable(pNdb) != 0)
2188       {
2189         return NDBT_FAILED;
2190       }
2191       ndbout << endl;
2192 
2193       ndbout << "insert...";
2194       if (afterTrans.loadTable(pNdb, records) != 0){
2195         return NDBT_FAILED;
2196       }
2197       ndbout << endl;
2198 
2199       ndbout << "update...";
2200       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
2201       {
2202         return NDBT_FAILED;
2203       }
2204       ndbout << endl;
2205 
2206       ndbout << "delete...";
2207       if (afterTrans.clearTable(pNdb) != 0)
2208       {
2209         return NDBT_FAILED;
2210       }
2211       ndbout << endl;
2212     }
2213 
2214     // Drop table
2215     dict->dropTable(pTabName.c_str());
2216   }
2217  end:
2218 
2219   return result;
2220 }
2221 
2222 /*
2223   Run rename column with restart
2224 */
2225 int
runColumnRenameSR(NDBT_Context * ctx,NDBT_Step * step)2226 runColumnRenameSR(NDBT_Context* ctx, NDBT_Step* step){
2227   int result = NDBT_OK;
2228 
2229   Ndb* pNdb = GETNDB(step);
2230   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
2231   int records = ctx->getNumRecords();
2232   const int loops = ctx->getNumLoops();
2233   NdbRestarter res;
2234 
2235   ndbout << "|- " << ctx->getTab()->getName() << endl;
2236 
2237   NdbDictionary::Table myTab= *(ctx->getTab());
2238 
2239   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2240     // Try to create table in db
2241 
2242     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
2243       return NDBT_FAILED;
2244     }
2245 
2246     // Verify that table is in db
2247     const NdbDictionary::Table* pTab2 =
2248       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
2249     if (pTab2 == NULL){
2250       ndbout << myTab.getName() << " was not found in DB"<< endl;
2251       return NDBT_FAILED;
2252     }
2253     ctx->setTab(pTab2);
2254 
2255     /*
2256       Check that table already has a varpart, otherwise add attr is
2257       not possible.
2258     */
2259     if (pTab2->getForceVarPart() == false)
2260     {
2261       const NdbDictionary::Column *col;
2262       for (Uint32 i= 0; (col= pTab2->getColumn(i)) != 0; i++)
2263       {
2264         if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
2265             (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
2266           break;
2267       }
2268       if (col == 0)
2269       {
2270         /* Alter table add attribute not applicable, just mark success. */
2271         dict->dropTable(pTab2->getName());
2272         break;
2273       }
2274     }
2275 
2276     ndbout << "Load table" << endl;
2277     // Load table
2278     HugoTransactions beforeTrans(*ctx->getTab());
2279     if (beforeTrans.loadTable(pNdb, records) != 0){
2280       return NDBT_FAILED;
2281     }
2282     ndbout << "Load table completed" << endl;
2283 
2284         // Add attributes to table.
2285     BaseString pTabName(pTab2->getName());
2286 
2287     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
2288     if (oldTable) {
2289       NdbDictionary::Table newTable= *oldTable;
2290 
2291       NDBT_Attribute newcol1("NEWKOL1", NdbDictionary::Column::Unsigned, 1,
2292                             false, true, 0,
2293                             NdbDictionary::Column::StorageTypeMemory, true);
2294       newTable.addColumn(newcol1);
2295       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2296 	     "runColumnRename failed");
2297       /* Need to purge old version and reload new version after alter table. */
2298       dict->invalidateTable(pTabName.c_str());
2299     }
2300     else {
2301       result = NDBT_FAILED;
2302     }
2303     ndbout << "Added column completed" << endl;
2304     {
2305       const NdbDictionary::Table* oldTable = dict->getTable(pTabName.c_str());
2306       if (oldTable) {
2307         NdbDictionary::Table newTable= *oldTable;
2308         int colNum= newTable.getNoOfColumns()-1;
2309         NdbDictionary::Column* addedCol= newTable.getColumn(colNum);
2310         addedCol->setName("renamed_NEWKOL1");
2311         CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2312                "runColumnRename failed");
2313         /* Need to purge old version and reload new version after alter table. */
2314         dict->invalidateTable(pTabName.c_str());
2315       }
2316       else {
2317         result = NDBT_FAILED;
2318         break;
2319       }
2320     }
2321 
2322     ndbout << "Column rename completed" << endl;
2323     {
2324       const NdbDictionary::Table* pTab = dict->getTable(pTabName.c_str());
2325       CHECK2(pTab != NULL, "Table not found");
2326       HugoTransactions afterTrans(*pTab);
2327 
2328       ndbout_c("performing system restart");
2329       CHECK2(res.restartAll(false, true, false) == 0,
2330              "restart all failed");
2331       CHECK2(res.waitClusterNoStart() == 0,
2332              "waitClusterNoStart failed");
2333       CHECK2(res.startAll() == 0,
2334              "startAll failed");
2335       CHECK2(res.waitClusterStarted() == 0,
2336              "waitClusterStarted failed");
2337 
2338       ndbout << "Checking renamed column" << endl;
2339       pTab = dict->getTable(pTabName.c_str());
2340       const NdbDictionary::Column* addedCol= pTab->getColumn("renamed_NEWKOL1");
2341       CHECK2((addedCol) && addedCol->getColumnNo() == pTab->getNoOfColumns()-1,
2342              "runColumnRename failed");
2343 
2344       ndbout << "delete...";
2345       if (afterTrans.clearTable(pNdb) != 0)
2346       {
2347         return NDBT_FAILED;
2348       }
2349       ndbout << endl;
2350 
2351       ndbout << "insert...";
2352       if (afterTrans.loadTable(pNdb, records) != 0){
2353         return NDBT_FAILED;
2354       }
2355       ndbout << endl;
2356 
2357       ndbout << "update...";
2358       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
2359       {
2360         return NDBT_FAILED;
2361       }
2362       ndbout << endl;
2363 
2364       ndbout << "delete...";
2365       if (afterTrans.clearTable(pNdb) != 0)
2366       {
2367         return NDBT_FAILED;
2368       }
2369       ndbout << endl;
2370     }
2371 
2372     // Drop table
2373     dict->dropTable(pTabName.c_str());
2374   }
2375  end:
2376 
2377   return result;
2378 }
2379 
2380 /*
2381   Run online alter table add attributes.
2382  */
2383 int
runTableAddAttrs(NDBT_Context * ctx,NDBT_Step * step)2384 runTableAddAttrs(NDBT_Context* ctx, NDBT_Step* step){
2385 
2386   int result = NDBT_OK;
2387 
2388   Ndb* pNdb = GETNDB(step);
2389   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
2390   int records = ctx->getNumRecords();
2391   const int loops = ctx->getNumLoops();
2392 
2393   ndbout << "|- " << ctx->getTab()->getName() << endl;
2394 
2395   NdbDictionary::Table myTab= *(ctx->getTab());
2396 
2397   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2398     // Try to create table in db
2399 
2400     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
2401       return NDBT_FAILED;
2402     }
2403 
2404     // Verify that table is in db
2405     const NdbDictionary::Table* pTab2 =
2406       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
2407     if (pTab2 == NULL){
2408       ndbout << myTab.getName() << " was not found in DB"<< endl;
2409       return NDBT_FAILED;
2410     }
2411     ctx->setTab(pTab2);
2412 
2413     /*
2414       Check that table already has a varpart, otherwise add attr is
2415       not possible.
2416     */
2417     if (pTab2->getForceVarPart() == false)
2418     {
2419       const NdbDictionary::Column *col;
2420       for (Uint32 i= 0; (col= pTab2->getColumn(i)) != 0; i++)
2421       {
2422         if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
2423             (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
2424           break;
2425       }
2426       if (col == 0)
2427       {
2428         /* Alter table add attribute not applicable, just mark success. */
2429         dict->dropTable(pTab2->getName());
2430         break;
2431       }
2432     }
2433 
2434     ndbout << "Load table" << endl;
2435     // Load table
2436     HugoTransactions beforeTrans(*ctx->getTab());
2437     if (beforeTrans.loadTable(pNdb, records) != 0){
2438       return NDBT_FAILED;
2439     }
2440     ndbout << "Load table completed" << endl;
2441 
2442     // Add attributes to table.
2443     BaseString pTabName(pTab2->getName());
2444 
2445     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
2446     if (oldTable) {
2447       NdbDictionary::Table newTable= *oldTable;
2448 
2449       NDBT_Attribute newcol1("NEWKOL1", NdbDictionary::Column::Unsigned, 1,
2450                             false, true, 0,
2451                             NdbDictionary::Column::StorageTypeMemory, true);
2452       newTable.addColumn(newcol1);
2453       NDBT_Attribute newcol2("NEWKOL2", NdbDictionary::Column::Char, 14,
2454                             false, true, 0,
2455                             NdbDictionary::Column::StorageTypeMemory, true);
2456       newTable.addColumn(newcol2);
2457       NDBT_Attribute newcol3("NEWKOL3", NdbDictionary::Column::Bit, 20,
2458                             false, true, 0,
2459                             NdbDictionary::Column::StorageTypeMemory, true);
2460       newTable.addColumn(newcol3);
2461       NDBT_Attribute newcol4("NEWKOL4", NdbDictionary::Column::Varbinary, 42,
2462                             false, true, 0,
2463                             NdbDictionary::Column::StorageTypeMemory, true);
2464       newTable.addColumn(newcol4);
2465 
2466       CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2467 	     "TableAddAttrs failed");
2468       /* Need to purge old version and reload new version after alter table. */
2469       dict->invalidateTable(pTabName.c_str());
2470     }
2471     else {
2472       result = NDBT_FAILED;
2473     }
2474 
2475     ndbout << "Altered table completed" << endl;
2476     {
2477       const NdbDictionary::Table* pTab = dict->getTable(pTabName.c_str());
2478       CHECK2(pTab != NULL, "Table not found");
2479       HugoTransactions afterTrans(*pTab);
2480 
2481       ndbout << "delete...";
2482       if (afterTrans.clearTable(pNdb) != 0)
2483       {
2484         return NDBT_FAILED;
2485       }
2486       ndbout << endl;
2487 
2488       ndbout << "insert...";
2489       if (afterTrans.loadTable(pNdb, records) != 0){
2490         return NDBT_FAILED;
2491       }
2492       ndbout << endl;
2493 
2494       ndbout << "update...";
2495       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
2496       {
2497         return NDBT_FAILED;
2498       }
2499       ndbout << endl;
2500 
2501       ndbout << "delete...";
2502       if (afterTrans.clearTable(pNdb) != 0)
2503       {
2504         return NDBT_FAILED;
2505       }
2506       ndbout << endl;
2507     }
2508 
2509     // Drop table.
2510     dict->dropTable(pTabName.c_str());
2511   }
2512  end:
2513 
2514   return result;
2515 }
2516 
2517 /*
2518   Run online alter table add attributes while running simultaneous
2519   transactions on it in separate thread.
2520  */
2521 int
runTableAddAttrsDuring(NDBT_Context * ctx,NDBT_Step * step)2522 runTableAddAttrsDuring(NDBT_Context* ctx, NDBT_Step* step){
2523 
2524   int result = NDBT_OK;
2525   int abortAlter = ctx->getProperty("AbortAlter", Uint32(0));
2526 
2527   int records = ctx->getNumRecords();
2528   const int loops = ctx->getNumLoops();
2529   NdbRestarter res;
2530 
2531   ndbout << "|- " << ctx->getTab()->getName() << endl;
2532 
2533   NdbDictionary::Table myTab= *(ctx->getTab());
2534 
2535   if (myTab.getForceVarPart() == false)
2536   {
2537     const NdbDictionary::Column *col;
2538     for (Uint32 i= 0; (col= myTab.getColumn(i)) != 0; i++)
2539     {
2540       if (col->getStorageType() == NDB_STORAGETYPE_MEMORY &&
2541           (col->getDynamic() || col->getArrayType() != NDB_ARRAYTYPE_FIXED))
2542         break;
2543     }
2544     if (col == 0)
2545     {
2546       ctx->stopTest();
2547       return NDBT_OK;
2548     }
2549   }
2550 
2551   //if
2552 
2553   for (int l = 0; l < loops && result == NDBT_OK ; l++){
2554     ndbout << l << ": " << endl;
2555 
2556     Ndb* pNdb = GETNDB(step);
2557     NdbDictionary::Dictionary* dict = pNdb->getDictionary();
2558 
2559     /*
2560       Check that table already has a varpart, otherwise add attr is
2561       not possible.
2562     */
2563 
2564     // Add attributes to table.
2565     ndbout << "Altering table" << endl;
2566 
2567     const NdbDictionary::Table * oldTable = dict->getTable(myTab.getName());
2568     if (oldTable) {
2569       NdbDictionary::Table newTable= *oldTable;
2570 
2571       char name[256];
2572       BaseString::snprintf(name, sizeof(name), "NEWCOL%d", l);
2573       NDBT_Attribute newcol1(name, NdbDictionary::Column::Unsigned, 1,
2574                              false, true, 0,
2575                              NdbDictionary::Column::StorageTypeMemory, true);
2576       newTable.addColumn(newcol1);
2577       //ToDo: check #loops, how many columns l
2578 
2579       if (abortAlter == 0)
2580       {
2581         CHECK2(dict->alterTable(*oldTable, newTable) == 0,
2582                "TableAddAttrsDuring failed");
2583       }
2584       else
2585       {
2586         int nodeId = res.getNode(NdbRestarter::NS_RANDOM);
2587         res.insertErrorInNode(nodeId, 4029);
2588         CHECK2(dict->alterTable(*oldTable, newTable) != 0,
2589                "TableAddAttrsDuring failed");
2590       }
2591 
2592       dict->invalidateTable(myTab.getName());
2593       const NdbDictionary::Table * newTab = dict->getTable(myTab.getName());
2594       CHECK2(newTab != NULL, "'newTab' not found");
2595       HugoTransactions hugoTrans(* newTab);
2596       hugoTrans.scanUpdateRecords(pNdb, records);
2597     }
2598     else {
2599       result= NDBT_FAILED;
2600       break;
2601     }
2602   }
2603  end:
2604 
2605   ctx->stopTest();
2606 
2607   return result;
2608 }
2609 
2610 static void
f(const NdbDictionary::Column * col)2611 f(const NdbDictionary::Column * col){
2612   if(col == 0){
2613     abort();
2614   }
2615 }
2616 
2617 int
runTestDictionaryPerf(NDBT_Context * ctx,NDBT_Step * step)2618 runTestDictionaryPerf(NDBT_Context* ctx, NDBT_Step* step){
2619   Vector<char*> cols;
2620   Vector<const NdbDictionary::Table*> tabs;
2621   int i;
2622 
2623   Ndb* pNdb = GETNDB(step);
2624 
2625   const Uint32 count = NDBT_Tables::getNumTables();
2626   for (i=0; i < (int)count; i++){
2627     const NdbDictionary::Table * tab = NDBT_Tables::getTable(i);
2628     pNdb->getDictionary()->createTable(* tab);
2629 
2630     const NdbDictionary::Table * tab2 = pNdb->getDictionary()->getTable(tab->getName());
2631 
2632     for(int j = 0; j<tab->getNoOfColumns(); j++){
2633       cols.push_back((char*)tab2);
2634       cols.push_back(strdup(tab->getColumn(j)->getName()));
2635     }
2636   }
2637 
2638   const Uint32 times = 10000000;
2639 
2640   ndbout_c("%d tables and %d columns",
2641 	   NDBT_Tables::getNumTables(), cols.size()/2);
2642 
2643   char ** tcols = cols.getBase();
2644 
2645   srand((unsigned int)time(0));
2646   Uint32 size = cols.size() / 2;
2647   //char ** columns = &cols[0];
2648   Uint64 start = NdbTick_CurrentMillisecond();
2649   for(i = 0; i<(int)times; i++){
2650     int j = 2 * (rand() % size);
2651     const NdbDictionary::Table* tab = (const NdbDictionary::Table*)tcols[j];
2652     const char * col = tcols[j+1];
2653     const NdbDictionary::Column* column = tab->getColumn(col);
2654     f(column);
2655   }
2656   Uint64 stop = NdbTick_CurrentMillisecond();
2657   stop -= start;
2658 
2659   Uint64 per = stop;
2660   per *= 1000;
2661   per /= times;
2662 
2663   ndbout_c("%d random getColumn(name) in %lld ms -> %u us/get",
2664 	   times, stop, Uint32(per));
2665 
2666   return NDBT_OK;
2667 }
2668 
2669 int
runCreateLogfileGroup(NDBT_Context * ctx,NDBT_Step * step)2670 runCreateLogfileGroup(NDBT_Context* ctx, NDBT_Step* step){
2671   Ndb* pNdb = GETNDB(step);
2672   NdbDictionary::LogfileGroup lg;
2673   lg.setName("DEFAULT-LG");
2674   lg.setUndoBufferSize(8*1024*1024);
2675 
2676   int oneDictParticipantFail = ctx->getProperty("OneDictParticipantFail",
2677                                                 (Uint32)0);
2678   if (oneDictParticipantFail)
2679   {
2680     NdbRestarter restarter;
2681     const int anyDbNodeId = restarter.getNode(NdbRestarter::NS_RANDOM);
2682     restarter.insertErrorInNode(anyDbNodeId, 15001);
2683 
2684     if ((pNdb->getDictionary()->createLogfileGroup(lg)) == 0)
2685     {
2686       g_err << "Error: Should have failed to create logfilegroup"
2687             << " due to error insertion" << endl;
2688 
2689       // Leave the data nodes error-free before failing
2690       restarter.insertErrorInNode(anyDbNodeId, 0);
2691       return NDBT_FAILED;
2692     }
2693 
2694     restarter.insertErrorInNode(anyDbNodeId, 0); // clear error
2695 
2696     // Recreate LFG below
2697   }
2698 
2699   int res = pNdb->getDictionary()->createLogfileGroup(lg);
2700   if(res != 0){
2701     g_err << "Failed to create logfilegroup:"
2702 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2703     return NDBT_FAILED;
2704   }
2705 
2706   NdbDictionary::Undofile uf;
2707   uf.setPath("undofile01.dat");
2708   uf.setSize(5*1024*1024);
2709   uf.setLogfileGroup("DEFAULT-LG");
2710 
2711   res = pNdb->getDictionary()->createUndofile(uf);
2712   if(res != 0){
2713     g_err << "Failed to create undofile:"
2714 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2715     return NDBT_FAILED;
2716   }
2717 
2718   uf.setPath("undofile02.dat");
2719   uf.setSize(5*1024*1024);
2720   uf.setLogfileGroup("DEFAULT-LG");
2721 
2722   res = pNdb->getDictionary()->createUndofile(uf);
2723   if(res != 0){
2724     g_err << "Failed to create undofile:"
2725 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2726     return NDBT_FAILED;
2727   }
2728 
2729   return NDBT_OK;
2730 }
2731 
2732 int
runCreateTablespace(NDBT_Context * ctx,NDBT_Step * step)2733 runCreateTablespace(NDBT_Context* ctx, NDBT_Step* step){
2734   Ndb* pNdb = GETNDB(step);
2735   NdbDictionary::Tablespace lg;
2736   lg.setName("DEFAULT-TS");
2737   lg.setExtentSize(1024*1024);
2738   lg.setDefaultLogfileGroup("DEFAULT-LG");
2739 
2740   int oneDictParticipantFail = ctx->getProperty("OneDictParticipantFail",
2741                                                 (Uint32)0);
2742 
2743   if (oneDictParticipantFail)
2744   {
2745     NdbRestarter restarter;
2746     const int anyDbNodeId = restarter.getNode(NdbRestarter::NS_RANDOM);
2747 
2748     restarter.insertErrorInNode(anyDbNodeId, 16001);
2749 
2750     if ((pNdb->getDictionary()->createTablespace(lg)) == 0)
2751     {
2752       g_err << "Error: Should have failed to createTablespace"
2753             << " due to error insertion." << endl;
2754 
2755       // Leave the data nodes error-free before failing
2756       restarter.insertErrorInNode(anyDbNodeId, 0);
2757       return NDBT_FAILED;
2758     }
2759 
2760     restarter.insertErrorInNode(anyDbNodeId, 0); // clear error
2761 
2762     // recreate TS below.
2763   }
2764 
2765   int res = pNdb->getDictionary()->createTablespace(lg);
2766   if(res != 0){
2767     g_err << "Failed to create tablespace:"
2768 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2769     return NDBT_FAILED;
2770   }
2771 
2772   NdbDictionary::Datafile uf;
2773   uf.setPath("datafile01.dat");
2774   uf.setSize(10*1024*1024);
2775   uf.setTablespace("DEFAULT-TS");
2776 
2777   res = pNdb->getDictionary()->createDatafile(uf);
2778   if(res != 0){
2779     g_err << "Failed to create datafile:"
2780 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2781     return NDBT_FAILED;
2782   }
2783   return NDBT_OK;
2784 }
2785 
2786 int
runDropTableSpaceLogFileGroup(NDBT_Context * ctx,NDBT_Step * step)2787 runDropTableSpaceLogFileGroup(NDBT_Context* ctx, NDBT_Step* step)
2788 {
2789   Ndb* pNdb = GETNDB(step);
2790 
2791   if (pNdb->getDictionary()->dropDatafile(
2792       pNdb->getDictionary()->getDatafile(0, "datafile01.dat")) != 0)
2793   {
2794     g_err << "Error: Failed to drop datafile: "
2795           << pNdb->getDictionary()->getNdbError() << endl;
2796     return NDBT_FAILED;
2797   }
2798 
2799   if (pNdb->getDictionary()->dropTablespace(pNdb->getDictionary()->
2800                                             getTablespace("DEFAULT-TS")) != 0)
2801   {
2802     g_err << "Error: Failed to drop tablespace: "
2803           << pNdb->getDictionary()->getNdbError() << endl;
2804     return NDBT_FAILED;
2805   }
2806 
2807   if (pNdb->getDictionary()->dropLogfileGroup(
2808       pNdb->getDictionary()->getLogfileGroup("DEFAULT-LG")) != 0)
2809   {
2810     g_err << "Error: Drop of LFG Failed"
2811           << endl << pNdb->getDictionary()->getNdbError() << endl;
2812     return NDBT_FAILED;
2813   }
2814   return NDBT_OK;
2815 }
2816 
2817 int
runCreateDiskTable(NDBT_Context * ctx,NDBT_Step * step)2818 runCreateDiskTable(NDBT_Context* ctx, NDBT_Step* step){
2819   Ndb* pNdb = GETNDB(step);
2820 
2821   NdbDictionary::Table tab = *ctx->getTab();
2822   tab.setTablespaceName("DEFAULT-TS");
2823 
2824   for(Uint32 i = 0; i<(Uint32)tab.getNoOfColumns(); i++)
2825     if(!tab.getColumn(i)->getPrimaryKey())
2826       tab.getColumn(i)->setStorageType(NdbDictionary::Column::StorageTypeDisk);
2827 
2828   int res;
2829   res = pNdb->getDictionary()->createTable(tab);
2830   if(res != 0){
2831     g_err << "Failed to create table:"
2832 	  << endl << pNdb->getDictionary()->getNdbError() << endl;
2833     return NDBT_FAILED;
2834   }
2835 
2836   return NDBT_OK;
2837 }
2838 
getColumnMaxLength(const NdbDictionary::Column * c)2839 int getColumnMaxLength(const NdbDictionary::Column* c)
2840 {
2841   int length= c->getLength();
2842   if (c->getArrayType() == NDB_ARRAYTYPE_FIXED)
2843   {
2844     /* Not yet set - need to calculate from type etc. */
2845     DictTabInfo::Attribute attrDesc;
2846 
2847     attrDesc.init();
2848     attrDesc.AttributeExtType= c->getType();
2849     attrDesc.AttributeExtLength= c->getLength();
2850     attrDesc.AttributeExtPrecision= c->getPrecision();
2851     attrDesc.AttributeExtScale= c->getScale();
2852 
2853     if (!attrDesc.translateExtType())
2854     {
2855       return 0;
2856     }
2857 
2858     if (attrDesc.AttributeSize == 0)
2859     {
2860       // bits...
2861       length = 4 * ((c->getLength() + 31) / 32);
2862     }
2863     else
2864     {
2865       length = ((1 << attrDesc.AttributeSize) * c->getLength()) >> 3;
2866     }
2867   }
2868 
2869   return length;
2870 }
2871 
2872 #include <NDBT_Tables.hpp>
2873 
2874 #define SAFTY 300
2875 
runFailAddFragment(NDBT_Context * ctx,NDBT_Step * step)2876 int runFailAddFragment(NDBT_Context* ctx, NDBT_Step* step){
2877   static int acclst[] = { 3001, 6200, 6202 };
2878   static int tuplst[] = { 4007, 4008, 4009, 4010, 4032, 4033, 4034 };
2879   static int tuxlst[] = { 12001, 12002, 12003, 12004,
2880                           6201, 6203 };
2881   static unsigned acccnt = sizeof(acclst)/sizeof(acclst[0]);
2882   static unsigned tupcnt = sizeof(tuplst)/sizeof(tuplst[0]);
2883   static unsigned tuxcnt = sizeof(tuxlst)/sizeof(tuxlst[0]);
2884 
2885   NdbRestarter restarter;
2886   int nodeId = restarter.getMasterNodeId();
2887   Ndb* pNdb = GETNDB(step);
2888   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
2889   NdbDictionary::Table tab(*ctx->getTab());
2890   tab.setFragmentType(NdbDictionary::Object::FragAllLarge);
2891 
2892   int errNo = 0;
2893 #ifdef NDB_USE_GET_ENV
2894   char buf[100];
2895   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
2896   {
2897     errNo = atoi(buf);
2898     ndbout_c("Using errno: %u", errNo);
2899   }
2900 #endif
2901   const NdbDictionary::Table* origTab= ctx->getTab();
2902   HugoCalculator calc(*origTab);
2903 
2904   // Add defaults to some columns
2905   for (int colNum= 0; colNum < tab.getNoOfColumns(); colNum++)
2906   {
2907     const NdbDictionary::Column* origCol= origTab->getColumn(colNum);
2908     NdbDictionary::Column* col= tab.getColumn(colNum);
2909     if (!origCol->getPrimaryKey())
2910     {
2911       if (myRandom48(2) == 0)
2912       {
2913         char defaultBuf[ NDB_MAX_TUPLE_SIZE ];
2914         Uint32 real_len;
2915         Uint32 updatesVal = myRandom48(1 << 16);
2916         const char* def= calc.calcValue(0, colNum, updatesVal,
2917                                         defaultBuf,
2918                                         getColumnMaxLength(origCol),
2919                                         &real_len);
2920         if (col->setDefaultValue(def, real_len) != 0)
2921         {
2922           ndbout_c("Error setting default value\n");
2923           return NDBT_FAILED;
2924         }
2925         NdbDictionary::NdbDataPrintFormat dpf;
2926         ndbout << "Set default for column " << origCol->getName()
2927                << " to ";
2928 
2929         NdbDictionary::printFormattedValue(ndbout,
2930                                            dpf,
2931                                            col,
2932                                            def);
2933         ndbout << endl;
2934       }
2935     }
2936   }
2937 
2938   // ordered index on first few columns
2939   NdbDictionary::Index idx("X");
2940   idx.setTable(tab.getName());
2941   idx.setType(NdbDictionary::Index::OrderedIndex);
2942   idx.setLogging(false);
2943   for (int cnt = 0, i_hate_broken_compilers = 0;
2944        cnt < 3 &&
2945        i_hate_broken_compilers < tab.getNoOfColumns();
2946        i_hate_broken_compilers++) {
2947     if (NdbSqlUtil::check_column_for_ordered_index
2948         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
2949         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
2950         NdbDictionary::Column::StorageTypeDisk)
2951     {
2952       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
2953       cnt++;
2954     }
2955   }
2956 
2957   for (Uint32 i = 0; i<(Uint32)tab.getNoOfColumns(); i++)
2958   {
2959     if (tab.getColumn(i)->getStorageType() ==
2960         NdbDictionary::Column::StorageTypeDisk)
2961     {
2962       NDBT_Tables::create_default_tablespace(pNdb);
2963       break;
2964     }
2965   }
2966 
2967   const int loops = ctx->getNumLoops();
2968   int result = NDBT_OK;
2969   (void)pDic->dropTable(tab.getName());
2970 
2971   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
2972   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
2973 
2974   for (int l = 0; l < loops; l++) {
2975     for (unsigned i0 = 0; i0 < acccnt; i0++) {
2976       unsigned j = (l == 0 ? i0 : myRandom48(acccnt));
2977       int errval = acclst[j];
2978       if (errNo != 0 && errNo != errval)
2979         continue;
2980       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
2981       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
2982       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
2983              "failed to set error insert");
2984       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2985       CHECK2(pDic->createTable(tab) != 0,
2986              "failed to fail after error insert " << errval);
2987       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
2988              "failed to clean error insert value");
2989       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
2990       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
2991       CHECK2(pDic->createTable(tab) == 0,
2992              pDic->getNdbError());
2993       CHECK2(pDic->dropTable(tab.getName()) == 0,
2994              pDic->getNdbError());
2995     }
2996     for (unsigned i1 = 0; i1 < tupcnt; i1++) {
2997       unsigned j = (l == 0 ? i1 : myRandom48(tupcnt));
2998       int errval = tuplst[j];
2999       if (errNo != 0 && errNo != errval)
3000         continue;
3001       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
3002       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
3003       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
3004              "failed to set error insert");
3005       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
3006       CHECK2(pDic->createTable(tab) != 0,
3007              "failed to fail after error insert " << errval);
3008       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
3009              "failed to clean error insert value");
3010       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
3011       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
3012       CHECK2(pDic->createTable(tab) == 0,
3013              pDic->getNdbError());
3014       CHECK2(pDic->dropTable(tab.getName()) == 0,
3015              pDic->getNdbError());
3016     }
3017     for (unsigned i2 = 0; i2 < tuxcnt; i2++) {
3018       unsigned j = (l == 0 ? i2 : myRandom48(tuxcnt));
3019       int errval = tuxlst[j];
3020       if (errNo != 0 && errNo != errval)
3021         continue;
3022       CHECK2(pDic->createTable(tab) == 0,
3023              pDic->getNdbError());
3024 
3025       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
3026       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
3027       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
3028              "failed to set error insert");
3029       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
3030 
3031       CHECK2(pDic->createIndex(idx) != 0,
3032              "failed to fail after error insert " << errval);
3033       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
3034              "failed to clean error insert value");
3035       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
3036       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
3037       CHECK2(pDic->createIndex(idx) == 0,
3038              pDic->getNdbError());
3039       CHECK2(pDic->dropTable(tab.getName()) == 0,
3040              pDic->getNdbError());
3041     }
3042   }
3043 end:
3044   return result;
3045 }
3046 
3047 // NFNR
3048 
3049 // Restarter controls dict ops : 1-run 2-pause 3-stop
3050 // synced by polling...
3051 
3052 static bool
send_dict_ops_cmd(NDBT_Context * ctx,Uint32 cmd)3053 send_dict_ops_cmd(NDBT_Context* ctx, Uint32 cmd)
3054 {
3055   ctx->setProperty("DictOps_CMD", cmd);
3056   while (1) {
3057     if (ctx->isTestStopped())
3058       return false;
3059     if (ctx->getProperty("DictOps_ACK") == cmd)
3060       break;
3061     NdbSleep_MilliSleep(100);
3062   }
3063   return true;
3064 }
3065 
3066 static bool
recv_dict_ops_run(NDBT_Context * ctx)3067 recv_dict_ops_run(NDBT_Context* ctx)
3068 {
3069   while (1) {
3070     if (ctx->isTestStopped())
3071       return false;
3072     Uint32 cmd = ctx->getProperty("DictOps_CMD");
3073     ctx->setProperty("DictOps_ACK", cmd);
3074     if (cmd == 1)
3075       break;
3076     if (cmd == 3)
3077       return false;
3078     NdbSleep_MilliSleep(100);
3079   }
3080   return true;
3081 }
3082 
3083 int
runRestarts(NDBT_Context * ctx,NDBT_Step * step)3084 runRestarts(NDBT_Context* ctx, NDBT_Step* step)
3085 {
3086   static int errlst_master[] = {   // non-crashing
3087     7175,       // send one fake START_PERMREF
3088     0
3089   };
3090   static int errlst_node[] = {
3091     7174,       // crash before sending DICT_LOCK_REQ
3092     7121,       // crash at receive START_PERMCONF
3093     0
3094   };
3095   const uint errcnt_master = sizeof(errlst_master)/sizeof(errlst_master[0]);
3096   const uint errcnt_node = sizeof(errlst_node)/sizeof(errlst_node[0]);
3097 
3098   myRandom48Init((long)NdbTick_CurrentMillisecond());
3099   NdbRestarter restarter;
3100   int result = NDBT_OK;
3101   const int loops = ctx->getNumLoops();
3102 
3103   for (int l = 0; l < loops && result == NDBT_OK; l++) {
3104     g_info << "1: === loop " << l << " ===" << endl;
3105 
3106     // assuming 2-way replicated
3107 
3108     int numnodes = restarter.getNumDbNodes();
3109     CHECK(numnodes >= 1);
3110     if (numnodes == 1)
3111       break;
3112 
3113     int masterNodeId = restarter.getMasterNodeId();
3114     CHECK(masterNodeId != -1);
3115 
3116     // for more complex cases need more restarter support methods
3117 
3118     int nodeIdList[2] = { 0, 0 };
3119     int nodeIdCnt = 0;
3120 
3121     if (numnodes >= 2) {
3122       int rand = myRandom48(numnodes);
3123       int nodeId = restarter.getRandomNotMasterNodeId(rand);
3124       CHECK(nodeId != -1);
3125       nodeIdList[nodeIdCnt++] = nodeId;
3126     }
3127 
3128     if (numnodes >= 4 && (myRandom48(2) == 0) && (restarter.getNumNodeGroups() > 1)) {
3129       int rand = myRandom48(numnodes);
3130       int nodeId = restarter.getRandomNodeOtherNodeGroup(nodeIdList[0], rand);
3131       CHECK(nodeId != -1);
3132       if (nodeId != masterNodeId)
3133         nodeIdList[nodeIdCnt++] = nodeId;
3134     }
3135 
3136     g_info << "1: master=" << masterNodeId << " nodes=" << nodeIdList[0] << "," << nodeIdList[1] << endl;
3137 
3138     const uint timeout = 60; //secs for node wait
3139     const unsigned maxsleep = 2000; //ms
3140 
3141     bool NF_ops = ctx->getProperty("Restart_NF_ops");
3142     uint NF_type = ctx->getProperty("Restart_NF_type");
3143     bool NR_ops = ctx->getProperty("Restart_NR_ops");
3144     bool NR_error = ctx->getProperty("Restart_NR_error");
3145 
3146     g_info << "1: " << (NF_ops ? "run" : "pause") << " dict ops" << endl;
3147     if (! send_dict_ops_cmd(ctx, NF_ops ? 1 : 2))
3148       break;
3149     NdbSleep_MilliSleep(myRandom48(maxsleep));
3150 
3151     {
3152       for (int i = 0; i < nodeIdCnt; i++) {
3153         int nodeId = nodeIdList[i];
3154 
3155         bool nostart = true;
3156         bool abort = NF_type == 0 ? myRandom48(2) : (NF_type == 2);
3157         bool initial = myRandom48(2);
3158 
3159         char flags[40];
3160         strcpy(flags, "flags: nostart");
3161         if (abort)
3162           strcat(flags, ",abort");
3163         if (initial)
3164           strcat(flags, ",initial");
3165 
3166         g_info << "1: restart " << nodeId << " " << flags << endl;
3167         CHECK(restarter.restartOneDbNode(nodeId, initial, nostart, abort) == 0);
3168       }
3169     }
3170 
3171     g_info << "1: wait for nostart" << endl;
3172     CHECK(restarter.waitNodesNoStart(nodeIdList, nodeIdCnt, timeout) == 0);
3173     NdbSleep_MilliSleep(myRandom48(maxsleep));
3174 
3175     int err_master = 0;
3176     int err_node[2] = { 0, 0 };
3177 
3178     if (NR_error) {
3179       err_master = errlst_master[l % errcnt_master];
3180 
3181       // limitation: cannot have 2 node restarts and crash_insert
3182       // one node may die for real (NF during startup)
3183 
3184       for (int i = 0; i < nodeIdCnt && nodeIdCnt == 1; i++) {
3185         err_node[i] = errlst_node[l % errcnt_node];
3186       }
3187     }
3188 
3189     g_info << "1: " << (NR_ops ? "run" : "pause") << " dict ops" << endl;
3190     if (! send_dict_ops_cmd(ctx, NR_ops ? 1 : 2))
3191       break;
3192     NdbSleep_MilliSleep(myRandom48(maxsleep));
3193 
3194     g_info << "1: start nodes" << endl;
3195     CHECK(restarter.startNodes(nodeIdList, nodeIdCnt) == 0);
3196 
3197     if (NR_error) {
3198       {
3199         int err = err_master;
3200         if (err != 0) {
3201           g_info << "1: insert master error " << err << endl;
3202           CHECK(restarter.insertErrorInNode(masterNodeId, err) == 0);
3203         }
3204       }
3205 
3206       for (int i = 0; i < nodeIdCnt; i++) {
3207         int nodeId = nodeIdList[i];
3208 
3209         int err = err_node[i];
3210         if (err != 0) {
3211           g_info << "1: insert node " << nodeId << " error " << err << endl;
3212           CHECK(restarter.insertErrorInNode(nodeId, err) == 0);
3213         }
3214       }
3215     }
3216     NdbSleep_MilliSleep(myRandom48(maxsleep));
3217 
3218     g_info << "1: wait cluster started" << endl;
3219     CHECK(restarter.waitClusterStarted(timeout) == 0);
3220     CHK_NDB_READY(GETNDB(step));
3221     NdbSleep_MilliSleep(myRandom48(maxsleep));
3222 
3223     g_info << "1: restart done" << endl;
3224   }
3225 
3226   g_info << "1: stop dict ops" << endl;
3227   send_dict_ops_cmd(ctx, 3);
3228 
3229   return result;
3230 }
3231 
3232 int
runDictOps(NDBT_Context * ctx,NDBT_Step * step)3233 runDictOps(NDBT_Context* ctx, NDBT_Step* step)
3234 {
3235   myRandom48Init((long)NdbTick_CurrentMillisecond());
3236   int result = NDBT_OK;
3237 
3238   for (int l = 0; result == NDBT_OK; l++) {
3239     if (! recv_dict_ops_run(ctx))
3240       break;
3241 
3242     g_info << "2: === loop " << l << " ===" << endl;
3243 
3244     Ndb* pNdb = GETNDB(step);
3245     NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
3246     const NdbDictionary::Table* pTab = ctx->getTab();
3247     //const char* tabName = pTab->getName(); //XXX what goes on?
3248     char tabName[40];
3249     strcpy(tabName, pTab->getName());
3250 
3251     const unsigned long maxsleep = 100; //ms
3252 
3253     g_info << "2: create table" << endl;
3254     {
3255       uint count = 0;
3256     try_create:
3257       count++;
3258       if (pDic->createTable(*pTab) != 0) {
3259         const NdbError err = pDic->getNdbError();
3260         if (count == 1)
3261           g_err << "2: " << tabName << ": create failed: " << err << endl;
3262         if (err.code != 711) {
3263           result = NDBT_FAILED;
3264           break;
3265         }
3266         NdbSleep_MilliSleep(myRandom48(maxsleep));
3267         goto try_create;
3268       }
3269     }
3270     NdbSleep_MilliSleep(myRandom48(maxsleep));
3271 
3272     g_info << "2: verify create" << endl;
3273     const NdbDictionary::Table* pTab2 = pDic->getTable(tabName);
3274     if (pTab2 == NULL) {
3275       const NdbError err = pDic->getNdbError();
3276       g_err << "2: " << tabName << ": verify create: " << err << endl;
3277       result = NDBT_FAILED;
3278       break;
3279     }
3280     NdbSleep_MilliSleep(myRandom48(maxsleep));
3281 
3282     // replace by the Retrieved table
3283     pTab = pTab2;
3284 
3285     // create indexes
3286     const char** indlist = NDBT_Tables::getIndexes(tabName);
3287     uint indnum = 0;
3288     while (indlist != 0 && *indlist != 0) {
3289       uint count = 0;
3290     try_create_index:
3291       count++;
3292       if (count == 1)
3293         g_info << "2: create index " << indnum << " " << *indlist << endl;
3294       NdbDictionary::Index ind;
3295       char indName[200];
3296       sprintf(indName, "%s_X%u", tabName, indnum);
3297       ind.setName(indName);
3298       ind.setTable(tabName);
3299       if (strcmp(*indlist, "UNIQUE") == 0) {
3300         ind.setType(NdbDictionary::Index::UniqueHashIndex);
3301         ind.setLogging(pTab->getLogging());
3302       } else if (strcmp(*indlist, "ORDERED") == 0) {
3303         ind.setType(NdbDictionary::Index::OrderedIndex);
3304         ind.setLogging(false);
3305       } else {
3306         require(false);
3307       }
3308       const char** indtemp = indlist;
3309       while (*++indtemp != 0) {
3310         ind.addColumn(*indtemp);
3311       }
3312       if (pDic->createIndex(ind) != 0) {
3313         const NdbError err = pDic->getNdbError();
3314         if (count == 1)
3315           g_err << "2: " << indName << ": create failed: " << err << endl;
3316         if (err.code != 711) {
3317           result = NDBT_FAILED;
3318           break;
3319         }
3320         NdbSleep_MilliSleep(myRandom48(maxsleep));
3321         goto try_create_index;
3322       }
3323       indlist = ++indtemp;
3324       indnum++;
3325     }
3326     if (result == NDBT_FAILED)
3327       break;
3328 
3329     uint indcount = indnum;
3330 
3331     int records = myRandom48(ctx->getNumRecords());
3332     g_info << "2: load " << records << " records" << endl;
3333     HugoTransactions hugoTrans(*pTab);
3334     if (hugoTrans.loadTable(pNdb, records) != 0) {
3335       // XXX get error code from hugo
3336       g_err << "2: " << tabName << ": load failed" << endl;
3337       result = NDBT_FAILED;
3338       break;
3339     }
3340     NdbSleep_MilliSleep(myRandom48(maxsleep));
3341 
3342     // drop indexes
3343     indnum = 0;
3344     while (indnum < indcount) {
3345       uint count = 0;
3346     try_drop_index:
3347       count++;
3348       if (count == 1)
3349         g_info << "2: drop index " << indnum << endl;
3350       char indName[200];
3351       sprintf(indName, "%s_X%u", tabName, indnum);
3352       if (pDic->dropIndex(indName, tabName) != 0) {
3353         const NdbError err = pDic->getNdbError();
3354         if (count == 1)
3355           g_err << "2: " << indName << ": drop failed: " << err << endl;
3356         if (err.code != 711) {
3357           result = NDBT_FAILED;
3358           break;
3359         }
3360         NdbSleep_MilliSleep(myRandom48(maxsleep));
3361         goto try_drop_index;
3362       }
3363       indnum++;
3364     }
3365     if (result == NDBT_FAILED)
3366       break;
3367 
3368     g_info << "2: drop" << endl;
3369     {
3370       uint count = 0;
3371     try_drop:
3372       count++;
3373       if (pDic->dropTable(tabName) != 0) {
3374         const NdbError err = pDic->getNdbError();
3375         if (count == 1)
3376           g_err << "2: " << tabName << ": drop failed: " << err << endl;
3377         if (err.code != 711) {
3378           result = NDBT_FAILED;
3379           break;
3380         }
3381         NdbSleep_MilliSleep(myRandom48(maxsleep));
3382         goto try_drop;
3383       }
3384     }
3385     NdbSleep_MilliSleep(myRandom48(maxsleep));
3386 
3387     g_info << "2: verify drop" << endl;
3388     const NdbDictionary::Table* pTab3 = pDic->getTable(tabName);
3389     if (pTab3 != NULL) {
3390       g_err << "2: " << tabName << ": verify drop: table exists" << endl;
3391       result = NDBT_FAILED;
3392       break;
3393     }
3394     if (pDic->getNdbError().code != 709 &&
3395         pDic->getNdbError().code != 723) {
3396       const NdbError err = pDic->getNdbError();
3397       g_err << "2: " << tabName << ": verify drop: " << err << endl;
3398       result = NDBT_FAILED;
3399       break;
3400     }
3401     NdbSleep_MilliSleep(myRandom48(maxsleep));
3402   }
3403 
3404   return result;
3405 }
3406 
3407 int
runBug21755(NDBT_Context * ctx,NDBT_Step * step)3408 runBug21755(NDBT_Context* ctx, NDBT_Step* step)
3409 {
3410   char buf[256];
3411   NdbRestarter res;
3412   NdbDictionary::Table pTab0 = * ctx->getTab();
3413   NdbDictionary::Table pTab1 = pTab0;
3414 
3415   if (res.getNumDbNodes() < 2)
3416     return NDBT_OK;
3417 
3418   Ndb* pNdb = GETNDB(step);
3419   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
3420 
3421   if (pDic->createTable(pTab0))
3422   {
3423     ndbout << pDic->getNdbError() << endl;
3424     return NDBT_FAILED;
3425   }
3426 
3427   NdbDictionary::Index idx0;
3428   BaseString::snprintf(buf, sizeof(buf), "%s-idx", pTab0.getName());
3429   idx0.setName(buf);
3430   idx0.setType(NdbDictionary::Index::OrderedIndex);
3431   idx0.setTable(pTab0.getName());
3432   idx0.setStoredIndex(false);
3433   for (Uint32 i = 0; i<(Uint32)pTab0.getNoOfColumns(); i++)
3434   {
3435     const NdbDictionary::Column * col = pTab0.getColumn(i);
3436     if(col->getPrimaryKey()){
3437       idx0.addIndexColumn(col->getName());
3438     }
3439   }
3440 
3441   if (pDic->createIndex(idx0))
3442   {
3443     ndbout << pDic->getNdbError() << endl;
3444     return NDBT_FAILED;
3445   }
3446 
3447   BaseString::snprintf(buf, sizeof(buf), "%s-2", pTab1.getName());
3448   pTab1.setName(buf);
3449 
3450   if (pDic->createTable(pTab1))
3451   {
3452     ndbout << pDic->getNdbError() << endl;
3453     return NDBT_FAILED;
3454   }
3455 
3456   {
3457     const NdbDictionary::Table* pTab = pDic->getTable(pTab0.getName());
3458     if (pTab == NULL) {
3459       g_err << "Table 'pTab0': " << pTab0.getName()
3460             << ", not found on line " << __LINE__
3461             <<", error: " << pDic->getNdbError()
3462             << endl;
3463       return NDBT_FAILED;
3464     }
3465     HugoTransactions t0 (*pTab);
3466     t0.loadTable(pNdb, 1000);
3467   }
3468 
3469   {
3470     const NdbDictionary::Table* pTab = pDic->getTable(pTab1.getName());
3471     if (pTab == NULL) {
3472       g_err << "Table 'pTab1': " << pTab1.getName()
3473             << ", not found on line " << __LINE__
3474             <<", error: " << pDic->getNdbError()
3475             << endl;
3476       return NDBT_FAILED;
3477     }
3478     HugoTransactions t1 (*pTab);
3479     t1.loadTable(pNdb, 1000);
3480   }
3481 
3482   int node = res.getRandomNotMasterNodeId(rand());
3483   res.restartOneDbNode(node, false, true, true);
3484 
3485   if (pDic->dropTable(pTab1.getName()))
3486   {
3487     ndbout << pDic->getNdbError() << endl;
3488     return NDBT_FAILED;
3489   }
3490 
3491   BaseString::snprintf(buf, sizeof(buf), "%s-idx2", pTab0.getName());
3492   idx0.setName(buf);
3493   if (pDic->createIndex(idx0))
3494   {
3495     ndbout << pDic->getNdbError() << endl;
3496     return NDBT_FAILED;
3497   }
3498 
3499   res.waitNodesNoStart(&node, 1);
3500   res.startNodes(&node, 1);
3501 
3502   if (res.waitClusterStarted())
3503   {
3504     return NDBT_FAILED;
3505   }
3506   CHK_NDB_READY(pNdb);
3507 
3508   if (pDic->dropTable(pTab0.getName()))
3509   {
3510     ndbout << pDic->getNdbError() << endl;
3511     return NDBT_FAILED;
3512   }
3513 
3514   return NDBT_OK;
3515 }
3516 
3517 static
3518 int
create_tablespace(NdbDictionary::Dictionary * pDict,const char * lgname,const char * tsname,const char * dfname)3519 create_tablespace(NdbDictionary::Dictionary* pDict,
3520                   const char * lgname,
3521                   const char * tsname,
3522                   const char * dfname)
3523 {
3524   NdbDictionary::Tablespace ts;
3525   ts.setName(tsname);
3526   ts.setExtentSize(1024*1024);
3527   ts.setDefaultLogfileGroup(lgname);
3528 
3529   if(pDict->createTablespace(ts) != 0)
3530   {
3531     g_err << "Failed to create tablespace:"
3532           << endl << pDict->getNdbError() << endl;
3533     return NDBT_FAILED;
3534   }
3535 
3536   NdbDictionary::Datafile df;
3537   df.setPath(dfname);
3538   df.setSize(1*1024*1024);
3539   df.setTablespace(tsname);
3540 
3541   if(pDict->createDatafile(df) != 0)
3542   {
3543     g_err << "Failed to create datafile:"
3544           << endl << pDict->getNdbError() << endl;
3545     return NDBT_FAILED;
3546   }
3547   return 0;
3548 }
3549 
3550 int
runBug24631(NDBT_Context * ctx,NDBT_Step * step)3551 runBug24631(NDBT_Context* ctx, NDBT_Step* step)
3552 {
3553   char tsname[256];
3554   char dfname[256];
3555   char lgname[256];
3556   char ufname[256];
3557   NdbRestarter res;
3558 
3559   if (res.getNumDbNodes() < 2)
3560     return NDBT_OK;
3561 
3562   Ndb* pNdb = GETNDB(step);
3563   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3564 
3565   NdbDictionary::Dictionary::List list;
3566   if (pDict->listObjects(list) == -1)
3567     return NDBT_FAILED;
3568 
3569   const char * lgfound = 0;
3570 
3571   for (Uint32 i = 0; i<list.count; i++)
3572   {
3573     switch(list.elements[i].type){
3574     case NdbDictionary::Object::LogfileGroup:
3575       lgfound = list.elements[i].name;
3576       break;
3577     default:
3578       break;
3579     }
3580     if (lgfound)
3581       break;
3582   }
3583 
3584   if (lgfound == 0)
3585   {
3586     BaseString::snprintf(lgname, sizeof(lgname), "LG-%u", rand());
3587     NdbDictionary::LogfileGroup lg;
3588 
3589     lg.setName(lgname);
3590     lg.setUndoBufferSize(8*1024*1024);
3591     if(pDict->createLogfileGroup(lg) != 0)
3592     {
3593       g_err << "Failed to create logfilegroup:"
3594 	    << endl << pDict->getNdbError() << endl;
3595       return NDBT_FAILED;
3596     }
3597 
3598     NdbDictionary::Undofile uf;
3599     BaseString::snprintf(ufname, sizeof(ufname), "%s-%u", lgname, rand());
3600     uf.setPath(ufname);
3601     uf.setSize(2*1024*1024);
3602     uf.setLogfileGroup(lgname);
3603 
3604     if(pDict->createUndofile(uf) != 0)
3605     {
3606       g_err << "Failed to create undofile:"
3607             << endl << pDict->getNdbError() << endl;
3608       return NDBT_FAILED;
3609     }
3610   }
3611   else
3612   {
3613     BaseString::snprintf(lgname, sizeof(lgname), "%s", lgfound);
3614   }
3615 
3616   BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand());
3617   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u.dat", tsname, rand());
3618 
3619   if (create_tablespace(pDict, lgname, tsname, dfname))
3620     return NDBT_FAILED;
3621 
3622 
3623   int node = res.getRandomNotMasterNodeId(rand());
3624   res.restartOneDbNode(node, false, true, true);
3625   NdbSleep_SecSleep(3);
3626 
3627   if (pDict->dropDatafile(pDict->getDatafile(0, dfname)) != 0)
3628   {
3629     g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
3630     return NDBT_FAILED;
3631   }
3632 
3633   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3634   {
3635     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3636     return NDBT_FAILED;
3637   }
3638 
3639   if (res.waitNodesNoStart(&node, 1))
3640     return NDBT_FAILED;
3641 
3642   res.startNodes(&node, 1);
3643   if (res.waitClusterStarted())
3644     return NDBT_FAILED;
3645   CHK_NDB_READY(pNdb);
3646 
3647   if (create_tablespace(pDict, lgname, tsname, dfname))
3648     return NDBT_FAILED;
3649 
3650   if (pDict->dropDatafile(pDict->getDatafile(0, dfname)) != 0)
3651   {
3652     g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
3653     return NDBT_FAILED;
3654   }
3655 
3656   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3657   {
3658     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3659     return NDBT_FAILED;
3660   }
3661 
3662   if (lgfound == 0)
3663   {
3664     if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgname)) != 0)
3665       return NDBT_FAILED;
3666   }
3667 
3668   return NDBT_OK;
3669 }
3670 
3671 int
runBug29186(NDBT_Context * ctx,NDBT_Step * step)3672 runBug29186(NDBT_Context* ctx, NDBT_Step* step)
3673 {
3674   int lgError = 15000;
3675   int tsError = 16000;
3676   char lgname[256];
3677   char ufname[256];
3678   char tsname[256];
3679   char dfname[256];
3680 
3681   NdbRestarter restarter;
3682 
3683   if (restarter.getNumDbNodes() < 2){
3684     ctx->stopTest();
3685     return NDBT_OK;
3686   }
3687 
3688   Ndb* pNdb = GETNDB(step);
3689   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
3690   NdbDictionary::Dictionary::List list;
3691 
3692   if (pDict->listObjects(list) == -1)
3693     return NDBT_FAILED;
3694 
3695   // 1.create logfile group
3696   const char * lgfound = 0;
3697 
3698   for (Uint32 i = 0; i<list.count; i++)
3699   {
3700     switch(list.elements[i].type){
3701     case NdbDictionary::Object::LogfileGroup:
3702       lgfound = list.elements[i].name;
3703       break;
3704     default:
3705       break;
3706     }
3707     if (lgfound)
3708       break;
3709   }
3710 
3711   if (lgfound == 0)
3712   {
3713     BaseString::snprintf(lgname, sizeof(lgname), "LG-%u", rand());
3714     NdbDictionary::LogfileGroup lg;
3715 
3716     lg.setName(lgname);
3717     lg.setUndoBufferSize(8*1024*1024);
3718     if(pDict->createLogfileGroup(lg) != 0)
3719     {
3720       g_err << "Failed to create logfilegroup:"
3721             << endl << pDict->getNdbError() << endl;
3722       return NDBT_FAILED;
3723     }
3724   }
3725   else
3726   {
3727     BaseString::snprintf(lgname, sizeof(lgname), "%s", lgfound);
3728   }
3729 
3730   if(restarter.waitClusterStarted(60)){
3731     g_err << "waitClusterStarted failed"<< endl;
3732     return NDBT_FAILED;
3733   }
3734   CHK_NDB_READY(pNdb);
3735 
3736   if(restarter.insertErrorInAllNodes(lgError) != 0){
3737     g_err << "failed to set error insert"<< endl;
3738     return NDBT_FAILED;
3739   }
3740 
3741   g_info << "error inserted"  << endl;
3742   g_info << "waiting some before add log file"  << endl;
3743   g_info << "starting create log file group"  << endl;
3744 
3745   NdbDictionary::Undofile uf;
3746   BaseString::snprintf(ufname, sizeof(ufname), "%s-%u", lgname, rand());
3747   uf.setPath(ufname);
3748   uf.setSize(2*1024*1024);
3749   uf.setLogfileGroup(lgname);
3750 
3751   if(pDict->createUndofile(uf) == 0)
3752   {
3753     g_err << "Create log file group should fail on error_insertion " << lgError << endl;
3754     return NDBT_FAILED;
3755   }
3756 
3757   //clear lg error
3758   if(restarter.insertErrorInAllNodes(15099) != 0){
3759     g_err << "failed to set error insert"<< endl;
3760     return NDBT_FAILED;
3761   }
3762   NdbSleep_SecSleep(5);
3763 
3764   //lg error has been cleared, so we can add undo file
3765   if(pDict->createUndofile(uf) != 0)
3766   {
3767     g_err << "Failed to create undofile:"
3768           << endl << pDict->getNdbError() << endl;
3769     return NDBT_FAILED;
3770   }
3771 
3772   if(restarter.waitClusterStarted(60)){
3773     g_err << "waitClusterStarted failed"<< endl;
3774     return NDBT_FAILED;
3775   }
3776   CHK_NDB_READY(pNdb);
3777 
3778   if(restarter.insertErrorInAllNodes(tsError) != 0){
3779     g_err << "failed to set error insert"<< endl;
3780     return NDBT_FAILED;
3781   }
3782   g_info << "error inserted"  << endl;
3783   g_info << "waiting some before create table space"  << endl;
3784   g_info << "starting create table space"  << endl;
3785 
3786   //r = runCreateTablespace(ctx, step);
3787   BaseString::snprintf(tsname,  sizeof(tsname), "TS-%u", rand());
3788   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u-1.dat", tsname, rand());
3789 
3790   NdbDictionary::Tablespace ts;
3791   ts.setName(tsname);
3792   ts.setExtentSize(1024*1024);
3793   ts.setDefaultLogfileGroup(lgname);
3794 
3795   if(pDict->createTablespace(ts) != 0)
3796   {
3797     g_err << "Failed to create tablespace:"
3798           << endl << pDict->getNdbError() << endl;
3799     return NDBT_FAILED;
3800   }
3801 
3802   NdbDictionary::Datafile df;
3803   df.setPath(dfname);
3804   df.setSize(1*1024*1024);
3805   df.setTablespace(tsname);
3806 
3807   if(pDict->createDatafile(df) == 0)
3808   {
3809     g_err << "Create table space should fail on error_insertion " << tsError << endl;
3810     return NDBT_FAILED;
3811   }
3812   //Clear the inserted error
3813   if(restarter.insertErrorInAllNodes(16099) != 0){
3814     g_err << "failed to set error insert"<< endl;
3815     return NDBT_FAILED;
3816   }
3817   NdbSleep_SecSleep(5);
3818 
3819   if (pDict->dropTablespace(pDict->getTablespace(tsname)) != 0)
3820   {
3821     g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
3822     return NDBT_FAILED;
3823   }
3824 
3825   if (lgfound == 0)
3826   {
3827     if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgname)) != 0)
3828       return NDBT_FAILED;
3829   }
3830 
3831   return NDBT_OK;
3832 }
3833 
3834 struct RandSchemaOp
3835 {
RandSchemaOpRandSchemaOp3836   RandSchemaOp(unsigned * randseed = 0) {
3837     if (randseed == 0)
3838     {
3839       ownseed = (unsigned)NdbTick_CurrentMillisecond();
3840       seed = &ownseed;
3841     }
3842     else
3843     {
3844       seed = randseed;
3845     }
3846   }
3847   struct Obj
3848   {
3849     BaseString m_name;
3850     Uint32 m_type;
3851     struct Obj* m_parent;
3852     Vector<Obj*> m_dependant;
3853   };
3854 
3855   Vector<Obj*> m_objects;
3856 
3857   int schema_op(Ndb*);
3858   int validate(Ndb*);
3859   int cleanup(Ndb*);
3860 
3861   Obj* get_obj(Uint32 mask);
3862   int create_table(Ndb*);
3863   int create_index(Ndb*, Obj*);
3864   int alter_table(Ndb*, Obj*);
3865   int drop_obj(Ndb*, Obj*);
3866 
3867   void remove_obj(Obj*);
3868 private:
3869   unsigned * seed;
3870   unsigned ownseed;
3871 };
3872 
3873 template class Vector<RandSchemaOp::Obj*>;
3874 
3875 int
schema_op(Ndb * ndb)3876 RandSchemaOp::schema_op(Ndb* ndb)
3877 {
3878   struct Obj* obj = 0;
3879   Uint32 type = 0;
3880 loop:
3881   switch(ndb_rand_r(seed) % 5){
3882   case 0:
3883     return create_table(ndb);
3884   case 1:
3885     if ((obj = get_obj(1 << NdbDictionary::Object::UserTable)) == 0)
3886       goto loop;
3887     return create_index(ndb, obj);
3888   case 2:
3889     type = (1 << NdbDictionary::Object::UserTable);
3890     goto drop_object;
3891   case 3:
3892     type =
3893       (1 << NdbDictionary::Object::UniqueHashIndex) |
3894       (1 << NdbDictionary::Object::OrderedIndex);
3895     goto drop_object;
3896   case 4:
3897     if ((obj = get_obj(1 << NdbDictionary::Object::UserTable)) == 0)
3898       goto loop;
3899     return alter_table(ndb, obj);
3900   default:
3901     goto loop;
3902   }
3903 
3904 drop_object:
3905   if ((obj = get_obj(type)) == 0)
3906     goto loop;
3907   return drop_obj(ndb, obj);
3908 }
3909 
3910 RandSchemaOp::Obj*
get_obj(Uint32 mask)3911 RandSchemaOp::get_obj(Uint32 mask)
3912 {
3913   Vector<Obj*> tmp;
3914   for (Uint32 i = 0; i<m_objects.size(); i++)
3915   {
3916     if ((1 << m_objects[i]->m_type) & mask)
3917       tmp.push_back(m_objects[i]);
3918   }
3919 
3920   if (tmp.size())
3921   {
3922     return tmp[ndb_rand_r(seed)%tmp.size()];
3923   }
3924   return 0;
3925 }
3926 
3927 int
create_table(Ndb * ndb)3928 RandSchemaOp::create_table(Ndb* ndb)
3929 {
3930   int numTables = NDBT_Tables::getNumTables();
3931   int num = ndb_rand_r(seed) % numTables;
3932   NdbDictionary::Table pTab = * NDBT_Tables::getTable(num);
3933 
3934   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3935   pTab.setForceVarPart(true);
3936 
3937   if (pDict->getTable(pTab.getName()))
3938   {
3939     char buf[100];
3940     BaseString::snprintf(buf, sizeof(buf), "%s-%d",
3941                          pTab.getName(), ndb_rand_r(seed));
3942     pTab.setName(buf);
3943     if (pDict->createTable(pTab))
3944       return NDBT_FAILED;
3945   }
3946   else
3947   {
3948     if (NDBT_Tables::createTable(ndb, pTab.getName()))
3949     {
3950       return NDBT_FAILED;
3951     }
3952   }
3953 
3954   ndbout_c("create table %s",  pTab.getName());
3955   const NdbDictionary::Table* tab2 = pDict->getTable(pTab.getName());
3956   if (tab2 == NULL) {
3957     g_err << "Table : " << pTab.getName()
3958           << ", not found on line " << __LINE__
3959           <<", error: " << pDict->getNdbError()
3960           << endl;
3961     return NDBT_FAILED;
3962   }
3963   HugoTransactions trans(*tab2);
3964   trans.loadTable(ndb, 1000);
3965 
3966   Obj *obj = new Obj;
3967   obj->m_name.assign(pTab.getName());
3968   obj->m_type = NdbDictionary::Object::UserTable;
3969   obj->m_parent = 0;
3970   m_objects.push_back(obj);
3971 
3972   return NDBT_OK;
3973 }
3974 
3975 int
create_index(Ndb * ndb,Obj * tab)3976 RandSchemaOp::create_index(Ndb* ndb, Obj* tab)
3977 {
3978   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
3979   const NdbDictionary::Table * pTab = pDict->getTable(tab->m_name.c_str());
3980 
3981   if (pTab == 0)
3982   {
3983     return NDBT_FAILED;
3984   }
3985 
3986   bool ordered = ndb_rand_r(seed) & 1;
3987   bool stored = ndb_rand_r(seed) & 1;
3988 
3989   Uint32 type = ordered ?
3990     NdbDictionary::Index::OrderedIndex :
3991     NdbDictionary::Index::UniqueHashIndex;
3992 
3993   char buf[255];
3994   BaseString::snprintf(buf, sizeof(buf), "%s-%s",
3995                        pTab->getName(),
3996                        ordered ? "OI" : "UI");
3997 
3998   if (pDict->getIndex(buf, pTab->getName()))
3999   {
4000     // Index exists...let it be ok
4001     return NDBT_OK;
4002   }
4003 
4004   ndbout_c("create index %s", buf);
4005   NdbDictionary::Index idx0;
4006   idx0.setName(buf);
4007   idx0.setType((NdbDictionary::Index::Type)type);
4008   idx0.setTable(pTab->getName());
4009   idx0.setStoredIndex(ordered ? false : stored);
4010 
4011   for (Uint32 i = 0; i<(Uint32)pTab->getNoOfColumns(); i++)
4012   {
4013     if (pTab->getColumn(i)->getPrimaryKey())
4014       idx0.addColumn(pTab->getColumn(i)->getName());
4015   }
4016   if (pDict->createIndex(idx0))
4017   {
4018     ndbout << pDict->getNdbError() << endl;
4019     return NDBT_FAILED;
4020   }
4021   Obj *obj = new Obj;
4022   obj->m_name.assign(buf);
4023   obj->m_type = type;
4024   obj->m_parent = tab;
4025   m_objects.push_back(obj);
4026 
4027   tab->m_dependant.push_back(obj);
4028   return NDBT_OK;
4029 }
4030 
4031 int
drop_obj(Ndb * ndb,Obj * obj)4032 RandSchemaOp::drop_obj(Ndb* ndb, Obj* obj)
4033 {
4034   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
4035 
4036   if (obj->m_type == NdbDictionary::Object::UserTable)
4037   {
4038     ndbout_c("drop table %s", obj->m_name.c_str());
4039     /**
4040      * Drop of table automatically drops all indexes
4041      */
4042     if (pDict->dropTable(obj->m_name.c_str()))
4043     {
4044       return NDBT_FAILED;
4045     }
4046     while(obj->m_dependant.size())
4047     {
4048       remove_obj(obj->m_dependant[0]);
4049     }
4050     remove_obj(obj);
4051   }
4052   else if (obj->m_type == NdbDictionary::Object::UniqueHashIndex ||
4053            obj->m_type == NdbDictionary::Object::OrderedIndex)
4054   {
4055     ndbout_c("drop index %s", obj->m_name.c_str());
4056     if (pDict->dropIndex(obj->m_name.c_str(),
4057                          obj->m_parent->m_name.c_str()))
4058     {
4059       return NDBT_FAILED;
4060     }
4061     remove_obj(obj);
4062   }
4063   return NDBT_OK;
4064 }
4065 
4066 void
remove_obj(Obj * obj)4067 RandSchemaOp::remove_obj(Obj* obj)
4068 {
4069   Uint32 i;
4070   if (obj->m_parent)
4071   {
4072     bool found = false;
4073     for (i = 0; i<obj->m_parent->m_dependant.size(); i++)
4074     {
4075       if (obj->m_parent->m_dependant[i] == obj)
4076       {
4077         found = true;
4078         obj->m_parent->m_dependant.erase(i);
4079         break;
4080       }
4081     }
4082     require(found);
4083   }
4084 
4085   {
4086     bool found = false;
4087     for (i = 0; i<m_objects.size(); i++)
4088     {
4089       if (m_objects[i] == obj)
4090       {
4091         found = true;
4092         m_objects.erase(i);
4093         break;
4094       }
4095     }
4096     require(found);
4097   }
4098   delete obj;
4099 }
4100 
4101 int
alter_table(Ndb * ndb,Obj * obj)4102 RandSchemaOp::alter_table(Ndb* ndb, Obj* obj)
4103 {
4104   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
4105   const NdbDictionary::Table * pOld = pDict->getTable(obj->m_name.c_str());
4106   NdbDictionary::Table tNew = * pOld;
4107 
4108   BaseString ops;
4109   unsigned mask = 3;
4110 
4111   unsigned type;
4112   while (ops.length() == 0 && (mask != 0))
4113   {
4114     switch((type = (ndb_rand_r(seed) & 1))){
4115     default:
4116     case 0:{
4117       if ((mask & (1 << type)) == 0)
4118         break;
4119       BaseString name;
4120       name.assfmt("newcol_%d", tNew.getNoOfColumns());
4121       NdbDictionary::Column col(name.c_str());
4122       col.setType(NdbDictionary::Column::Unsigned);
4123       col.setDynamic(true);
4124       col.setPrimaryKey(false);
4125       col.setNullable(true);
4126       NdbDictionary::Table save = tNew;
4127       tNew.addColumn(col);
4128       if (!pDict->supportedAlterTable(* pOld, tNew))
4129       {
4130         ndbout_c("not supported...");
4131         mask &= ~(1 << type);
4132         tNew = save;
4133         break;
4134       }
4135       ops.append(" addcol");
4136       break;
4137     }
4138     case 1:{
4139       BaseString name;
4140       do
4141       {
4142         unsigned no = ndb_rand_r(seed);
4143         name.assfmt("%s_%u", pOld->getName(), no);
4144       } while (pDict->getTable(name.c_str()));
4145       tNew.setName(name.c_str());
4146       ops.appfmt(" rename: %s", name.c_str());
4147       break;
4148     }
4149 
4150     }
4151   }
4152 
4153   if (ops.length())
4154   {
4155     ndbout_c("altering %s ops: %s", pOld->getName(), ops.c_str());
4156     if (pDict->alterTable(*pOld, tNew) != 0)
4157     {
4158       g_err << pDict->getNdbError() << endl;
4159       return NDBT_FAILED;
4160     }
4161     if (strcmp(pOld->getName(), tNew.getName()))
4162     {
4163       obj->m_name.assign(tNew.getName());
4164     }
4165     pDict->invalidateTable(pOld->getName());
4166   }
4167 
4168   return NDBT_OK;
4169 }
4170 
4171 
4172 int
validate(Ndb * ndb)4173 RandSchemaOp::validate(Ndb* ndb)
4174 {
4175   NdbDictionary::Dictionary* pDict = ndb->getDictionary();
4176   for (Uint32 i = 0; i<m_objects.size(); i++)
4177   {
4178     if (m_objects[i]->m_type == NdbDictionary::Object::UserTable)
4179     {
4180       const NdbDictionary::Table* tab2 =
4181         pDict->getTable(m_objects[i]->m_name.c_str());
4182 
4183       if (tab2 == NULL) {
4184         g_err << "Table: " << m_objects[i]->m_name.c_str()
4185               << ", not found on line " << __LINE__
4186               <<", error: " << pDict->getNdbError()
4187               << endl;
4188         return NDBT_FAILED;
4189       }
4190       HugoTransactions trans(*tab2);
4191       trans.scanUpdateRecords(ndb, 1000);
4192       trans.clearTable(ndb);
4193       trans.loadTable(ndb, 1000);
4194     }
4195   }
4196 
4197   return NDBT_OK;
4198 }
4199 
4200 /*
4201       SystemTable = 1,        ///< System table
4202       UserTable = 2,          ///< User table (may be temporary)
4203       UniqueHashIndex = 3,    ///< Unique un-ordered hash index
4204       OrderedIndex = 6,       ///< Non-unique ordered index
4205       HashIndexTrigger = 7,   ///< Index maintenance, internal
4206       IndexTrigger = 8,       ///< Index maintenance, internal
4207       SubscriptionTrigger = 9,///< Backup or replication, internal
4208       ReadOnlyConstraint = 10,///< Trigger, internal
4209       Tablespace = 20,        ///< Tablespace
4210       LogfileGroup = 21,      ///< Logfile group
4211       Datafile = 22,          ///< Datafile
4212       Undofile = 23           ///< Undofile
4213 */
4214 
4215 int
cleanup(Ndb * ndb)4216 RandSchemaOp::cleanup(Ndb* ndb)
4217 {
4218   Int32 i;
4219   for (i = m_objects.size() - 1; i >= 0; i--)
4220   {
4221     switch(m_objects[i]->m_type){
4222     case NdbDictionary::Object::UniqueHashIndex:
4223     case NdbDictionary::Object::OrderedIndex:
4224       if (drop_obj(ndb, m_objects[i]))
4225         return NDBT_FAILED;
4226 
4227       break;
4228     default:
4229       break;
4230     }
4231   }
4232 
4233   for (i = m_objects.size() - 1; i >= 0; i--)
4234   {
4235     switch(m_objects[i]->m_type){
4236     case NdbDictionary::Object::UserTable:
4237       if (drop_obj(ndb, m_objects[i]))
4238         return NDBT_FAILED;
4239       break;
4240     default:
4241       break;
4242     }
4243   }
4244 
4245   require(m_objects.size() == 0);
4246   return NDBT_OK;
4247 }
4248 
4249 extern unsigned opt_seed;
4250 
4251 int
runDictRestart(NDBT_Context * ctx,NDBT_Step * step)4252 runDictRestart(NDBT_Context* ctx, NDBT_Step* step)
4253 {
4254   Ndb* pNdb = GETNDB(step);
4255   int loops = ctx->getNumLoops();
4256 
4257   unsigned seed = opt_seed;
4258   NdbMixRestarter res(&seed);
4259   RandSchemaOp dict(&seed);
4260   if (res.getNumDbNodes() < 2)
4261     return NDBT_OK;
4262 
4263   if (res.init(ctx, step))
4264     return NDBT_FAILED;
4265 
4266   for (int i = 0; i<loops; i++)
4267   {
4268     for (Uint32 j = 0; j<10; j++)
4269       if (dict.schema_op(pNdb))
4270         return NDBT_FAILED;
4271 
4272     if (res.dostep(ctx, step))
4273       return NDBT_FAILED;
4274 
4275     if (dict.validate(pNdb))
4276       return NDBT_FAILED;
4277   }
4278 
4279   if (res.finish(ctx, step))
4280     return NDBT_FAILED;
4281 
4282   if (dict.validate(pNdb))
4283     return NDBT_FAILED;
4284 
4285   if (dict.cleanup(pNdb))
4286     return NDBT_FAILED;
4287 
4288   return NDBT_OK;
4289 }
4290 
4291 int
runBug29501(NDBT_Context * ctx,NDBT_Step * step)4292 runBug29501(NDBT_Context* ctx, NDBT_Step* step) {
4293   NdbRestarter res;
4294   NdbDictionary::LogfileGroup lg;
4295   lg.setName("DEFAULT-LG");
4296   lg.setUndoBufferSize(8*1024*1024);
4297 
4298   if (res.getNumDbNodes() < 2)
4299     return NDBT_OK;
4300 
4301   Ndb* pNdb = GETNDB(step);
4302   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4303 
4304   int node = res.getRandomNotMasterNodeId(rand());
4305   res.restartOneDbNode(node, true, true, false);
4306 
4307   if(pDict->createLogfileGroup(lg) != 0){
4308     g_err << "Failed to create logfilegroup:"
4309         << endl << pDict->getNdbError() << endl;
4310     return NDBT_FAILED;
4311   }
4312 
4313   NdbDictionary::Undofile uf;
4314   uf.setPath("undofile01.dat");
4315   uf.setSize(5*1024*1024);
4316   uf.setLogfileGroup("DEFAULT-LG");
4317 
4318   if(pDict->createUndofile(uf) != 0){
4319     g_err << "Failed to create undofile:"
4320         << endl << pDict->getNdbError() << endl;
4321     return NDBT_FAILED;
4322   }
4323 
4324   res.waitNodesNoStart(&node, 1);
4325   res.startNodes(&node, 1);
4326 
4327   if (res.waitClusterStarted()){
4328   	g_err << "Node restart failed"
4329   	<< endl << pDict->getNdbError() << endl;
4330       return NDBT_FAILED;
4331   }
4332   CHK_NDB_READY(pNdb);
4333 
4334   if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lg.getName())) != 0){
4335   	g_err << "Drop of LFG Failed"
4336   	<< endl << pDict->getNdbError() << endl;
4337     return NDBT_FAILED;
4338   }
4339 
4340   return NDBT_OK;
4341 }
4342 
4343 int
runDropDDObjects(NDBT_Context * ctx,NDBT_Step * step)4344 runDropDDObjects(NDBT_Context* ctx, NDBT_Step* step){
4345   //Purpose is to drop all tables, data files, Table spaces and LFG's
4346   Uint32 i = 0;
4347 
4348   Ndb* pNdb = GETNDB(step);
4349   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4350 
4351   NdbDictionary::Dictionary::List list;
4352   if (pDict->listObjects(list) == -1)
4353     return NDBT_FAILED;
4354 
4355   //Search the list and drop all tables found
4356   const char * tableFound = 0;
4357   for (i = 0; i < list.count; i++){
4358     switch(list.elements[i].type){
4359       case NdbDictionary::Object::UserTable:
4360         tableFound = list.elements[i].name;
4361         if(tableFound != 0){
4362           if(strcmp(list.elements[i].database, "TEST_DB") == 0 &&
4363              !is_prefix(tableFound, "NDB$BLOB"))
4364           {
4365       	    if(pDict->dropTable(tableFound) != 0){
4366               g_err << "Failed to drop table: " << tableFound << pDict->getNdbError() << endl;
4367               return NDBT_FAILED;
4368             }
4369           }
4370         }
4371         tableFound = 0;
4372         break;
4373       default:
4374         break;
4375     }
4376   }
4377 
4378   //Search the list and drop all data file found
4379   const char * dfFound = 0;
4380   for (i = 0; i < list.count; i++){
4381     switch(list.elements[i].type){
4382       case NdbDictionary::Object::Datafile:
4383         dfFound = list.elements[i].name;
4384         if(dfFound != 0){
4385       	  if(pDict->dropDatafile(pDict->getDatafile(0, dfFound)) != 0){
4386             g_err << "Failed to drop datafile: " << pDict->getNdbError() << endl;
4387             return NDBT_FAILED;
4388           }
4389         }
4390         dfFound = 0;
4391         break;
4392       default:
4393         break;
4394     }
4395   }
4396 
4397   //Search the list and drop all Table Spaces Found
4398   const char * tsFound  = 0;
4399   for (i = 0; i <list.count; i++){
4400     switch(list.elements[i].type){
4401       case NdbDictionary::Object::Tablespace:
4402         tsFound = list.elements[i].name;
4403         if(tsFound != 0){
4404           if(pDict->dropTablespace(pDict->getTablespace(tsFound)) != 0){
4405             g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
4406             return NDBT_FAILED;
4407           }
4408         }
4409         tsFound = 0;
4410         break;
4411       default:
4412         break;
4413     }
4414   }
4415 
4416   //Search the list and drop all LFG Found
4417   //Currently only 1 LGF is supported, but written for future
4418   //when more then one is supported.
4419   const char * lgFound  = 0;
4420   for (i = 0; i < list.count; i++){
4421     switch(list.elements[i].type){
4422       case NdbDictionary::Object::LogfileGroup:
4423         lgFound = list.elements[i].name;
4424         if(lgFound != 0){
4425           if (pDict->dropLogfileGroup(pDict->getLogfileGroup(lgFound)) != 0){
4426             g_err << "Failed to drop tablespace: " << pDict->getNdbError() << endl;
4427             return NDBT_FAILED;
4428           }
4429        }
4430         lgFound = 0;
4431         break;
4432       default:
4433         break;
4434     }
4435   }
4436 
4437   return NDBT_OK;
4438 }
4439 
4440 int
runWaitStarted(NDBT_Context * ctx,NDBT_Step * step)4441 runWaitStarted(NDBT_Context* ctx, NDBT_Step* step){
4442 
4443   NdbRestarter restarter;
4444   restarter.waitClusterStarted(300);
4445   CHK_NDB_READY(GETNDB(step));
4446 
4447   NdbSleep_SecSleep(3);
4448   return NDBT_OK;
4449 }
4450 
4451 int
testDropDDObjectsSetup(NDBT_Context * ctx,NDBT_Step * step)4452 testDropDDObjectsSetup(NDBT_Context* ctx, NDBT_Step* step){
4453   //Purpose is to setup to test DropDDObjects
4454   char tsname[256];
4455   char dfname[256];
4456 
4457   Ndb* pNdb = GETNDB(step);
4458   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4459 
4460   NdbDictionary::LogfileGroup lg;
4461   lg.setName("DEFAULT-LG");
4462   lg.setUndoBufferSize(8*1024*1024);
4463 
4464 
4465   if(pDict->createLogfileGroup(lg) != 0){
4466     g_err << "Failed to create logfilegroup:"
4467         << endl << pDict->getNdbError() << endl;
4468     return NDBT_FAILED;
4469   }
4470 
4471   NdbDictionary::Undofile uf;
4472   uf.setPath("undofile01.dat");
4473   uf.setSize(5*1024*1024);
4474   uf.setLogfileGroup("DEFAULT-LG");
4475 
4476   if(pDict->createUndofile(uf) != 0){
4477     g_err << "Failed to create undofile:"
4478         << endl << pDict->getNdbError() << endl;
4479     return NDBT_FAILED;
4480   }
4481 
4482   BaseString::snprintf(tsname, sizeof(tsname), "TS-%u", rand());
4483   BaseString::snprintf(dfname, sizeof(dfname), "%s-%u.dat", tsname, rand());
4484 
4485   if (create_tablespace(pDict, lg.getName(), tsname, dfname)){
4486   	g_err << "Failed to create undofile:"
4487         << endl << pDict->getNdbError() << endl;
4488     return NDBT_FAILED;
4489   }
4490 
4491   return NDBT_OK;
4492 }
4493 
4494 int
runBug36072(NDBT_Context * ctx,NDBT_Step * step)4495 runBug36072(NDBT_Context* ctx, NDBT_Step* step)
4496 {
4497   Ndb* pNdb = GETNDB(step);
4498   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4499   NdbRestarter res;
4500 
4501   int err[] = { 6016,
4502 #ifdef BUG_46856
4503                 6017,
4504 #endif
4505                 0 };
4506   for (Uint32 i = 0; err[i] != 0; i++)
4507   {
4508     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
4509 
4510     if (res.dumpStateAllNodes(val2, 2))
4511       return NDBT_FAILED;
4512 
4513     if (res.insertErrorInAllNodes(932)) // arbit
4514       return NDBT_FAILED;
4515 
4516     int code = err[i];
4517 
4518     if (code == 6016)
4519     {
4520       if (res.insertErrorInAllNodes(code))
4521         return NDBT_FAILED;
4522     }
4523 
4524     NdbDictionary::LogfileGroup lg;
4525     lg.setName("DEFAULT-LG");
4526     lg.setUndoBufferSize(8*1024*1024);
4527 
4528     NdbDictionary::Undofile uf;
4529     uf.setPath("undofile01.dat");
4530     uf.setSize(5*1024*1024);
4531     uf.setLogfileGroup("DEFAULT-LG");
4532 
4533     int r = pDict->createLogfileGroup(lg);
4534     if (code == 6017)
4535     {
4536       if (r)
4537       {
4538         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
4539         return NDBT_FAILED;
4540       }
4541 
4542       if (res.insertErrorInAllNodes(err[i]))
4543         return NDBT_FAILED;
4544 
4545       pDict->createUndofile(uf);
4546     }
4547 
4548     if (res.waitClusterNoStart())
4549       return NDBT_FAILED;
4550 
4551     res.startAll();
4552     if (res.waitClusterStarted())
4553       return NDBT_FAILED;
4554     CHK_NDB_READY(pNdb);
4555 
4556     if (code == 6016)
4557     {
4558       NdbDictionary::LogfileGroup lg2 = pDict->getLogfileGroup("DEFAULT-LG");
4559       NdbError err= pDict->getNdbError();
4560       if( (int) err.classification == (int) ndberror_cl_none)
4561       {
4562         ndbout << __LINE__ << endl;
4563         return NDBT_FAILED;
4564       }
4565 
4566       if (pDict->createLogfileGroup(lg) != 0)
4567       {
4568         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
4569         return NDBT_FAILED;
4570       }
4571     }
4572     else
4573     {
4574       NdbDictionary::Undofile uf2 = pDict->getUndofile(0, "undofile01.dat");
4575       NdbError err= pDict->getNdbError();
4576       if( (int) err.classification == (int) ndberror_cl_none)
4577       {
4578         ndbout << __LINE__ << endl;
4579         return NDBT_FAILED;
4580       }
4581 
4582       if (pDict->createUndofile(uf) != 0)
4583       {
4584         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
4585         return NDBT_FAILED;
4586       }
4587     }
4588 
4589     {
4590       NdbDictionary::LogfileGroup lg2 = pDict->getLogfileGroup("DEFAULT-LG");
4591       NdbError err= pDict->getNdbError();
4592       if( (int) err.classification != (int) ndberror_cl_none)
4593       {
4594         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
4595         return NDBT_FAILED;
4596       }
4597 
4598       if (pDict->dropLogfileGroup(lg2))
4599       {
4600         ndbout << __LINE__ << " : " << pDict->getNdbError() << endl;
4601         return NDBT_FAILED;
4602       }
4603     }
4604   }
4605 
4606   return NDBT_OK;
4607 }
4608 
4609 int
restartClusterInitial(NDBT_Context * ctx,NDBT_Step * step)4610 restartClusterInitial(NDBT_Context* ctx, NDBT_Step* step)
4611 {
4612   NdbRestarter res;
4613 
4614   res.restartAll2(NdbRestarter::NRRF_INITIAL |
4615                   NdbRestarter::NRRF_NOSTART |
4616                   NdbRestarter::NRRF_ABORT);
4617   if (res.waitClusterNoStart())
4618     return NDBT_FAILED;
4619 
4620   res.startAll();
4621   if (res.waitClusterStarted())
4622     return NDBT_FAILED;
4623   CHK_NDB_READY(GETNDB(step));
4624 
4625   return NDBT_OK;
4626 }
4627 
4628 
4629 int
DropDDObjectsVerify(NDBT_Context * ctx,NDBT_Step * step)4630 DropDDObjectsVerify(NDBT_Context* ctx, NDBT_Step* step){
4631   //Purpose is to verify test DropDDObjects worked
4632   Uint32 i = 0;
4633 
4634   Ndb* pNdb = GETNDB(step);
4635   NdbDictionary::Dictionary* pDict = pNdb->getDictionary();
4636 
4637   NdbDictionary::Dictionary::List list;
4638   if (pDict->listObjects(list) == -1)
4639     return NDBT_FAILED;
4640 
4641   bool ddFound  = false;
4642   for (i = 0; i <list.count; i++){
4643     switch(list.elements[i].type){
4644       case NdbDictionary::Object::Tablespace:
4645         ddFound = true;
4646         break;
4647       case NdbDictionary::Object::LogfileGroup:
4648         ddFound = true;
4649         break;
4650       default:
4651         break;
4652     }
4653     if(ddFound == true){
4654       g_err << "DropDDObjects Failed: DD found:"
4655         << endl;
4656       return NDBT_FAILED;
4657     }
4658   }
4659   return NDBT_OK;
4660 }
4661 
4662 // Bug48604
4663 
4664 // string messages between local/remote steps identified by stepNo-1
4665 // each Msg<loc><rem> waits for Ack<loc><rem>
4666 
4667 static const uint MaxMsg = 100;
4668 
4669 static bool
send_msg(NDBT_Context * ctx,int loc,int rem,const char * msg)4670 send_msg(NDBT_Context* ctx, int loc, int rem, const char* msg)
4671 {
4672   char msgName[20], ackName[20];
4673   sprintf(msgName, "Msg%d%d", loc, rem);
4674   sprintf(ackName, "Ack%d%d", loc, rem);
4675   g_info << loc << ": send to:" << rem << " msg:" << msg << endl;
4676   ctx->setProperty(msgName, msg);
4677   int cnt = 0;
4678   while (1)
4679   {
4680     if (ctx->isTestStopped())
4681       return false;
4682     int ret;
4683     if ((ret = ctx->getProperty(ackName, (Uint32)0)) != 0)
4684       break;
4685     if (++cnt % 100 == 0)
4686       g_info << loc << ": send to:" << rem << " wait for ack" << endl;
4687     NdbSleep_MilliSleep(10);
4688   }
4689   ctx->setProperty(ackName, (Uint32)0);
4690   return true;
4691 }
4692 
4693 static bool
poll_msg(NDBT_Context * ctx,int loc,int rem,char * msg)4694 poll_msg(NDBT_Context* ctx, int loc, int rem, char* msg)
4695 {
4696   char msgName[20], ackName[20];
4697   sprintf(msgName, "Msg%d%d", rem, loc);
4698   sprintf(ackName, "Ack%d%d", rem, loc);
4699   const char* ptr;
4700   if ((ptr = ctx->getProperty(msgName, (char*)0)) != 0 && ptr[0] != 0)
4701   {
4702     require(strlen(ptr) < MaxMsg);
4703     memset(msg, 0, MaxMsg);
4704     strcpy(msg, ptr);
4705     g_info << loc << ": recv from:" << rem << " msg:" << msg << endl;
4706     ctx->setProperty(msgName, "");
4707     ctx->setProperty(ackName, (Uint32)1);
4708     return true;
4709   }
4710   return false;
4711 }
4712 
4713 static int
recv_msg(NDBT_Context * ctx,int loc,int rem,char * msg)4714 recv_msg(NDBT_Context* ctx, int loc, int rem, char* msg)
4715 {
4716   uint cnt = 0;
4717   while (1)
4718   {
4719     if (ctx->isTestStopped())
4720       return false;
4721     if (poll_msg(ctx, loc, rem, msg))
4722       break;
4723     if (++cnt % 100 == 0)
4724       g_info << loc << ": recv from:" << rem << " wait for msg" << endl;
4725     NdbSleep_MilliSleep(10);
4726   }
4727   return true;
4728 }
4729 
4730 const char* tabName_Bug48604 = "TBug48604";
4731 const char* indName_Bug48604 = "TBug48604X1";
4732 
4733 static const NdbDictionary::Table*
runBug48604createtable(NDBT_Context * ctx,NDBT_Step * step)4734 runBug48604createtable(NDBT_Context* ctx, NDBT_Step* step)
4735 {
4736   Ndb* pNdb = GETNDB(step);
4737   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4738   const NdbDictionary::Table* pTab = 0;
4739   int result = NDBT_OK;
4740   do
4741   {
4742     NdbDictionary::Table tab(tabName_Bug48604);
4743     {
4744       NdbDictionary::Column col("a");
4745       col.setType(NdbDictionary::Column::Unsigned);
4746       col.setPrimaryKey(true);
4747       tab.addColumn(col);
4748     }
4749     {
4750       NdbDictionary::Column col("b");
4751       col.setType(NdbDictionary::Column::Unsigned);
4752       col.setNullable(false);
4753       tab.addColumn(col);
4754     }
4755     CHECK(pDic->createTable(tab) == 0);
4756     CHECK((pTab = pDic->getTable(tabName_Bug48604)) != 0);
4757   }
4758   while (0);
4759   return pTab;
4760 }
4761 
4762 static const NdbDictionary::Index*
runBug48604createindex(NDBT_Context * ctx,NDBT_Step * step)4763 runBug48604createindex(NDBT_Context* ctx, NDBT_Step* step)
4764 {
4765   Ndb* pNdb = GETNDB(step);
4766   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4767   const NdbDictionary::Index* pInd = 0;
4768   int result = NDBT_OK;
4769   do {
4770     NdbDictionary::Index ind(indName_Bug48604);
4771     ind.setTable(tabName_Bug48604);
4772     ind.setType(NdbDictionary::Index::OrderedIndex);
4773     ind.setLogging(false);
4774     ind.addColumn("b");
4775     g_info << "index create.." << endl;
4776     CHECK(pDic->createIndex(ind) == 0);
4777     CHECK((pInd = pDic->getIndex(indName_Bug48604, tabName_Bug48604)) != 0);
4778     g_info << "index created" << endl;
4779     return pInd;
4780   }
4781   while (0);
4782   return pInd;
4783 }
4784 
4785 int
runBug48604(NDBT_Context * ctx,NDBT_Step * step)4786 runBug48604(NDBT_Context* ctx, NDBT_Step* step)
4787 {
4788   Ndb* pNdb = GETNDB(step);
4789   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4790   const NdbDictionary::Table* pTab = 0;
4791   const NdbDictionary::Index* pInd = 0;
4792   (void)pDic->dropTable(tabName_Bug48604);
4793   int loc = step->getStepNo() - 1;
4794   require(loc == 0);
4795   g_err << "main" << endl;
4796   int result = NDBT_OK;
4797   int loops = ctx->getNumLoops();
4798   char msg[MaxMsg];
4799 
4800   do
4801   {
4802     CHECK((pTab = runBug48604createtable(ctx, step)) != 0);
4803     CHECK(send_msg(ctx, 0, 1, "s"));
4804 
4805     int loop = 0;
4806     while (result == NDBT_OK && loop++ < loops)
4807     {
4808       g_err << "loop:" << loop << endl;
4809       {
4810         // create index fully while uncommitted ops wait
4811         const char* ops[][3] =
4812         {
4813           { "ozin", "oc", "oa" },       // 0: before 1-2: after
4814           { "oziun", "oc", "oa" },
4815           { "ozidn", "oc", "oa" },
4816           { "ozicun", "oc", "oa" },
4817           { "ozicuuun", "oc", "oa" },
4818           { "ozicdn", "oc", "oa" },
4819           { "ozicdin", "oc", "oa" },
4820           { "ozicdidiuuudidn", "oc", "oa" },
4821           { "ozicdidiuuudidin", "oc", "oa" }
4822         };
4823         const int cnt = sizeof(ops)/sizeof(ops[0]);
4824         int i;
4825         for (i = 0; result == NDBT_OK && i < cnt; i++)
4826         {
4827           int j;
4828           for (j = 1; result == NDBT_OK && j <= 2; j++)
4829           {
4830             if (ops[i][j] == 0)
4831               continue;
4832             CHECK(send_msg(ctx, 0, 1, ops[i][0]));
4833             CHECK(recv_msg(ctx, 0, 1, msg) && msg[0] == 'o');
4834             CHECK((pInd = runBug48604createindex(ctx, step)) != 0);
4835             CHECK(send_msg(ctx, 0, 1, ops[i][j]));
4836             CHECK(recv_msg(ctx, 0, 1, msg) && msg[0] == 'o');
4837 
4838             CHECK(pDic->dropIndex(indName_Bug48604, tabName_Bug48604) == 0);
4839             g_info << "index dropped" << endl;
4840           }
4841         }
4842       }
4843     }
4844   }
4845   while (0);
4846 
4847   (void)send_msg(ctx, 0, 1, "x");
4848   ctx->stopTest();
4849   g_err << "main: exit:" << result << endl;
4850   return result;
4851 }
4852 
4853 int
runBug48604ops(NDBT_Context * ctx,NDBT_Step * step)4854 runBug48604ops(NDBT_Context* ctx, NDBT_Step* step)
4855 {
4856   Ndb* pNdb = GETNDB(step);
4857   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4858   const NdbDictionary::Table* pTab = 0;
4859   //const NdbDictionary::Index* pInd = 0;
4860   int loc = step->getStepNo() - 1;
4861   require(loc > 0);
4862   g_err << "ops: loc:" << loc << endl;
4863   int result = NDBT_OK;
4864   int records = ctx->getNumRecords();
4865   char msg[MaxMsg];
4866 
4867   do
4868   {
4869     CHECK(recv_msg(ctx, loc, 0, msg));
4870     require(msg[0] == 's');
4871     CHECK((pTab = pDic->getTable(tabName_Bug48604)) != 0);
4872     HugoOperations ops(*pTab);
4873     bool have_trans = false;
4874     int opseq = 0;
4875 
4876     while (result == NDBT_OK && !ctx->isTestStopped())
4877     {
4878       CHECK(recv_msg(ctx, loc, 0, msg));
4879       if (msg[0] == 'x')
4880         break;
4881       if (msg[0] == 'o')
4882       {
4883         char* p = &msg[1];
4884         int c;
4885         while (result == NDBT_OK && (c = *p++) != 0)
4886         {
4887           if (c == 'n')
4888           {
4889             require(have_trans);
4890             CHECK(ops.execute_NoCommit(pNdb) == 0);
4891             g_info << loc << ": not committed" << endl;
4892             continue;
4893           }
4894           if (c == 'c')
4895           {
4896             require(have_trans);
4897             CHECK(ops.execute_Commit(pNdb) == 0);
4898             ops.closeTransaction(pNdb);
4899             have_trans = false;
4900             g_info << loc << ": committed" << endl;
4901             continue;
4902           }
4903           if (c == 'a')
4904           {
4905             require(have_trans);
4906             CHECK(ops.execute_Rollback(pNdb) == 0);
4907             ops.closeTransaction(pNdb);
4908             have_trans = false;
4909             g_info << loc << ": aborted" << endl;
4910             continue;
4911           }
4912           if (c == 'i' || c == 'u' || c == 'd')
4913           {
4914             if (!have_trans)
4915             {
4916               CHECK(ops.startTransaction(pNdb) == 0);
4917               have_trans = true;
4918               g_info << loc << ": trans started" << endl;
4919             }
4920             int i;
4921             for (i = 0; result == NDBT_OK && i < records; i++)
4922             {
4923               if (c == 'i')
4924                   CHECK(ops.pkInsertRecord(pNdb, i, 1, opseq) == 0);
4925               if (c == 'u')
4926                 CHECK(ops.pkUpdateRecord(pNdb, i, 1, opseq) == 0);
4927               if (c == 'd')
4928                 CHECK(ops.pkDeleteRecord(pNdb, i, 1) == 0);
4929             }
4930             char op_str[2];
4931             sprintf(op_str, "%c", c);
4932             g_info << loc << ": op:" << op_str << " records:" << records << endl;
4933             opseq++;
4934             continue;
4935           }
4936           if (c == 'z')
4937           {
4938             CHECK(ops.clearTable(pNdb) == 0);
4939             continue;
4940           }
4941           require(false);
4942         }
4943         CHECK(send_msg(ctx, loc, 0, "o"));
4944         continue;
4945       }
4946       require(false);
4947     }
4948   } while (0);
4949 
4950   g_err << "ops: loc:" << loc << " exit:" << result << endl;
4951   if (result != NDBT_OK)
4952     ctx->stopTest();
4953   return result;
4954 }
4955 
4956 int
runBug54651(NDBT_Context * ctx,NDBT_Step * step)4957 runBug54651(NDBT_Context* ctx, NDBT_Step* step)
4958 {
4959   Ndb* pNdb = GETNDB(step);
4960   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
4961 
4962   for (Uint32 j = 0; j< 2; j++)
4963   {
4964     pDic->createTable(* ctx->getTab());
4965 
4966     const NdbDictionary::Table * pTab =pDic->getTable(ctx->getTab()->getName());
4967     NdbDictionary::Table copy = * pTab;
4968     BaseString name;
4969     name.assfmt("%s_1", pTab->getName());
4970     copy.setName(name.c_str());
4971 
4972     if (pDic->createTable(copy))
4973     {
4974       ndbout_c("Failed to create table...");
4975       ndbout << pDic->getNdbError() << endl;
4976       return NDBT_FAILED;
4977     }
4978 
4979     NdbDictionary::Table alter = * pTab;
4980     alter.setName(name.c_str());
4981     for (Uint32 i = 0; i<2; i++)
4982     {
4983       // now rename org table to same name...
4984       if (pDic->alterTable(* pTab, alter) == 0)
4985       {
4986         ndbout << "Alter with duplicate name succeeded!!" << endl;
4987         return NDBT_FAILED;
4988       }
4989 
4990       ndbout << "Alter with duplicate name failed...good" << endl
4991              << pDic->getNdbError() << endl;
4992     }
4993 
4994     pDic->dropTable(copy.getName());
4995     pDic->dropTable(ctx->getTab()->getName());
4996   }
4997   return NDBT_OK;
4998 }
4999 
5000 /** telco-6.4 **/
5001 
5002 // begin schema trans
5003 
5004 #undef chk1
5005 #undef chk2
5006 
5007 static bool st_core_on_err = false;
5008 
5009 #define chk1(x) \
5010   do { \
5011     if (x) break; \
5012     g_err << "FAIL " << __LINE__ << " " << #x << endl; \
5013     if (st_core_on_err) abort(); \
5014     goto err; \
5015   } while (0)
5016 
5017 #define chk2(x, e) \
5018   do { \
5019     if (x) break; \
5020     g_err << "FAIL " << __LINE__ << " " << #x << ": " << e << endl; \
5021     if (st_core_on_err) abort(); \
5022     goto err; \
5023   } while (0)
5024 
5025 static uint
urandom(uint m)5026 urandom(uint m)
5027 {
5028   require(m != 0);
5029   uint n = (uint)ndb_rand();
5030   return n % m;
5031 }
5032 
5033 static bool
randomly(uint k,uint m)5034 randomly(uint k, uint m)
5035 {
5036   uint n = urandom(m);
5037   return n < k;
5038 }
5039 
5040 // structs
5041 
5042 struct ST_Obj;
5043 template class Vector<ST_Obj*>;
5044 typedef Vector<ST_Obj*> ST_Objlist;
5045 
5046 static ST_Objlist st_objlist;
5047 #ifndef NDEBUG
5048 static const ST_Obj* st_find_obj(const char* db, const char* name);
5049 #endif
5050 
5051 #define ST_MAX_NAME_SIZE  (MAX_TAB_NAME_SIZE + 100)
5052 
5053 struct ST_Obj {
5054   NdbDictionary::Object::Type type;
5055   char dbname[ST_MAX_NAME_SIZE];
5056   char name[ST_MAX_NAME_SIZE];
5057   int id;
5058   enum { Skip = 0xFFFF }; // mark ignored objects in List
5059   bool create; // true/false = create/drop prepared or committed
5060   bool commit;
existsST_Obj5061   bool exists() const { // visible to trans
5062     return !(!create && commit);
5063   }
is_triggerST_Obj5064   virtual bool is_trigger() const {
5065     return false;
5066   }
is_indexST_Obj5067   virtual bool is_index() const {
5068     return false;
5069   }
is_tableST_Obj5070   virtual bool is_table() const {
5071     return false;
5072   }
realnameST_Obj5073   virtual const char* realname() const {
5074     return name;
5075   }
ST_ObjST_Obj5076   ST_Obj(const char* a_dbname, const char* a_name) {
5077     type = NdbDictionary::Object::TypeUndefined;
5078     strcpy(dbname, a_dbname);
5079     strcpy(name, a_name);
5080     id = -1;
5081     create = false; // init as dropped
5082     commit = true;
5083     assert(st_find_obj(dbname, name) == 0);
5084     st_objlist.push_back(this);
5085   }
~ST_ObjST_Obj5086   virtual ~ST_Obj() {}
5087 };
5088 
5089 static NdbOut&
operator <<(NdbOut & out,const ST_Obj & obj)5090 operator<<(NdbOut& out, const ST_Obj& obj)
5091 {
5092   out << obj.name << "[" << obj.id << "]";
5093   return out;
5094 }
5095 
5096 struct ST_Trg : public ST_Obj {
5097   struct ST_Ind* ind;
5098   TriggerEvent::Value event;
5099   mutable char realname_buf[ST_MAX_NAME_SIZE];
is_triggerST_Trg5100   virtual bool is_trigger() const {
5101     return true;
5102   }
5103   virtual const char* realname() const;
ST_TrgST_Trg5104   ST_Trg(const char* a_db, const char* a_name) :
5105     ST_Obj(a_db, a_name) {
5106     ind = 0;
5107   }
~ST_TrgST_Trg5108   virtual ~ST_Trg() {}
5109 };
5110 
5111 template class Vector<ST_Trg*>;
5112 typedef Vector<ST_Trg*> ST_Trglist;
5113 
5114 struct ST_Ind : public ST_Obj {
5115   struct ST_Tab* tab;
5116   const NdbDictionary::Index* ind;
5117   const NdbDictionary::Index* ind_r; // retrieved
5118   BaseString colnames;
5119   ST_Trglist* trglist;
5120   int trgcount;
is_indexST_Ind5121   virtual bool is_index() const {
5122     return true;
5123   }
is_uniqueST_Ind5124   bool is_unique() const {
5125     return type == NdbDictionary::Object::UniqueHashIndex;
5126   }
trgST_Ind5127   const ST_Trg& trg(int k) const {
5128     return *((*trglist)[k]);
5129   }
trgST_Ind5130   ST_Trg& trg(int k) {
5131     return *((*trglist)[k]);
5132   }
ST_IndST_Ind5133   ST_Ind(const char* a_db, const char* a_name) :
5134     ST_Obj(a_db, a_name) {
5135     tab = 0;
5136     ind = 0;
5137     ind_r = 0;
5138     trglist = new ST_Trglist;
5139     trgcount = 0;
5140   }
~ST_IndST_Ind5141   virtual ~ST_Ind() {
5142     delete ind;
5143     delete trglist;
5144     ind = 0;
5145     trglist = 0;
5146   }
5147 };
5148 
5149 const char*
realname() const5150 ST_Trg::realname() const
5151 {
5152   if (!exists())
5153     return name;
5154   const char* p = name;
5155   const char* q = strchr(p, '<');
5156   const char* r = strchr(p, '>');
5157   require(q != 0 && r != 0 && q < r);
5158   require(ind->id != -1);
5159   sprintf(realname_buf, "%.*s%d%s", (int)(q - p), p, ind->id, r + 1);
5160   return realname_buf;
5161 }
5162 
5163 template class Vector<ST_Ind*>;
5164 typedef Vector<ST_Ind*> ST_Indlist;
5165 
5166 struct ST_Tab : public ST_Obj {
5167   const NdbDictionary::Table* tab;
5168   const NdbDictionary::Table* tab_r; // retrieved
5169   ST_Indlist* indlist;
5170   int indcount;
5171   int induniquecount;
5172   int indorderedcount;
is_tableST_Tab5173   virtual bool is_table() const {
5174     return true;
5175   }
indST_Tab5176   const ST_Ind& ind(int j) const {
5177     return *((*indlist)[j]);
5178   }
indST_Tab5179   ST_Ind& ind(int j) {
5180     return *((*indlist)[j]);
5181   }
ST_TabST_Tab5182   ST_Tab(const char* a_db, const char* a_name) :
5183     ST_Obj(a_db, a_name) {
5184     tab = 0;
5185     tab_r = 0;
5186     indlist = new ST_Indlist;
5187     indcount = 0;
5188     induniquecount = 0;
5189     indorderedcount = 0;
5190   }
~ST_TabST_Tab5191   virtual ~ST_Tab() {
5192     delete tab;
5193     delete indlist;
5194     tab = 0;
5195     indlist = 0;
5196   }
5197 };
5198 
5199 template class Vector<ST_Tab*>;
5200 typedef Vector<ST_Tab*> ST_Tablist;
5201 
5202 struct ST_Restarter : public NdbRestarter {
5203   int get_status();
5204   const ndb_mgm_node_state& get_state(int node_id);
ST_RestarterST_Restarter5205   ST_Restarter() {
5206     int i;
5207     for (i = 0; i < MAX_NODES; i++)
5208       state[i].node_type = NDB_MGM_NODE_TYPE_UNKNOWN;
5209     first_time = true;
5210   }
5211 protected:
5212   void set_state(const ndb_mgm_node_state& state);
5213   ndb_mgm_node_state state[MAX_NODES];
5214   bool first_time;
5215 };
5216 
5217 const ndb_mgm_node_state&
get_state(int node_id)5218 ST_Restarter::get_state(int node_id) {
5219   require(node_id > 0 && node_id < MAX_NODES);
5220   require(!first_time);
5221   return state[node_id];
5222 }
5223 
5224 void
set_state(const ndb_mgm_node_state & new_state)5225 ST_Restarter::set_state(const ndb_mgm_node_state& new_state)
5226 {
5227   int node_id = new_state.node_id;
5228   require(1 <= node_id && node_id < MAX_NODES);
5229 
5230   require(new_state.node_type == NDB_MGM_NODE_TYPE_MGM ||
5231           new_state.node_type == NDB_MGM_NODE_TYPE_NDB ||
5232           new_state.node_type == NDB_MGM_NODE_TYPE_API);
5233 
5234   ndb_mgm_node_state& old_state = state[node_id];
5235   if (!first_time)
5236     require(old_state.node_type == new_state.node_type);
5237   old_state = new_state;
5238 }
5239 
5240 int
get_status()5241 ST_Restarter::get_status()
5242 {
5243   if (getStatus() == -1)
5244     return -1;
5245   int i;
5246   for (i = 0; i < (int)mgmNodes.size(); i++)
5247     set_state(mgmNodes[i]);
5248   for (i = 0; i < (int)ndbNodes.size(); i++)
5249     set_state(ndbNodes[i]);
5250   for (i = 0; i < (int)apiNodes.size(); i++)
5251     set_state(apiNodes[i]);
5252   first_time = false;
5253   return 0;
5254 }
5255 
5256 struct ST_Con {
5257   Ndb_cluster_connection* ncc;
5258   Ndb* ndb;
5259   NdbDictionary::Dictionary* dic;
5260   ST_Restarter* restarter;
5261   int numdbnodes;
5262   char dbname[ST_MAX_NAME_SIZE];
5263   ST_Tablist* tablist;
5264   int tabcount;
5265   bool tx_on;
5266   bool tx_commit;
5267   bool is_xcon;
5268   ST_Con* xcon;
5269   int node_id;
5270   int loop;
tabST_Con5271   const ST_Tab& tab(int i) const {
5272     return *((*tablist)[i]);
5273   }
tabST_Con5274   ST_Tab& tab(int i) {
5275     return *((*tablist)[i]);
5276   }
ST_ConST_Con5277   ST_Con(Ndb_cluster_connection* a_ncc,
5278          Ndb* a_ndb,
5279          ST_Restarter* a_restarter) {
5280     ncc = a_ncc;
5281     ndb = a_ndb;
5282     dic = a_ndb->getDictionary();
5283     restarter = a_restarter;
5284     numdbnodes = restarter->getNumDbNodes();
5285     require(numdbnodes >= 1);
5286     sprintf(dbname, "%s", ndb->getDatabaseName());
5287     tablist = new ST_Tablist;
5288     tabcount = 0;
5289     tx_on = false;
5290     tx_commit = false;
5291     is_xcon = false;
5292     xcon = 0;
5293     node_id = ncc->node_id();
5294     {
5295       require(restarter->get_status() == 0);
5296       const ndb_mgm_node_state& state = restarter->get_state(node_id);
5297       require(state.node_type == NDB_MGM_NODE_TYPE_API);
5298       require(state.version != 0); // means "connected"
5299       g_info << "node_id:" << node_id << endl;
5300     }
5301     loop = -1;
5302   }
~ST_ConST_Con5303   ~ST_Con() {
5304     if (!is_xcon) {
5305       delete tablist;
5306     } else {
5307       delete ndb;
5308       delete ncc;
5309     }
5310     tablist = 0;
5311     ndb = 0;
5312     ncc = 0;
5313   }
5314 };
5315 
5316 // initialization
5317 
5318 static int
st_drop_all_tables(ST_Con & c)5319 st_drop_all_tables(ST_Con& c)
5320 {
5321   g_info << "st_drop_all_tables" << endl;
5322   NdbDictionary::Dictionary::List list;
5323   chk2(c.dic->listObjects(list) == 0, c.dic->getNdbError());
5324   int n;
5325   for (n = 0; n < (int)list.count; n++) {
5326     const NdbDictionary::Dictionary::List::Element& element =
5327       list.elements[n];
5328     if (element.type == NdbDictionary::Object::UserTable &&
5329         strcmp(element.database, "TEST_DB") == 0) {
5330       chk2(c.dic->dropTable(element.name) == 0, c.dic->getNdbError());
5331     }
5332   }
5333   return 0;
5334 err:
5335   return -1;
5336 }
5337 
5338 static void
st_init_objects(ST_Con & c,NDBT_Context * ctx)5339 st_init_objects(ST_Con& c, NDBT_Context* ctx)
5340 {
5341   int numTables = ctx->getNumTables();
5342   c.tabcount = 0;
5343   int i;
5344   for (i = 0; i < numTables; i++) {
5345     const NdbDictionary::Table* pTab = 0;
5346 #ifdef ndb_test_ALL_TABLES_is_fixed
5347     const NdbDictionary::Table** tables = ctx->getTables();
5348     pTab = tables[i];
5349 #else
5350     const Vector<BaseString>& tables = ctx->getSuite()->m_tables_in_test;
5351     pTab = NDBT_Tables::getTable(tables[i].c_str());
5352 #endif
5353     require(pTab != 0 && pTab->getName() != 0);
5354 
5355     {
5356       bool ok = true;
5357       int n;
5358       for (n = 0; n < pTab->getNoOfColumns(); n++) {
5359         const NdbDictionary::Column* pCol = pTab->getColumn(n);
5360         require(pCol != 0);
5361         if (pCol->getStorageType() !=
5362             NdbDictionary::Column::StorageTypeMemory) {
5363           g_err << pTab->getName() << ": skip non-mem table for now" << endl;
5364           ok = false;
5365           break;
5366         }
5367       }
5368       if (!ok)
5369         continue;
5370     }
5371 
5372     c.tablist->push_back(new ST_Tab(c.dbname, pTab->getName()));
5373     c.tabcount++;
5374     ST_Tab& tab = *c.tablist->back();
5375     tab.type = NdbDictionary::Object::UserTable;
5376     tab.tab = new NdbDictionary::Table(*pTab);
5377 
5378     const char** indspec = NDBT_Tables::getIndexes(tab.name);
5379 
5380     while (indspec != 0 && *indspec != 0) {
5381       char ind_name[ST_MAX_NAME_SIZE];
5382       int ind_len = snprintf(ind_name,
5383                              ST_MAX_NAME_SIZE,
5384                              "%sX%d",
5385                              tab.name,
5386                              tab.indcount);
5387       require(ind_len < ST_MAX_NAME_SIZE);
5388       tab.indlist->push_back(new ST_Ind("sys", ind_name));
5389       ST_Ind& ind = *tab.indlist->back();
5390       ind.tab = &tab;
5391 
5392       NdbDictionary::Index* pInd = new NdbDictionary::Index(ind.name);
5393       pInd->setTable(tab.name);
5394       pInd->setLogging(false);
5395 
5396       const char* type = *indspec++;
5397       if (strcmp(type, "UNIQUE") == 0) {
5398         ind.type = NdbDictionary::Object::UniqueHashIndex;
5399         pInd->setType((NdbDictionary::Index::Type)ind.type);
5400         tab.induniquecount++;
5401 
5402         { char trg_name[ST_MAX_NAME_SIZE];
5403           int trg_len = snprintf(trg_name,
5404                                  ST_MAX_NAME_SIZE,
5405                                  "NDB$INDEX_<%s>_UI",
5406                                  ind.name);
5407           require(trg_len < ST_MAX_NAME_SIZE);
5408           ind.trglist->push_back(new ST_Trg("", trg_name));
5409           ST_Trg& trg = *ind.trglist->back();
5410           trg.ind = &ind;
5411           trg.type = NdbDictionary::Object::HashIndexTrigger;
5412           trg.event = TriggerEvent::TE_INSERT;
5413         }
5414         ind.trgcount = 1;
5415       }
5416       else if (strcmp(type, "ORDERED") == 0) {
5417         ind.type = NdbDictionary::Object::OrderedIndex;
5418         pInd->setType((NdbDictionary::Index::Type)ind.type);
5419         tab.indorderedcount++;
5420 
5421         { char trg_name[ST_MAX_NAME_SIZE];
5422           int trg_len = snprintf(trg_name,
5423                                  ST_MAX_NAME_SIZE,
5424                                  "NDB$INDEX_<%s>_CUSTOM",
5425                                  ind.name);
5426           require(trg_len < ST_MAX_NAME_SIZE);
5427           ind.trglist->push_back(new ST_Trg("", trg_name));
5428           ST_Trg& trg = *ind.trglist->back();
5429           trg.ind = &ind;
5430           trg.type = NdbDictionary::Object::IndexTrigger;
5431           trg.event = TriggerEvent::TE_CUSTOM;
5432         }
5433         ind.trgcount = 1;
5434       }
5435       else
5436       {
5437         require(false);
5438       }
5439 
5440       const char* sep = "";
5441       const char* colname;
5442       while ((colname = *indspec++) != 0) {
5443         const NdbDictionary::Column* col = tab.tab->getColumn(colname);
5444         require(col != 0);
5445         pInd->addColumn(*col);
5446 
5447         ind.colnames.appfmt("%s%s", sep, colname);
5448         sep = ",";
5449       }
5450 
5451       ind.ind = pInd;
5452       tab.indcount++;
5453     }
5454   }
5455 }
5456 
5457 // node states
5458 
5459 static int
st_report_db_nodes(ST_Con & c,NdbOut & out)5460 st_report_db_nodes(ST_Con& c, NdbOut& out)
5461 {
5462   chk1(c.restarter->get_status() == 0);
5463   char r1[100]; // up
5464   char r2[100]; // down
5465   char r3[100]; // unknown
5466   r1[0] =r2[0] = r3[0] = 0;
5467   int i;
5468   for (i = 1; i < MAX_NODES; i++) {
5469     const ndb_mgm_node_state& state = c.restarter->get_state(i);
5470     if (state.node_type == NDB_MGM_NODE_TYPE_NDB) {
5471       char* r = 0;
5472       if (state.node_status == NDB_MGM_NODE_STATUS_STARTED)
5473         r = r1;
5474       else if (state.node_status == NDB_MGM_NODE_STATUS_NO_CONTACT)
5475         r = r2;
5476       else
5477         r = r3;
5478       sprintf(r + strlen(r), "%s%d", r[0] == 0 ? "" : ",", i);
5479     }
5480   }
5481   if (r2[0] != 0 || r3[0] != 0) {
5482     out << "nodes up:" << r1 << " down:" << r2 << " unknown:" << r3 << endl;
5483     goto err;
5484   }
5485   out << "nodes up:" << r1 << " (all)" << endl;
5486   return 0;
5487 err:
5488   return -1;
5489 }
5490 
5491 static int
st_check_db_nodes(ST_Con & c,int ignore_node_id=-1)5492 st_check_db_nodes(ST_Con& c, int ignore_node_id = -1)
5493 {
5494   chk1(c.restarter->get_status() == 0);
5495   int i;
5496   for (i = 1; i < MAX_NODES; i++) {
5497     const ndb_mgm_node_state& state = c.restarter->get_state(i);
5498     if (state.node_type == NDB_MGM_NODE_TYPE_NDB &&
5499         i != ignore_node_id) {
5500       chk2(state.node_status == NDB_MGM_NODE_STATUS_STARTED, " node:" << i);
5501     }
5502   }
5503   return 0;
5504 err:
5505   return -1;
5506 }
5507 
5508 #if 0
5509 static int
5510 st_wait_db_node_up(ST_Con& c, int node_id)
5511 {
5512   int count = 0;
5513   int max_count = 30;
5514   int milli_sleep = 2000;
5515   while (count++ < max_count) {
5516     // get status and check that other db nodes have not crashed
5517     chk1(st_check_db_nodes(c, node_id) == 0);
5518 
5519     const ndb_mgm_node_state& state = c.restarter->get_state(node_id);
5520     require(state.node_type == NDB_MGM_NODE_TYPE_NDB);
5521     if (state.node_status == NDB_MGM_NODE_STATUS_STARTED)
5522       break;
5523     g_info << "waiting count:" << count << "/" << max_count << endl;
5524     NdbSleep_MilliSleep(milli_sleep);
5525   }
5526   return 0;
5527 err:
5528   return -1;
5529 }
5530 #endif
5531 
5532 // extra connection (separate API node)
5533 
5534 static int
st_start_xcon(ST_Con & c)5535 st_start_xcon(ST_Con& c)
5536 {
5537   require(c.xcon == 0);
5538   g_info << "start extra connection" << endl;
5539 
5540   do {
5541     int ret;
5542     Ndb_cluster_connection* xncc = new Ndb_cluster_connection;
5543     chk2((ret = xncc->connect(30, 1, 0)) == 0, "ret:" << ret);
5544     chk2((ret = xncc->wait_until_ready(30, 10)) == 0, "ret:" << ret);
5545     Ndb* xndb = new Ndb(xncc, c.dbname);
5546     chk1(xndb->init() == 0);
5547     chk1(xndb->waitUntilReady(30) == 0);
5548     // share restarter
5549     c.xcon = new ST_Con(xncc, xndb, c.restarter);
5550     // share objects
5551     c.xcon->tablist = c.tablist;
5552     c.xcon->tabcount = c.tabcount;
5553     c.xcon->is_xcon = true;
5554   } while (0);
5555   return 0;
5556 err:
5557   return -1;
5558 }
5559 
5560 static int
st_stop_xcon(ST_Con & c)5561 st_stop_xcon(ST_Con& c)
5562 {
5563   require(c.xcon != 0);
5564   int node_id = c.xcon->node_id;
5565   g_info << "stop extra connection node_id:" << node_id << endl;
5566 
5567   c.xcon->restarter = 0;
5568   c.xcon->tablist = 0;
5569   c.xcon->tabcount = 0;
5570   delete c.xcon;
5571   c.xcon = 0;
5572   int count = 0;
5573   while (1) {
5574     chk1(c.restarter->get_status() == 0);
5575     const ndb_mgm_node_state& state = c.restarter->get_state(node_id);
5576     require(state.node_type == NDB_MGM_NODE_TYPE_API);
5577     if (state.version == 0) // means "disconnected"
5578       break;
5579     g_info << "waiting count:" << ++count << endl;
5580     NdbSleep_MilliSleep(10 * count);
5581   }
5582   return 0;
5583 err:
5584   return -1;
5585 }
5586 
5587 // error insert
5588 
5589 struct ST_Errins {
5590   int value;              // error value to insert
5591   int code;               // ndb error code to expect
5592   int master;             // insert on master / non-master (-1 = random)
5593   int node;               // insert on node id
5594   const ST_Errins* list;  // include another list
5595   bool ends;              // end list
ST_ErrinsST_Errins5596   ST_Errins() :
5597     value(0), code(0), master(-1), node(0), list(0), ends(true)
5598   {}
ST_ErrinsST_Errins5599   ST_Errins(const ST_Errins* l) :
5600     value(0), code(0), master(-1), node(0), list(l), ends(false)
5601   {}
ST_ErrinsST_Errins5602   ST_Errins(int v, int c, int m = -1) :
5603     value(v), code(c), master(m), node(0), list(0), ends(false)
5604   {}
5605 };
5606 
5607 static NdbOut&
operator <<(NdbOut & out,const ST_Errins & errins)5608 operator<<(NdbOut& out, const ST_Errins& errins)
5609 {
5610   out << "value:" << errins.value;
5611   out << " code:" << errins.code;
5612   out << " master:" << errins.master;
5613   out << " node:" << errins.node;
5614   return out;
5615 }
5616 
5617 static ST_Errins
st_get_errins(ST_Con & c,const ST_Errins * list)5618 st_get_errins(ST_Con& c, const ST_Errins* list)
5619 {
5620   uint size = 0;
5621   while (!list[size++].ends)
5622     ;
5623   require(size > 1);
5624   uint n = urandom(size - 1);
5625   const ST_Errins& errins = list[n];
5626   if (errins.list == 0) {
5627     require(errins.value != 0);
5628     return errins;
5629   }
5630   return st_get_errins(c, errins.list);
5631 }
5632 
5633 static int
st_do_errins(ST_Con & c,ST_Errins & errins)5634 st_do_errins(ST_Con& c, ST_Errins& errins)
5635 {
5636   require(errins.value != 0);
5637   if (c.numdbnodes < 2)
5638     errins.master = 1;
5639   else if (errins.master == -1)
5640     errins.master = randomly(1, 2);
5641   if (errins.master) {
5642     errins.node = c.restarter->getMasterNodeId();
5643   } else {
5644     uint rand = urandom(c.numdbnodes);
5645     errins.node = c.restarter->getRandomNotMasterNodeId(rand);
5646   }
5647   g_info << "errins: " << errins << endl;
5648   chk2(c.restarter->insertErrorInNode(errins.node, errins.value) == 0, errins);
5649   c.restarter->get_status(); // do sync call to ensure error has been inserted
5650   return 0;
5651 err:
5652   return -1;
5653 }
5654 
5655 // debug aid
5656 #ifndef NDEBUG
5657 static const ST_Obj*
st_find_obj(const char * dbname,const char * name)5658 st_find_obj(const char* dbname, const char* name)
5659 {
5660   const ST_Obj* ret_objp = 0;
5661   int i;
5662   for (i = 0; i < (int)st_objlist.size(); i++) {
5663     const ST_Obj* objp = st_objlist[i];
5664     if (strcmp(objp->dbname, dbname) == 0 &&
5665         strcmp(objp->name, name) == 0) {
5666       require(ret_objp == 0);
5667       ret_objp = objp;
5668     }
5669   }
5670   return ret_objp;
5671 }
5672 #endif
5673 
5674 #if 0
5675 static void
5676 st_print_obj(const char* dbname, const char* name, int line = 0)
5677 {
5678   const ST_Obj* objp = st_find_obj(dbname, name);
5679   g_info << name << ": by name:";
5680   if (objp != 0)
5681     g_info << " create:" << objp->create
5682            << " commit:" << objp->commit
5683            << " exists:" << objp->exists();
5684   else
5685     g_info << " not found";
5686   if (line != 0)
5687     g_info << " line:" << line;
5688   g_info << endl;
5689 }
5690 #endif
5691 
5692 // set object state
5693 
5694 static void
st_set_commit_obj(ST_Con & c,ST_Obj & obj)5695 st_set_commit_obj(ST_Con& c, ST_Obj& obj)
5696 {
5697   bool create_old = obj.create;
5698   bool commit_old = obj.commit;
5699   if (!c.tx_commit && !obj.commit)
5700     obj.create = !obj.create;
5701   obj.commit = true;
5702   if (create_old != obj.create || commit_old != obj.commit) {
5703     g_info << obj.name << ": set commit:"
5704            << " create:" << create_old << "->" << obj.create
5705            << " commit:" << commit_old << "->" << obj.commit << endl;
5706   }
5707 }
5708 
5709 #if 0
5710 static void
5711 st_set_commit_trg(ST_Con& c, ST_Trg& trg)
5712 {
5713   st_set_commit_obj(c, trg);
5714 }
5715 #endif
5716 
5717 static void
st_set_commit_ind(ST_Con & c,ST_Ind & ind)5718 st_set_commit_ind(ST_Con& c, ST_Ind& ind)
5719 {
5720   st_set_commit_obj(c, ind);
5721   int k;
5722   for (k = 0; k < ind.trgcount; k++) {
5723     ST_Trg& trg = ind.trg(k);
5724     st_set_commit_obj(c, trg);
5725   }
5726 }
5727 
5728 static void
st_set_commit_tab(ST_Con & c,ST_Tab & tab)5729 st_set_commit_tab(ST_Con& c, ST_Tab& tab)
5730 {
5731   st_set_commit_obj(c, tab);
5732   int j;
5733   for (j = 0; j < tab.indcount; j++) {
5734     ST_Ind& ind = tab.ind(j);
5735     st_set_commit_ind(c, ind);
5736   }
5737 }
5738 
5739 static void
st_set_commit_all(ST_Con & c)5740 st_set_commit_all(ST_Con& c)
5741 {
5742   int i;
5743   for (i = 0; i < c.tabcount; i++) {
5744     ST_Tab& tab = c.tab(i);
5745     st_set_commit_tab(c, tab);
5746   }
5747 }
5748 
5749 static void
st_set_create_obj(ST_Con & c,ST_Obj & obj,bool create)5750 st_set_create_obj(ST_Con& c, ST_Obj& obj, bool create)
5751 {
5752   bool create_old = obj.create;
5753   bool commit_old = obj.commit;
5754   obj.create = create;
5755   obj.commit = !c.tx_on;
5756   if (create_old != obj.create || commit_old != obj.commit) {
5757     g_info << obj.name << ": set create:"
5758            << " create:" << create_old << "->" << obj.create
5759            << " commit:" << commit_old << "->" << obj.commit << endl;
5760   }
5761 }
5762 
5763 static void
st_set_create_trg(ST_Con & c,ST_Trg & trg,bool create)5764 st_set_create_trg(ST_Con& c, ST_Trg& trg, bool create)
5765 {
5766   st_set_create_obj(c, trg, create);
5767 }
5768 
5769 static void
st_set_create_ind(ST_Con & c,ST_Ind & ind,bool create)5770 st_set_create_ind(ST_Con& c, ST_Ind& ind, bool create)
5771 {
5772   st_set_create_obj(c, ind, create);
5773   int k;
5774   for (k = 0; k < ind.trgcount; k++) {
5775     ST_Trg& trg = ind.trg(k);
5776     st_set_create_trg(c, trg, create);
5777   }
5778 }
5779 
5780 static void
st_set_create_tab(ST_Con & c,ST_Tab & tab,bool create)5781 st_set_create_tab(ST_Con& c, ST_Tab& tab, bool create)
5782 {
5783   st_set_create_obj(c, tab, create);
5784   int j;
5785   for (j = 0; j < tab.indcount; j++) {
5786     ST_Ind& ind = tab.ind(j);
5787     if (create == true)
5788       require(!ind.exists());
5789     else {
5790       if (ind.exists())
5791         st_set_create_ind(c, ind, false);
5792     }
5793   }
5794 }
5795 
5796 // verify against database listing
5797 
5798 static bool
st_known_type(const NdbDictionary::Dictionary::List::Element & element)5799 st_known_type(const NdbDictionary::Dictionary::List::Element& element)
5800 {
5801   return element.id != ST_Obj::Skip;
5802 }
5803 
5804 static int
st_find_object(const NdbDictionary::Dictionary::List & list,NdbDictionary::Object::Type type,int id)5805 st_find_object(const NdbDictionary::Dictionary::List& list,
5806                NdbDictionary::Object::Type type, int id)
5807 {
5808   int n;
5809   for (n = 0; n < (int)list.count; n++) {
5810     const NdbDictionary::Dictionary::List::Element& element =
5811       list.elements[n];
5812     if (element.type == type && (int)element.id == id)
5813       return n;
5814   }
5815   return -1;
5816 }
5817 
5818 // filter out irrelevant by whatever means (we need listObjects2)
5819 static int
st_list_objects(ST_Con & c,NdbDictionary::Dictionary::List & list)5820 st_list_objects(ST_Con& c, NdbDictionary::Dictionary::List& list)
5821 {
5822   g_info << "st_list_objects" << endl;
5823   int keep[256];
5824   memset(keep, 0, sizeof(keep));
5825   chk2(c.dic->listObjects(list) == 0, c.dic->getNdbError());
5826   int n;
5827   // tables
5828   for (n = 0; n < (int)list.count; n++) {
5829     const NdbDictionary::Dictionary::List::Element& element =
5830       list.elements[n];
5831     if (element.type == NdbDictionary::Object::UserTable) {
5832       int i;
5833       for (i = 0; i < c.tabcount; i++) {
5834         const ST_Tab& tab = c.tab(i);
5835         if (strcmp(element.name, tab.name) == 0)
5836           keep[n]++;
5837       }
5838     }
5839     require(keep[n] <= 1);
5840   }
5841   // indexes
5842   for (n = 0; n < (int)list.count; n++) {
5843     const NdbDictionary::Dictionary::List::Element& element =
5844       list.elements[n];
5845     if (element.type == NdbDictionary::Object::UniqueHashIndex ||
5846         element.type == NdbDictionary::Object::OrderedIndex) {
5847       int i, j;
5848       for (i = 0; i < c.tabcount; i++) {
5849         const ST_Tab& tab = c.tab(i);
5850         for (j = 0; j < tab.indcount; j++) {
5851           const ST_Ind& ind = tab.ind(j);
5852           if (strcmp(element.name, ind.name) == 0)
5853             keep[n]++;
5854         }
5855       }
5856     }
5857     require(keep[n] <= 1);
5858   }
5859   // triggers
5860   for (n = 0; n < (int)list.count; n++) {
5861     const NdbDictionary::Dictionary::List::Element& element =
5862       list.elements[n];
5863     if (element.type == NdbDictionary::Object::HashIndexTrigger) {
5864       int id, n2;
5865       chk2(sscanf(element.name, "NDB$INDEX_%d_UI", &id) == 1,
5866            element.name);
5867       n2 = st_find_object(list, NdbDictionary::Object::UniqueHashIndex, id);
5868       chk2(n2 >= 0, element.name);
5869       if (keep[n2])
5870         keep[n]++;
5871     }
5872     if (element.type == NdbDictionary::Object::IndexTrigger) {
5873       int id, n2;
5874       chk2(sscanf(element.name, "NDB$INDEX_%d_CUSTOM", &id) == 1,
5875            element.name);
5876       n2 = st_find_object(list, NdbDictionary::Object::OrderedIndex, id);
5877       chk2(n2 >= 0, element.name);
5878       if (keep[n2])
5879         keep[n]++;
5880     }
5881     require(keep[n] <= 1);
5882   }
5883   // mark ignored
5884   for (n = 0; n < (int)list.count; n++) {
5885     NdbDictionary::Dictionary::List::Element& element =
5886       list.elements[n];
5887     g_info << "id=" << element.id << " type=" << element.type
5888            << " name=" << element.name << " keep=" << keep[n] << endl;
5889     if (!keep[n]) {
5890       require(element.id != ST_Obj::Skip);
5891       element.id = ST_Obj::Skip;
5892     }
5893   }
5894   return 0;
5895 err:
5896   return -1;
5897 }
5898 
5899 static bool
st_match_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element)5900 st_match_obj(const ST_Obj& obj,
5901              const NdbDictionary::Dictionary::List::Element& element)
5902 {
5903   int veryverbose = 0;
5904   if (veryverbose) {
5905     g_info
5906       << "match:"
5907       << " " << obj.type << "-" << element.type
5908       << " " << obj.dbname << "-" << element.database
5909       << " " << obj.realname() << "-" << element.name << endl;
5910   }
5911   return
5912     obj.type == element.type &&
5913     strcmp(obj.dbname, element.database) == 0 &&
5914     strcmp(obj.realname(), element.name) == 0;
5915 }
5916 
5917 static int // check state
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element)5918 st_verify_obj(const ST_Obj& obj,
5919               const NdbDictionary::Dictionary::List::Element& element)
5920 {
5921   chk2(obj.exists(), obj.name);
5922 
5923   if (obj.commit)
5924     chk2(element.state == NdbDictionary::Object::StateOnline, obj.name);
5925 
5926   // other states are inconsistent
5927 
5928   else if (obj.create) {
5929     if (obj.is_table() || obj.is_index())
5930       chk2(element.state == NdbDictionary::Object::StateBuilding, obj.name);
5931     if (obj.is_trigger())
5932       chk2(element.state == NdbDictionary::Object::StateBuilding, obj.name);
5933   }
5934   else {
5935     if (obj.is_trigger())
5936       chk2(element.state == NdbDictionary::Object::StateOnline, obj.name);
5937     if (obj.is_table() || obj.is_index())
5938       chk2(element.state == NdbDictionary::Object::StateDropping, obj.name);
5939   }
5940   return 0;
5941 err:
5942   return -1;
5943 }
5944 
5945 static int // find on list
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List & list)5946 st_verify_obj(const ST_Obj& obj,
5947               const NdbDictionary::Dictionary::List& list)
5948 {
5949   int found = 0;
5950   int n;
5951   for (n = 0; n < (int)list.count; n++) {
5952     const NdbDictionary::Dictionary::List::Element& element =
5953       list.elements[n];
5954     if (!st_known_type(element))
5955       continue;
5956     if (st_match_obj(obj, element)) {
5957       chk1(st_verify_obj(obj, element) == 0);
5958       found += 1;
5959     }
5960   }
5961   if (obj.exists())
5962     chk2(found == 1, obj.name);
5963   else
5964     chk2(found == 0, obj.name);
5965   return 0;
5966 err:
5967   return -1;
5968 }
5969 
5970 static int // possible match
st_verify_obj(const ST_Obj & obj,const NdbDictionary::Dictionary::List::Element & element,int & found)5971 st_verify_obj(const ST_Obj& obj,
5972              const NdbDictionary::Dictionary::List::Element& element,
5973              int& found)
5974 {
5975   if (obj.exists()) {
5976     if (st_match_obj(obj, element)) {
5977       chk1(st_verify_obj(obj, element) == 0);
5978       found += 1;
5979     }
5980   }
5981   else {
5982     chk2(st_match_obj(obj, element) == false, obj.name);
5983   }
5984   return 0;
5985 err:
5986   return -1;
5987 }
5988 
5989 static int
st_verify_list(ST_Con & c)5990 st_verify_list(ST_Con& c)
5991 {
5992   NdbDictionary::Dictionary::List list;
5993   chk1(st_list_objects(c, list) == 0);
5994   int i, j, k, n;
5995   // us vs list
5996   for (i = 0; i < c.tabcount; i++) {
5997     const ST_Tab& tab = c.tab(i);
5998     chk1(st_verify_obj(tab, list) == 0);
5999     for (j = 0; j < tab.indcount; j++) {
6000       const ST_Ind& ind = tab.ind(j);
6001       chk1(st_verify_obj(ind, list) == 0);
6002       for (k = 0; k < ind.trgcount; k++) {
6003         const ST_Trg& trg = ind.trg(k);
6004         chk1(st_verify_obj(trg, list) == 0);
6005       }
6006     }
6007   }
6008   // list vs us
6009   for (n = 0; n < (int)list.count; n++) {
6010     const NdbDictionary::Dictionary::List::Element& element =
6011       list.elements[n];
6012     if (!st_known_type(element))
6013       continue;
6014     int found = 0;
6015     for (i = 0; i < c.tabcount; i++) {
6016       const ST_Tab& tab = c.tab(i);
6017       chk1(st_verify_obj(tab, element, found) == 0);
6018       for (j = 0; j < tab.indcount; j++) {
6019         const ST_Ind& ind = tab.ind(j);
6020         chk1(st_verify_obj(ind, element, found) == 0);
6021         for (k = 0; k < ind.trgcount; k++) {
6022           const ST_Trg& trg = ind.trg(k);
6023           chk1(st_verify_obj(trg, element, found) == 0);
6024         }
6025       }
6026     }
6027     const char* dot = element.database[0] != 0 ? "." : "";
6028     chk2(found == 1, element.database << dot << element.name);
6029   }
6030   return 0;
6031 err:
6032   return -1;
6033 }
6034 
6035 // wait for DICT to finish current trans
6036 
6037 static int
st_wait_idle(ST_Con & c)6038 st_wait_idle(ST_Con& c)
6039 {
6040   // todo: use try-lock when available
6041   g_info << "st_wait_idle" << endl;
6042   int count = 0;
6043   int max_count = 60;
6044   int milli_sleep = 1000;
6045   while (count++ < max_count) {
6046     NdbDictionary::Dictionary::List list;
6047     chk1(st_list_objects(c, list) == 0);
6048     bool ok = true;
6049     int n;
6050     for (n = 0; n < (int)list.count; n++) {
6051       const NdbDictionary::Dictionary::List::Element& element =
6052         list.elements[n];
6053       if (!st_known_type(element))
6054         continue;
6055       if (element.state != NdbDictionary::Object::StateOnline) {
6056         ok = false;
6057         break;
6058       }
6059     }
6060     if (ok)
6061       return 0;
6062     g_info << "waiting count:" << count << "/" << max_count << endl;
6063     NdbSleep_MilliSleep(milli_sleep);
6064   }
6065   g_err << "st_wait_idle: objects did not become Online" << endl;
6066 err:
6067   return -1;
6068 }
6069 
6070 // ndb dict comparisons (non-retrieved vs retrieved)
6071 
6072 static int
st_equal_column(const NdbDictionary::Column & c1,const NdbDictionary::Column & c2,NdbDictionary::Object::Type type)6073 st_equal_column(const NdbDictionary::Column& c1,
6074                 const NdbDictionary::Column& c2,
6075                 NdbDictionary::Object::Type type)
6076 {
6077   chk1(strcmp(c1.getName(), c2.getName()) == 0);
6078   chk1(c1.getNullable() == c2.getNullable());
6079   if (type == NdbDictionary::Object::UserTable) {
6080     chk1(c1.getPrimaryKey() == c2.getPrimaryKey());
6081   }
6082   if (0) { // should fix
6083     chk1(c1.getColumnNo() == c2.getColumnNo());
6084   }
6085   chk1(c1.getType() == c2.getType());
6086   if (c1.getType() == NdbDictionary::Column::Decimal ||
6087       c1.getType() == NdbDictionary::Column::Decimalunsigned) {
6088     chk1(c1.getPrecision() == c2.getPrecision());
6089     chk1(c1.getScale() == c2.getScale());
6090   }
6091   if (c1.getType() != NdbDictionary::Column::Blob &&
6092       c1.getType() != NdbDictionary::Column::Text) {
6093     chk1(c1.getLength() == c2.getLength());
6094   } else {
6095     chk1(c1.getInlineSize() == c2.getInlineSize());
6096     chk1(c1.getPartSize() == c2.getPartSize());
6097     chk1(c1.getStripeSize() == c2.getStripeSize());
6098   }
6099   chk1(c1.getCharset() == c2.getCharset());
6100   if (type == NdbDictionary::Object::UserTable) {
6101     chk1(c1.getPartitionKey() == c2.getPartitionKey());
6102   }
6103   chk1(c1.getArrayType() == c2.getArrayType());
6104   chk1(c1.getStorageType() == c2.getStorageType());
6105   chk1(c1.getDynamic() == c2.getDynamic());
6106   chk1(c1.getAutoIncrement() == c2.getAutoIncrement());
6107   return 0;
6108 err:
6109   return -1;
6110 }
6111 
6112 static int
st_equal_table(const NdbDictionary::Table & t1,const NdbDictionary::Table & t2)6113 st_equal_table(const NdbDictionary::Table& t1, const NdbDictionary::Table& t2)
6114 {
6115   chk1(strcmp(t1.getName(), t2.getName()) == 0);
6116   chk1(t1.getLogging() == t2.getLogging());
6117   chk1(t1.getFragmentType() == t2.getFragmentType());
6118   chk1(t1.getKValue() == t2.getKValue());
6119   chk1(t1.getMinLoadFactor() == t2.getMinLoadFactor());
6120   chk1(t1.getMaxLoadFactor() == t2.getMaxLoadFactor());
6121   chk1(t1.getNoOfColumns() == t2.getNoOfColumns());
6122   /*
6123    * There is no method to get type of table...
6124    * On the other hand SystemTable/UserTable should be just Table
6125    * and "System" should be an independent property.
6126    */
6127   NdbDictionary::Object::Type type;
6128   type = NdbDictionary::Object::UserTable;
6129   int n;
6130   for (n = 0; n < t1.getNoOfColumns(); n++) {
6131     const NdbDictionary::Column* c1 = t1.getColumn(n);
6132     const NdbDictionary::Column* c2 = t2.getColumn(n);
6133     require(c1 != 0 && c2 != 0);
6134     chk2(st_equal_column(*c1, *c2, type) == 0, "col:" << n);
6135   }
6136   chk1(t1.getNoOfPrimaryKeys() == t2.getNoOfPrimaryKeys());
6137   chk1(t1.getTemporary() == t2.getTemporary());
6138   chk1(t1.getForceVarPart() == t2.getForceVarPart());
6139   return 0;
6140 err:
6141   return -1;
6142 }
6143 
6144 static int
st_equal_index(const NdbDictionary::Index & i1,const NdbDictionary::Index & i2)6145 st_equal_index(const NdbDictionary::Index& i1, const NdbDictionary::Index& i2)
6146 {
6147   chk1(strcmp(i1.getName(), i2.getName()) == 0);
6148   require(i1.getTable() != 0 && i2.getTable() != 0);
6149   chk1(strcmp(i1.getTable(), i2.getTable()) == 0);
6150   chk1(i1.getNoOfColumns() == i2.getNoOfColumns());
6151   chk1(i1.getType() == i2.getType());
6152   NdbDictionary::Object::Type type;
6153   type = (NdbDictionary::Object::Type)i1.getType();
6154   int n;
6155   for (n = 0; n < (int)i1.getNoOfColumns(); n++) {
6156     const NdbDictionary::Column* c1 = i1.getColumn(n);
6157     const NdbDictionary::Column* c2 = i2.getColumn(n);
6158     require(c1 != 0 && c2 != 0);
6159     chk2(st_equal_column(*c1, *c2, type) == 0, "col:" << n);
6160   }
6161   chk1(i1.getLogging() == i2.getLogging());
6162   chk1(i1.getTemporary() == i2.getTemporary());
6163   return 0;
6164 err:
6165   return -1;
6166 }
6167 
6168 // verify against database objects (hits all nodes randomly)
6169 
6170 static int
st_verify_table(ST_Con & c,ST_Tab & tab)6171 st_verify_table(ST_Con& c, ST_Tab& tab)
6172 {
6173   c.dic->invalidateTable(tab.name);
6174   const NdbDictionary::Table* pTab = c.dic->getTable(tab.name);
6175   tab.tab_r = pTab;
6176   if (tab.exists()) {
6177     chk2(pTab != 0, c.dic->getNdbError());
6178     chk1(st_equal_table(*tab.tab, *pTab) == 0);
6179     tab.id = pTab->getObjectId();
6180     g_info << tab << ": verified exists tx_on:" << c.tx_on << endl;
6181   } else {
6182     chk2(pTab == 0, tab);
6183     chk2(c.dic->getNdbError().code == 723, c.dic->getNdbError());
6184     g_info << tab << ": verified not exists tx_on:" << c.tx_on << endl;
6185     tab.id = -1;
6186   }
6187   return 0;
6188 err:
6189   return -1;
6190 }
6191 
6192 static int
st_verify_index(ST_Con & c,ST_Ind & ind)6193 st_verify_index(ST_Con& c, ST_Ind& ind)
6194 {
6195   ST_Tab& tab = *ind.tab;
6196   c.dic->invalidateIndex(ind.name, tab.name);
6197   const NdbDictionary::Index* pInd = c.dic->getIndex(ind.name, tab.name);
6198   ind.ind_r = pInd;
6199   if (ind.exists()) {
6200     chk2(pInd != 0, c.dic->getNdbError());
6201     chk1(st_equal_index(*ind.ind, *pInd) == 0);
6202     ind.id = pInd->getObjectId();
6203     g_info << ind << ": verified exists tx_on:" << c.tx_on << endl;
6204   } else {
6205     chk2(pInd == 0, ind);
6206     chk2(c.dic->getNdbError().code == 4243, c.dic->getNdbError());
6207     g_info << ind << ": verified not exists tx_on:" << c.tx_on << endl;
6208     ind.id = -1;
6209   }
6210   return 0;
6211 err:
6212   return -1;
6213 }
6214 
6215 static int
st_verify_all(ST_Con & c)6216 st_verify_all(ST_Con& c)
6217 {
6218   chk1(st_verify_list(c) == 0);
6219   int i, j;
6220   for (i = 0; i < c.tabcount; i++) {
6221     ST_Tab& tab = c.tab(i);
6222     chk1(st_verify_table(c, tab) == 0);
6223     for (j = 0; j < tab.indcount; j++) {
6224       ST_Ind& ind = tab.ind(j);
6225       chk1(st_verify_index(c, ind) == 0);
6226     }
6227   }
6228   return 0;
6229 err:
6230   return -1;
6231 }
6232 
6233 // subroutines
6234 
6235 static const uint
6236 ST_CommitFlag = 0;
6237 
6238 static const uint
6239 ST_AbortFlag = NdbDictionary::Dictionary::SchemaTransAbort;
6240 
6241 static const uint
6242 ST_BackgroundFlag = NdbDictionary::Dictionary::SchemaTransBackground;
6243 
6244 struct ST_Retry {
6245   int max_tries;
6246   int sleep_ms;
6247 };
6248 
6249 static int
st_begin_trans(ST_Con & c,int code=0)6250 st_begin_trans(ST_Con& c, int code = 0)
6251 {
6252   g_info << "begin trans";
6253   if (code == 0) {
6254     g_info << endl;
6255     chk2(c.dic->beginSchemaTrans() == 0, c.dic->getNdbError());
6256     chk1(c.dic->hasSchemaTrans() == true);
6257     c.tx_on = true;
6258   } else {
6259     g_info << " - expect error " << code << endl;
6260     chk1(c.dic->beginSchemaTrans() == -1);
6261     const NdbError& error = c.dic->getNdbError();
6262     chk2(error.code == code, error << " wanted: " << code);
6263   }
6264   return 0;
6265 err:
6266   return -1;
6267 }
6268 
6269 static int
st_begin_trans(ST_Con & c,ST_Errins errins)6270 st_begin_trans(ST_Con& c, ST_Errins errins)
6271 {
6272   require(errins.code != 0);
6273   chk1(st_do_errins(c, errins) == 0);
6274   chk1(st_begin_trans(c, errins.code) == 0);
6275   return 0;
6276 err:
6277   return -1;
6278 }
6279 
6280 static int
st_begin_trans(ST_Con & c,ST_Retry retry)6281 st_begin_trans(ST_Con& c, ST_Retry retry)
6282 {
6283   int tries = 0;
6284   while (++tries <= retry.max_tries) {
6285     int code = 0;
6286     if (c.dic->beginSchemaTrans() == -1) {
6287       code = c.dic->getNdbError().code;
6288       require(code != 0);
6289     }
6290     chk2(code == 0 || code == 780 || code == 701, c.dic->getNdbError());
6291     if (code == 0) {
6292       chk1(c.dic->hasSchemaTrans() == true);
6293       g_info << "begin trans at try " << tries << endl;
6294       break;
6295     }
6296     NdbSleep_MilliSleep(retry.sleep_ms);
6297   }
6298   return 0;
6299 err:
6300   return -1;
6301 }
6302 
6303 static int
st_end_trans(ST_Con & c,uint flags)6304 st_end_trans(ST_Con& c, uint flags)
6305 {
6306   g_info << "end trans flags:" << hex << flags << endl;
6307   int res= c.dic->endSchemaTrans(flags);
6308   g_info << "end trans result:" << res << endl;
6309   chk2(res == 0, c.dic->getNdbError());
6310   c.tx_on = false;
6311   c.tx_commit = !(flags & ST_AbortFlag);
6312   st_set_commit_all(c);
6313   return 0;
6314 err:
6315   return -1;
6316 }
6317 
6318 static int
st_end_trans_aborted(ST_Con & c,uint flags)6319 st_end_trans_aborted(ST_Con& c, uint flags)
6320 {
6321   g_info << "end trans flags:" << hex << flags << endl;
6322   int res= c.dic->endSchemaTrans(flags);
6323   g_info << "end trans result:" << res << endl;
6324   if (flags & ST_AbortFlag)
6325     chk1(res == 0);
6326   else
6327     chk1(res != 0);
6328   c.tx_on = false;
6329   c.tx_commit = (flags & ST_AbortFlag);
6330   return 0;
6331 err:
6332   return -1;
6333 }
6334 
6335 static int
st_end_trans(ST_Con & c,ST_Errins errins,uint flags)6336 st_end_trans(ST_Con& c, ST_Errins errins, uint flags)
6337 {
6338   chk1(st_do_errins(c, errins) == 0);
6339   chk1(st_end_trans(c, flags) == 0);
6340   return 0;
6341 err:
6342   return -1;
6343 }
6344 
6345 static int
st_end_trans_aborted(ST_Con & c,ST_Errins errins,uint flags)6346 st_end_trans_aborted(ST_Con& c, ST_Errins errins, uint flags)
6347 {
6348   chk1(st_do_errins(c, errins) == 0);
6349   chk1(st_end_trans_aborted(c, flags) == 0);
6350   return 0;
6351 err:
6352   return -1;
6353 }
6354 
6355 static int
st_load_table(ST_Con & c,ST_Tab & tab,int rows=1000)6356 st_load_table(ST_Con& c, ST_Tab& tab, int rows = 1000)
6357 {
6358   g_info << tab.name << ": load data rows:" << rows << endl;
6359   chk1(tab.tab_r != NULL);
6360   {
6361     HugoTransactions ht(*tab.tab_r);
6362     chk1(ht.loadTable(c.ndb, rows) == 0);
6363   }
6364   return 0;
6365 err:
6366   return -1;
6367 }
6368 
6369 static int
st_create_table(ST_Con & c,ST_Tab & tab,int code=0)6370 st_create_table(ST_Con& c, ST_Tab& tab, int code = 0)
6371 {
6372   g_info << tab.name << ": create table";
6373   if (code == 0) {
6374     g_info << endl;
6375     require(!tab.exists());
6376     chk2(c.dic->createTable(*tab.tab) == 0, c.dic->getNdbError());
6377     g_info << tab.name << ": created" << endl;
6378     st_set_create_tab(c, tab, true);
6379   }
6380   else {
6381     g_info << " - expect error " << code << endl;
6382     chk1(c.dic->createTable(*tab.tab) == -1);
6383     const NdbError& error = c.dic->getNdbError();
6384     chk2(error.code == code, error << " wanted: " << code);
6385   }
6386   chk1(st_verify_table(c, tab) == 0);
6387   return 0;
6388 err:
6389   return -1;
6390 }
6391 
6392 static int
st_create_table(ST_Con & c,ST_Tab & tab,ST_Errins errins)6393 st_create_table(ST_Con& c, ST_Tab& tab, ST_Errins errins)
6394 {
6395   require(errins.code != 0);
6396   chk1(st_do_errins(c, errins) == 0);
6397   chk1(st_create_table(c, tab, errins.code) == 0);
6398   return 0;
6399 err:
6400   return -1;
6401 }
6402 
6403 static int
st_drop_table(ST_Con & c,ST_Tab & tab,int code=0)6404 st_drop_table(ST_Con& c, ST_Tab& tab, int code = 0)
6405 {
6406   g_info << tab.name << ": drop table";
6407   if (code == 0) {
6408     g_info << endl;
6409     require(tab.exists());
6410     c.dic->invalidateTable(tab.name);
6411     chk2(c.dic->dropTable(tab.name) == 0, c.dic->getNdbError());
6412     g_info << tab.name << ": dropped" << endl;
6413     st_set_create_tab(c, tab, false);
6414   } else {
6415     g_info << " - expect error " << code << endl;
6416     c.dic->invalidateTable(tab.name);
6417     chk1(c.dic->dropTable(tab.name) == -1);
6418     const NdbError& error = c.dic->getNdbError();
6419     chk2(error.code == code, error << " wanted: " << code);
6420   }
6421   chk1(st_verify_table(c, tab) == 0);
6422   return 0;
6423 err:
6424   return -1;
6425 }
6426 
6427 static int
st_drop_table(ST_Con & c,ST_Tab & tab,ST_Errins errins)6428 st_drop_table(ST_Con& c, ST_Tab& tab, ST_Errins errins)
6429 {
6430   require(errins.code != 0);
6431   chk1(st_do_errins(c, errins) == 0);
6432   chk1(st_drop_table(c, tab, errins.code) == 0);
6433   return 0;
6434 err:
6435   return -1;
6436 }
6437 
6438 static int
st_create_index(ST_Con & c,ST_Ind & ind,int code=0)6439 st_create_index(ST_Con& c, ST_Ind& ind, int code = 0)
6440 {
6441   ST_Tab& tab = *ind.tab;
6442   g_info << ind.name << ": create index on "
6443          << tab.name << "(" << ind.colnames.c_str() << ")";
6444   if (code == 0) {
6445     g_info << endl;
6446     require(!ind.exists());
6447     chk2(c.dic->createIndex(*ind.ind, *tab.tab_r) == 0, c.dic->getNdbError());
6448     st_set_create_ind(c, ind, true);
6449     g_info << ind.name << ": created" << endl;
6450   } else {
6451     g_info << " - expect error " << code << endl;
6452     chk1(c.dic->createIndex(*ind.ind, *tab.tab_r) == -1);
6453     const NdbError& error = c.dic->getNdbError();
6454     chk2(error.code == code, error << " wanted: " << code);
6455   }
6456   chk1(st_verify_index(c, ind) == 0);
6457   return 0;
6458 err:
6459   return -1;
6460 }
6461 
6462 static int
st_create_index(ST_Con & c,ST_Ind & ind,ST_Errins errins)6463 st_create_index(ST_Con& c, ST_Ind& ind, ST_Errins errins)
6464 {
6465   require(errins.code != 0);
6466   chk1(st_do_errins(c, errins) == 0);
6467   chk1(st_create_index(c, ind, errins.code) == 0);
6468   return 0;
6469 err:
6470   return -1;
6471 }
6472 
6473 static int
st_drop_index(ST_Con & c,ST_Ind & ind,int code=0)6474 st_drop_index(ST_Con& c, ST_Ind& ind, int code = 0)
6475 {
6476   ST_Tab& tab = *ind.tab;
6477   g_info << ind.name << ": drop index";
6478   if (code == 0) {
6479     g_info << endl;
6480     require(ind.exists());
6481     c.dic->invalidateIndex(ind.name, tab.name);
6482     chk2(c.dic->dropIndex(ind.name, tab.name) == 0, c.dic->getNdbError());
6483     g_info << ind.name << ": dropped" << endl;
6484     st_set_create_ind(c, ind, false);
6485   } else {
6486     g_info << " expect error " << code << endl;
6487     c.dic->invalidateIndex(ind.name, tab.name);
6488     chk1(c.dic->dropIndex(ind.name, tab.name) == -1);
6489     const NdbError& error = c.dic->getNdbError();
6490     chk2(error.code == code, error << " wanted: " << code);
6491   }
6492   chk1(st_verify_index(c, ind) == 0);
6493   return 0;
6494 err:
6495   return -1;
6496 }
6497 
6498 static int
st_drop_index(ST_Con & c,ST_Ind & ind,ST_Errins errins)6499 st_drop_index(ST_Con& c, ST_Ind& ind, ST_Errins errins)
6500 {
6501   require(errins.code != 0);
6502   chk1(st_do_errins(c, errins) == 0);
6503   chk1(st_drop_index(c, ind, errins.code) == 0);
6504   return 0;
6505 err:
6506   return -1;
6507 }
6508 
6509 static int
st_create_table_index(ST_Con & c,ST_Tab & tab)6510 st_create_table_index(ST_Con& c, ST_Tab& tab)
6511 {
6512   chk1(st_create_table(c, tab) == 0);
6513   int j;
6514   for (j = 0; j < tab.indcount; j++) {
6515     ST_Ind& ind = tab.ind(j);
6516     chk1(st_create_index(c, ind) == 0);
6517   }
6518   return 0;
6519 err:
6520   return -1;
6521 }
6522 
6523 // drop all
6524 
6525 static int
st_drop_test_tables(ST_Con & c)6526 st_drop_test_tables(ST_Con& c)
6527 {
6528   g_info << "st_drop_test_tables" << endl;
6529   int i;
6530   for (i = 0; i < c.tabcount; i++) {
6531     ST_Tab& tab = c.tab(i);
6532     if (tab.exists())
6533       chk1(st_drop_table(c, tab) == 0);
6534   }
6535   return 0;
6536 err:
6537   return -1;
6538 }
6539 
6540 // error insert values
6541 
6542 static const ST_Errins
6543 st_errins_begin_trans[] = {
6544   ST_Errins(6101, 780),
6545   ST_Errins()
6546 };
6547 
6548 static const ST_Errins
6549 st_errins_end_trans1[] = {
6550   ST_Errins(ERR_INSERT_MASTER_FAILURE1, 0, 1),
6551   ST_Errins()
6552 };
6553 
6554 static const ST_Errins
6555 st_errins_end_trans2[] = {
6556   ST_Errins(ERR_INSERT_MASTER_FAILURE2, 0, 1),
6557   ST_Errins()
6558 };
6559 
6560 static const ST_Errins
6561 st_errins_end_trans3[] = {
6562   ST_Errins(ERR_INSERT_MASTER_FAILURE3, 0, 1),
6563   ST_Errins()
6564 };
6565 
6566 static const ST_Errins
6567 st_errins_table[] = {
6568   ST_Errins(6111, 783),
6569   ST_Errins(6121, 9121),
6570   //ST_Errins(6131, 9131),
6571   ST_Errins()
6572 };
6573 
6574 static ST_Errins
6575 st_errins_index[] = {
6576   ST_Errins(st_errins_table),
6577   ST_Errins(6112, 783),
6578   ST_Errins(6113, 783),
6579   ST_Errins(6114, 783),
6580   ST_Errins(6122, 9122),
6581   ST_Errins(6123, 9123),
6582   ST_Errins(6124, 9124),
6583   //ST_Errins(6132, 9131),
6584   //ST_Errins(6133, 9131),
6585   //ST_Errins(6134, 9131),
6586   //ST_Errins(6135, 9131),
6587   ST_Errins()
6588 };
6589 
6590 static ST_Errins
6591 st_errins_index_create[] = {
6592   ST_Errins(st_errins_index),
6593   ST_Errins(6116, 783),
6594   ST_Errins(6126, 9126),
6595   //ST_Errins(6136, 9136),
6596   ST_Errins()
6597 };
6598 
6599 static ST_Errins
6600 st_errins_index_drop[] = {
6601   ST_Errins(st_errins_index),
6602   ST_Errins()
6603 };
6604 
6605 // specific test cases
6606 
6607 static int
st_test_create(ST_Con & c,int arg=-1)6608 st_test_create(ST_Con& c, int arg = -1)
6609 {
6610   int do_abort = (arg == 1);
6611   int i;
6612   chk1(st_begin_trans(c) == 0);
6613   for (i = 0; i < c.tabcount; i++) {
6614     ST_Tab& tab = c.tab(i);
6615     chk1(st_create_table_index(c, tab) == 0);
6616   }
6617   chk1(st_verify_list(c) == 0);
6618   if (!do_abort)
6619     chk1(st_end_trans(c, 0) == 0);
6620   else
6621     chk1(st_end_trans(c, ST_AbortFlag) == 0);
6622   chk1(st_verify_list(c) == 0);
6623   if (!do_abort)
6624     chk1(st_drop_test_tables(c) == 0);
6625   return NDBT_OK;
6626 err:
6627   return NDBT_FAILED;
6628 }
6629 
6630 static int
st_test_drop(ST_Con & c,int arg=-1)6631 st_test_drop(ST_Con& c, int arg = -1)
6632 {
6633   int do_abort = (arg == 1);
6634   int i;
6635   for (i = 0; i < c.tabcount; i++) {
6636     ST_Tab& tab = c.tab(i);
6637     chk1(st_create_table_index(c, tab) == 0);
6638   }
6639   chk1(st_begin_trans(c) == 0);
6640   for (i = 0; i < c.tabcount; i++) {
6641     ST_Tab& tab = c.tab(i);
6642     chk1(st_drop_table(c, tab) == 0);
6643   }
6644   chk1(st_verify_list(c) == 0);
6645   if (!do_abort)
6646     chk1(st_end_trans(c, 0) == 0);
6647   else
6648     chk1(st_end_trans(c, ST_AbortFlag) == 0);
6649   chk1(st_verify_list(c) == 0);
6650   return NDBT_OK;
6651 err:
6652   return NDBT_FAILED;
6653 }
6654 
6655 static int
st_test_rollback_create_table(ST_Con & c,int arg=-1)6656 st_test_rollback_create_table(ST_Con& c, int arg = -1)
6657 {
6658   int i;
6659   chk1(st_begin_trans(c) == 0);
6660   for (i = 0; i < c.tabcount; i++) {
6661     ST_Tab& tab = c.tab(i);
6662     if (i % 2 == 0) {
6663       ST_Errins errins(6111, 783, 0); // fail CTa seize op
6664       chk1(st_create_table(c, tab, errins) == 0);
6665     } else {
6666       chk1(st_create_table(c, tab) == 0);
6667     }
6668   }
6669   chk1(st_end_trans(c, 0) == 0);
6670   chk1(st_verify_list(c) == 0);
6671   for (i = 0; i < c.tabcount; i++) {
6672     ST_Tab& tab = c.tab(i);
6673     if (i % 2 == 0)
6674       require(!tab.exists());
6675     else {
6676       require(tab.exists());
6677       chk1(st_drop_table(c, tab) == 0);
6678     }
6679   }
6680   return NDBT_OK;
6681 err:
6682   return NDBT_FAILED;
6683 }
6684 
6685 static int
st_test_rollback_drop_table(ST_Con & c,int arg=-1)6686 st_test_rollback_drop_table(ST_Con& c, int arg = -1)
6687 {
6688   int i;
6689   for (i = 0; i < c.tabcount; i++) {
6690     ST_Tab& tab = c.tab(i);
6691     chk1(st_create_table(c, tab) == 0);
6692   }
6693   chk1(st_begin_trans(c) == 0);
6694   for (i = 0; i < c.tabcount; i++) {
6695     ST_Tab& tab = c.tab(i);
6696     if (i % 2 == 0) {
6697       ST_Errins errins(6111, 783, 0); // fail DTa seize op
6698       chk1(st_drop_table(c, tab, errins) == 0);
6699     } else {
6700       chk1(st_drop_table(c, tab) == 0);
6701     }
6702   }
6703   chk1(st_end_trans(c, 0) == 0);
6704   chk1(st_verify_list(c) == 0);
6705   for (i = 0; i < c.tabcount; i++) {
6706     ST_Tab& tab = c.tab(i);
6707     if (i % 2 == 0) {
6708       require(tab.exists());
6709       chk1(st_drop_table(c, tab) == 0);
6710     } else {
6711       require(!tab.exists());
6712     }
6713   }
6714   return NDBT_OK;
6715 err:
6716   return NDBT_FAILED;
6717 }
6718 
6719 static int
st_test_rollback_create_index(ST_Con & c,int arg=-1)6720 st_test_rollback_create_index(ST_Con& c, int arg = -1)
6721 {
6722   int i, j;
6723   for (i = 0; i < c.tabcount; i++) {
6724     ST_Tab& tab = c.tab(i);
6725     if (tab.indcount < 1)
6726       continue;
6727     chk1(st_create_table(c, tab) == 0);
6728     chk1(st_begin_trans(c) == 0);
6729     for (j = 0; j < tab.indcount; j++) {
6730       ST_Ind& ind = tab.ind(j);
6731       if (j % 2 == 0) {
6732         ST_Errins errins(6116, 783, 0); // fail BIn seize op
6733         chk1(st_create_index(c, ind, errins) == 0);
6734       } else {
6735         chk1(st_create_index(c, ind) == 0);
6736       }
6737     }
6738     chk1(st_end_trans(c, 0) == 0);
6739     chk1(st_verify_list(c) == 0);
6740     for (j = 0; j < tab.indcount; j++) {
6741       ST_Ind& ind = tab.ind(j);
6742       if (j % 2 == 0)
6743         require(!ind.exists());
6744       else {
6745         require(ind.exists());
6746         chk1(st_drop_index(c, ind) == 0);
6747       }
6748     }
6749     chk1(st_drop_table(c, tab) == 0);
6750   }
6751   return NDBT_OK;
6752 err:
6753   return NDBT_FAILED;
6754 }
6755 
6756 static int
st_test_rollback_drop_index(ST_Con & c,int arg=-1)6757 st_test_rollback_drop_index(ST_Con& c, int arg = -1)
6758 {
6759   int i, j;
6760   for (i = 0; i < c.tabcount; i++) {
6761     ST_Tab& tab = c.tab(i);
6762     if (tab.indcount < 1)
6763       continue;
6764     chk1(st_create_table_index(c, tab) == 0);
6765   }
6766   for (i = 0; i < c.tabcount; i++) {
6767     ST_Tab& tab = c.tab(i);
6768     if (tab.indcount < 1)
6769       continue;
6770     chk1(st_begin_trans(c) == 0);
6771     for (j = 0; j < tab.indcount; j++) {
6772       ST_Ind& ind = tab.ind(j);
6773       if (j % 2 == 0) {
6774         ST_Errins errins(6114, 783, 0); // fail ATr seize op
6775         chk1(st_drop_index(c, ind, errins) == 0);
6776       } else {
6777         chk1(st_drop_index(c, ind) == 0);
6778       }
6779     }
6780     chk1(st_end_trans(c, 0) == 0);
6781     chk1(st_verify_list(c) == 0);
6782     for (j = 0; j < tab.indcount; j++) {
6783       ST_Ind& ind = tab.ind(j);
6784       if (j % 2 == 0) {
6785         require(ind.exists());
6786         chk1(st_drop_index(c, ind) == 0);
6787       } else {
6788         require(!ind.exists());
6789       }
6790     }
6791   }
6792   return NDBT_OK;
6793 err:
6794   return NDBT_FAILED;
6795 }
6796 
6797 static int
st_test_dup_create_table(ST_Con & c,int arg=-1)6798 st_test_dup_create_table(ST_Con& c, int arg = -1)
6799 {
6800   int do_trans;
6801   int do_abort;
6802   int i;
6803   for (do_trans = 0; do_trans <= 1; do_trans++) {
6804     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6805       g_info << "trans:" << do_trans
6806              << " abort:" << do_abort << endl;
6807       for (i = 0; i < c.tabcount; i++) {
6808         ST_Tab& tab = c.tab(i);
6809         if (do_trans)
6810           chk1(st_begin_trans(c) == 0);
6811         chk1(st_create_table(c, tab) == 0);
6812         chk1(st_create_table(c, tab, 721) == 0);
6813         if (do_trans) {
6814           if (!do_abort)
6815             chk1(st_end_trans(c, 0) == 0);
6816           else
6817             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6818         }
6819         chk1(st_verify_list(c) == 0);
6820         if (tab.exists()) {
6821           chk1(st_drop_table(c, tab) == 0);
6822         }
6823       }
6824     }
6825   }
6826   return NDBT_OK;
6827 err:
6828   return NDBT_FAILED;
6829 }
6830 
6831 static int
st_test_dup_drop_table(ST_Con & c,int arg=-1)6832 st_test_dup_drop_table(ST_Con& c, int arg = -1)
6833 {
6834   int do_trans;
6835   int do_abort;
6836   int i;
6837   for (do_trans = 0; do_trans <= 1; do_trans++) {
6838     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6839       g_info << "trans:" << do_trans
6840              << " abort:" << do_abort << endl;
6841       for (i = 0; i < c.tabcount; i++) {
6842         ST_Tab& tab = c.tab(i);
6843         chk1(st_create_table(c, tab) == 0);
6844         if (do_trans)
6845           chk1(st_begin_trans(c) == 0);
6846         chk1(st_drop_table(c, tab) == 0);
6847         if (!do_trans)
6848           chk1(st_drop_table(c, tab, 723) == 0);
6849         else
6850           chk1(st_drop_table(c, tab, 785) == 0);
6851         if (do_trans) {
6852           if (!do_abort)
6853             chk1(st_end_trans(c, 0) == 0);
6854           else
6855             chk1(st_end_trans(c, ST_AbortFlag) == 0);
6856         }
6857         chk1(st_verify_list(c) == 0);
6858         if (tab.exists()) {
6859           chk1(st_drop_table(c, tab) == 0);
6860         }
6861       }
6862     }
6863   }
6864   return NDBT_OK;
6865 err:
6866   return NDBT_FAILED;
6867 }
6868 
6869 static int
st_test_dup_create_index(ST_Con & c,int arg=-1)6870 st_test_dup_create_index(ST_Con& c, int arg = -1)
6871 {
6872   int do_trans;
6873   int do_abort;
6874   int i, j;
6875   for (do_trans = 0; do_trans <= 1; do_trans++) {
6876     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6877       g_info << "trans:" << do_trans
6878              << " abort:" << do_abort << endl;
6879       for (i = 0; i < c.tabcount; i++) {
6880         ST_Tab& tab = c.tab(i);
6881         if (tab.indcount < 1)
6882           continue;
6883         chk1(st_create_table(c, tab) == 0);
6884         for (j = 0; j < tab.indcount; j++) {
6885           ST_Ind& ind = tab.ind(j);
6886           if (do_trans)
6887             chk1(st_begin_trans(c) == 0);
6888           chk1(st_create_index(c, ind) == 0);
6889           chk1(st_create_index(c, ind, 721) == 0);
6890           if (do_trans) {
6891             if (!do_abort)
6892               chk1(st_end_trans(c, 0) == 0);
6893             else
6894               chk1(st_end_trans(c, ST_AbortFlag) == 0);
6895           }
6896           chk1(st_verify_list(c) == 0);
6897         }
6898         chk1(st_drop_table(c, tab) == 0);
6899       }
6900     }
6901   }
6902   return NDBT_OK;
6903 err:
6904   return NDBT_FAILED;
6905 }
6906 
6907 static int
st_test_dup_drop_index(ST_Con & c,int arg=-1)6908 st_test_dup_drop_index(ST_Con& c, int arg = -1)
6909 {
6910   int do_trans;
6911   int do_abort;
6912   int i, j;
6913   for (do_trans = 0; do_trans <= 1; do_trans++) {
6914     for (do_abort = 0; do_abort <= do_trans; do_abort++) {
6915       g_info << "trans:" << do_trans
6916              << " abort:" << do_abort << endl;
6917       for (i = 0; i < c.tabcount; i++) {
6918         ST_Tab& tab = c.tab(i);
6919         if (tab.indcount < 1)
6920           continue;
6921         chk1(st_create_table(c, tab) == 0);
6922         for (j = 0; j < tab.indcount; j++) {
6923           ST_Ind& ind = tab.ind(j);
6924           chk1(st_create_index(c, ind) == 0);
6925           if (do_trans)
6926             chk1(st_begin_trans(c) == 0);
6927           chk1(st_drop_index(c, ind) == 0);
6928           if (!do_trans)
6929             chk1(st_drop_index(c, ind, 4243) == 0);
6930           else
6931             chk1(st_drop_index(c, ind, 785) == 0);
6932           if (do_trans) {
6933             if (!do_abort)
6934               chk1(st_end_trans(c, 0) == 0);
6935             else
6936               chk1(st_end_trans(c, ST_AbortFlag) == 0);
6937           }
6938           chk1(st_verify_list(c) == 0);
6939         }
6940         chk1(st_drop_table(c, tab) == 0);
6941       }
6942     }
6943   }
6944   return NDBT_OK;
6945 err:
6946   return NDBT_FAILED;
6947 }
6948 
6949 static int
st_test_build_index(ST_Con & c,int arg=-1)6950 st_test_build_index(ST_Con& c, int arg = -1)
6951 {
6952   int i, j;
6953   for (i = 0; i < c.tabcount; i++) {
6954     ST_Tab& tab = c.tab(i);
6955     if (tab.indcount < 1)
6956       continue;
6957     chk1(st_create_table(c, tab) == 0);
6958     chk1(st_load_table(c, tab) == 0);
6959     for (j = 0; j < tab.indcount; j++) {
6960       ST_Ind& ind = tab.ind(j);
6961       chk1(st_create_index(c, ind) == 0);
6962       chk1(st_verify_list(c) == 0);
6963     }
6964     chk1(st_drop_table(c, tab) == 0);
6965   }
6966   return NDBT_OK;
6967 err:
6968   return NDBT_FAILED;
6969 }
6970 
6971 static ST_Errins
6972 st_test_local_create_list[] = {
6973   ST_Errins(8033, 293, 1),    // TC trigger
6974   ST_Errins(8033, 293, 0),
6975   ST_Errins(4003, 4237, 1),   // TUP trigger
6976   ST_Errins(4003, 4237, 0),
6977   ST_Errins(8034, 292, 1),    // TC index
6978   ST_Errins(8034, 292, 0)
6979 };
6980 
6981 static int
st_test_local_create(ST_Con & c,int arg=-1)6982 st_test_local_create(ST_Con& c, int arg = -1)
6983 {
6984   const int n = arg;
6985   ST_Errins *list = st_test_local_create_list;
6986   const int listlen =
6987     sizeof(st_test_local_create_list)/sizeof(st_test_local_create_list[0]);
6988   require(0 <= n && n < listlen);
6989   const bool only_unique = (n == 0 || n == 1 || n == 4 || n == 5);
6990   int i, j;
6991   for (i = 0; i < c.tabcount; i++) {
6992     ST_Tab& tab = c.tab(i);
6993     bool tabdone = false;
6994     for (j = 0; j < tab.indcount; j++) {
6995       ST_Ind& ind = tab.ind(j);
6996       if (only_unique && !ind.is_unique())
6997         continue;
6998       if (!tabdone) {
6999         chk1(st_create_table(c, tab) == 0);
7000         chk1(st_load_table(c, tab) == 0);
7001         tabdone = true;
7002       }
7003       ST_Errins errins = list[n];
7004       chk1(st_create_index(c, ind, errins) == 0);
7005       chk1(st_verify_list(c) == 0);
7006     }
7007     if (tabdone)
7008       chk1(st_drop_table(c, tab) == 0);
7009   }
7010   return NDBT_OK;
7011 err:
7012   return NDBT_FAILED;
7013 }
7014 
7015 // random test cases
7016 
7017 static const uint ST_AllowAbort = 1;
7018 static const uint ST_AllowErrins = 2;
7019 
7020 static int
st_test_trans(ST_Con & c,int arg=-1)7021 st_test_trans(ST_Con& c, int arg = -1)
7022 {
7023   if ((arg & ST_AllowErrins) && randomly(2, 3)) {
7024     ST_Errins errins = st_get_errins(c, st_errins_begin_trans);
7025     chk1(st_begin_trans(c, errins) == 0);
7026   } else {
7027     chk1(st_begin_trans(c) == 0);
7028     if (randomly(1, 5)) {
7029       g_info << "try duplicate begin trans" << endl;
7030       chk1(st_begin_trans(c, 4410) == 0);
7031       chk1(c.dic->hasSchemaTrans() == true);
7032     }
7033     if ((arg & ST_AllowAbort) && randomly(1, 3)) {
7034       chk1(st_end_trans(c, ST_AbortFlag) == 0);
7035     } else {
7036       chk1(st_end_trans(c, 0) == 0);
7037     }
7038   }
7039   return NDBT_OK;
7040 err:
7041   return NDBT_FAILED;
7042 }
7043 
7044 static int
st_test_create_table(ST_Con & c,int arg=-1)7045 st_test_create_table(ST_Con& c, int arg = -1)
7046 {
7047   bool trans = randomly(3, 4);
7048   bool simpletrans = !trans && randomly(1, 2);
7049   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
7050   if (trans) {
7051     chk1(st_begin_trans(c) == 0);
7052   }
7053   int i;
7054   for (i = 0; i < c.tabcount; i++) {
7055     ST_Tab& tab = c.tab(i);
7056     if (tab.exists()) {
7057       g_info << tab.name << ": skip existing" << endl;
7058       continue;
7059     }
7060     g_info << tab.name << ": to create" << endl;
7061     if (simpletrans) {
7062       chk1(st_begin_trans(c) == 0);
7063     }
7064     if ((arg & ST_AllowErrins) && randomly(1, 3)) {
7065       ST_Errins errins = st_get_errins(c, st_errins_table);
7066       chk1(st_create_table(c, tab, errins) == 0);
7067       if (simpletrans) {
7068         if (randomly(1, 2))
7069           chk1(st_end_trans(c, 0) == 0);
7070         else
7071           chk1(st_end_trans(c, ST_AbortFlag) == 0);
7072       }
7073     } else {
7074       chk1(st_create_table(c, tab) == 0);
7075       if (simpletrans) {
7076         uint flags = 0;
7077         if ((arg & ST_AllowAbort) && randomly(4, 5))
7078           flags |= ST_AbortFlag;
7079         chk1(st_end_trans(c, flags) == 0);
7080       }
7081     }
7082     if (tab.exists() && randomly(1, 3)) {
7083       g_info << tab.name << ": try duplicate create" << endl;
7084       chk1(st_create_table(c, tab, 721) == 0);
7085     }
7086   }
7087   if (trans) {
7088     uint flags = 0;
7089     if ((arg & ST_AllowAbort) && randomly(4, 5))
7090       flags |= ST_AbortFlag;
7091     chk1(st_end_trans(c, flags) == 0);
7092   }
7093   return NDBT_OK;
7094 err:
7095   return NDBT_FAILED;
7096 }
7097 
7098 static int
st_test_drop_table(ST_Con & c,int arg=-1)7099 st_test_drop_table(ST_Con& c, int arg = -1)
7100 {
7101   bool trans = randomly(3, 4);
7102   bool simpletrans = !trans && randomly(1, 2);
7103   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
7104   if (trans) {
7105     chk1(st_begin_trans(c) == 0);
7106   }
7107   int i;
7108   for (i = 0; i < c.tabcount; i++) {
7109     ST_Tab& tab = c.tab(i);
7110     if (!tab.exists()) {
7111       g_info << tab.name << ": skip not existing" << endl;
7112       continue;
7113     }
7114     g_info << tab.name << ": to drop" << endl;
7115     if (simpletrans) {
7116       chk1(st_begin_trans(c) == 0);
7117     }
7118     if ((arg & ST_AllowErrins) && randomly(1, 3)) {
7119       ST_Errins errins = st_get_errins(c, st_errins_table);
7120       chk1(st_drop_table(c, tab, errins) == 0);
7121       if (simpletrans) {
7122         if (randomly(1, 2))
7123           chk1(st_end_trans(c, 0) == 0);
7124         else
7125           chk1(st_end_trans(c, ST_AbortFlag) == 0);
7126       }
7127     } else {
7128       chk1(st_drop_table(c, tab) == 0);
7129       if (simpletrans) {
7130         uint flags = 0;
7131         if ((arg & ST_AllowAbort) && randomly(4, 5))
7132           flags |= ST_AbortFlag;
7133         chk1(st_end_trans(c, flags) == 0);
7134       }
7135     }
7136     if (!tab.exists() && randomly(1, 3)) {
7137       g_info << tab.name << ": try duplicate drop" << endl;
7138       chk1(st_drop_table(c, tab, 723) == 0);
7139     }
7140   }
7141   if (trans) {
7142     uint flags = 0;
7143     if ((arg & ST_AllowAbort) && randomly(4, 5))
7144       flags |= ST_AbortFlag;
7145     chk1(st_end_trans(c, flags) == 0);
7146   }
7147   return NDBT_OK;
7148 err:
7149   return NDBT_FAILED;
7150 }
7151 
7152 static int
st_test_table(ST_Con & c,int arg=-1)7153 st_test_table(ST_Con& c, int arg = -1)
7154 {
7155   chk1(st_test_create_table(c) == NDBT_OK);
7156   chk1(st_test_drop_table(c) == NDBT_OK);
7157   return NDBT_OK;
7158 err:
7159   return NDBT_FAILED;
7160 }
7161 
7162 static int
st_test_create_index(ST_Con & c,int arg=-1)7163 st_test_create_index(ST_Con& c, int arg = -1)
7164 {
7165   bool trans = randomly(3, 4);
7166   bool simpletrans = !trans && randomly(1, 2);
7167   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
7168   if (trans) {
7169     chk1(st_begin_trans(c) == 0);
7170   }
7171   int i, j;
7172   for (i = 0; i < c.tabcount; i++) {
7173     ST_Tab& tab = c.tab(i);
7174     if (tab.indcount == 0)
7175       continue;
7176     if (!tab.exists()) {
7177       g_info << tab.name << ": to create" << endl;
7178       chk1(st_create_table(c, tab) == 0);
7179     }
7180     for (j = 0; j < tab.indcount; j++) {
7181       ST_Ind& ind = tab.ind(j);
7182       if (ind.exists()) {
7183         g_info << ind.name << ": skip existing" << endl;
7184         continue;
7185       }
7186       g_info << ind.name << ": to create" << endl;
7187       if (simpletrans) {
7188         chk1(st_begin_trans(c) == 0);
7189       }
7190       if ((arg & ST_AllowErrins) && randomly(1, 3)) {
7191         const ST_Errins* list = st_errins_index_create;
7192         ST_Errins errins = st_get_errins(c, list);
7193         chk1(st_create_index(c, ind, errins) == 0);
7194         if (simpletrans) {
7195           if (randomly(1, 2))
7196             chk1(st_end_trans(c, 0) == 0);
7197           else
7198             chk1(st_end_trans(c, ST_AbortFlag) == 0);
7199         }
7200       } else {
7201         chk1(st_create_index(c, ind) == 0);
7202         if (simpletrans) {
7203           uint flags = 0;
7204           if ((arg & ST_AllowAbort) && randomly(4, 5))
7205             flags |= ST_AbortFlag;
7206           chk1(st_end_trans(c, flags) == 0);
7207         }
7208       }
7209       if (ind.exists() && randomly(1, 3)) {
7210         g_info << ind.name << ": try duplicate create" << endl;
7211         chk1(st_create_index(c, ind, 721) == 0);
7212       }
7213     }
7214   }
7215   if (trans) {
7216     uint flags = 0;
7217     if ((arg & ST_AllowAbort) && randomly(4, 5))
7218       flags |= ST_AbortFlag;
7219     chk1(st_end_trans(c, flags) == 0);
7220   }
7221   return NDBT_OK;
7222 err:
7223   return NDBT_FAILED;
7224 }
7225 
7226 static int
st_test_drop_index(ST_Con & c,int arg=-1)7227 st_test_drop_index(ST_Con& c, int arg = -1)
7228 {
7229   bool trans = randomly(3, 4);
7230   bool simpletrans = !trans && randomly(1, 2);
7231   g_info << "trans:" << trans << " simpletrans:" << simpletrans << endl;
7232   if (trans) {
7233     chk1(st_begin_trans(c) == 0);
7234   }
7235   int i, j;
7236   for (i = 0; i < c.tabcount; i++) {
7237     ST_Tab& tab = c.tab(i);
7238     if (tab.indcount == 0)
7239       continue;
7240     if (!tab.exists()) {
7241       g_info << tab.name << ": skip not existing" << endl;
7242       continue;
7243     }
7244     for (j = 0; j < tab.indcount; j++) {
7245       ST_Ind& ind = tab.ind(j);
7246       if (!ind.exists()) {
7247         g_info << ind.name << ": skip not existing" << endl;
7248         continue;
7249       }
7250       g_info << ind.name << ": to drop" << endl;
7251       if (simpletrans) {
7252         chk1(st_begin_trans(c) == 0);
7253       }
7254       if ((arg & ST_AllowErrins) && randomly(1, 3)) {
7255         const ST_Errins* list = st_errins_index_drop;
7256         ST_Errins errins = st_get_errins(c, list);
7257         chk1(st_drop_index(c, ind, errins) == 0);
7258         if (simpletrans) {
7259           if (randomly(1, 2))
7260             chk1(st_end_trans(c, 0) == 0);
7261           else
7262             chk1(st_end_trans(c, ST_AbortFlag) == 0);
7263         }
7264       } else {
7265         chk1(st_drop_index(c, ind) == 0);
7266         if (simpletrans) {
7267           uint flags = 0;
7268           if ((arg & ST_AllowAbort) && randomly(4, 5))
7269             flags |= ST_AbortFlag;
7270           chk1(st_end_trans(c, flags) == 0);
7271         }
7272       }
7273       if (!ind.exists() && randomly(1, 3)) {
7274         g_info << ind.name << ": try duplicate drop" << endl;
7275         chk1(st_drop_index(c, ind, 4243) == 0);
7276       }
7277     }
7278   }
7279   if (trans) {
7280     uint flags = 0;
7281     if ((arg & ST_AllowAbort) && randomly(4, 5))
7282       flags |= ST_AbortFlag;
7283     chk1(st_end_trans(c, flags) == 0);
7284   }
7285   return NDBT_OK;
7286 err:
7287   return NDBT_FAILED;
7288 }
7289 
7290 static int
st_test_index(ST_Con & c,int arg=-1)7291 st_test_index(ST_Con& c, int arg = -1)
7292 {
7293   chk1(st_test_create_index(c) == NDBT_OK);
7294   chk1(st_test_drop_index(c) == NDBT_OK);
7295   return NDBT_OK;
7296 err:
7297   return NDBT_FAILED;
7298 }
7299 
7300 // node failure and system restart
7301 
7302 static int
st_test_anf_parse(ST_Con & c,int arg=-1)7303 st_test_anf_parse(ST_Con& c, int arg = -1)
7304 {
7305   int i;
7306   chk1(st_start_xcon(c) == 0);
7307   {
7308     ST_Con& xc = *c.xcon;
7309     chk1(st_begin_trans(xc) == 0);
7310     for (i = 0; i < c.tabcount; i++) {
7311       ST_Tab& tab = c.tab(i);
7312       chk1(st_create_table_index(xc, tab) == 0);
7313     }
7314     // DICT aborts the trans
7315     xc.tx_on = false;
7316     xc.tx_commit = false;
7317     st_set_commit_all(xc);
7318     chk1(st_stop_xcon(c) == 0);
7319     chk1(st_wait_idle(c) == 0);
7320     chk1(st_verify_list(c) == 0);
7321   }
7322   return NDBT_OK;
7323 err:
7324   return NDBT_FAILED;
7325 }
7326 
7327 static int
st_test_anf_background(ST_Con & c,int arg=-1)7328 st_test_anf_background(ST_Con& c, int arg = -1)
7329 {
7330   int i;
7331   chk1(st_start_xcon(c) == 0);
7332   {
7333     ST_Con& xc = *c.xcon;
7334     chk1(st_begin_trans(xc) == 0);
7335     for (i = 0; i < c.tabcount; i++) {
7336       ST_Tab& tab = c.tab(i);
7337       chk1(st_create_table(xc, tab) == 0);
7338     }
7339     // DICT takes over and completes the trans
7340     st_end_trans(xc, ST_BackgroundFlag);
7341     chk1(st_stop_xcon(c) == 0);
7342     chk1(st_wait_idle(c) == 0);
7343     chk1(st_verify_list(c) == 0);
7344   }
7345   return NDBT_OK;
7346 err:
7347   return NDBT_FAILED;
7348 }
7349 
7350 static int
st_test_anf_fail_begin(ST_Con & c,int arg=-1)7351 st_test_anf_fail_begin(ST_Con& c, int arg = -1)
7352 {
7353   chk1(st_start_xcon(c) == 0);
7354   {
7355     ST_Con& xc = *c.xcon;
7356 
7357     ST_Errins errins1(6102, -1, 1); // master kills us at begin
7358     ST_Errins errins2(6103, -1, 0); // slave delays conf
7359     chk1(st_do_errins(xc, errins1) == 0);
7360     chk1(st_do_errins(xc, errins2) == 0);
7361 
7362     chk1(st_begin_trans(xc, 4009) == 0);
7363 
7364     // DICT aborts the trans
7365     xc.tx_on = false;
7366     xc.tx_commit = false;
7367     st_set_commit_all(xc);
7368     chk1(st_stop_xcon(c) == 0);
7369 
7370     // xc may get 4009 before takeover is ready (5000 ms delay)
7371     ST_Retry retry = { 100, 100 }; // 100 * 100ms = 10000ms
7372     chk1(st_begin_trans(c, retry) == 0);
7373     chk1(st_wait_idle(c) == 0);
7374     chk1(st_verify_list(c) == 0);
7375   }
7376   return NDBT_OK;
7377 err:
7378   return NDBT_FAILED;
7379 }
7380 
7381 static int
st_test_snf_parse(ST_Con & c,int arg=-1)7382 st_test_snf_parse(ST_Con& c, int arg = -1)
7383 {
7384   bool do_abort = (arg == 1);
7385   chk1(st_begin_trans(c) == 0);
7386   int node_id;
7387   node_id = -1;
7388   int i;
7389   int midcount;
7390   midcount = c.tabcount / 2;
7391 
7392   for (i = 0; i < c.tabcount; i++) {
7393     ST_Tab& tab = c.tab(i);
7394     if (i == midcount) {
7395       require(c.numdbnodes > 1);
7396       uint rand = urandom(c.numdbnodes);
7397       node_id = c.restarter->getRandomNotMasterNodeId(rand);
7398       g_info << "restart node " << node_id << " (async)" << endl;
7399       const int flags = NdbRestarter::NRRF_NOSTART;
7400       chk1(c.restarter->restartOneDbNode2(node_id, flags) == 0);
7401       chk1(c.restarter->waitNodesNoStart(&node_id, 1) == 0);
7402       chk1(c.restarter->startNodes(&node_id, 1) == 0);
7403     }
7404     chk1(st_create_table_index(c, tab) == 0);
7405   }
7406   if (!do_abort)
7407     chk1(st_end_trans(c, 0) == 0);
7408   else
7409     chk1(st_end_trans(c, ST_AbortFlag) == 0);
7410 
7411   g_info << "wait for node " << node_id << " to come up" << endl;
7412   chk1(c.restarter->waitClusterStarted() == 0);
7413   CHK_NDB_READY(c.ndb);
7414   g_info << "verify all" << endl;
7415   chk1(st_verify_all(c) == 0);
7416   return NDBT_OK;
7417 err:
7418   return NDBT_FAILED;
7419 }
7420 
7421 static int
st_test_mnf_parse(ST_Con & c,int arg=-1)7422 st_test_mnf_parse(ST_Con& c, int arg = -1)
7423 {
7424   const NdbDictionary::Table* pTab;
7425   bool do_abort = (arg == 1);
7426   chk1(st_begin_trans(c) == 0);
7427   int node_id;
7428   node_id = -1;
7429   int i;
7430   int midcount;
7431   midcount = c.tabcount / 2;
7432 
7433   for (i = 0; i < c.tabcount; i++) {
7434     ST_Tab& tab = c.tab(i);
7435     chk1(st_create_table_index(c, tab) == 0);
7436     if (i == midcount) {
7437       require(c.numdbnodes > 1);
7438       node_id = c.restarter->getMasterNodeId();
7439       g_info << "restart node " << node_id << " (async)" << endl;
7440       const int flags = NdbRestarter::NRRF_NOSTART;
7441       chk1(c.restarter->restartOneDbNode2(node_id, flags) == 0);
7442       chk1(c.restarter->waitNodesNoStart(&node_id, 1) == 0);
7443       chk1(c.restarter->startNodes(&node_id, 1) == 0);
7444       break;
7445     }
7446   }
7447   if (!do_abort)
7448     chk1(st_end_trans_aborted(c, ST_CommitFlag) == 0);
7449   else
7450     chk1(st_end_trans_aborted(c, ST_AbortFlag) == 0);
7451 
7452   g_info << "wait for node " << node_id << " to come up" << endl;
7453   chk1(c.restarter->waitClusterStarted() == 0);
7454   CHK_NDB_READY(c.ndb);
7455   g_info << "verify all" << endl;
7456   for (i = 0; i < c.tabcount; i++) {
7457     ST_Tab& tab = c.tab(i);
7458     // Verify that table is not in db
7459     c.dic->invalidateTable(tab.name);
7460     pTab =
7461       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
7462     chk1(pTab == NULL);
7463   }
7464 /*
7465   chk1(st_verify_all(c) == 0);
7466 */
7467   return NDBT_OK;
7468 err:
7469   return NDBT_FAILED;
7470 }
7471 
7472 static int
st_test_mnf_prepare(ST_Con & c,int arg=-1)7473 st_test_mnf_prepare(ST_Con& c, int arg = -1)
7474 {
7475   NdbRestarter restarter;
7476   //int master = restarter.getMasterNodeId();
7477   ST_Errins errins = st_get_errins(c, st_errins_end_trans1);
7478   int i;
7479 
7480   chk1(st_begin_trans(c) == 0);
7481   for (i = 0; i < c.tabcount; i++) {
7482     ST_Tab& tab = c.tab(i);
7483     chk1(st_create_table_index(c, tab) == 0);
7484   }
7485   if (arg == 1)
7486   {
7487     chk1(st_end_trans_aborted(c, errins, ST_BackgroundFlag) == 0);
7488     chk1(st_wait_idle(c) == 0);
7489   }
7490   else
7491     chk1(st_end_trans_aborted(c, errins, ST_CommitFlag) == 0);
7492   chk1(c.restarter->waitClusterStarted() == 0);
7493   CHK_NDB_READY(c.ndb);
7494   //st_wait_db_node_up(c, master);
7495   for (i = 0; i < c.tabcount; i++) {
7496     ST_Tab& tab = c.tab(i);
7497     // Verify that table is not in db
7498     c.dic->invalidateTable(tab.name);
7499     const NdbDictionary::Table* pTab =
7500       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
7501     chk1(pTab == NULL);
7502   }
7503   return NDBT_OK;
7504 err:
7505   return NDBT_FAILED;
7506 }
7507 
7508 static int
st_test_mnf_commit1(ST_Con & c,int arg=-1)7509 st_test_mnf_commit1(ST_Con& c, int arg = -1)
7510 {
7511   NdbRestarter restarter;
7512   //int master = restarter.getMasterNodeId();
7513   ST_Errins errins = st_get_errins(c, st_errins_end_trans2);
7514   int i;
7515 
7516   chk1(st_begin_trans(c) == 0);
7517   for (i = 0; i < c.tabcount; i++) {
7518     ST_Tab& tab = c.tab(i);
7519     chk1(st_create_table_index(c, tab) == 0);
7520   }
7521   if (arg == 1)
7522   {
7523     chk1(st_end_trans(c, errins, ST_BackgroundFlag) == 0);
7524     chk1(st_wait_idle(c) == 0);
7525   }
7526   else
7527     chk1(st_end_trans(c, errins, ST_CommitFlag) == 0);
7528   chk1(c.restarter->waitClusterStarted() == 0);
7529   CHK_NDB_READY(c.ndb);
7530   //st_wait_db_node_up(c, master);
7531   for (i = 0; i < c.tabcount; i++) {
7532     ST_Tab& tab = c.tab(i);
7533     chk1(st_verify_table(c, tab) == 0);
7534   }
7535   chk1(st_drop_test_tables(c) == 0);
7536   return NDBT_OK;
7537 err:
7538   return NDBT_FAILED;
7539 }
7540 
7541 static int
st_test_mnf_commit2(ST_Con & c,int arg=-1)7542 st_test_mnf_commit2(ST_Con& c, int arg = -1)
7543 {
7544   NdbRestarter restarter;
7545   //int master = restarter.getMasterNodeId();
7546   ST_Errins errins = st_get_errins(c, st_errins_end_trans3);
7547   int i;
7548 
7549   chk1(st_begin_trans(c) == 0);
7550   for (i = 0; i < c.tabcount; i++) {
7551     ST_Tab& tab = c.tab(i);
7552     chk1(st_create_table_index(c, tab) == 0);
7553   }
7554   if (arg == 1)
7555   {
7556     chk1(st_end_trans(c, errins, ST_BackgroundFlag) == 0);
7557     chk1(st_wait_idle(c) == 0);
7558   }
7559   else
7560     chk1(st_end_trans(c, errins, ST_CommitFlag) == 0);
7561   chk1(c.restarter->waitClusterStarted() == 0);
7562   CHK_NDB_READY(c.ndb);
7563   //st_wait_db_node_up(c, master);
7564   chk1(st_verify_all(c) == 0);
7565   for (i = 0; i < c.tabcount; i++) {
7566     ST_Tab& tab = c.tab(i);
7567     chk1(st_load_table(c, tab) == 0);
7568   }
7569   chk1(st_drop_test_tables(c) == 0);
7570   return NDBT_OK;
7571 err:
7572   return NDBT_FAILED;
7573 }
7574 
7575 static int
st_test_mnf_run_commit(ST_Con & c,int arg=-1)7576 st_test_mnf_run_commit(ST_Con& c, int arg = -1)
7577 {
7578   const NdbDictionary::Table* pTab;
7579   NdbRestarter restarter;
7580   //int master = restarter.getMasterNodeId();
7581   int i;
7582 
7583   if (arg == FAIL_BEGIN)
7584   {
7585     // No transaction to be found if only one node left
7586     if (restarter.getNumDbNodes() < 3)
7587       return NDBT_OK;
7588     chk1(st_begin_trans(c) == -1);
7589     goto verify;
7590   }
7591   else
7592     chk1(st_begin_trans(c) == 0);
7593   for (i = 0; i < c.tabcount; i++) {
7594     ST_Tab& tab = c.tab(i);
7595     if (arg == FAIL_CREATE)
7596     {
7597       chk1(st_create_table_index(c, tab) == -1);
7598       goto verify;
7599     }
7600     else
7601       chk1(st_create_table_index(c, tab) == 0);
7602   }
7603   if (arg == FAIL_END)
7604   {
7605     chk1(st_end_trans(c, ST_CommitFlag) == -1);
7606   }
7607   else // if (arg == SUCCEED_COMMIT)
7608     chk1(st_end_trans(c, ST_CommitFlag) == 0);
7609 
7610 verify:
7611   g_info << "wait for master node to come up" << endl;
7612   chk1(c.restarter->waitClusterStarted() == 0);
7613   CHK_NDB_READY(c.ndb);
7614   //st_wait_db_node_up(c, master);
7615   g_info << "verify all" << endl;
7616   for (i = 0; i < c.tabcount; i++) {
7617     ST_Tab& tab = c.tab(i);
7618     switch (arg) {
7619     case FAIL_BEGIN:
7620     case FAIL_CREATE:
7621     case FAIL_END:
7622     {
7623       // Verify that table is not in db
7624       c.dic->invalidateTable(tab.name);
7625       pTab =
7626         NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
7627       chk1(pTab == NULL);
7628       break;
7629     }
7630     default:
7631       chk1(st_verify_table(c, tab) == 0);
7632     }
7633   }
7634 
7635   return NDBT_OK;
7636 err:
7637   return NDBT_FAILED;
7638 }
7639 
7640 static int
st_test_mnf_run_abort(ST_Con & c,int arg=-1)7641 st_test_mnf_run_abort(ST_Con& c, int arg = -1)
7642 {
7643   NdbRestarter restarter;
7644   //int master = restarter.getMasterNodeId();
7645   const NdbDictionary::Table* pTab;
7646   bool do_abort = (arg == SUCCEED_ABORT);
7647   int i;
7648 
7649   chk1(st_begin_trans(c) == 0);
7650   for (i = 0; i < c.tabcount; i++) {
7651     ST_Tab& tab = c.tab(i);
7652     chk1(st_create_table_index(c, tab) == 0);
7653   }
7654   if (!do_abort)
7655     chk1(st_end_trans(c, ST_CommitFlag) == -1);
7656   else
7657     chk1(st_end_trans_aborted(c, ST_AbortFlag) == 0);
7658 
7659   g_info << "wait for master node to come up" << endl;
7660   chk1(c.restarter->waitClusterStarted() == 0);
7661   CHK_NDB_READY(c.ndb);
7662   //st_wait_db_node_up(c, master);
7663   g_info << "verify all" << endl;
7664   for (i = 0; i < c.tabcount; i++) {
7665     ST_Tab& tab = c.tab(i);
7666     // Verify that table is not in db
7667     c.dic->invalidateTable(tab.name);
7668     pTab =
7669       NDBT_Table::discoverTableFromDb(c.ndb, tab.name);
7670     chk1(pTab == NULL);
7671   }
7672 
7673   return NDBT_OK;
7674 err:
7675   return NDBT_FAILED;
7676 }
7677 
7678 static int
st_test_mnf_start_partial(ST_Con & c,int arg=-1)7679 st_test_mnf_start_partial(ST_Con& c, int arg = -1)
7680 {
7681   ST_Errins errins(ERR_INSERT_PARTIAL_START_FAIL, 0, 1); // slave skips start
7682   chk1(st_do_errins(c, errins) == 0);
7683   return st_test_mnf_run_commit(c, arg);
7684 err:
7685   return -1;
7686 }
7687 
7688 static int
st_test_mnf_parse_partial(ST_Con & c,int arg=-1)7689 st_test_mnf_parse_partial(ST_Con& c, int arg = -1)
7690 {
7691   ST_Errins errins(ERR_INSERT_PARTIAL_PARSE_FAIL, 0, 1); // slave skips parse
7692   chk1(st_do_errins(c, errins) == 0);
7693   return st_test_mnf_run_commit(c, arg);
7694 err:
7695   return -1;
7696 }
7697 
7698 static int
st_test_mnf_flush_prepare_partial(ST_Con & c,int arg=-1)7699 st_test_mnf_flush_prepare_partial(ST_Con& c, int arg = -1)
7700 {
7701   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_PREPARE_FAIL, 0, 1); // slave skips flush prepare
7702   chk1(st_do_errins(c, errins) == 0);
7703   return st_test_mnf_run_commit(c, arg);
7704 err:
7705   return -1;
7706 }
7707 
7708 static int
st_test_mnf_prepare_partial(ST_Con & c,int arg=-1)7709 st_test_mnf_prepare_partial(ST_Con& c, int arg = -1)
7710 {
7711   ST_Errins errins(ERR_INSERT_PARTIAL_PREPARE_FAIL, 0, 1); // slave skips prepare
7712   chk1(st_do_errins(c, errins) == 0);
7713   return st_test_mnf_run_commit(c, arg);
7714 err:
7715   return -1;
7716 }
7717 
7718 static int
st_test_mnf_abort_parse_partial(ST_Con & c,int arg=-1)7719 st_test_mnf_abort_parse_partial(ST_Con& c, int arg = -1)
7720 {
7721   ST_Errins errins(ERR_INSERT_PARTIAL_ABORT_PARSE_FAIL, 0, 1); // slave skips abort parse
7722   chk1(st_do_errins(c, errins) == 0);
7723   return st_test_mnf_run_abort(c, arg);
7724 err:
7725   return -1;
7726 }
7727 
7728 static int
st_test_mnf_abort_prepare_partial(ST_Con & c,int arg=-1)7729 st_test_mnf_abort_prepare_partial(ST_Con& c, int arg = -1)
7730 {
7731   ST_Errins errins(ERR_INSERT_PARTIAL_ABORT_PREPARE_FAIL, 0, 1); // slave skips abort prepare
7732   chk1(st_do_errins(c, errins) == 0);
7733   return st_test_mnf_run_abort(c, arg);
7734 err:
7735   return -1;
7736 }
7737 
7738 static int
st_test_mnf_flush_commit_partial(ST_Con & c,int arg=-1)7739 st_test_mnf_flush_commit_partial(ST_Con& c, int arg = -1)
7740 {
7741   NdbRestarter restarter;
7742   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_COMMIT_FAIL, 0, 1); // slave skips flush commit
7743   chk1(st_do_errins(c, errins) == 0);
7744   if (restarter.getNumDbNodes() < 3)
7745     // If new master is only node and it hasn't flush commit, we abort
7746     return st_test_mnf_run_commit(c, FAIL_END);
7747   else
7748     return st_test_mnf_run_commit(c, arg);
7749 err:
7750   return -1;
7751 }
7752 
7753 static int
st_test_mnf_commit_partial(ST_Con & c,int arg=-1)7754 st_test_mnf_commit_partial(ST_Con& c, int arg = -1)
7755 {
7756   ST_Errins errins(ERR_INSERT_PARTIAL_COMMIT_FAIL, 0, 1); // slave skips commit
7757   chk1(st_do_errins(c, errins) == 0);
7758   return st_test_mnf_run_commit(c, arg);
7759 err:
7760   return -1;
7761 }
7762 
7763 static int
st_test_mnf_flush_complete_partial(ST_Con & c,int arg=-1)7764 st_test_mnf_flush_complete_partial(ST_Con& c, int arg = -1)
7765 {
7766   ST_Errins errins(ERR_INSERT_PARTIAL_FLUSH_COMPLETE_FAIL, 0, 1); // slave skips flush complete
7767   chk1(st_do_errins(c, errins) == 0);
7768   return st_test_mnf_run_commit(c, arg);
7769 err:
7770   return -1;
7771 }
7772 
7773 static int
st_test_mnf_complete_partial(ST_Con & c,int arg=-1)7774 st_test_mnf_complete_partial(ST_Con& c, int arg = -1)
7775 {
7776   ST_Errins errins(ERR_INSERT_PARTIAL_COMPLETE_FAIL, 0, 1); // slave skips complete
7777   chk1(st_do_errins(c, errins) == 0);
7778   return st_test_mnf_run_commit(c, arg);
7779 err:
7780   return -1;
7781 }
7782 
7783 static int
st_test_mnf_end_partial(ST_Con & c,int arg=-1)7784 st_test_mnf_end_partial(ST_Con& c, int arg = -1)
7785 {
7786   ST_Errins errins(ERR_INSERT_PARTIAL_END_FAIL, 0, 1); // slave skips end
7787   chk1(st_do_errins(c, errins) == 0);
7788   return st_test_mnf_run_commit(c, arg);
7789 err:
7790   return -1;
7791 }
7792 
7793 static int
st_test_sr_parse(ST_Con & c,int arg=-1)7794 st_test_sr_parse(ST_Con& c, int arg = -1)
7795 {
7796   bool do_abort = (arg == 1);
7797   chk1(st_begin_trans(c) == 0);
7798   int i;
7799   for (i = 0; i < c.tabcount; i++) {
7800     ST_Tab& tab = c.tab(i);
7801     chk1(st_create_table_index(c, tab) == 0);
7802   }
7803   if (!do_abort)
7804     chk1(st_end_trans(c, 0) == 0);
7805   else
7806     chk1(st_end_trans(c, ST_AbortFlag) == 0);
7807 
7808   g_info << "restart all" << endl;
7809   int flags;
7810   flags = NdbRestarter::NRRF_NOSTART;
7811   chk1(c.restarter->restartAll2(flags) == 0);
7812   g_info << "wait for cluster started" << endl;
7813   chk1(c.restarter->waitClusterNoStart() == 0);
7814   chk1(c.restarter->startAll() == 0);
7815   chk1(c.restarter->waitClusterStarted() == 0);
7816   CHK_NDB_READY(c.ndb);
7817   g_info << "verify all" << endl;
7818   chk1(st_verify_all(c) == 0);
7819   return NDBT_OK;
7820 err:
7821   return NDBT_FAILED;
7822 }
7823 
7824 #if 0
7825 static int
7826 st_test_sr_commit(ST_Con& c, int arg = -1)
7827 {
7828   g_info << "not yet" << endl;
7829   return NDBT_OK;
7830 }
7831 #endif
7832 
7833 // run test cases
7834 
7835 struct ST_Test {
7836   const char* key;
7837   int mindbnodes;
7838   int arg;
7839   int (*func)(ST_Con& c, int arg);
7840   const char* name;
7841   const char* desc;
7842 };
7843 
7844 static NdbOut&
operator <<(NdbOut & out,const ST_Test & test)7845 operator<<(NdbOut& out, const ST_Test& test)
7846 {
7847   out << "CASE " << test.key;
7848   out << " " << test.name;
7849   if (test.arg != -1)
7850     out << "+" << test.arg;
7851   out << " - " << test.desc;
7852   return out;
7853 }
7854 
7855 static const ST_Test
7856 st_test_list[] = {
7857 #define func(f) f, #f
7858   // specific ops
7859   { "a1", 1, 0,
7860      func(st_test_create),
7861      "create all within trans, commit" },
7862   { "a2", 1, 1,
7863      func(st_test_create),
7864      "create all within trans, abort" },
7865   { "a3", 1, 0,
7866      func(st_test_drop),
7867      "drop all within trans, commit" },
7868   { "a4", 1, 1,
7869      func(st_test_drop),
7870      "drop all within trans, abort" },
7871   { "b1", 1, -1,
7872     func(st_test_rollback_create_table),
7873     "partial rollback of create table ops" },
7874   { "b2", 1, -1,
7875     func(st_test_rollback_drop_table),
7876     "partial rollback of drop table ops" },
7877   { "b3", 1, -1,
7878     func(st_test_rollback_create_index),
7879     "partial rollback of create index ops" },
7880   { "b4", 1, -1,
7881     func(st_test_rollback_drop_index),
7882     "partial rollback of drop index ops" },
7883   { "c1", 1, -1,
7884     func(st_test_dup_create_table),
7885     "try to create same table twice" },
7886   { "c2", 1, -1,
7887     func(st_test_dup_drop_table),
7888     "try to drop same table twice" },
7889   { "c3", 1, -1,
7890     func(st_test_dup_create_index),
7891     "try to create same index twice" },
7892   { "c4", 1, -1,
7893     func(st_test_dup_drop_index),
7894     "try to drop same index twice" },
7895   { "d1", 1, -1,
7896     func(st_test_build_index),
7897     "build index on non-empty table" },
7898   { "e1", 1, 0,
7899     func(st_test_local_create),
7900     "fail trigger create in TC, master errins 8033" },
7901   { "e2", 2, 1,
7902     func(st_test_local_create),
7903     "fail trigger create in TC, slave errins 8033" },
7904   { "e3", 1, 2,
7905     func(st_test_local_create),
7906     "fail trigger create in TUP, master errins 4003" },
7907   { "e4", 2, 3,
7908     func(st_test_local_create),
7909     "fail trigger create in TUP, slave errins 4003" },
7910   { "e5", 1, 4,
7911     func(st_test_local_create),
7912     "fail index create in TC, master errins 8034" },
7913   { "e6", 2, 5,
7914     func(st_test_local_create),
7915     "fail index create in TC, slave errins 8034" },
7916   // random ops
7917   { "o1", 1, 0,
7918     func(st_test_trans),
7919     "start and stop schema trans" },
7920   { "o2", 1, ST_AllowAbort,
7921     func(st_test_trans),
7922     "start and stop schema trans, allow abort" },
7923   { "o3", 1, ST_AllowAbort | ST_AllowErrins,
7924     func(st_test_trans),
7925     "start and stop schema trans, allow abort errins" },
7926   //
7927   { "p1", 1, 0,
7928     func(st_test_create_table),
7929     "create tables at random" },
7930   { "p2", 1, ST_AllowAbort,
7931     func(st_test_create_table),
7932     "create tables at random, allow abort" },
7933   { "p3", 1, ST_AllowAbort | ST_AllowErrins,
7934     func(st_test_create_table),
7935     "create tables at random, allow abort errins" },
7936   //
7937   { "p4", 1, 0,
7938     func(st_test_table),
7939     "create and drop tables at random" },
7940   { "p5", 1, ST_AllowAbort,
7941     func(st_test_table),
7942     "create and drop tables at random, allow abort" },
7943   { "p6", 1, ST_AllowAbort | ST_AllowErrins,
7944     func(st_test_table),
7945     "create and drop tables at random, allow abort errins" },
7946   //
7947   { "q1", 1, 0,
7948     func(st_test_create_index),
7949     "create indexes at random" },
7950   { "q2", 1, ST_AllowAbort,
7951     func(st_test_create_index),
7952     "create indexes at random, allow abort" },
7953   { "q3", 1, ST_AllowAbort | ST_AllowErrins,
7954     func(st_test_create_index),
7955     "create indexes at random, allow abort errins" },
7956   //
7957   { "q4", 1, 0,
7958     func(st_test_index),
7959     "create and drop indexes at random" },
7960   { "q5", 1, ST_AllowAbort,
7961     func(st_test_index),
7962     "create and drop indexes at random, allow abort" },
7963   { "q6", 1, ST_AllowAbort | ST_AllowErrins,
7964     func(st_test_index),
7965     "create and drop indexes at random, allow abort errins" },
7966   // node failure and system restart
7967   { "u1", 1, -1,
7968     func(st_test_anf_parse),
7969     "api node fail in parse phase" },
7970   { "u2", 1, -1,
7971     func(st_test_anf_background),
7972     "api node fail after background trans" },
7973   { "u3", 2, -1,
7974     func(st_test_anf_fail_begin),
7975     "api node fail in middle of kernel begin trans" },
7976   //
7977   { "v1", 2, 0,
7978     func(st_test_snf_parse),
7979     "slave node fail in parse phase, commit" },
7980   { "v2", 2, 1,
7981     func(st_test_snf_parse),
7982     "slave node fail in parse phase, abort" },
7983   { "w1", 1, 0,
7984     func(st_test_sr_parse),
7985     "system restart in parse phase, commit" },
7986   { "w2", 1, 1,
7987     func(st_test_sr_parse),
7988     "system restart in parse phase, abort" },
7989 #ifdef ndb_master_failure
7990   { "x1", 2, 0,
7991     func(st_test_mnf_parse),
7992     "master node fail in parse phase, commit" },
7993   { "x2", 2, 1,
7994     func(st_test_mnf_parse),
7995     "master node fail in parse phase, abort" },
7996   { "x3", 2, 0,
7997     func(st_test_mnf_prepare),
7998     "master node fail in prepare phase" },
7999   { "x4", 2, 0,
8000     func(st_test_mnf_commit1),
8001     "master node fail in start of commit phase" },
8002   { "x5", 2, 0,
8003     func(st_test_mnf_commit2),
8004     "master node fail in end of commit phase" },
8005   { "y1", 2, SUCCEED_COMMIT,
8006     func(st_test_mnf_start_partial),
8007     "master node fail in start phase, retry will succeed" },
8008   { "y2", 2, FAIL_CREATE,
8009     func(st_test_mnf_parse_partial),
8010     "master node fail in parse phase, partial rollback" },
8011   { "y3", 2, FAIL_END,
8012     func(st_test_mnf_flush_prepare_partial),
8013     "master node fail in flush prepare phase, partial rollback" },
8014   { "y4", 2, FAIL_END,
8015     func(st_test_mnf_prepare_partial),
8016     "master node fail in prepare phase, partial rollback" },
8017   { "y5", 2, SUCCEED_COMMIT,
8018     func(st_test_mnf_flush_commit_partial),
8019     "master node fail in flush commit phase, partial rollback" },
8020   { "y6", 2, SUCCEED_COMMIT,
8021     func(st_test_mnf_commit_partial),
8022     "master node fail in commit phase, commit, partial rollforward" },
8023   { "y7", 2, SUCCEED_COMMIT,
8024     func(st_test_mnf_flush_complete_partial),
8025     "master node fail in flush complete phase, commit, partial rollforward" },
8026   { "y8", 2, SUCCEED_COMMIT,
8027     func(st_test_mnf_complete_partial),
8028     "master node fail in complete phase, commit, partial rollforward" },
8029   { "y9", 2, SUCCEED_COMMIT,
8030     func(st_test_mnf_end_partial),
8031     "master node fail in end phase, commit, partial rollforward" },
8032   { "z1", 2, SUCCEED_ABORT,
8033     func(st_test_mnf_abort_parse_partial),
8034     "master node fail in abort parse phase, partial rollback" },
8035   { "z2", 2, FAIL_END,
8036     func(st_test_mnf_abort_prepare_partial),
8037     "master node fail in abort prepare phase, partial rollback" },
8038   { "z3", 2, 1,
8039     func(st_test_mnf_prepare),
8040     "master node fail in prepare phase in background" },
8041   { "z4", 2, 1,
8042     func(st_test_mnf_commit1),
8043     "master node fail in start of commit phase in background" },
8044   { "z5", 2, 1,
8045     func(st_test_mnf_commit2),
8046     "master node fail in end of commit phase in background" },
8047 
8048 #endif
8049 #undef func
8050 };
8051 
8052 static const int
8053 st_test_count = sizeof(st_test_list)/sizeof(st_test_list[0]);
8054 
8055 static const char* st_test_case = 0;
8056 static const char* st_test_skip = 0;
8057 
8058 static bool
st_test_match(const ST_Test & test)8059 st_test_match(const ST_Test& test)
8060 {
8061   const char* p = 0;
8062   if (st_test_case == 0)
8063     goto skip;
8064   if (strstr(st_test_case, test.key) != 0)
8065     goto skip;
8066   p = strchr(st_test_case, test.key[0]);
8067   if (p != 0 && (p[1] < '0' || p[1] > '9'))
8068     goto skip;
8069   return false;
8070 skip:
8071   if (st_test_skip == 0)
8072     return true;
8073   if (strstr(st_test_skip, test.key) != 0)
8074     return false;
8075   p = strchr(st_test_skip, test.key[0]);
8076   if (p != 0 && (p[1] < '0' || p[1] > '9'))
8077     return false;
8078   return true;
8079 }
8080 
8081 static int
st_test(ST_Con & c,const ST_Test & test)8082 st_test(ST_Con& c, const ST_Test& test)
8083 {
8084   chk1(st_end_trans(c, ST_AbortFlag) == 0);
8085   chk1(st_drop_test_tables(c) == 0);
8086   chk1(st_check_db_nodes(c) == 0);
8087 
8088   g_err << test << endl;
8089   if (c.numdbnodes < test.mindbnodes) {
8090     g_err << "skip, too few db nodes" << endl;
8091     return NDBT_OK;
8092   }
8093 
8094   chk1((*test.func)(c, test.arg) == NDBT_OK);
8095   chk1(st_check_db_nodes(c) == 0);
8096   //chk1(st_verify_list(c) == 0);
8097 
8098   return NDBT_OK;
8099 err:
8100   return NDBT_FAILED;
8101 }
8102 
8103 static int st_random_seed = -1;
8104 
8105 int
runSchemaTrans(NDBT_Context * ctx,NDBT_Step * step)8106 runSchemaTrans(NDBT_Context* ctx, NDBT_Step* step)
8107 {
8108 #ifdef NDB_USE_GET_ENV
8109   { const char* env = NdbEnv_GetEnv("NDB_TEST_DBUG", 0, 0);
8110     if (env != 0 && env[0] != 0) // e.g. d:t:L:F:o,ndb_test.log
8111       DBUG_PUSH(env);
8112   }
8113   { const char* env = NdbEnv_GetEnv("NDB_TEST_CORE", 0, 0);
8114     if (env != 0 && env[0] != 0 && env[0] != '0' && env[0] != 'N')
8115       st_core_on_err = true;
8116   }
8117   { const char* env = NdbEnv_GetEnv("NDB_TEST_CASE", 0, 0);
8118     st_test_case = env;
8119   }
8120   { const char* env = NdbEnv_GetEnv("NDB_TEST_SKIP", 0, 0);
8121     st_test_skip = env;
8122   }
8123   { const char* env = NdbEnv_GetEnv("NDB_TEST_SEED", 0, 0);
8124     if (env != 0)
8125       st_random_seed = atoi(env);
8126   }
8127 #endif
8128   if (st_test_case != 0 && strcmp(st_test_case, "?") == 0) {
8129     int i;
8130     ndbout << "case func+arg desc" << endl;
8131     for (i = 0; i < st_test_count; i++) {
8132       const ST_Test& test = st_test_list[i];
8133       ndbout << test << endl;
8134     }
8135     return NDBT_WRONGARGS;
8136   }
8137 
8138   if (st_random_seed == -1)
8139     st_random_seed = NdbHost_GetProcessId();
8140   if (st_random_seed != 0) {
8141     g_err << "random seed: " << st_random_seed << endl;
8142     ndb_srand(st_random_seed);
8143   } else {
8144     g_err << "random seed: loop number" << endl;
8145   }
8146 
8147   Ndb_cluster_connection* ncc = &ctx->m_cluster_connection;
8148   Ndb* ndb = GETNDB(step);
8149   ST_Restarter* restarter = new ST_Restarter;
8150   ST_Con c(ncc, ndb, restarter);
8151 
8152   chk1(st_drop_all_tables(c) == 0);
8153   st_init_objects(c, ctx);
8154 
8155   int numloops;
8156   numloops = ctx->getNumLoops();
8157 
8158   for (c.loop = 0; numloops == 0 || c.loop < numloops; c.loop++) {
8159     g_err << "LOOP " << c.loop << endl;
8160     if (st_random_seed == 0)
8161       ndb_srand(c.loop);
8162     int i;
8163     for (i = 0; i < st_test_count; i++) {
8164       const ST_Test& test = st_test_list[i];
8165       if (st_test_match(test)) {
8166         chk1(st_test(c, test) == NDBT_OK);
8167       }
8168     }
8169   }
8170 
8171   st_report_db_nodes(c, g_err);
8172   return NDBT_OK;
8173 err:
8174   st_report_db_nodes(c, g_err);
8175   return NDBT_FAILED;
8176 }
8177 
8178 // end schema trans
8179 
8180 int
runFailCreateHashmap(NDBT_Context * ctx,NDBT_Step * step)8181 runFailCreateHashmap(NDBT_Context* ctx, NDBT_Step* step)
8182 {
8183   static int lst[] = { 6204, 6205, 6206, 6207, 6208, 6209, 6210, 6211, 0 };
8184 
8185   NdbRestarter restarter;
8186   int nodeId = restarter.getMasterNodeId();
8187   Ndb* pNdb = GETNDB(step);
8188   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8189 
8190   int errNo = 0;
8191 #ifdef NDB_USE_GET_ENV
8192   char buf[100];
8193   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
8194   {
8195     errNo = atoi(buf);
8196     ndbout_c("Using errno: %u", errNo);
8197   }
8198 #endif
8199   const int loops = ctx->getNumLoops();
8200   int result = NDBT_OK;
8201 
8202   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
8203   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
8204 
8205   NdbDictionary::HashMap hm;
8206   pDic->initDefaultHashMap(hm, 1);
8207 
8208 loop:
8209   if (pDic->getHashMap(hm, hm.getName()) != -1)
8210   {
8211     pDic->initDefaultHashMap(hm, rand() % 64);
8212     goto loop;
8213   }
8214 
8215   for (int l = 0; l < loops; l++)
8216   {
8217     for (unsigned i0 = 0; lst[i0]; i0++)
8218     {
8219       unsigned j = (l == 0 ? i0 : myRandom48(i0 + l));
8220       int errval = lst[j];
8221       if (errNo != 0 && errNo != errval)
8222         continue;
8223       g_info << "insert error node=" << nodeId << " value=" << errval << endl;
8224       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
8225              "failed to set error insert");
8226       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
8227 
8228       int res = pDic->createHashMap(hm);
8229       CHECK2(res != 0, "create hashmap failed to fail");
8230 
8231       NdbDictionary::HashMap check;
8232       CHECK2(res != 0, "create hashmap existed");
8233 
8234       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
8235              "failed to clear error insert");
8236       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
8237     }
8238   }
8239 end:
8240   return result;
8241 }
8242 // end FAIL create hashmap
8243 
8244 int
runCreateHashmaps(NDBT_Context * ctx,NDBT_Step * step)8245 runCreateHashmaps(NDBT_Context* ctx, NDBT_Step* step)
8246 {
8247   NdbRestarter restarter;
8248   // int nodeId = restarter.getMasterNodeId();
8249   Ndb* pNdb = GETNDB(step);
8250   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8251 
8252   const int loops = ctx->getNumLoops();
8253   int result = NDBT_OK;
8254 
8255   NdbDictionary::HashMap hm;
8256 
8257   int created = 0;
8258   for (int i = 1; i <= NDB_DEFAULT_HASHMAP_BUCKETS && created < loops ; i++)
8259   {
8260     pDic->initDefaultHashMap(hm, i);
8261     int res = pDic->getHashMap(hm, hm.getName());
8262     if (res == -1)
8263     {
8264       const NdbError err = pDic->getNdbError();
8265       if (err.code != 723)
8266       {
8267         g_err << "getHashMap: " << hm.getName() << ": " << err << endl;
8268         result = NDBT_FAILED;
8269         break;
8270       }
8271       int res = pDic->createHashMap(hm);
8272       if (res == -1)
8273       {
8274         const NdbError err = pDic->getNdbError();
8275         if (err.code != 707 && err.code != 712)
8276         {
8277           g_err << "createHashMap: " << hm.getName() << ": " << err << endl;
8278           result = NDBT_FAILED;
8279         }
8280         break;
8281       }
8282       created++;
8283     }
8284   }
8285 
8286   // Drop all hashmaps (and everything else) with initial restart
8287   ndbout << "Restarting cluster" << endl;
8288   restarter.restartAll(/* initial */ true);
8289   restarter.waitClusterStarted();
8290 
8291   return result;
8292 }
8293 // end FAIL create hashmap
8294 
8295 int
runFailAddPartition(NDBT_Context * ctx,NDBT_Step * step)8296 runFailAddPartition(NDBT_Context* ctx, NDBT_Step* step)
8297 {
8298   static int lst[] = { 7211, 7212, 4050, 12008, 6212, 6124, 6213, 6214, 0 };
8299 
8300   Ndb* pNdb = GETNDB(step);
8301   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8302   NdbDictionary::Table tab(*ctx->getTab());
8303   NdbRestarter restarter;
8304   int nodeId = restarter.getMasterNodeId();
8305 
8306   int errNo = 0;
8307 #ifdef NDB_USE_GET_ENV
8308   char buf[100];
8309   if (NdbEnv_GetEnv("ERRNO", buf, sizeof(buf)))
8310   {
8311     errNo = atoi(buf);
8312     ndbout_c("Using errno: %u", errNo);
8313   }
8314 #endif
8315   // ordered index on first few columns
8316   NdbDictionary::Index idx("X");
8317   idx.setTable(tab.getName());
8318   idx.setType(NdbDictionary::Index::OrderedIndex);
8319   idx.setLogging(false);
8320   for (int cnt = 0, i_hate_broken_compilers = 0;
8321        cnt < 3 &&
8322        i_hate_broken_compilers < tab.getNoOfColumns();
8323        i_hate_broken_compilers++) {
8324     if (NdbSqlUtil::check_column_for_ordered_index
8325         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
8326         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
8327         NdbDictionary::Column::StorageTypeDisk)
8328     {
8329       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
8330       cnt++;
8331     }
8332   }
8333 
8334   for (int i = 0; i<tab.getNoOfColumns(); i++)
8335   {
8336     if (tab.getColumn(i)->getStorageType() ==
8337         NdbDictionary::Column::StorageTypeDisk)
8338     {
8339       NDBT_Tables::create_default_tablespace(pNdb);
8340       break;
8341     }
8342   }
8343 
8344   const int loops = ctx->getNumLoops();
8345   int result = NDBT_OK;
8346   (void)pDic->dropTable(tab.getName());
8347   if (pDic->createTable(tab) != 0)
8348   {
8349     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8350     return NDBT_FAILED;
8351   }
8352 
8353   if (pDic->createIndex(idx) != 0)
8354   {
8355     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8356     return NDBT_FAILED;
8357   }
8358 
8359   const NdbDictionary::Table * org = pDic->getTable(tab.getName());
8360   NdbDictionary::Table altered = * org;
8361   altered.setFragmentCount(org->getFragmentCount() +
8362                            restarter.getNumDbNodes());
8363   altered.setPartitionBalance(NdbDictionary::Object::PartitionBalance_Specific);
8364 
8365   if (pDic->beginSchemaTrans())
8366   {
8367     ndbout << "Failed to beginSchemaTrans()" << pDic->getNdbError() << endl;
8368     return NDBT_FAILED;
8369   }
8370 
8371   if (pDic->prepareHashMap(*org, altered) == -1)
8372   {
8373     ndbout << "Failed to create hashmap: " << pDic->getNdbError() << endl;
8374     return NDBT_FAILED;
8375   }
8376 
8377   if (pDic->endSchemaTrans())
8378   {
8379     ndbout << "Failed to endSchemaTrans()" << pDic->getNdbError() << endl;
8380     return NDBT_FAILED;
8381   }
8382 
8383   int dump1 = DumpStateOrd::SchemaResourceSnapshot;
8384   int dump2 = DumpStateOrd::SchemaResourceCheckLeak;
8385 
8386   for (int l = 0; l < loops; l++)
8387   {
8388     for (unsigned i0 = 0; lst[i0]; i0++)
8389     {
8390       unsigned j = (l == 0 ? i0 : myRandom48(sizeof(lst)/sizeof(lst[0]) - 1));
8391       int errval = lst[j];
8392       if (errNo != 0 && errNo != errval)
8393         continue;
8394       g_err << "insert error node=" << nodeId << " value=" << errval << endl;
8395       CHECK(restarter.dumpStateAllNodes(&dump1, 1) == 0);
8396       CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
8397              "failed to set error insert");
8398 
8399       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
8400 
8401       int res = pDic->alterTable(*org, altered);
8402       if (res)
8403       {
8404         ndbout << pDic->getNdbError() << endl;
8405       }
8406       CHECK2(res != 0,
8407              "failed to fail after error insert " << errval);
8408       CHECK2(restarter.insertErrorInNode(nodeId, 0) == 0,
8409              "failed to clear error insert");
8410       CHECK(restarter.dumpStateAllNodes(&dump2, 1) == 0);
8411       NdbSleep_MilliSleep(SAFTY); // Hope that snapshot has arrived
8412 
8413       int dump3[] = {DumpStateOrd::DihAddFragFailCleanedUp, org->getTableId()};
8414       CHECK(restarter.dumpStateAllNodes(dump3, 2) == 0);
8415 
8416       const NdbDictionary::Table* check = pDic->getTable(tab.getName());
8417 
8418       CHECK2((check->getObjectId() == org->getObjectId() &&
8419               check->getObjectVersion() == org->getObjectVersion()),
8420              "table has been altered!");
8421     }
8422   }
8423 
8424 end:
8425   (void)pDic->dropTable(tab.getName());
8426   return result;
8427 }
8428 // fail add partition
8429 
8430 int
runTableAddPartition(NDBT_Context * ctx,NDBT_Step * step)8431 runTableAddPartition(NDBT_Context* ctx, NDBT_Step* step){
8432 
8433   int result = NDBT_OK;
8434 
8435   Ndb* pNdb = GETNDB(step);
8436   NdbDictionary::Dictionary* dict = pNdb->getDictionary();
8437   int records = ctx->getNumRecords();
8438   const int loops = ctx->getNumLoops();
8439 
8440   ndbout << "|- " << ctx->getTab()->getName() << endl;
8441 
8442   NdbDictionary::Table myTab= *(ctx->getTab());
8443   myTab.setFragmentType(NdbDictionary::Object::HashMapPartition);
8444 
8445   for (int l = 0; l < loops && result == NDBT_OK ; l++)
8446   {
8447     // Try to create table in db
8448     if (NDBT_Tables::createTable(pNdb, myTab.getName()) != 0){
8449       return NDBT_FAILED;
8450     }
8451 
8452     // Verify that table is in db
8453     const NdbDictionary::Table* pTab2 =
8454       NDBT_Table::discoverTableFromDb(pNdb, myTab.getName());
8455     if (pTab2 == NULL){
8456       ndbout << myTab.getName() << " was not found in DB"<< endl;
8457       return NDBT_FAILED;
8458     }
8459     ctx->setTab(pTab2);
8460 
8461 #if 1
8462     // Load table
8463     const NdbDictionary::Table* pTab;
8464     CHECK((pTab = ctx->getTab()) != NULL);
8465     HugoTransactions beforeTrans(*pTab);
8466     if (beforeTrans.loadTable(pNdb, records) != 0){
8467       return NDBT_FAILED;
8468     }
8469 #endif
8470 
8471     // Add attributes to table.
8472     BaseString pTabName(pTab2->getName());
8473     const NdbDictionary::Table * oldTable = dict->getTable(pTabName.c_str());
8474 
8475     NdbDictionary::Table newTable= *oldTable;
8476 
8477     newTable.setFragmentCount(2 * oldTable->getFragmentCount());
8478     newTable.setPartitionBalance(
8479       NdbDictionary::Object::PartitionBalance_Specific);
8480     CHECK2(dict->alterTable(*oldTable, newTable) == 0,
8481            "TableAddAttrs failed");
8482 
8483     /* Need to purge old version and reload new version after alter table. */
8484     dict->invalidateTable(pTabName.c_str());
8485 
8486 #if 0
8487     {
8488       HugoTransactions afterTrans(* dict->getTable(pTabName.c_str()));
8489 
8490       ndbout << "delete...";
8491       if (afterTrans.clearTable(pNdb) != 0)
8492       {
8493         return NDBT_FAILED;
8494       }
8495       ndbout << endl;
8496 
8497       ndbout << "insert...";
8498       if (afterTrans.loadTable(pNdb, records) != 0){
8499         return NDBT_FAILED;
8500       }
8501       ndbout << endl;
8502 
8503       ndbout << "update...";
8504       if (afterTrans.scanUpdateRecords(pNdb, records) != 0)
8505       {
8506         return NDBT_FAILED;
8507       }
8508       ndbout << endl;
8509 
8510       ndbout << "delete...";
8511       if (afterTrans.clearTable(pNdb) != 0)
8512       {
8513         return NDBT_FAILED;
8514       }
8515       ndbout << endl;
8516     }
8517 #endif
8518     abort();
8519     // Drop table.
8520     dict->dropTable(pTabName.c_str());
8521   }
8522 end:
8523 
8524   return result;
8525 }
8526 
8527 int
runBug41905(NDBT_Context * ctx,NDBT_Step * step)8528 runBug41905(NDBT_Context* ctx, NDBT_Step* step)
8529 {
8530   const NdbDictionary::Table* pTab = ctx->getTab();
8531   BaseString tabName(pTab->getName());
8532   Ndb* pNdb = GETNDB(step);
8533   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8534 
8535   NdbDictionary::Table creTab = *pTab;
8536   creTab.setForceVarPart(true);
8537   int ret = NDBT_OK;
8538 
8539   (void)pDic->dropTable(tabName.c_str());
8540   if (pDic->createTable(creTab)) {
8541     g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
8542     ret = NDBT_FAILED;
8543   }
8544 
8545   Uint32 cols = creTab.getNoOfColumns();
8546   Uint32 vers = 0;
8547   while (ret == NDBT_OK) {
8548     const NdbDictionary::Table* pOldTab = pDic->getTableGlobal(tabName.c_str());
8549     require(pOldTab != 0);
8550 
8551     const Uint32 old_st = pOldTab->getObjectStatus();
8552     const Uint32 old_cols = pOldTab->getNoOfColumns();
8553     const Uint32 old_vers = pOldTab->getObjectVersion() >> 24;
8554 
8555     if (old_st != NdbDictionary::Object::Retrieved) {
8556       g_err << __LINE__ << ": " << "got status " << old_st << endl;
8557       ret = NDBT_FAILED;
8558       break;
8559     }
8560     // bug#41905 or related: other thread causes us to get old version
8561     if (old_cols != cols || old_vers != vers) {
8562       g_err << __LINE__ << ": "
8563             << "got cols,vers " << old_cols << "," << old_vers
8564             << " expected " << cols << "," << vers << endl;
8565       ret = NDBT_FAILED;
8566       break;
8567     }
8568     if (old_cols >= 100)
8569       break;
8570     const NdbDictionary::Table& oldTab = *pOldTab;
8571 
8572     NdbDictionary::Table newTab = oldTab;
8573     char colName[100];
8574     sprintf(colName, "COL41905_%02d", cols);
8575     g_info << "add " << colName << endl;
8576     NDBT_Attribute newCol(colName, NdbDictionary::Column::Unsigned, 1,
8577                           false, true, (CHARSET_INFO*)0,
8578                           NdbDictionary::Column::StorageTypeMemory, true);
8579     newTab.addColumn(newCol);
8580 
8581     ctx->setProperty("Bug41905", 1);
8582     NdbSleep_MilliSleep(10);
8583 
8584     const bool removeEarly = (uint)rand() % 2;
8585     g_info << "removeEarly = " << removeEarly << endl;
8586 
8587     if (pDic->beginSchemaTrans() != 0) {
8588       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
8589       ret = NDBT_FAILED;
8590       break;
8591     }
8592     if (pDic->alterTable(oldTab, newTab) != 0) {
8593       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
8594       ret = NDBT_FAILED;
8595       break;
8596     }
8597 
8598     if (removeEarly)
8599       pDic->removeTableGlobal(*pOldTab, 0);
8600 
8601     if (pDic->endSchemaTrans() != 0) {
8602       g_err << __LINE__ << ": " << pDic->getNdbError() << endl;
8603       ret = NDBT_FAILED;
8604       break;
8605     }
8606 
8607     cols++;
8608     vers++;
8609     if (!removeEarly)
8610       pDic->removeTableGlobal(*pOldTab, 0);
8611     ctx->setProperty("Bug41905", 2);
8612     NdbSleep_MilliSleep(10);
8613   }
8614 
8615   ctx->setProperty("Bug41905", 3);
8616   return ret;
8617 }
8618 
8619 int
runBug41905getTable(NDBT_Context * ctx,NDBT_Step * step)8620 runBug41905getTable(NDBT_Context* ctx, NDBT_Step* step)
8621 {
8622   const NdbDictionary::Table* pTab = ctx->getTab();
8623   BaseString tabName(pTab->getName());
8624   Ndb* pNdb = GETNDB(step);
8625   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8626 
8627   while (1) {
8628     while (1) {
8629       if (ctx->getProperty("Bug41905") == 1)
8630         break;
8631       if (ctx->getProperty("Bug41905") == 3)
8632         goto out;
8633       NdbSleep_MilliSleep(10);
8634     }
8635 
8636     uint ms = (uint)rand() % 1000;
8637     NdbSleep_MilliSleep(ms);
8638     g_info << "get begin ms=" << ms << endl;
8639 
8640     Uint32 count = 0;
8641     Uint32 oldstatus = 0;
8642     while (1) {
8643       count++;
8644       const NdbDictionary::Table* pTmp = pDic->getTableGlobal(tabName.c_str());
8645       require(pTmp != 0);
8646       Uint32 code = pDic->getNdbError().code;
8647       Uint32 status = pTmp->getObjectStatus();
8648       if (oldstatus == 2 && status == 3)
8649         g_info << "code=" << code << " status=" << status << endl;
8650       oldstatus = status;
8651       pDic->removeTableGlobal(*pTmp, 0);
8652       if (ctx->getProperty("Bug41905") != 1)
8653         break;
8654       NdbSleep_MilliSleep(10);
8655     }
8656     g_info << "get end count=" << count << endl;
8657   }
8658 
8659 out:
8660   (void)pDic->dropTable(tabName.c_str());
8661   return NDBT_OK;
8662 }
8663 
8664 static
8665 int
createIndexes(NdbDictionary::Dictionary * pDic,const NdbDictionary::Table & tab,int cnt)8666 createIndexes(NdbDictionary::Dictionary* pDic,
8667               const NdbDictionary::Table & tab, int cnt)
8668 {
8669   for (int i = 0; i<cnt && i < tab.getNoOfColumns(); i++)
8670   {
8671     char buf[256];
8672     NdbDictionary::Index idx0;
8673     BaseString::snprintf(buf, sizeof(buf), "%s-idx-%u", tab.getName(), i);
8674     idx0.setName(buf);
8675     idx0.setType(NdbDictionary::Index::OrderedIndex);
8676     idx0.setTable(tab.getName());
8677     idx0.setStoredIndex(false);
8678     idx0.addIndexColumn(tab.getColumn(i)->getName());
8679 
8680     if (pDic->createIndex(idx0))
8681     {
8682       ndbout << pDic->getNdbError() << endl;
8683       return NDBT_FAILED;
8684     }
8685   }
8686 
8687   return 0;
8688 }
8689 
8690 int
runBug46552(NDBT_Context * ctx,NDBT_Step * step)8691 runBug46552(NDBT_Context* ctx, NDBT_Step* step)
8692 {
8693   Ndb* pNdb = GETNDB(step);
8694   const NdbDictionary::Table* pTab = ctx->getTab();
8695   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8696 
8697   NdbRestarter res;
8698   int numDbNodes = res.getNumDbNodes();
8699   getNodeGroups(res);
8700   int num_replicas = (numDbNodes - numNoNodeGroups) / numNodeGroups;
8701   if (res.getNumDbNodes() < 2 || num_replicas != 2)
8702     return NDBT_OK;
8703 
8704   NdbDictionary::Table tab0 = *pTab;
8705   NdbDictionary::Table tab1 = *pTab;
8706 
8707   BaseString name;
8708   name.assfmt("%s_0", tab0.getName());
8709   tab0.setName(name.c_str());
8710   name.assfmt("%s_1", tab1.getName());
8711   tab1.setName(name.c_str());
8712 
8713   pDic->dropTable(tab0.getName());
8714   pDic->dropTable(tab1.getName());
8715 
8716   if (pDic->createTable(tab0))
8717   {
8718     ndbout << pDic->getNdbError() << endl;
8719     return NDBT_FAILED;
8720   }
8721 
8722   if (pDic->createTable(tab1))
8723   {
8724     ndbout << pDic->getNdbError() << endl;
8725     return NDBT_FAILED;
8726   }
8727 
8728   if (createIndexes(pDic, tab1, 4))
8729     return NDBT_FAILED;
8730 
8731   Vector<int> group1;
8732   Vector<int> group2;
8733   Bitmask<256/32> nodeGroupMap;
8734   for (int j = 0; j<res.getNumDbNodes(); j++)
8735   {
8736     int node = res.getDbNodeId(j);
8737     int ng = res.getNodeGroup(node);
8738     if (nodeGroupMap.get(ng))
8739     {
8740       group2.push_back(node);
8741     }
8742     else
8743     {
8744       group1.push_back(node);
8745       nodeGroupMap.set(ng);
8746     }
8747   }
8748 
8749   res.restartNodes(group1.getBase(), (int)group1.size(),
8750                    NdbRestarter::NRRF_NOSTART |
8751                    NdbRestarter::NRRF_ABORT);
8752 
8753   res.waitNodesNoStart(group1.getBase(), (int)group1.size());
8754   res.startNodes(group1.getBase(), (int)group1.size());
8755   res.waitClusterStarted();
8756 
8757   res.restartNodes(group2.getBase(), (int)group2.size(),
8758                    NdbRestarter::NRRF_NOSTART |
8759                    NdbRestarter::NRRF_ABORT);
8760   res.waitNodesNoStart(group2.getBase(), (int)group2.size());
8761   res.startNodes(group2.getBase(), (int)group2.size());
8762   res.waitClusterStarted();
8763   CHK_NDB_READY(pNdb);
8764 
8765   if (pDic->dropTable(tab0.getName()))
8766   {
8767     ndbout << pDic->getNdbError() << endl;
8768     return NDBT_FAILED;
8769   }
8770 
8771   if (pDic->createTable(tab0))
8772   {
8773     ndbout << pDic->getNdbError() << endl;
8774     return NDBT_FAILED;
8775   }
8776 
8777   if (createIndexes(pDic, tab0, 4))
8778     return NDBT_FAILED;
8779 
8780   res.restartAll2(NdbRestarter::NRRF_NOSTART | NdbRestarter::NRRF_ABORT);
8781   res.waitClusterNoStart();
8782   res.startAll();
8783   res.waitClusterStarted();
8784   CHK_NDB_READY(pNdb);
8785 
8786   if (pDic->dropTable(tab0.getName()))
8787   {
8788     ndbout << pDic->getNdbError() << endl;
8789     return NDBT_FAILED;
8790   }
8791 
8792   if (pDic->dropTable(tab1.getName()))
8793   {
8794     ndbout << pDic->getNdbError() << endl;
8795     return NDBT_FAILED;
8796   }
8797 
8798   return NDBT_OK;
8799 }
8800 
8801 int
runBug46585(NDBT_Context * ctx,NDBT_Step * step)8802 runBug46585(NDBT_Context* ctx, NDBT_Step* step)
8803 {
8804   Ndb* pNdb = GETNDB(step);
8805   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8806   NdbDictionary::Table tab(*ctx->getTab());
8807   NdbRestarter res;
8808   int records = ctx->getNumRecords();
8809 
8810   // ordered index on first few columns
8811   NdbDictionary::Index idx("X");
8812   idx.setTable(tab.getName());
8813   idx.setType(NdbDictionary::Index::OrderedIndex);
8814   idx.setLogging(false);
8815   for (int cnt = 0, i_hate_broken_compilers = 0;
8816        cnt < 3 &&
8817        i_hate_broken_compilers < tab.getNoOfColumns();
8818        i_hate_broken_compilers++) {
8819     if (NdbSqlUtil::check_column_for_ordered_index
8820         (tab.getColumn(i_hate_broken_compilers)->getType(), 0) == 0 &&
8821         tab.getColumn(i_hate_broken_compilers)->getStorageType() !=
8822         NdbDictionary::Column::StorageTypeDisk)
8823     {
8824       idx.addColumn(*tab.getColumn(i_hate_broken_compilers));
8825       cnt++;
8826     }
8827   }
8828 
8829   for (int i = 0; i<tab.getNoOfColumns(); i++)
8830   {
8831     if (tab.getColumn(i)->getStorageType() ==
8832         NdbDictionary::Column::StorageTypeDisk)
8833     {
8834       NDBT_Tables::create_default_tablespace(pNdb);
8835       break;
8836     }
8837   }
8838 
8839   const int loops = ctx->getNumLoops();
8840   int result = NDBT_OK;
8841   (void)pDic->dropTable(tab.getName());
8842   if (pDic->createTable(tab) != 0)
8843   {
8844     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8845     return NDBT_FAILED;
8846   }
8847 
8848   if (pDic->createIndex(idx) != 0)
8849   {
8850     ndbout << "FAIL: " << pDic->getNdbError() << endl;
8851     return NDBT_FAILED;
8852   }
8853 
8854   for (int i = 0; i<loops; i++)
8855   {
8856     const NdbDictionary::Table * org = pDic->getTable(tab.getName());
8857     {
8858       CHECK(org != NULL);
8859       HugoTransactions trans(* org);
8860       CHECK2(trans.loadTable(pNdb, records) == 0,
8861            "load table failed");
8862     }
8863 
8864     NdbDictionary::Table altered = * org;
8865     altered.setFragmentCount(org->getFragmentCount() + 1);
8866     altered.setPartitionBalance(
8867       NdbDictionary::Object::PartitionBalance_Specific);
8868     ndbout_c("alter from %u to %u partitions",
8869              org->getFragmentCount(),
8870              altered.getFragmentCount());
8871 
8872     if (pDic->beginSchemaTrans())
8873     {
8874       ndbout << "Failed to beginSchemaTrans()" << pDic->getNdbError() << endl;
8875       return NDBT_FAILED;
8876     }
8877 
8878     if (pDic->prepareHashMap(*org, altered) == -1)
8879     {
8880       ndbout << "Failed to create hashmap: " << pDic->getNdbError() << endl;
8881       return NDBT_FAILED;
8882     }
8883 
8884     if (pDic->endSchemaTrans())
8885     {
8886       ndbout << "Failed to endSchemaTrans()" << pDic->getNdbError() << endl;
8887       return NDBT_FAILED;
8888     }
8889 
8890     result = pDic->alterTable(*org, altered);
8891     if (result)
8892     {
8893       ndbout << pDic->getNdbError() << endl;
8894     }
8895     if (pDic->getNdbError().code == 1224)
8896     {
8897       /**
8898        * To many fragments is an acceptable error
8899        *   depending on configuration used for test-case
8900        */
8901       result = NDBT_OK;
8902       goto end;
8903     }
8904     CHECK2(result == 0,
8905            "failed to alter");
8906 
8907     pDic->invalidateTable(tab.getName());
8908     {
8909       const NdbDictionary::Table * alteredP = pDic->getTable(tab.getName());
8910       CHECK2(alteredP->getFragmentCount() == altered.getFragmentCount(),
8911              "altered table does not have correct frag count");
8912 
8913       HugoTransactions trans(* alteredP);
8914 
8915       CHECK2(trans.scanUpdateRecords(pNdb, records) == 0,
8916              "scan update failed");
8917       trans.startTransaction(pNdb);
8918       trans.pkUpdateRecord(pNdb, 0);
8919       trans.execute_Commit(pNdb);
8920       ndbout_c("before restart, gci: %d", trans.getRecordGci(0));
8921       trans.closeTransaction(pNdb);
8922     }
8923 
8924     switch(i % 2){
8925     case 0:
8926       if (res.getNumDbNodes() > 1)
8927       {
8928         int nodeId = res.getNode(NdbRestarter::NS_RANDOM);
8929         ndbout_c("performing node-restart of node %d", nodeId);
8930         CHECK2(res.restartOneDbNode(nodeId,
8931                                     false,
8932                                     true,
8933                                     true) == 0,
8934                "restart one node failed");
8935         CHECK2(res.waitNodesNoStart(&nodeId, 1) == 0,
8936                "wait node started failed");
8937         CHECK2(res.startNodes(&nodeId, 1) == 0,
8938                "start node failed");
8939         break;
8940       }
8941       // Fall through - only system restart possible with one node
8942     case 1:
8943     {
8944       ndbout_c("performing system restart");
8945       CHECK2(res.restartAll(false, true, false) == 0,
8946              "restart all failed");
8947       CHECK2(res.waitClusterNoStart() == 0,
8948              "waitClusterNoStart failed");
8949       CHECK2(res.startAll() == 0,
8950              "startAll failed");
8951       break;
8952     }
8953     }
8954     CHECK2(res.waitClusterStarted() == 0,
8955            "wait cluster started failed");
8956     CHK_NDB_READY(pNdb);
8957 
8958     Uint32 restartGCI = 0;
8959     CHECK2(pDic->getRestartGCI(&restartGCI) == 0,
8960            "getRestartGCI failed");
8961     ndbout_c("restartGCI: %u", restartGCI);
8962 
8963     pDic->invalidateTable(tab.getName());
8964     {
8965       const NdbDictionary::Table * alteredP = pDic->getTable(tab.getName());
8966       CHECK(alteredP != NULL);
8967       HugoTransactions trans(* alteredP);
8968 
8969       int cnt;
8970       CHECK2(trans.selectCount(pNdb, 0, &cnt) == 0,
8971              "select count failed");
8972 
8973       CHECK2(cnt == records,
8974              "table does not have correct record count: "
8975              << cnt << " != " << records);
8976 
8977       CHECK2(alteredP->getFragmentCount() == altered.getFragmentCount(),
8978              "altered table does not have correct frag count");
8979 
8980       CHECK2(trans.scanUpdateRecords(pNdb, records) == 0,
8981              "scan update failed");
8982       CHECK2(trans.pkUpdateRecords(pNdb, records) == 0,
8983              "pkUpdateRecords failed");
8984       CHECK2(trans.clearTable(pNdb) == 0,
8985              "clear table failed");
8986     }
8987   }
8988 
8989 end:
8990   (void)pDic->dropTable(tab.getName());
8991   return result;
8992 }
8993 
8994 int
runBug53944(NDBT_Context * ctx,NDBT_Step * step)8995 runBug53944(NDBT_Context* ctx, NDBT_Step* step)
8996 {
8997   Ndb* pNdb = GETNDB(step);
8998   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
8999   NdbDictionary::Table tab(*ctx->getTab());
9000   NdbRestarter res;
9001 
9002   Vector<int> ids;
9003   for (unsigned i = 0; i< 25; i++)
9004   {
9005     NdbDictionary::Table copy = tab;
9006     BaseString name;
9007     name.appfmt("%s_%u", copy.getName(), i);
9008     copy.setName(name.c_str());
9009     int res = pDic->createTable(copy);
9010     if (res)
9011     {
9012       g_err << "Failed to create table" << copy.getName() << "\n"
9013             << pDic->getNdbError() << endl;
9014       return NDBT_FAILED;
9015     }
9016     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
9017     if (tab == 0)
9018     {
9019       g_err << "Failed to retreive table" << copy.getName() << endl;
9020       return NDBT_FAILED;
9021 
9022     }
9023     ids.push_back(tab->getObjectId());
9024   }
9025 
9026   res.restartAll2(NdbRestarter::NRRF_ABORT | NdbRestarter::NRRF_NOSTART);
9027   res.waitClusterNoStart();
9028   res.startAll();
9029   res.waitClusterStarted();
9030   CHK_NDB_READY(pNdb);
9031 
9032   for (unsigned i = 0; i< 25; i++)
9033   {
9034     NdbDictionary::Table copy = tab;
9035     BaseString name;
9036     name.appfmt("%s_%u", copy.getName(), i);
9037     copy.setName(name.c_str());
9038     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
9039     if (tab == 0)
9040     {
9041       g_err << "Failed to retreive table" << copy.getName() << endl;
9042       return NDBT_FAILED;
9043 
9044     }
9045     int res = pDic->dropTable(copy.getName());
9046     if (res)
9047     {
9048       g_err << "Failed to drop table" << copy.getName() << "\n"
9049             << pDic->getNdbError() << endl;
9050       return NDBT_FAILED;
9051     }
9052   }
9053 
9054   Vector<int> ids2;
9055   for (unsigned i = 0; i< 25; i++)
9056   {
9057     NdbDictionary::Table copy = tab;
9058     BaseString name;
9059     name.appfmt("%s_%u", copy.getName(), i);
9060     copy.setName(name.c_str());
9061     int res = pDic->createTable(copy);
9062     if (res)
9063     {
9064       g_err << "Failed to create table" << copy.getName() << "\n"
9065             << pDic->getNdbError() << endl;
9066       return NDBT_FAILED;
9067     }
9068     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
9069     if (tab == 0)
9070     {
9071       g_err << "Failed to retreive table" << copy.getName() << endl;
9072       return NDBT_FAILED;
9073 
9074     }
9075     ids2.push_back(tab->getObjectId());
9076   }
9077 
9078   for (unsigned i = 0; i< 25; i++)
9079   {
9080     NdbDictionary::Table copy = tab;
9081     BaseString name;
9082     name.appfmt("%s_%u", copy.getName(), i);
9083     copy.setName(name.c_str());
9084     const NdbDictionary::Table* tab = pDic->getTable(copy.getName());
9085     if (tab == 0)
9086     {
9087       g_err << "Failed to retreive table" << copy.getName() << endl;
9088       return NDBT_FAILED;
9089 
9090     }
9091     int res = pDic->dropTable(copy.getName());
9092     if (res)
9093     {
9094       g_err << "Failed to drop table" << copy.getName() << "\n"
9095             << pDic->getNdbError() << endl;
9096       return NDBT_FAILED;
9097     }
9098   }
9099 
9100   /**
9101    * With Bug53944 - none of the table-id have been reused in this scenario
9102    *   check that atleast 15 of the 25 have been to return OK
9103    */
9104   unsigned reused = 0;
9105   for (unsigned i = 0; i<ids.size(); i++)
9106   {
9107     int id = ids[i];
9108     for (unsigned j = 0; j<ids2.size(); j++)
9109     {
9110       if (ids2[j] == id)
9111       {
9112         reused++;
9113         break;
9114       }
9115     }
9116   }
9117 
9118   ndbout_c("reused %u table-ids out of %u",
9119            (unsigned)reused, (unsigned)ids.size());
9120 
9121   if (reused >= (ids.size() >> 2))
9122   {
9123     return NDBT_OK;
9124   }
9125   else
9126   {
9127     return NDBT_FAILED;
9128   }
9129 }
9130 
9131 // Bug58277 + Bug57057
9132 
9133 #define CHK2(b, e) \
9134   if (!(b)) { \
9135     g_err << "ERR: " << #b << " failed at line " << __LINE__ \
9136           << ": " << e << endl; \
9137     result = NDBT_FAILED; \
9138     break; \
9139   }
9140 
9141 // allow list of expected error codes which do not cause NDBT_FAILED
9142 #define CHK3(b, e, x) \
9143   if (!(b)) { \
9144     int n = sizeof(x)/sizeof(x[0]); \
9145     int i; \
9146     for (i = 0; i < n; i++) { \
9147       int s = (x[i] >= 0 ? +1 : -1); \
9148       if (e.code == s * x[i]) { \
9149         if (s == +1) \
9150           g_info << "OK: " << #b << " failed at line " << __LINE__ \
9151                 << ": " << e << endl; \
9152         break; \
9153       } \
9154     } \
9155     if (i == n) { \
9156       g_err << "ERR: " << #b << " failed at line " << __LINE__ \
9157             << ": " << e << endl; \
9158       result = NDBT_FAILED; \
9159     } \
9160     break; \
9161   }
9162 
9163 const char* tabName_Bug58277 = "TBug58277";
9164 const char* indName_Bug58277 = "TBug58277X1";
9165 
9166 static void
sync_main_step(NDBT_Context * ctx,NDBT_Step * step,const char * state)9167 sync_main_step(NDBT_Context* ctx, NDBT_Step* step, const char* state)
9168 {
9169   // total sub-steps
9170   Uint32 sub_steps = ctx->getProperty("SubSteps", (Uint32)0);
9171   require(sub_steps != 0);
9172   // count has been reset before
9173   require(ctx->getProperty("SubCount", (Uint32)0) == 0);
9174   // set the state
9175   g_info << "step main: set " << state << endl;
9176   require(ctx->getProperty(state, (Uint32)0) == 0);
9177   ctx->setProperty(state, (Uint32)1);
9178   // wait for sub-steps
9179   ctx->getPropertyWait("SubCount", sub_steps);
9180   if (ctx->isTestStopped())
9181     return;
9182   g_info << "step main: sub-steps got " << state << endl;
9183   // reset count and state
9184   ctx->setProperty("SubCount", (Uint32)0);
9185   ctx->setProperty(state, (Uint32)0);
9186 }
9187 
9188 static void
sync_sub_step(NDBT_Context * ctx,NDBT_Step * step,const char * state)9189 sync_sub_step(NDBT_Context* ctx, NDBT_Step* step, const char* state)
9190 {
9191   // wait for main step to set state
9192   g_info << "step " << step->getStepNo() << ": wait for " << state << endl;
9193   ctx->getPropertyWait(state, (Uint32)1);
9194   if (ctx->isTestStopped())
9195     return;
9196   // add to sub-step counter
9197   ctx->incProperty("SubCount");
9198   g_info << "step " << step->getStepNo() << ": got " << state << endl;
9199   // continue to run until next sync
9200 }
9201 
9202 static int
runBug58277createtable(NDBT_Context * ctx,NDBT_Step * step)9203 runBug58277createtable(NDBT_Context* ctx, NDBT_Step* step)
9204 {
9205   Ndb* pNdb = GETNDB(step);
9206   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9207   int result = NDBT_OK;
9208   const int rows = ctx->getNumRecords();
9209   const char* tabname = tabName_Bug58277;
9210 
9211   do
9212   {
9213     CHK2(rows > 0, "cannot use --records=0"); // others require this
9214     g_info << "create table " << tabname << endl;
9215     NdbDictionary::Table tab(tabname);
9216     const char* name[] = { "a", "b" };
9217     for (int i = 0; i <= 1; i++)
9218     {
9219       NdbDictionary::Column c(name[i]);
9220       c.setType(NdbDictionary::Column::Unsigned);
9221       c.setPrimaryKey(i == 0);
9222       c.setNullable(false);
9223       tab.addColumn(c);
9224     }
9225     if (rand() % 3 != 0)
9226     {
9227       g_info << "set FragAllLarge" << endl;
9228       tab.setFragmentType(NdbDictionary::Object::FragAllLarge);
9229     }
9230     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
9231   }
9232   while (0);
9233   return result;
9234 }
9235 
9236 static int
runBug58277loadtable(NDBT_Context * ctx,NDBT_Step * step)9237 runBug58277loadtable(NDBT_Context* ctx, NDBT_Step* step)
9238 {
9239   Ndb* pNdb = GETNDB(step);
9240   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9241   int result = NDBT_OK;
9242   const int rows = ctx->getNumRecords();
9243   const char* tabname = tabName_Bug58277;
9244 
9245   do
9246   {
9247     g_info << "load table" << endl;
9248     const NdbDictionary::Table* pTab = 0;
9249     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
9250 
9251     int cnt = 0;
9252     for (int i = 0; i < rows; i++)
9253     {
9254       int retries = 10;
9255   retry:
9256       NdbTransaction* pTx = 0;
9257       CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
9258 
9259       NdbOperation* pOp = 0;
9260       CHK2((pOp = pTx->getNdbOperation(pTab)) != 0, pTx->getNdbError());
9261       CHK2(pOp->insertTuple() == 0, pOp->getNdbError());
9262       Uint32 aVal = i;
9263       Uint32 bVal = rand() % rows;
9264       CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9265       CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
9266 
9267       do
9268       {
9269         int x[] = {
9270          -630
9271         };
9272         int res = pTx->execute(Commit);
9273         if (res != 0 &&
9274             pTx->getNdbError().status == NdbError::TemporaryError)
9275         {
9276           retries--;
9277           if (retries >= 0)
9278           {
9279             pTx->close();
9280             NdbSleep_MilliSleep(10);
9281             goto retry;
9282           }
9283         }
9284         CHK3(res == 0, pTx->getNdbError(), x);
9285         cnt++;
9286       }
9287       while (0);
9288       CHK2(result == NDBT_OK, "load failed");
9289       pNdb->closeTransaction(pTx);
9290     }
9291     CHK2(result == NDBT_OK, "load failed");
9292     g_info << "load " << cnt << " rows" << endl;
9293   }
9294   while (0);
9295   return result;
9296 }
9297 
9298 static int
runBug58277createindex(NDBT_Context * ctx,NDBT_Step * step)9299 runBug58277createindex(NDBT_Context* ctx, NDBT_Step* step)
9300 {
9301   Ndb* pNdb = GETNDB(step);
9302   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9303   int result = NDBT_OK;
9304   const char* tabname = tabName_Bug58277;
9305   const char* indname = indName_Bug58277;
9306 
9307   do
9308   {
9309     g_info << "create index " << indname << endl;
9310     NdbDictionary::Index ind(indname);
9311     ind.setTable(tabname);
9312     ind.setType(NdbDictionary::Index::OrderedIndex);
9313     ind.setLogging(false);
9314     ind.addColumn("b");
9315     CHK2(pDic->createIndex(ind) == 0, pDic->getNdbError());
9316 
9317     const NdbDictionary::Index* pInd = 0;
9318     CHK2((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError());
9319   }
9320   while (0);
9321   return result;
9322 }
9323 
9324 // separate error handling test
9325 int
runBug58277errtest(NDBT_Context * ctx,NDBT_Step * step)9326 runBug58277errtest(NDBT_Context* ctx, NDBT_Step* step)
9327 {
9328   Ndb* pNdb = GETNDB(step);
9329   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9330   const int loops = ctx->getNumLoops();
9331   int result = NDBT_OK;
9332   //const int rows = ctx->getNumRecords();
9333   NdbRestarter restarter;
9334   const char* tabname = tabName_Bug58277;
9335   const char* indname = indName_Bug58277;
9336   (void)pDic->dropTable(tabname);
9337 
9338   const int errloops = loops < 5 ? loops : 5;
9339   int errloop = 0;
9340   while (!ctx->isTestStopped() && errloop < errloops)
9341   {
9342     g_info << "===== errloop " << errloop << " =====" << endl;
9343 
9344     if (errloop == 0)
9345     {
9346       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
9347       CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
9348       CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
9349     }
9350     const NdbDictionary::Index* pInd = 0;
9351     CHK2((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError());
9352 
9353     int errins[] = {
9354       12008, 909,  // TuxNoFreeScanOp
9355       12009, 4259  // InvalidBounds
9356     };
9357     const int errcnt = (int)(sizeof(errins)/sizeof(errins[0]));
9358     for (int i = 0; i < errcnt; i += 2)
9359     {
9360       const int ei = errins[i + 0];
9361       const int ec = errins[i + 1];
9362       CHK2(restarter.insertErrorInAllNodes(ei) == 0, "value " << ei);
9363 
9364       NdbTransaction* pSTx = 0;
9365       CHK2((pSTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
9366       NdbIndexScanOperation* pSOp = 0;
9367       CHK2((pSOp = pSTx->getNdbIndexScanOperation(pInd)) != 0, pSTx->getNdbError());
9368 
9369       NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
9370       Uint32 flags = 0;
9371       CHK2(pSOp->readTuples(lm, flags) == 0, pSOp->getNdbError());
9372 
9373       Uint32 aVal = 0;
9374       CHK2(pSOp->getValue("a", (char*)&aVal) != 0, pSOp->getNdbError());
9375       CHK2(pSTx->execute(NoCommit) == 0, pSTx->getNdbError());
9376       // before fixes 12009 failed to fail at once here
9377       CHK2(pSOp->nextResult(true) == -1, "failed to fail on " << ei);
9378       CHK2(pSOp->getNdbError().code == ec, "expect " << ec << " got " << pSOp->getNdbError());
9379       pNdb->closeTransaction(pSTx);
9380 
9381       g_info << "error " << ei << " " << ec << " ok" << endl;
9382       CHK2(restarter.insertErrorInAllNodes(0) == 0, "value " << 0);
9383     }
9384     CHK2(result == NDBT_OK, "test error handling failed");
9385 
9386     errloop++;
9387     if (errloop == errloops)
9388     {
9389       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9390       g_info << "table " << tabname << " dropped" << endl;
9391     }
9392   }
9393   if (result != NDBT_OK)
9394   {
9395     g_info << "stop test at line " << __LINE__ << endl;
9396     ctx->stopTest();
9397   }
9398   return result;
9399 }
9400 
9401 int
runBug58277drop(NDBT_Context * ctx,NDBT_Step * step)9402 runBug58277drop(NDBT_Context* ctx, NDBT_Step* step)
9403 {
9404   Ndb* pNdb = GETNDB(step);
9405   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9406   int result = NDBT_OK;
9407   const char* tabname = tabName_Bug58277;
9408   const char* indname = indName_Bug58277;
9409   int dropms = 0;
9410 
9411   while (!ctx->isTestStopped())
9412   {
9413     sync_sub_step(ctx, step, "Start");
9414     if (ctx->isTestStopped())
9415       break;
9416     dropms = ctx->getProperty("DropMs", (Uint32)0);
9417     NdbSleep_MilliSleep(dropms);
9418 
9419     g_info << "drop index " << indname << endl;
9420     CHK2(pDic->dropIndex(indname, tabname) == 0, pDic->getNdbError());
9421     pDic->invalidateIndex(indname, tabname);
9422     CHK2(pDic->getIndex(indname, tabname) == 0, "failed");
9423     g_info << "drop index done" << endl;
9424 
9425     sync_sub_step(ctx, step, "Stop");
9426     if (ctx->isTestStopped())
9427       break;
9428   }
9429   if (result != NDBT_OK)
9430   {
9431     g_info << "stop test at line " << __LINE__ << endl;
9432     ctx->stopTest();
9433   }
9434   return result;
9435 }
9436 
9437 static int
runBug58277scanop(NDBT_Context * ctx,NDBT_Step * step,int cnt[1+3])9438 runBug58277scanop(NDBT_Context* ctx, NDBT_Step* step, int cnt[1+3])
9439 {
9440   Ndb* pNdb = GETNDB(step);
9441   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9442   int result = NDBT_OK;
9443   const int rows = ctx->getNumRecords();
9444   const char* tabname = tabName_Bug58277;
9445   const char* indname = indName_Bug58277;
9446   const int range_max = ctx->getProperty("RANGE_MAX", (Uint32)0);
9447   require(range_max > 0);
9448   const bool scan_delete = ctx->getProperty("SCAN_DELETE", (Uint32)0);
9449 
9450   do
9451   {
9452     const NdbDictionary::Index* pInd = 0;
9453     {
9454       int x[] = {
9455         4243  // Index not found
9456       };
9457       pDic->invalidateIndex(indname, tabname);
9458       CHK3((pInd = pDic->getIndex(indname, tabname)) != 0, pDic->getNdbError(), x);
9459     }
9460 
9461     NdbTransaction* pSTx = 0;
9462     CHK2((pSTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
9463     NdbIndexScanOperation* pSOp = 0;
9464     CHK2((pSOp = pSTx->getNdbIndexScanOperation(pInd)) != 0, pSTx->getNdbError());
9465     NdbOperation::LockMode lm = NdbOperation::LM_Exclusive;
9466     Uint32 flags = 0;
9467     int range_cnt = rand() % range_max;
9468     if (range_cnt > 1 || rand() % 5 == 0)
9469       flags |= NdbIndexScanOperation::SF_MultiRange;
9470     CHK2(pSOp->readTuples(lm, flags) == 0, pSOp->getNdbError());
9471     g_info << "range cnt " << range_cnt << endl;
9472     for (int i = 0; i < range_cnt; )
9473     {
9474       int tlo = -1;
9475       int thi = -1;
9476       if (rand() % 5 == 0)
9477       {
9478         if (rand() % 5 != 0)
9479           tlo = 0 + rand() % 2;
9480         if (rand() % 5 != 0)
9481           thi = 2 + rand() % 2;
9482       }
9483       else
9484         tlo = 4;
9485       // apparently no bounds is not allowed (see also bug#57396)
9486       if (tlo == -1 && thi == -1)
9487         continue;
9488       Uint32 blo = 0;
9489       Uint32 bhi = 0;
9490       if (tlo != -1)
9491       {
9492         blo = rand() % rows;
9493         CHK2(pSOp->setBound("b", tlo, &blo) == 0, pSOp->getNdbError());
9494       }
9495       if (thi != -1)
9496       {
9497         bhi = rand() % (rows + 1);
9498         if (bhi < blo)
9499           bhi = rand() % (rows + 1);
9500         CHK2(pSOp->setBound("b", thi, &bhi) == 0, pSOp->getNdbError());
9501       }
9502       CHK2(pSOp->end_of_bound() == 0, pSOp->getNdbError());
9503       i++;
9504     }
9505     CHK2(result == NDBT_OK, "set bound ranges failed");
9506 
9507     Uint32 aVal = 0;
9508     CHK2(pSOp->getValue("a", (char*)&aVal) != 0, pSOp->getNdbError());
9509     CHK2(pSTx->execute(NoCommit) == 0, pSTx->getNdbError());
9510 
9511     while (1)
9512     {
9513       int ret;
9514       {
9515         int x[] = {
9516           241,  // Invalid schema object version
9517           274,  // Time-out in NDB, probably caused by deadlock
9518           283,  // Table is being dropped
9519           284,  // Table not defined in transaction coordinator
9520           910,  // Index is being dropped
9521           1226  // Table is being dropped
9522         };
9523         CHK3((ret = pSOp->nextResult(true)) != -1, pSOp->getNdbError(), x);
9524       }
9525       require(ret == 0 || ret == 1);
9526       if (ret == 1)
9527         break;
9528 
9529       NdbTransaction* pTx = 0;
9530       CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
9531 
9532       while (1)
9533       {
9534         int type = 1 + rand() % 3;
9535         if (type == 2) // insert->update
9536           type = 1;
9537         if (scan_delete)
9538           type = 3;
9539         do
9540         {
9541           if (type == 1)
9542           {
9543             NdbOperation* pOp = 0;
9544             CHK2((pOp = pSOp->updateCurrentTuple(pTx)) != 0, pSOp->getNdbError());
9545             Uint32 bVal = (Uint32)(rand() % rows);
9546             CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
9547             break;
9548           }
9549           if (type == 3)
9550           {
9551             CHK2(pSOp->deleteCurrentTuple(pTx) == 0, pSOp->getNdbError());
9552             break;
9553           }
9554           require(false);
9555         }
9556         while (0);
9557         CHK2(result == NDBT_OK, "scan takeover error");
9558         cnt[type]++;
9559         {
9560           int x[] = {
9561             266,  // Time-out in NDB, probably caused by deadlock
9562             499,  // Scan take over error
9563             631,  // 631
9564             4350  // Transaction already aborted
9565           };
9566           CHK3(pTx->execute(NoCommit) == 0, pTx->getNdbError(), x);
9567         }
9568 
9569         CHK2((ret = pSOp->nextResult(false)) != -1, pSOp->getNdbError());
9570         require(ret == 0 || ret == 2);
9571         if (ret == 2)
9572           break;
9573       }
9574       CHK2(result == NDBT_OK, "batch failed");
9575 
9576       {
9577         int x[] = {
9578           266,  // Time-out in NDB, probably caused by deadlock
9579           4350  // Transaction already aborted
9580         };
9581         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9582       }
9583       pNdb->closeTransaction(pTx);
9584     }
9585     CHK2(result == NDBT_OK, "batch failed");
9586     pNdb->closeTransaction(pSTx);
9587   }
9588   while (0);
9589   return result;
9590 }
9591 
9592 int
runBug58277scan(NDBT_Context * ctx,NDBT_Step * step)9593 runBug58277scan(NDBT_Context* ctx, NDBT_Step* step)
9594 {
9595   int result = NDBT_OK;
9596 
9597   while (!ctx->isTestStopped())
9598   {
9599     sync_sub_step(ctx, step, "Start");
9600     if (ctx->isTestStopped())
9601       break;
9602     g_info << "start scan loop" << endl;
9603     while (!ctx->isTestStopped())
9604     {
9605       g_info << "start scan" << endl;
9606       int cnt[1+3] = { 0, 0, 0, 0 };
9607       CHK2(runBug58277scanop(ctx, step, cnt) == NDBT_OK, "scan failed");
9608       g_info << "scan ops " << cnt[1] << "/-/" << cnt[3] << endl;
9609 
9610       if (ctx->getProperty("Stop", (Uint32)0) == 1)
9611       {
9612         sync_sub_step(ctx, step, "Stop");
9613         break;
9614       }
9615     }
9616     CHK2(result == NDBT_OK, "scan loop failed");
9617   }
9618   if (result != NDBT_OK)
9619   {
9620     g_info << "stop test at line " << __LINE__ << endl;
9621     ctx->stopTest();
9622   }
9623   return result;
9624 }
9625 
9626 static int
runBug58277pkop(NDBT_Context * ctx,NDBT_Step * step,int cnt[1+3])9627 runBug58277pkop(NDBT_Context* ctx, NDBT_Step* step, int cnt[1+3])
9628 {
9629   Ndb* pNdb = GETNDB(step);
9630   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9631   int result = NDBT_OK;
9632   const int rows = ctx->getNumRecords();
9633   const char* tabname = tabName_Bug58277;
9634 
9635   do
9636   {
9637     const NdbDictionary::Table* pTab = 0;
9638     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
9639 
9640     NdbTransaction* pTx = 0;
9641     CHK2((pTx = pNdb->startTransaction()) != 0, pNdb->getNdbError());
9642     NdbOperation* pOp = 0;
9643     CHK2((pOp = pTx->getNdbOperation(pTab)) != 0, pTx->getNdbError());
9644     int type = 1 + rand() % 3;
9645     Uint32 aVal = rand() % rows;
9646     Uint32 bVal = rand() % rows;
9647 
9648     do
9649     {
9650       if (type == 1)
9651       {
9652         CHK2(pOp->updateTuple() == 0, pOp->getNdbError());
9653         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9654         CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
9655         int x[] = {
9656           266,  // Time-out in NDB, probably caused by deadlock
9657          -626   // Tuple did not exist
9658         };
9659         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9660         break;
9661       }
9662       if (type == 2)
9663       {
9664         CHK2(pOp->insertTuple() == 0, pOp->getNdbError());
9665         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9666         CHK2(pOp->setValue("b", bVal) == 0, pOp->getNdbError());
9667         int x[] = {
9668           266,  // Time-out in NDB, probably caused by deadlock
9669          -630   // Tuple already existed when attempting to insert
9670         };
9671         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9672         break;
9673       }
9674       if (type == 3)
9675       {
9676         CHK2(pOp->deleteTuple() == 0, pOp->getNdbError());
9677         CHK2(pOp->equal("a", (char*)&aVal) == 0, pOp->getNdbError());
9678         int x[] = {
9679           266,  // Time-out in NDB, probably caused by deadlock
9680          -626   // Tuple did not exist
9681         };
9682         CHK3(pTx->execute(Commit) == 0, pTx->getNdbError(), x);
9683         break;
9684       }
9685       require(false);
9686     }
9687     while (0);
9688     CHK2(result == NDBT_OK, "pk op failed");
9689 
9690     pNdb->closeTransaction(pTx);
9691     cnt[type]++;
9692   }
9693   while (0);
9694   return result;
9695 }
9696 
9697 int
runBug58277pk(NDBT_Context * ctx,NDBT_Step * step)9698 runBug58277pk(NDBT_Context* ctx, NDBT_Step* step)
9699 {
9700   int result = NDBT_OK;
9701 
9702   while (!ctx->isTestStopped())
9703   {
9704     sync_sub_step(ctx, step, "Start");
9705     if (ctx->isTestStopped())
9706       break;
9707 
9708     g_info << "start pk loop" << endl;
9709     int cnt[1+3] = { 0, 0, 0, 0 };
9710     while (!ctx->isTestStopped())
9711     {
9712       CHK2(runBug58277pkop(ctx, step, cnt) == NDBT_OK, "pk op failed");
9713 
9714       if (ctx->getProperty("Stop", (Uint32)0) == 1)
9715       {
9716         sync_sub_step(ctx, step, "Stop");
9717         break;
9718       }
9719     }
9720     CHK2(result == NDBT_OK, "pk loop failed");
9721     g_info << "pk ops " << cnt[1] << "/" << cnt[2] << "/" << cnt[3] << endl;
9722   }
9723   if (result != NDBT_OK)
9724   {
9725     g_info << "stop test at line " << __LINE__ << endl;
9726     ctx->stopTest();
9727   }
9728   return result;
9729 }
9730 
9731 int
runBug58277rand(NDBT_Context * ctx,NDBT_Step * step)9732 runBug58277rand(NDBT_Context* ctx, NDBT_Step* step)
9733 {
9734   int result = NDBT_OK;
9735   NdbRestarter restarter;
9736 
9737   while (!ctx->isTestStopped())
9738   {
9739     int sleepms = rand() % 5000;
9740     g_info << "rand sleep " << sleepms << " ms" << endl;
9741     NdbSleep_MilliSleep(sleepms);
9742     if (rand() % 5 == 0)
9743     {
9744       g_info << "rand force LCP" << endl;
9745       int dump1[] = { DumpStateOrd::DihStartLcpImmediately };
9746       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9747     }
9748   }
9749   if (result != NDBT_OK)
9750   {
9751     g_info << "stop test at line " << __LINE__ << endl;
9752     ctx->stopTest();
9753   }
9754   g_info << "rand exit" << endl;
9755   return result;
9756 }
9757 
9758 int
runBug58277(NDBT_Context * ctx,NDBT_Step * step)9759 runBug58277(NDBT_Context* ctx, NDBT_Step* step)
9760 {
9761   Ndb* pNdb = GETNDB(step);
9762   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9763   const int loops = ctx->getNumLoops();
9764   int result = NDBT_OK;
9765   const bool rss_check = ctx->getProperty("RSS_CHECK", (Uint32)0);
9766   NdbRestarter restarter;
9767   const char* tabname = tabName_Bug58277;
9768   const char* indname = indName_Bug58277;
9769   (void)pDic->dropTable(tabname);
9770 
9771   int loop = 0;
9772   while (!ctx->isTestStopped())
9773   {
9774     g_info << "===== loop " << loop << " =====" << endl;
9775 
9776     if (loop == 0)
9777     {
9778       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
9779       CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
9780     }
9781 
9782     if (rss_check)
9783     {
9784       g_info << "save all resource usage" << endl;
9785       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
9786       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9787     }
9788 
9789     CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
9790 
9791     int dropmin = 1000;
9792     int dropmax = 9000;
9793     int dropms = dropmin + rand() % (dropmax - dropmin + 1);
9794     g_info << "drop in " << dropms << " ms" << endl;
9795     ctx->setProperty("DropMs", dropms);
9796 
9797     sync_main_step(ctx, step, "Start");
9798     if (ctx->isTestStopped())
9799       break;
9800 
9801     // vary Stop time a bit in either direction
9802     int stopvar = rand() % 100;
9803     int stopsgn = (rand() % 2 == 0 ? +1 : -1);
9804     int stopms = dropms + stopsgn * stopvar;
9805     NdbSleep_MilliSleep(stopms);
9806 
9807     sync_main_step(ctx, step, "Stop");
9808     if (ctx->isTestStopped())
9809       break;
9810 
9811     // index must have been dropped
9812     pDic->invalidateIndex(indname, tabname);
9813     CHK2(pDic->getIndex(indname, tabname) == 0, "failed");
9814 
9815     if (rss_check)
9816     {
9817       g_info << "check all resource usage" << endl;
9818       int dump2[] = { DumpStateOrd::SchemaResourceCheckLeak };
9819       CHK2(restarter.dumpStateAllNodes(dump2, 1) == 0, "failed");
9820 
9821       g_info << "check cluster is up" << endl;
9822       CHK2(restarter.waitClusterStarted() == 0, "failed");
9823       CHK_NDB_READY(pNdb);
9824     }
9825 
9826     if (++loop == loops)
9827     {
9828       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9829       g_info << "table " << tabname << " dropped" << endl;
9830       break;
9831     }
9832   }
9833 
9834   g_info << "stop test at line " << __LINE__ << endl;
9835   ctx->stopTest();
9836   return result;
9837 }
9838 
9839 int
runBug57057(NDBT_Context * ctx,NDBT_Step * step)9840 runBug57057(NDBT_Context* ctx, NDBT_Step* step)
9841 {
9842   Ndb* pNdb = GETNDB(step);
9843   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9844   const int loops = ctx->getNumLoops();
9845   int result = NDBT_OK;
9846   const bool rss_check = ctx->getProperty("RSS_CHECK", (Uint32)0);
9847   NdbRestarter restarter;
9848   const char* tabname = tabName_Bug58277;
9849   //const char* indname = indName_Bug58277;
9850   (void)pDic->dropTable(tabname);
9851 
9852   int loop = 0;
9853   while (!ctx->isTestStopped())
9854   {
9855     g_info << "===== loop " << loop << " =====" << endl;
9856 
9857     if (loop == 0)
9858     {
9859       CHK2(runBug58277createtable(ctx, step) == NDBT_OK, "create table failed");
9860       CHK2(runBug58277createindex(ctx, step) == NDBT_OK, "create index failed");
9861     }
9862 
9863     CHK2(runBug58277loadtable(ctx, step) == NDBT_OK, "load table failed");
9864 
9865     if (rss_check)
9866     {
9867       g_info << "save all resource usage" << endl;
9868       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
9869       CHK2(restarter.dumpStateAllNodes(dump1, 1) == 0, "failed");
9870     }
9871 
9872     int dropmin = 1000;
9873     int dropmax = 2000;
9874     int dropms = dropmin + rand() % (dropmax - dropmin + 1);
9875     int stopms = dropms;
9876 
9877     sync_main_step(ctx, step, "Start");
9878     if (ctx->isTestStopped())
9879       break;
9880 
9881     g_info << "stop in " << stopms << " ms" << endl;
9882     NdbSleep_MilliSleep(stopms);
9883 
9884     sync_main_step(ctx, step, "Stop");
9885     if (ctx->isTestStopped())
9886       break;
9887 
9888     if (rss_check)
9889     {
9890       g_info << "check all resource usage" << endl;
9891       int dump2[] = { DumpStateOrd::SchemaResourceCheckLeak };
9892       CHK2(restarter.dumpStateAllNodes(dump2, 1) == 0, "failed");
9893 
9894       g_info << "check cluster is up" << endl;
9895       CHK2(restarter.waitClusterStarted() == 0, "failed");
9896       CHK_NDB_READY(pNdb);
9897     }
9898 
9899     if (++loop == loops)
9900     {
9901       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
9902       g_info << "table " << tabname << " dropped" << endl;
9903       break;
9904     }
9905   }
9906 
9907   g_info << "stop test at line " << __LINE__ << endl;
9908   ctx->stopTest();
9909   return result;
9910 }
9911 
9912 /**
9913  * This is a regression test for Bug #14647210 "CAN CRASH ALL NODES EASILY
9914  * WHEN RESTARTING MORE THAN 6 NODES SIMULTANEOUSLY". The cause of this bug
9915  * was that DICT did not handle GET_TABINFOREF signals.
9916  */
9917 static int
runGetTabInfoRef(NDBT_Context * ctx,NDBT_Step * step)9918 runGetTabInfoRef(NDBT_Context* ctx, NDBT_Step* step)
9919 {
9920   NdbRestarter restarter;
9921   if (restarter.getNumDbNodes() == 1)
9922   {
9923     g_info << "Cannot do this test with just one datanode." << endl;
9924     return NDBT_OK;
9925   }
9926 
9927   /**
9928    * This error insert makes DICT respond with GET_TABINFOREF where
9929    * error==busy when receiving the next GET_TABINFOREQ signal.
9930    */
9931   restarter.insertErrorInAllNodes(6026);
9932 
9933   /* Find a node in each nodegroup to restart. */
9934   Vector<int> nodeSet;
9935   Bitmask<MAX_NDB_NODES/32> nodeGroupMap;
9936   for (int i = 0; i < restarter.getNumDbNodes(); i++)
9937   {
9938     const int node = restarter.getDbNodeId(i);
9939     const int ng = restarter.getNodeGroup(node);
9940     if (!nodeGroupMap.get(ng))
9941     {
9942       g_info << "Node " << node << " will be stopped." << endl;
9943       nodeSet.push_back(node);
9944       nodeGroupMap.set(ng);
9945     }
9946   }
9947 
9948   if (restarter.restartNodes(nodeSet.getBase(), (int)nodeSet.size(),
9949                              NdbRestarter::NRRF_NOSTART |
9950                              NdbRestarter::NRRF_ABORT))
9951   {
9952     g_err << "Failed to stop nodes" << endl;
9953     restarter.insertErrorInAllNodes(0);
9954     return NDBT_FAILED;
9955   }
9956 
9957   g_info << "Waiting for nodes to stop." << endl;
9958   if (restarter.waitNodesNoStart(nodeSet.getBase(), (int)nodeSet.size()))
9959   {
9960     g_err << "Failed to wait for nodes to stop" << endl;
9961     restarter.insertErrorInAllNodes(0);
9962     return NDBT_FAILED;
9963   }
9964 
9965   if (restarter.startNodes(nodeSet.getBase(), (int)nodeSet.size()))
9966   {
9967     g_err << "Failed to restart nodes" << endl;
9968     restarter.insertErrorInAllNodes(0);
9969     return NDBT_FAILED;
9970   }
9971 
9972   g_info << "Waiting for nodes to start again." << endl;
9973   if (restarter.waitClusterStarted() != 0)
9974   {
9975     g_err << "Failed to restart cluster " << endl;
9976     restarter.insertErrorInAllNodes(0);
9977     return NDBT_FAILED;
9978   }
9979 
9980   restarter.insertErrorInAllNodes(0);
9981   return NDBT_OK;
9982 } // runGetTabInfoRef()
9983 
9984 int
runBug13416603(NDBT_Context * ctx,NDBT_Step * step)9985 runBug13416603(NDBT_Context* ctx, NDBT_Step* step)
9986 {
9987   Ndb* pNdb = GETNDB(step);
9988   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
9989   NdbIndexStat is;
9990   NdbRestarter res;
9991 
9992   int elist[] = { 18026, 0 };
9993   const NdbDictionary::Table *pTab = pDic->getTable(ctx->getTab()->getName());
9994   const NdbDictionary::Index *pIdx = 0;
9995   NdbDictionary::Dictionary::List indexes;
9996   pDic->listIndexes(indexes, * pTab);
9997   for (unsigned i = 0; i < indexes.count; i++)
9998   {
9999     if ((pIdx = pDic->getIndex(indexes.elements[i].name, pTab->getName())) != 0)
10000       break;
10001   }
10002 
10003   if (pIdx == 0)
10004   {
10005     // Exit if there aren't any indexes in the table
10006     return NDBT_OK;
10007   }
10008 
10009   bool has_created_stat_tables = false;
10010   bool has_created_stat_events = false;
10011   pNdb->setDatabaseName("mysql");
10012   if (is.create_systables(pNdb) == 0)
10013   {
10014     has_created_stat_tables = true;
10015   }
10016 
10017   if (is.create_sysevents(pNdb) == 0)
10018   {
10019     has_created_stat_events = true;
10020   }
10021 
10022   chk2(is.create_listener(pNdb) == 0, is.getNdbError());
10023   chk2(is.execute_listener(pNdb) == 0, is.getNdbError());
10024 
10025   is.set_index(* pIdx, * pTab);
10026 
10027   {
10028     ndbout_c("%u - update_stat", __LINE__);
10029     chk2(is.update_stat(pNdb) == 0, is.getNdbError());
10030     int ret;
10031     ndbout_c("%u - poll_listener", __LINE__);
10032     chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
10033     chk1(ret == 1);
10034     // one event is expected
10035     ndbout_c("%u - next_listener", __LINE__);
10036     chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
10037     chk1(ret == 1);
10038     ndbout_c("%u - next_listener", __LINE__);
10039     chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
10040     chk1(ret == 0);
10041   }
10042 
10043   {
10044     Vector<Vector<int> > partitions = res.splitNodes();
10045     if (partitions.size() == 1)
10046       goto cleanup;
10047 
10048     for (unsigned i = 0; i < partitions.size(); i++)
10049     {
10050       printf("stopping: ");
10051       for (unsigned j = 0; j < partitions[i].size(); j++)
10052         printf("%d ", partitions[i][j]);
10053       printf("\n");
10054 
10055       res.restartNodes(partitions[i].getBase(),
10056                        partitions[i].size(),
10057                        NdbRestarter::NRRF_NOSTART | NdbRestarter::NRRF_ABORT);
10058       res.waitNodesNoStart(partitions[i].getBase(),
10059                            partitions[i].size());
10060 
10061       {
10062         ndbout_c("%u - update_stat", __LINE__);
10063         chk2(is.update_stat(pNdb) == 0, is.getNdbError());
10064         int ret;
10065         ndbout_c("%u - poll_listener", __LINE__);
10066         chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
10067         chk1(ret == 1);
10068         // one event is expected
10069         ndbout_c("%u - next_listener", __LINE__);
10070         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
10071         chk1(ret == 1);
10072         ndbout_c("%u - next_listener", __LINE__);
10073         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
10074         chk1(ret == 0);
10075       }
10076 
10077       res.startNodes(partitions[i].getBase(),
10078                      partitions[i].size());
10079       res.waitClusterStarted();
10080       CHK_NDB_READY(pNdb);
10081     }
10082   }
10083 
10084   for (int i = 0; elist[i] != 0; i++)
10085   {
10086     ndbout_c("testing errno: %u", elist[i]);
10087     res.insertErrorInAllNodes(elist[i]);
10088     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
10089     res.dumpStateAllNodes(val2, 2);
10090 
10091     {
10092       ndbout_c("%u - update_stat", __LINE__);
10093       int ret = is.update_stat(pNdb);
10094       ndbout_c("%u - update_stat => %d", __LINE__, ret);
10095       chk1(ret == -1);
10096       ndbout << is.getNdbError() << endl;
10097       ndbout_c("%u - poll_listener", __LINE__);
10098       chk2((ret = is.poll_listener(pNdb, 10000)) != -1, is.getNdbError());
10099       if (ret == 1)
10100       {
10101         /* After the new api is introduced, pollEvents() (old api version)
10102          * returns 1 when empty epoch is at the head of the event queue.
10103          * pollEvents2() (new api version) returns 1 when exceptional
10104          * epoch is at the head of the event queue.
10105          * So next_listener() must be called to handle them.
10106          */
10107         chk2((ret = is.next_listener(pNdb)) != -1, is.getNdbError());
10108       }
10109       // Check that the event queue is empty
10110       chk1(ret == 0);
10111     }
10112 
10113     /**
10114      * Wait for one of the nodes to have died...
10115      */
10116     int count_started = 0;
10117     int count_not_started = 0;
10118     int count_nok = 0;
10119     int down = 0;
10120     do
10121     {
10122       NdbSleep_MilliSleep(100);
10123       count_started = count_not_started = count_nok = 0;
10124       for (int i = 0; i < res.getNumDbNodes(); i++)
10125       {
10126         int n = res.getDbNodeId(i);
10127         if (res.getNodeStatus(n) == NDB_MGM_NODE_STATUS_NOT_STARTED)
10128         {
10129           count_not_started++;
10130           down = n;
10131         }
10132         else if (res.getNodeStatus(n) == NDB_MGM_NODE_STATUS_STARTED)
10133           count_started++;
10134         else
10135           count_nok ++;
10136       }
10137     } while (count_not_started != 1);
10138 
10139     res.startNodes(&down, 1);
10140     res.waitClusterStarted();
10141     CHK_NDB_READY(pNdb);
10142     res.insertErrorInAllNodes(0);
10143   }
10144 
10145 cleanup:
10146   // cleanup
10147   is.drop_listener(pNdb);
10148   if (has_created_stat_events)
10149   {
10150     is.drop_sysevents(pNdb);
10151   }
10152   if (has_created_stat_tables)
10153   {
10154     is.drop_systables(pNdb);
10155   }
10156 
10157   // Ensure that nodes will start after error inserts again.
10158   {
10159     const int restartState[] =
10160       { DumpStateOrd::CmvmiSetRestartOnErrorInsert, NRT_DoStart_Restart };
10161 
10162     require(res.dumpStateAllNodes(restartState,
10163                                   sizeof restartState/sizeof restartState[0])
10164             == 0);
10165   }
10166 
10167   return NDBT_OK;
10168 
10169 err:
10170   return NDBT_FAILED;
10171 }
10172 
10173 int
runIndexStatCreate(NDBT_Context * ctx,NDBT_Step * step)10174 runIndexStatCreate(NDBT_Context* ctx, NDBT_Step* step)
10175 {
10176   Ndb* pNdb = GETNDB(step);
10177   NdbIndexStat is;
10178 
10179   const int loops = ctx->getNumLoops();
10180 
10181   pNdb->setDatabaseName("mysql");
10182 
10183   Uint64 end = NdbTick_CurrentMillisecond() + 1000 * loops;
10184   do
10185   {
10186     if (is.create_systables(pNdb) == 0)
10187     {
10188       /**
10189        * OK
10190        */
10191     }
10192     else if (! (is.getNdbError().code == 701  || // timeout
10193                 is.getNdbError().code == 721  || // already exists
10194                 is.getNdbError().code == 4244 || // already exists
10195                 is.getNdbError().code == 4009))  // no connection
10196     {
10197       ndbout << is.getNdbError() << endl;
10198       return NDBT_FAILED;
10199     }
10200 
10201     is.drop_systables(pNdb);
10202   } while (!ctx->isTestStopped() && NdbTick_CurrentMillisecond() < end);
10203 
10204   return NDBT_OK;
10205 }
10206 
10207 int
runWL946(NDBT_Context * ctx,NDBT_Step * step)10208 runWL946(NDBT_Context* ctx, NDBT_Step* step)
10209 {
10210   Ndb* pNdb = GETNDB(step);
10211   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10212   const int loops = ctx->getNumLoops();
10213   const int records = ctx->getNumRecords();
10214   bool keep_table = false; // keep table and data
10215 #ifdef VM_TRACE
10216 #ifdef NDB_USE_GET_ENV
10217   {
10218     const char* p = NdbEnv_GetEnv("KEEP_TABLE_WL946", (char*)0, 0);
10219     if (p != 0 && strchr("1Y", p[0]) != 0)
10220       keep_table = true;
10221   }
10222 #endif
10223 #endif
10224   int result = NDBT_OK;
10225 
10226   const char* tabname = "T_WL946";
10227   (void)pDic->dropTable(tabname);
10228 
10229   for (int loop = 0; loop < loops; loop++)
10230   {
10231     g_info << "loop " << loop << "(" << loops << ")" << endl;
10232 
10233     NdbDictionary::Table tab;
10234     tab.setName(tabname);
10235 
10236     struct Coldef {
10237       const char* name;
10238       NdbDictionary::Column::Type type;
10239       int prec; // fractional precision 0-6
10240       int flag; // 1-pk 2-nullable 4-fractional 8-create index
10241       const char* indname;
10242     } coldef[] = {
10243       // primary key
10244       { "pk", NdbDictionary::Column::Unsigned, 0, 1, 0 },
10245       // deprecated
10246       { "a0", NdbDictionary::Column::Time, 0, 2|8, "x0" },
10247       { "a1", NdbDictionary::Column::Datetime, 0, 2|8, "x1" },
10248       { "a2", NdbDictionary::Column::Timestamp, 0, 2|8, "x2" },
10249       // fractional
10250       { "b0", NdbDictionary::Column::Time2, 0, 2|4|8, "y0" },
10251       { "b1", NdbDictionary::Column::Datetime2, 0, 2|4|8, "y1" },
10252       { "b2", NdbDictionary::Column::Timestamp2, 0, 2|4|8, "y2" },
10253       // update key
10254       { "uk", NdbDictionary::Column::Unsigned, 0, 0, 0 }
10255     };
10256     const int Colcnt = sizeof(coldef)/sizeof(coldef[0]);
10257 
10258     NdbDictionary::Column col[Colcnt];
10259     for (int i = 0; i < Colcnt; i++)
10260     {
10261       Coldef& d = coldef[i];
10262       NdbDictionary::Column& c = col[i];
10263       c.setName(d.name);
10264       c.setType(d.type);
10265       if (d.flag & 4)
10266       {
10267         d.prec = myRandom48(7);
10268         require(d.prec >= 0 && d.prec <= 6);
10269         c.setPrecision(d.prec);
10270       }
10271       c.setPrimaryKey(d.flag & 1);
10272       c.setNullable(d.flag & 2);
10273       tab.addColumn(c);
10274     }
10275 
10276     g_info << "create table " << tabname << endl;
10277     const NdbDictionary::Table* pTab = 0;
10278     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
10279     CHK2((pTab = pDic->getTable(tabname)) != 0, pDic->getNdbError());
10280 
10281     const NdbDictionary::Column* pCol[Colcnt];
10282     for (int i = 0; i < Colcnt; i++)
10283     {
10284       const Coldef& d = coldef[i];
10285       const NdbDictionary::Column* pc = 0;
10286       CHK2((pc = tab.getColumn(i)) != 0, pDic->getNdbError());
10287       CHK2(strcmp(pc->getName(), d.name) == 0, "name");
10288       CHK2(pc->getType() == d.type, "type");
10289       CHK2(pc->getPrecision() == d.prec, "prec");
10290       pCol[i] = pc;
10291     }
10292     CHK2(result == NDBT_OK, "verify columns");
10293 
10294     g_info << "create indexes" << endl;
10295     NdbDictionary::Index ind[Colcnt];
10296     const NdbDictionary::Index* pInd[Colcnt];
10297     for (int i = 0; i < Colcnt; i++)
10298     {
10299       Coldef& d = coldef[i];
10300       pInd[i] = 0;
10301       if (d.flag & 8)
10302       {
10303         NdbDictionary::Index& x = ind[i];
10304         x.setName(d.indname);
10305         x.setTable(tabname);
10306         x.setType(NdbDictionary::Index::OrderedIndex);
10307         x.setLogging(false);
10308         x.addColumn(d.name);
10309         const NdbDictionary::Index* px = 0;
10310         CHK2(pDic->createIndex(x) == 0, pDic->getNdbError());
10311         CHK2((px = pDic->getIndex(d.indname, tabname)) != 0, pDic->getNdbError());
10312         pInd[i] = px;
10313       }
10314     }
10315     CHK2(result == NDBT_OK, "create indexes");
10316 
10317     HugoTransactions trans(*pTab);
10318 
10319     g_info << "load records" << endl;
10320     CHK2(trans.loadTable(pNdb, records) == 0, trans.getNdbError());
10321 
10322     const int scanloops = 5;
10323     for (int j = 0; j < scanloops; j++)
10324     {
10325       g_info << "scan table " << j << "(" << scanloops << ")" << endl;
10326       CHK2(trans.scanReadRecords(pNdb, records) == 0, trans.getNdbError());
10327 
10328       for (int i = 0; i < Colcnt; i++)
10329       {
10330         Coldef& d = coldef[i];
10331         if (d.flag & 8)
10332         {
10333           g_info << "scan index " << d.indname << endl;
10334           const NdbDictionary::Index* px = pInd[i];
10335           CHK2(trans.scanReadRecords(pNdb, px, records) == 0, trans.getNdbError());
10336         }
10337       }
10338       CHK2(result == NDBT_OK, "index scan");
10339 
10340       g_info << "update records" << endl;
10341       CHK2(trans.scanUpdateRecords(pNdb, records) == 0, trans.getNdbError());
10342     }
10343     CHK2(result == NDBT_OK, "scans");
10344 
10345     if (loop + 1 < loops || !keep_table)
10346     {
10347       g_info << "delete records" << endl;
10348       CHK2(trans.clearTable(pNdb) == 0, trans.getNdbError());
10349 
10350       g_info << "drop table" << endl;
10351       CHK2(pDic->dropTable(tabname) == 0, pDic->getNdbError());
10352     }
10353   }
10354 
10355   if (result != NDBT_OK && !keep_table)
10356   {
10357     g_info << "drop table after error" << endl;
10358     (void)pDic->dropTable(tabname);
10359   }
10360   return result;
10361 }
10362 
10363 int
getOrCreateDefaultHashMap(NdbDictionary::Dictionary & dict,NdbDictionary::HashMap & hm,Uint32 buckets,Uint32 fragments)10364 getOrCreateDefaultHashMap(NdbDictionary::Dictionary& dict, NdbDictionary::HashMap& hm, Uint32 buckets, Uint32 fragments)
10365 {
10366   if (dict.getDefaultHashMap(hm, buckets, fragments) == 0)
10367   {
10368     return 0;
10369   }
10370 
10371   dict.initDefaultHashMap(hm, buckets, fragments);
10372   if (dict.createHashMap(hm, NULL) == -1)
10373   {
10374     return -1;
10375   }
10376 
10377   if (dict.getDefaultHashMap(hm, buckets, fragments) == 0)
10378   {
10379     return 0;
10380   }
10381 
10382   return -1;
10383 }
10384 
10385 struct Bug14645319_createTable_args
10386 {
10387   char const* template_name;
10388   char const* name;
10389   Uint32 buckets;
10390   Uint32 fragments;
10391 };
10392 
Bug14645319_createTable(Ndb * pNdb,NdbDictionary::Table & tab,int when,void * arg)10393 int Bug14645319_createTable(Ndb* pNdb, NdbDictionary::Table& tab, int when,
10394                                     void* arg)
10395 {
10396   Bug14645319_createTable_args& args = *static_cast<Bug14645319_createTable_args*>(arg);
10397   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10398   if (when == 0)
10399   {
10400     tab.setName(args.name);
10401     tab.setFragmentCount(args.fragments);
10402     if (args.fragments == 0)
10403     {
10404       tab.setFragmentData(0, 0);
10405     }
10406     NdbDictionary::HashMap hm;
10407     getOrCreateDefaultHashMap(*pDic, hm, args.buckets, args.fragments);
10408     tab.setHashMap(hm);
10409   }
10410   return 0;
10411 }
10412 
10413 int
runBug14645319(NDBT_Context * ctx,NDBT_Step * step)10414 runBug14645319(NDBT_Context* ctx, NDBT_Step* step)
10415 {
10416   Ndb* pNdb = GETNDB(step);
10417   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10418   int failures = 0;
10419 
10420   struct test_case {
10421     char const* description;
10422     int old_fragments;
10423     int old_buckets;
10424     int new_fragments;
10425     int new_buckets;
10426     int expected_buckets;
10427   };
10428 
10429   STATIC_ASSERT(NDB_DEFAULT_HASHMAP_BUCKETS % 240 == 0);
10430   STATIC_ASSERT(NDB_DEFAULT_HASHMAP_BUCKETS % 260 != 0);
10431   test_case test_cases[] = {
10432     { "Simulate online reorg, may or may not change hashmap depending on default fragment count",
10433       3, 120, 0, NDB_DEFAULT_HASHMAP_BUCKETS, 0 },
10434     { "Keep old hashmap since no new fragments",
10435       3, 120, 3, NDB_DEFAULT_HASHMAP_BUCKETS, 120 },
10436     { "Keep old hashmap size since old size a multiple of new fragment count",
10437       3, 120, 6, NDB_DEFAULT_HASHMAP_BUCKETS, 120 },
10438     { "Keep old hashmap size since new size not a multiple of old",
10439       3, 130, 6, NDB_DEFAULT_HASHMAP_BUCKETS, 130 },
10440     { "Extend hashmap",
10441       3, 120, 7, NDB_DEFAULT_HASHMAP_BUCKETS, NDB_DEFAULT_HASHMAP_BUCKETS },
10442     { "Keep old hashmap size since old size not multiple of old fragment count",
10443       5, 84, 7, 42, 84 },
10444     { "Shrink hashmap",
10445       3, 120, 6, 60, 60 },
10446   };
10447 
10448   Bug14645319_createTable_args args;
10449   args.template_name = ctx->getTab()->getName();
10450   args.name = "Bug14645319";
10451 
10452   for (size_t testi = 0; testi < NDB_ARRAY_SIZE(test_cases); testi++)
10453   {
10454     test_case const& test = test_cases[testi];
10455     int result = NDBT_FAILED;
10456 
10457     int old_fragments = 0;
10458     int old_buckets = 0;
10459     int new_fragments = 0;
10460     int new_buckets = 0;
10461 
10462     do {
10463       /* setup old table */
10464       args.buckets = test.old_buckets;
10465       args.fragments = test.old_fragments;
10466       result = NDBT_Tables::createTable(pNdb, args.template_name, false, false, Bug14645319_createTable, &args);
10467       if (result != 0) break;
10468 
10469       NdbDictionary::Table const& old_tab = *pDic->getTable(args.name);
10470 
10471       /* check old table properties */
10472       NdbDictionary::HashMap old_hm;
10473       result = pDic->getHashMap(old_hm, &old_tab);
10474       if (result != 0) break;
10475 
10476       old_fragments = old_tab.getFragmentCount();
10477       old_buckets = old_hm.getMapLen();
10478       if (old_fragments != test.old_fragments)
10479       {
10480         result = NDBT_FAILED;
10481         break;
10482       }
10483       if (old_buckets != test.old_buckets)
10484       {
10485         result = NDBT_FAILED;
10486         break;
10487       }
10488 
10489       /* alter table */
10490       NdbDictionary::Table new_tab = old_tab;
10491       new_tab.setFragmentCount(test.new_fragments);
10492       if (test.new_fragments == 0)
10493       {
10494         new_tab.setFragmentData(0, 0);
10495       }
10496       else
10497       {
10498         new_tab.setPartitionBalance(
10499           NdbDictionary::Object::PartitionBalance_Specific);
10500       }
10501 
10502       result = pDic->beginSchemaTrans();
10503       if (result != 0) break;
10504 
10505       result = pDic->prepareHashMap(old_tab, new_tab, test.new_buckets);
10506 
10507       result |= pDic->endSchemaTrans();
10508       if (result != 0) break;
10509 
10510       result = pDic->alterTable(old_tab, new_tab);
10511       if (result != 0) break;
10512 
10513       /* check */
10514       NdbDictionary::HashMap new_hm;
10515       result = pDic->getHashMap(new_hm, &new_tab);
10516       if (result != 0) break;
10517 
10518       new_fragments = new_tab.getFragmentCount();
10519       new_buckets = new_hm.getMapLen();
10520 
10521       if (test.expected_buckets > 0 &&
10522           new_buckets != test.expected_buckets)
10523       {
10524         result = NDBT_FAILED;
10525         break;
10526       }
10527       result = 0;
10528     } while (false);
10529 
10530     result |= pDic->dropTable(args.name);
10531 
10532     if (result == 0)
10533     {
10534       ndbout << "Test#" << (testi + 1) << " '" << test_cases[testi].description << "' passed" <<
10535         " (" << old_buckets << " => " << test_cases[testi].new_buckets << " => " << test_cases[testi].expected_buckets << ")" << endl;
10536     }
10537     else
10538     {
10539       ndbout << "Test#" << (testi + 1) << " '" << test_cases[testi].description << "' failed" <<
10540         " (" << old_buckets << " => " << test_cases[testi].new_buckets << " => " << new_buckets << " expected: " << test_cases[testi].expected_buckets << ")" << endl;
10541       failures++;
10542     }
10543   }
10544 
10545   return failures > 0 ? NDBT_FAILED : NDBT_OK;
10546 }
10547 
10548 // FK SR/NR
10549 
10550 #define CHK1(b) CHK2(b, "-");
10551 
10552 // myRandom48 seems too non-random
10553 #define myRandom48(x) (unsigned(ndb_rand()) % (x))
10554 #define myRandom48Init(x) (ndb_srand(x))
10555 
10556 // used for create and verify
10557 struct Fkdef {
10558   static const int tabmax = 5;
10559   static const int colmax = 5;
10560   static const int indmax = 5;
10561   static const int keymax = tabmax * 5;
10562   static const int strmax = 10;
10563   struct Ob {
10564     bool retrieved;
10565     int id;
10566     int version;
10567   };
10568   struct Col {
10569     char colname[strmax];
10570     bool pk;
10571     bool nullable; // false
10572     int icol; // pos in table columns
10573   };
10574   struct Ind : Ob {
10575     char indname[strmax];
10576     Col col[colmax];
10577     int ncol;
10578     bool pk;
10579     bool unique;
10580     const NdbDictionary::Index* pInd;
10581   };
10582   struct Tab : Ob {
10583     char tabname[strmax];
10584     Col col[colmax];
10585     int ncol;
10586     Ind ind[indmax]; // first "index" is primary key
10587     int nind;
10588     const NdbDictionary::Table* pTab;
10589   };
10590   struct Key : Ob {
10591     char keyname[strmax];
10592     char fullname[20 + strmax]; // bug#19122346
10593     // 0-parent 1-child
10594     const Tab* tab0;
10595     const Tab* tab1;
10596     const Ind* ind0;
10597     const Ind* ind1;
10598     NdbDictionary::ForeignKey::FkAction updateAction;
10599     NdbDictionary::ForeignKey::FkAction deleteAction;
10600   };
10601   struct List {
10602     NdbDictionary::Dictionary::List* list;
10603     int keystart; // FK stuff sorted to end of list starts here
ListFkdef::List10604     List() { list = 0; }
~ListFkdef::List10605     ~List() { delete list; }
10606   };
10607   Tab tab[tabmax];
10608   int ntab;
10609   Key key[keymax];
10610   int nkey;
10611   List list;
10612   bool nokeys;
10613   bool nodrop;
10614   int testcase;
10615 };
10616 
10617 static int
fk_compare_icol(const void * p1,const void * p2)10618 fk_compare_icol(const void* p1, const void* p2)
10619 {
10620   const Fkdef::Col& col1 = *(const Fkdef::Col*)p1;
10621   const Fkdef::Col& col2 = *(const Fkdef::Col*)p2;
10622   return col1.icol - col2.icol;
10623 }
10624 
10625 static int
fk_type(int t)10626 fk_type(int t)
10627 {
10628   if (
10629     t ==  NdbDictionary::Object::ForeignKey ||
10630     t ==  NdbDictionary::Object::FKParentTrigger ||
10631     t ==  NdbDictionary::Object::FKChildTrigger
10632   )
10633     return 1;
10634   return 0;
10635 }
10636 
10637 static int
fk_compare_element(const void * p1,const void * p2)10638 fk_compare_element(const void* p1, const void* p2)
10639 {
10640   const NdbDictionary::Dictionary::List::Element& e1 =
10641     *(const NdbDictionary::Dictionary::List::Element*)p1;
10642   const NdbDictionary::Dictionary::List::Element& e2 =
10643     *(const NdbDictionary::Dictionary::List::Element*)p2;
10644   int k = 0;
10645   if ((k = fk_type(e1.type) - fk_type(e2.type)) != 0)
10646     return k;
10647   if ((k = e1.type - e2.type) != 0)
10648     return k;
10649   if ((k = (int)e1.id - (int)e2.id) != 0)
10650     return k;
10651   return 0;
10652 }
10653 
10654 static bool
fk_find_element(const Fkdef::List & list,int type,const char * database,const char * name)10655 fk_find_element(const Fkdef::List& list, int type,
10656                 const char* database, const char* name)
10657 {
10658   int found = 0;
10659   for (int i = 0; i < (int)list.list->count; i++)
10660   {
10661     const NdbDictionary::Dictionary::List::Element& e =
10662       list.list->elements[i];
10663     if (e.type == type &&
10664         strcmp(e.database, database) == 0 &&
10665         strcmp(e.name, name) == 0)
10666     {
10667       found++;
10668     }
10669   }
10670   require(found == 0 || found == 1);
10671   return found;
10672 }
10673 
10674 // testcase 1: t0 (a0 pk, b0 key), t1 (a1 pk, b1 key), fk b1->a0
10675 
10676 static void
fk_define_tables1(Fkdef & d)10677 fk_define_tables1(Fkdef& d)
10678 {
10679   d.ntab = 2;
10680   for (int i = 0; i < d.ntab; i++)
10681   {
10682     Fkdef::Tab& dt = d.tab[i];
10683     sprintf(dt.tabname, "t%d", i);
10684     dt.ncol = 2;
10685     for (int j = 0; j < dt.ncol; j++)
10686     {
10687       Fkdef::Col& dc = dt.col[j];
10688       sprintf(dc.colname, "%c%d", 'a' + j, i);
10689       dc.pk = (j == 0);
10690       dc.nullable = false;
10691       dc.icol = j;
10692     }
10693     dt.nind = 2;
10694     dt.pTab = 0;
10695     dt.retrieved = false;
10696     {
10697       Fkdef::Ind& di = dt.ind[0];
10698       sprintf(di.indname, "%s", "pk");
10699       di.ncol = 1;
10700       di.col[0] = dt.col[0];
10701       di.pk = true;
10702       di.unique = true;
10703       di.pInd = 0;
10704       di.retrieved = false;
10705     }
10706     {
10707       Fkdef::Ind& di = dt.ind[1];
10708       sprintf(di.indname, "t%dx%d", i, 1);
10709       di.ncol = 1;
10710       di.col[0] = dt.col[1];
10711       di.pk = false;
10712       di.unique = false;
10713       di.pInd = 0;
10714       di.retrieved = false;
10715     }
10716   }
10717   g_info << "defined " << d.ntab << " tables" << endl;
10718 }
10719 
10720 static void
fk_define_keys1(Fkdef & d)10721 fk_define_keys1(Fkdef& d)
10722 {
10723   d.nkey = 1;
10724   Fkdef::Key& dk = d.key[0];
10725   sprintf(dk.keyname, "fk%d", 0);
10726   dk.tab0 = &d.tab[0];
10727   dk.tab1 = &d.tab[1];
10728   dk.ind0 = &dk.tab0->ind[0];
10729   dk.ind1 = &dk.tab1->ind[1];
10730   dk.updateAction = NdbDictionary::ForeignKey::NoAction;
10731   dk.deleteAction = NdbDictionary::ForeignKey::NoAction;
10732   dk.retrieved = false;
10733   g_info << "defined " << d.nkey << " keys" << endl;
10734 }
10735 
10736 // testcase 2: random
10737 
10738 static void
fk_define_tables2(Fkdef & d)10739 fk_define_tables2(Fkdef& d)
10740 {
10741   d.ntab = 1 + myRandom48(d.tabmax);
10742   for (int i = 0; i < d.ntab; i++)
10743   {
10744     Fkdef::Tab& dt = d.tab[i];
10745     sprintf(dt.tabname, "t%d", i);
10746     dt.ncol = 2 + myRandom48(d.colmax - 1);
10747     for (int j = 0; j < dt.ncol; j++)
10748     {
10749       Fkdef::Col& dc = dt.col[j];
10750       sprintf(dc.colname, "%c%d", 'a' + j, i);
10751       dc.pk = (j == 0 || myRandom48(d.colmax) == 0);
10752       dc.nullable = false;
10753       dc.icol = j;
10754     }
10755     dt.nind = 1 + myRandom48(d.indmax);
10756     dt.pTab = 0;
10757     dt.retrieved = false;
10758     for (int k = 0; k < dt.nind; k++)
10759     {
10760       Fkdef::Ind& di = dt.ind[k];
10761       if (k == 0)
10762       {
10763         sprintf(di.indname, "%s", "pk");
10764         di.ncol = 0;
10765         for (int j = 0; j < dt.ncol; j++)
10766         {
10767           Fkdef::Col& dc = dt.col[j];
10768           if (dc.pk)
10769             di.col[di.ncol++] = dc;
10770         }
10771         di.pk = true;
10772         di.unique = true;
10773       }
10774       else
10775       {
10776         di.unique = (myRandom48(3) != 0);
10777         sprintf(di.indname, "t%dx%d", i, k);
10778         di.ncol = 1 + myRandom48(dt.ncol);
10779         uint mask = 0;
10780         int n = 0;
10781         while (n < di.ncol)
10782         {
10783           int j = myRandom48(dt.ncol);
10784           Fkdef::Col& dc = dt.col[j];
10785           if ((mask & (1 << j)) == 0)
10786           {
10787             di.col[n++] = dc;
10788             mask |= (1 << j);
10789           }
10790         }
10791         if (di.unique)
10792           qsort(&di.col, di.ncol, sizeof(di.col[0]), fk_compare_icol);
10793       }
10794       di.pInd = 0;
10795       di.retrieved = false;
10796     }
10797   }
10798   g_info << "defined " << d.ntab << " tables" << endl;
10799 }
10800 
10801 static void
fk_define_keys2(Fkdef & d)10802 fk_define_keys2(Fkdef& d)
10803 {
10804   int nkey = 1 + myRandom48(d.ntab * 5);
10805   int k = 0;
10806   int ntrymax = nkey * 100;
10807   int ntry = 0;
10808   while (k < nkey && ntry++ < ntrymax)
10809   {
10810     Fkdef::Key& dk = d.key[k];
10811     new (&dk) Fkdef::Key;
10812     int i0 = myRandom48(d.ntab);
10813     int i1 = myRandom48(d.ntab);
10814     Fkdef::Tab& dt0 = d.tab[i0];
10815     Fkdef::Tab& dt1 = d.tab[i1];
10816     int k0 = myRandom48(dt0.nind);
10817     int k1 = myRandom48(dt1.nind);
10818     Fkdef::Ind& di0 = dt0.ind[k0];
10819     Fkdef::Ind& di1 = dt1.ind[k1];
10820     if (!di0.unique || di0.ncol != di1.ncol)
10821       continue;
10822     if (i0 == i1 && k0 == k1)
10823       if (myRandom48(10) != 0) // allowed but try to avoid
10824         continue;
10825     sprintf(dk.keyname, "fk%d", k);
10826     dk.tab0 = &dt0;
10827     dk.tab1 = &dt1;
10828     dk.ind0 = &di0;
10829     dk.ind1 = &di1;
10830     dk.updateAction = NdbDictionary::ForeignKey::NoAction;
10831     dk.deleteAction = NdbDictionary::ForeignKey::NoAction;
10832     dk.retrieved = false;
10833     k++;
10834   }
10835   d.nkey = k;
10836   g_info << "defined " << d.nkey << " keys tries:" << ntry << endl;
10837 }
10838 
10839 static void
fk_define_tables(Fkdef & d)10840 fk_define_tables(Fkdef& d)
10841 {
10842   if (d.testcase == 1)
10843     fk_define_tables1(d);
10844   else if (d.testcase == 2)
10845     fk_define_tables2(d);
10846   else
10847     require(false);
10848 }
10849 
10850 static void
fk_define_keys(Fkdef & d)10851 fk_define_keys(Fkdef& d)
10852 {
10853   if (d.nokeys)
10854   {
10855     d.nkey = 0;
10856     return;
10857   }
10858   if (d.testcase == 1)
10859     fk_define_keys1(d);
10860   else if (d.testcase == 2)
10861     fk_define_keys2(d);
10862   else
10863     require(false);
10864 }
10865 
10866 static void
fk_undefine_keys(Fkdef & d)10867 fk_undefine_keys(Fkdef& d)
10868 {
10869   d.nkey = 0;
10870 }
10871 
10872 static void
fk_define_all(Fkdef & d)10873 fk_define_all(Fkdef& d)
10874 {
10875   fk_define_tables(d);
10876   fk_define_keys(d);
10877 }
10878 
10879 static int
fk_create_table(Fkdef & d,Ndb * pNdb,int i)10880 fk_create_table(Fkdef& d, Ndb* pNdb, int i)
10881 {
10882   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10883   int result = NDBT_OK;
10884   do
10885   {
10886     Fkdef::Tab& dt = d.tab[i];
10887     NdbDictionary::Table tab;
10888     tab.setName(dt.tabname);
10889     for (int j = 0; j < dt.ncol; j++)
10890     {
10891       Fkdef::Col& dc = dt.col[j];
10892       NdbDictionary::Column col;
10893       col.setName(dc.colname);
10894       col.setType(NdbDictionary::Column::Unsigned);
10895       col.setPrimaryKey(dc.pk);
10896       col.setNullable(dc.nullable);
10897       tab.addColumn(col);
10898     }
10899     g_info << "create table " << dt.tabname << endl;
10900     CHK2(pDic->createTable(tab) == 0, pDic->getNdbError());
10901     const NdbDictionary::Table* pTab = 0;
10902     CHK2((pTab = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
10903     require(!dt.retrieved);
10904     dt.retrieved = true;
10905     dt.id = pTab->getObjectId();
10906     dt.version = pTab->getObjectVersion();
10907     dt.pTab = pTab;
10908     for (int k = 1; k < dt.nind; k++) // skip pk
10909     {
10910       Fkdef::Ind& di = dt.ind[k];
10911       NdbDictionary::Index ind;
10912       ind.setName(di.indname);
10913       ind.setTable(dt.tabname);
10914       if (di.unique)
10915       {
10916         ind.setType(NdbDictionary::Index::UniqueHashIndex);
10917         ind.setLogging(true);
10918       }
10919       else
10920       {
10921         ind.setType(NdbDictionary::Index::OrderedIndex);
10922         ind.setLogging(false);
10923       }
10924       for (int j = 0; j < di.ncol; j++)
10925       {
10926         const Fkdef::Col& dc = di.col[j];
10927         ind.addColumn(dc.colname);
10928       }
10929       g_info << "create index " << di.indname << endl;
10930       CHK2(pDic->createIndex(ind) == 0, pDic->getNdbError());
10931       const NdbDictionary::Index* pInd = 0;
10932       CHK2((pInd = pDic->getIndex(di.indname, dt.tabname)) != 0, pDic->getNdbError());
10933       require(!di.retrieved);
10934       di.retrieved = true;
10935       di.id = pInd->getObjectId();
10936       di.version = pInd->getObjectVersion();
10937       di.pInd = pInd;
10938     }
10939   }
10940   while (0);
10941   return result;
10942 }
10943 
10944 static int
fk_create_tables(Fkdef & d,Ndb * pNdb)10945 fk_create_tables(Fkdef& d, Ndb* pNdb)
10946 {
10947   int result = NDBT_OK;
10948   for (int i = 0; i < d.ntab; i++)
10949   {
10950     CHK1(fk_create_table(d, pNdb, i) == NDBT_OK);
10951   }
10952   return result;
10953 }
10954 
10955 static int
fk_create_key(Fkdef & d,Ndb * pNdb,int k)10956 fk_create_key(Fkdef& d, Ndb* pNdb, int k)
10957 {
10958   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
10959   int result = NDBT_OK;
10960   do
10961   {
10962     Fkdef::Key& dk = d.key[k];
10963     NdbDictionary::ForeignKey key;
10964     key.setName(dk.keyname);
10965     const Fkdef::Tab& dt0 = *dk.tab0;
10966     const Fkdef::Tab& dt1 = *dk.tab1;
10967     const Fkdef::Ind& di0 = *dk.ind0;
10968     const Fkdef::Ind& di1 = *dk.ind1;
10969     const NdbDictionary::Table* pTab0 = dt0.pTab;
10970     const NdbDictionary::Table* pTab1 = dt1.pTab;
10971     const NdbDictionary::Index* pInd0 = di0.pInd;
10972     const NdbDictionary::Index* pInd1 = di1.pInd;
10973     key.setParent(*pTab0, pInd0);
10974     key.setChild(*pTab1, pInd1);
10975     g_info << "create key " << dk.keyname << endl;
10976     CHK2(pDic->createForeignKey(key) == 0, pDic->getNdbError());
10977     {
10978       NdbDictionary::ForeignKey key;
10979       sprintf(dk.fullname, "%d/%d/%s", dt0.id, dt1.id, dk.keyname);
10980       CHK2(pDic->getForeignKey(key, dk.fullname) == 0, pDic->getNdbError());
10981       require(!dk.retrieved);
10982       dk.retrieved = true;
10983       dk.id = key.getObjectId();
10984       dk.version = key.getObjectVersion();
10985     }
10986   }
10987   while (0);
10988   return result;
10989 }
10990 
10991 static int
fk_create_keys(Fkdef & d,Ndb * pNdb)10992 fk_create_keys(Fkdef& d, Ndb* pNdb)
10993 {
10994   int result = NDBT_OK;
10995   for (int k = 0; k < d.nkey; k++)
10996   {
10997     CHK1(fk_create_key(d, pNdb, k) == NDBT_OK);
10998   }
10999   return result;
11000 }
11001 
11002 static int
fk_alter_table(Fkdef & d,Ndb * pNdb,int i)11003 fk_alter_table(Fkdef& d, Ndb* pNdb, int i)
11004 {
11005   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11006   int result = NDBT_OK;
11007   do
11008   {
11009     Fkdef::Tab& dt = d.tab[i];
11010     const NdbDictionary::Table* pTab1 = 0;
11011     CHK2((pTab1 = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
11012     g_info << "alter table " << dt.tabname << endl;
11013     int id1 = pTab1->getObjectId();
11014     int version1 = pTab1->getObjectVersion();
11015     g_info << "old: id=" << id1 << " version=" << hex << version1 << endl;
11016     CHK2(pDic->alterTable(*pTab1, *pTab1) == 0, pDic->getNdbError());
11017     pDic->invalidateTable(dt.tabname);
11018     const NdbDictionary::Table* pTab2 = 0;
11019     CHK2((pTab2 = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
11020     int id2 = pTab2->getObjectId();
11021     int version2 = pTab2->getObjectVersion();
11022     g_info << "old: id=" << id2 << " version=" << hex << version2 << endl;
11023     CHK2(id1 == id2, id1 << " != " << id2);
11024     CHK2(version1 != version2, version1 << " == " << version2);
11025     dt.id = id2;
11026     dt.version = version2;
11027   }
11028   while (0);
11029   return result;
11030 }
11031 
11032 static int
fk_alter_tables(Fkdef & d,Ndb * pNdb,bool atrandom)11033 fk_alter_tables(Fkdef& d, Ndb* pNdb, bool atrandom)
11034 {
11035   int result = NDBT_OK;
11036   for (int i = 0; i < d.ntab; i++)
11037   {
11038     if (!atrandom || myRandom48(2) == 0)
11039     {
11040       CHK1(fk_alter_table(d, pNdb, i) == NDBT_OK);
11041     }
11042   }
11043   return result;
11044 }
11045 
11046 static int
fk_create_all(Fkdef & d,Ndb * pNdb)11047 fk_create_all(Fkdef& d, Ndb* pNdb)
11048 {
11049   int result = NDBT_OK;
11050   do
11051   {
11052     CHK1(fk_create_tables(d, pNdb) == 0);
11053     CHK1(fk_create_keys(d, pNdb) == NDBT_OK);
11054     // imitate mysqld by doing an alter table afterwards
11055     CHK1(fk_alter_tables(d, pNdb, true) == NDBT_OK);
11056   }
11057   while (0);
11058   return result;
11059 }
11060 
11061 static int
fk_verify_table(const Fkdef & d,Ndb * pNdb,int i)11062 fk_verify_table(const Fkdef& d, Ndb* pNdb, int i)
11063 {
11064   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11065   int result = NDBT_OK;
11066   do
11067   {
11068     const Fkdef::Tab& dt = d.tab[i];
11069     g_info << "verify table " << dt.tabname << endl;
11070     const NdbDictionary::Table* pTab = 0;
11071     CHK2((pTab = pDic->getTable(dt.tabname)) != 0, pDic->getNdbError());
11072     int id = pTab->getObjectId();
11073     int version = pTab->getObjectVersion();
11074     require(dt.retrieved);
11075     CHK2(dt.id == id, dt.id << " != " << id);
11076     CHK2(dt.version == version, dt.version << " != " << version);
11077     for (int k = 1; k < dt.nind; k++) // skip pk
11078     {
11079       const Fkdef::Ind& di = dt.ind[k];
11080       g_info << "verify index " << di.indname << endl;
11081       const NdbDictionary::Index* pInd = 0;
11082       CHK2((pInd = pDic->getIndex(di.indname, dt.tabname)) != 0, pDic->getNdbError());
11083       int id = pInd->getObjectId();
11084       int version = pInd->getObjectVersion();
11085       require(di.retrieved);
11086       CHK2(di.id == id, di.id << " != " << id);
11087       CHK2(di.version == version, di.version << " != " << version);
11088     }
11089     CHK1(result == NDBT_OK);
11090   }
11091   while (0);
11092   return result;
11093 }
11094 
11095 static int
fk_verify_tables(const Fkdef & d,Ndb * pNdb)11096 fk_verify_tables(const Fkdef& d, Ndb* pNdb)
11097 {
11098   int result = NDBT_OK;
11099   for (int i = 0; i < d.ntab; i++)
11100   {
11101     CHK1(fk_verify_table(d, pNdb, i) == 0);
11102   }
11103   return result;
11104 }
11105 
11106 static int
fk_verify_key(const Fkdef & d,Ndb * pNdb,int k)11107 fk_verify_key(const Fkdef& d, Ndb* pNdb, int k)
11108 {
11109   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11110   int result = NDBT_OK;
11111   do
11112   {
11113     const Fkdef::Key& dk = d.key[k];
11114     g_info << "verify key " << dk.fullname << endl;
11115     NdbDictionary::ForeignKey key;
11116     CHK2(pDic->getForeignKey(key, dk.fullname) == 0, pDic->getNdbError());
11117     int id = key.getObjectId();
11118     int version = key.getObjectVersion();
11119     require(dk.retrieved);
11120     CHK2(dk.id == id, dk.id << " != " << id);
11121     CHK2(dk.version == version, dk.version << " != " << version);
11122     CHK2(strcmp(dk.fullname, key.getName()) == 0, dk.fullname << " != " << key.getName());
11123 #if 0 // can add more checks
11124     const Fkdef::Tab& dt0 = *dk.tab0;
11125     const Fkdef::Tab& dt1 = *dk.tab1;
11126     const Fkdef::Ind& di0 = *dk.ind0;
11127     const Fkdef::Ind& di1 = *dk.ind1;
11128 #endif
11129   }
11130   while (0);
11131   return result;
11132 }
11133 
11134 static int
fk_verify_keys(const Fkdef & d,Ndb * pNdb)11135 fk_verify_keys(const Fkdef& d, Ndb* pNdb)
11136 {
11137   int result = NDBT_OK;
11138   for (int k = 0; k < d.nkey; k++)
11139   {
11140     CHK1(fk_verify_key(d, pNdb, k) == 0);
11141   }
11142   return result;
11143 }
11144 
11145 static int
fk_verify_ddl(const Fkdef & d,Ndb * pNdb)11146 fk_verify_ddl(const Fkdef& d, Ndb* pNdb)
11147 {
11148   int result = NDBT_OK;
11149   do
11150   {
11151     g_info << "verify ddl" << endl;
11152     CHK1(fk_verify_tables(d, pNdb) == 0);
11153     CHK1(fk_verify_keys(d, pNdb) == 0);
11154   }
11155   while (0);
11156   return result;
11157 }
11158 
11159 static int
fk_verify_dml(const Fkdef & d,Ndb * pNdb,int records)11160 fk_verify_dml(const Fkdef& d, Ndb* pNdb, int records)
11161 {
11162   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11163   int result = NDBT_OK;
11164   const int batch = 1;
11165   const bool allowCV = false;
11166   const int errNoParent = 255;
11167   const int errHasChild = 256;
11168   do
11169   {
11170     if (!(d.testcase == 1 && records > 0))
11171       break;
11172     g_info << "verify dml" << endl;
11173     const Fkdef::Tab& dt0 = d.tab[0];
11174     const Fkdef::Tab& dt1 = d.tab[1];
11175     const NdbDictionary::Table* pTab0 = 0;
11176     const NdbDictionary::Table* pTab1 = 0;
11177     CHK2((pTab0 = pDic->getTable(dt0.tabname)) != 0, pDic->getNdbError());
11178     CHK2((pTab1 = pDic->getTable(dt1.tabname)) != 0, pDic->getNdbError());
11179     HugoTransactions tx0(*pTab0);
11180     HugoTransactions tx1(*pTab1);
11181     // insert into child t1 - not ok
11182     g_err << "expect error " << errNoParent << endl;
11183     CHK1(tx1.loadTable(pNdb, records, batch, allowCV) != 0);
11184     CHK2(tx1.getNdbError().code == errNoParent, tx1.getNdbError());
11185     // insert into parent t0 - ok
11186     CHK2(tx0.loadTable(pNdb, records, batch, allowCV) == 0,
11187          tx0.getNdbError());
11188     // insert into child t1 - ok (b1 is 0, a0 is 0,1,2,..)
11189     CHK2(tx1.loadTable(pNdb, records, batch, allowCV) == 0,
11190          tx1.getNdbError());
11191     // delete from parent - not ok
11192     g_err << "expect error " << errHasChild << endl;
11193     CHK1(tx0.pkDelRecords(pNdb, records, batch, allowCV) != 0);
11194     CHK2(tx0.getNdbError().code == errHasChild, tx0.getNdbError());
11195     // delete from child t1 - ok
11196     CHK2(tx1.pkDelRecords(pNdb, records, batch, allowCV) == 0,
11197          tx1.getNdbError());
11198     // delete from parent to - ok
11199     CHK2(tx0.pkDelRecords(pNdb, records, batch, allowCV) == 0,
11200          tx0.getNdbError());
11201   }
11202   while (0);
11203   return result;
11204 }
11205 
11206 static int
fk_retrieve_list(Fkdef & d,Ndb * pNdb,Fkdef::List & list)11207 fk_retrieve_list(Fkdef& d, Ndb* pNdb, Fkdef::List& list)
11208 {
11209   (void)d;
11210   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11211   int result = NDBT_OK;
11212   do
11213   {
11214     g_info << "list objects" << endl;
11215     require(list.list == 0);
11216     list.list = new NdbDictionary::Dictionary::List;
11217     CHK2(pDic->listObjects(*list.list) == 0, pDic->getNdbError());
11218     qsort(list.list->elements, list.list->count, sizeof(list.list->elements[0]),
11219           fk_compare_element);
11220     list.keystart = 0;
11221     for (int i = 0; i < (int)list.list->count; i++)
11222     {
11223       NdbDictionary::Dictionary::List::Element& e =
11224         list.list->elements[i];
11225       if (e.database == 0)
11226       {
11227         e.database = new char [1];
11228         e.database[0] = 0;
11229       }
11230       if (!fk_type(e.type))
11231         list.keystart++;
11232       g_info << "ob " << i << ":"
11233              << " type=" << e.type << " id=" << e.id
11234              << " db=" << e.database << " name=" << e.name << endl;
11235       if (i > 0)
11236       {
11237         const NdbDictionary::Dictionary::List::Element& e2 =
11238           list.list->elements[i - 1];
11239         CHK1(e.type != e2.type || e.id != e2.id);
11240       }
11241     }
11242     g_info << "list count=" << list.list->count
11243            << " keystart=" << list.keystart << endl;
11244   }
11245   while (0);
11246   return result;
11247 }
11248 
11249 static int
fk_verify_list(Fkdef & d,Ndb * pNdb,bool ignore_keys)11250 fk_verify_list(Fkdef& d, Ndb* pNdb, bool ignore_keys)
11251 {
11252   int result = NDBT_OK;
11253   do
11254   {
11255     Fkdef::List& list1 = d.list;
11256     if (list1.list == 0)
11257     {
11258       g_info << "retrieve first object list" << endl;
11259       CHK1(fk_retrieve_list(d, pNdb, list1) == 0);
11260     }
11261     else
11262     {
11263       g_info << "verify object list old vs new"
11264                 " ignore_keys=" << ignore_keys << endl;
11265       Fkdef::List list2;
11266       CHK1(fk_retrieve_list(d, pNdb, list2) == NDBT_OK);
11267       // optionally ignore FK stuff in either list
11268       int count1 = !ignore_keys ? list1.list->count : list1.keystart;
11269       int count2 = !ignore_keys ? list2.list->count : list2.keystart;
11270       CHK1(count1 == count2);
11271       for (int i = 0; i < count1; i++)
11272       {
11273         const NdbDictionary::Dictionary::List::Element& e1 =
11274           list1.list->elements[i];
11275         const NdbDictionary::Dictionary::List::Element& e2 =
11276           list2.list->elements[i];
11277         CHK2(e1.type == e2.type,
11278              i << ": " << e1.type << " != " << e2.type);
11279         CHK2(e1.id == e2.id,
11280              i << ": " << e1.id << " != " << e2.id);
11281         CHK2(strcmp(e1.database, e2.database) == 0,
11282              i << ": " << e1.database << " != " << e2.database);
11283         CHK2(strcmp(e1.name, e2.name) == 0,
11284              i << ": " << e1.name << " != " << e2.name);
11285       }
11286       CHK1(result == NDBT_OK);
11287       // replace old by new
11288       delete list1.list;
11289       list1.list = list2.list;
11290       list1.keystart = list2.keystart;
11291       list2.list = 0;
11292     }
11293     // verify objects vs list
11294     for (int i = 0; i < d.ntab; i++)
11295     {
11296       const Fkdef::Tab& dt = d.tab[i];
11297       CHK2(fk_find_element(list1, NdbDictionary::Object::UserTable,
11298            "TEST_DB", dt.tabname), dt.tabname);
11299       for (int k = 1; k < dt.nind; k++)
11300       {
11301         const Fkdef::Ind& di = dt.ind[k];
11302         if (di.unique)
11303         {
11304           CHK2(fk_find_element(list1, NdbDictionary::Object::UniqueHashIndex,
11305                "sys", di.indname), di.indname);
11306         }
11307         else
11308         {
11309           CHK2(fk_find_element(list1, NdbDictionary::Object::OrderedIndex,
11310                "sys", di.indname), di.indname);
11311         }
11312       }
11313       CHK1(result == NDBT_OK);
11314     }
11315     for (int k = 0; k < d.nkey; k++) {
11316       const Fkdef::Key& dk = d.key[k];
11317       CHK2(fk_find_element(list1, NdbDictionary::Object::ForeignKey,
11318            "", dk.fullname), dk.fullname);
11319       // could also check FK triggers..
11320     }
11321     CHK1(result == NDBT_OK);
11322   }
11323   while (0);
11324   return result;
11325 }
11326 
11327 static int
fk_drop_table(Fkdef & d,Ndb * pNdb,int i,bool force)11328 fk_drop_table(Fkdef& d, Ndb* pNdb, int i, bool force)
11329 {
11330   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11331   int result = NDBT_OK;
11332   do
11333   {
11334     Fkdef::Tab& dt = d.tab[i];
11335     g_info << "drop table " << dt.tabname
11336            << (force ? " (force)" : "") << endl;
11337     if (pDic->dropTable(dt.tabname) != 0)
11338     {
11339       const NdbError& err = pDic->getNdbError();
11340       CHK2(force, err);
11341       CHK2(err.code == 709 || err.code == 723, err);
11342       break;
11343     }
11344     // all indexes are dropped by ndb api
11345     // all related FKs child/parent are dropped by ndb api
11346   }
11347   while (0);
11348   return result;
11349 }
11350 
11351 static int
fk_drop_tables(Fkdef & d,Ndb * pNdb,bool force)11352 fk_drop_tables(Fkdef& d, Ndb* pNdb, bool force)
11353 {
11354   int result = NDBT_OK;
11355   for (int i = 0; i < d.ntab; i++)
11356   {
11357     CHK1(fk_drop_table(d, pNdb, i, force) == NDBT_OK);
11358   }
11359   return result;
11360 }
11361 
11362 static int
fk_drop_key(Fkdef & d,Ndb * pNdb,int k,bool force)11363 fk_drop_key(Fkdef& d, Ndb* pNdb, int k, bool force)
11364 {
11365   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11366   int result = NDBT_OK;
11367   do
11368   {
11369     Fkdef::Key& dk = d.key[k];
11370     g_info << "drop key " << dk.fullname
11371            << (force ? " (force)" : "") << endl;
11372     NdbDictionary::ForeignKey key;
11373     if (pDic->getForeignKey(key, dk.fullname) != 0)
11374     {
11375       const NdbError& err = pDic->getNdbError();
11376       CHK2(force, err);
11377       CHK2(err.code == 709 || err.code == 723 || err.code == 21040, err);
11378       break;
11379     }
11380     CHK2(pDic->dropForeignKey(key) == 0, pDic->getNdbError());
11381   }
11382   while (0);
11383   return result;
11384 }
11385 
11386 static int
fk_drop_keys(Fkdef & d,Ndb * pNdb,bool force)11387 fk_drop_keys(Fkdef& d, Ndb* pNdb, bool force)
11388 {
11389   int result = NDBT_OK;
11390   for (int k = 0; k < d.nkey; k++)
11391   {
11392     CHK1(fk_drop_key(d, pNdb, k, force) == NDBT_OK);
11393   }
11394   return result;
11395 }
11396 
11397 static int
fk_drop_all(Fkdef & d,Ndb * pNdb,bool force)11398 fk_drop_all(Fkdef& d, Ndb* pNdb, bool force)
11399 {
11400   int result = NDBT_OK;
11401   do
11402   {
11403     CHK1(fk_drop_keys(d, pNdb, force) == NDBT_OK);
11404     CHK1(fk_drop_tables(d, pNdb, force) == NDBT_OK);
11405   }
11406   while (0);
11407   return result;
11408 }
11409 
11410 // commit drop
11411 
11412 // just reset all retrieved
11413 static void
fk_dropped_all(Fkdef & d)11414 fk_dropped_all(Fkdef& d)
11415 {
11416   for (int i = 0; i < d.ntab; i++)
11417   {
11418     Fkdef::Tab& dt = d.tab[i];
11419     dt.retrieved = false;
11420     for (int k = 0; k < dt.nind; k++)
11421     {
11422       Fkdef::Ind& di = dt.ind[k];
11423       di.retrieved = false;
11424     }
11425   }
11426   for (int k = 0; k < d.nkey; k++)
11427   {
11428     Fkdef::Key& dk = d.key[k];
11429     dk.retrieved = false;
11430   }
11431 }
11432 
11433 // for FK_Bug18069680
11434 
11435 static int
fk_create_all_random(Fkdef & d,Ndb * pNdb)11436 fk_create_all_random(Fkdef& d, Ndb* pNdb)
11437 {
11438   int result = NDBT_OK;
11439   int ntab = 0;
11440   int nkey = 0;
11441   do
11442   {
11443     for (int i = 0; i < d.ntab; i++)
11444     {
11445       Fkdef::Tab& dt = d.tab[i];
11446       if (!dt.retrieved && myRandom48(3) == 0)
11447       {
11448         CHK1(fk_create_table(d, pNdb, i) == 0);
11449         require(dt.retrieved);
11450         ntab++;
11451       }
11452     }
11453     CHK1(result == NDBT_OK);
11454     for (int k = 0; k < d.nkey; k++)
11455     {
11456       Fkdef::Key& dk = d.key[k];
11457       if (!dk.retrieved && myRandom48(3) == 0 &&
11458           dk.tab0->retrieved && dk.tab1->retrieved)
11459       {
11460         CHK1(fk_create_key(d, pNdb, k) == 0);
11461         require(dk.retrieved);
11462         nkey++;
11463       }
11464     }
11465     CHK1(result == NDBT_OK);
11466     require(ntab <= d.ntab && nkey <= d.nkey);
11467   }
11468   while (ntab < d.ntab || nkey < d.nkey);
11469   return result;
11470 }
11471 
11472 static int
fk_drop_indexes_under(const Fkdef & d,Ndb * pNdb)11473 fk_drop_indexes_under(const Fkdef& d, Ndb* pNdb)
11474 {
11475   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11476   int result = NDBT_OK;
11477   do
11478   {
11479     for (int i = 0; i < d.ntab; i++)
11480     {
11481       const Fkdef::Tab& dt = d.tab[i];
11482       for (int k = 1; k < dt.nind; k++) // skip pk
11483       {
11484         const Fkdef::Ind& di = dt.ind[k];
11485         int parent = 0;
11486         int child = 0;
11487         for (int m = 0; m < d.nkey; m++)
11488         {
11489           const Fkdef::Key& dk = d.key[m];
11490           if (dk.ind0 == &di)
11491             parent++;
11492           if (dk.ind1 == &di)
11493             child++;
11494         }
11495         if (parent != 0 || child != 0)
11496         {
11497           // drop must fail
11498           g_info << "try to drop index under " << di.indname
11499                  << " parent:" << parent << " child:" << child << endl;
11500           int ret = pDic->dropIndex(di.indname, dt.tabname);
11501           CHK2(ret != 0, "no error on drop underlying index");
11502           const NdbError& err = pDic->getNdbError();
11503           // could be either error code depending on check order
11504           CHK2(err.code == 21081 || err.code == 21082, pDic->getNdbError());
11505         }
11506       }
11507       CHK1(result == NDBT_OK);
11508     }
11509     CHK1(result == NDBT_OK);
11510   }
11511   while (0);
11512   return result;
11513 }
11514 
11515 // for manual testing
11516 static void
fk_env_options(Fkdef & d)11517 fk_env_options(Fkdef& d)
11518 {
11519   // random seed
11520   int seed = NdbHost_GetProcessId();
11521 #ifdef NDB_USE_GET_ENV
11522   {
11523     const char* p = NdbEnv_GetEnv("RANDOM_SEED", (char*)0, 0);
11524     if (p != 0)
11525       seed = atoi(p);
11526   }
11527 #endif
11528   myRandom48Init(seed);
11529   g_err << "random seed: " << seed << endl;
11530   // create no FKs at all
11531   d.nokeys = false;
11532 #ifdef NDB_USE_GET_ENV
11533   {
11534     const char* p = NdbEnv_GetEnv("FK_NOKEYS", (char*)0, 0);
11535     if (p != 0 && strchr("1Y", p[0]) != 0)
11536       d.nokeys = true;
11537   }
11538 #endif
11539   // do not drop objects at end
11540   d.nodrop = false;
11541 #ifdef NDB_USE_GET_ENV
11542   {
11543     const char* p = NdbEnv_GetEnv("FK_NODROP", (char*)0, 0);
11544     if (p != 0 && strchr("1Y", p[0]) != 0)
11545       d.nodrop = true;
11546   }
11547 #endif
11548 }
11549 
11550 int
runFK_SRNR(NDBT_Context * ctx,NDBT_Step * step)11551 runFK_SRNR(NDBT_Context* ctx, NDBT_Step* step)
11552 {
11553   Ndb* pNdb = GETNDB(step);
11554   const int loops = ctx->getNumLoops();
11555   const int records = ctx->getNumRecords();
11556   int result = NDBT_OK;
11557 
11558   NdbRestarter restarter;
11559   const int numdbnodes = restarter.getNumDbNodes();
11560 
11561   Fkdef d;
11562   d.testcase = ctx->getProperty("testcase", (Uint32)0);
11563   fk_env_options(d);
11564   fk_define_all(d);
11565 
11566   do
11567   {
11568     (void)fk_drop_all(d, pNdb, true);
11569     CHK1(fk_create_all(d, pNdb) == NDBT_OK);
11570     CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11571     CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11572     CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11573 
11574     for (int loop = 0; loop < loops; loop++)
11575     {
11576       g_info << "loop " << loop << "<" << loops << endl;
11577 
11578       bool rs = (numdbnodes == 1 || myRandom48(2) == 0);
11579       if (rs)
11580       {
11581         g_info << "restart all" << endl;
11582         CHK1(restarter.restartAll() == 0);
11583       }
11584       else
11585       {
11586         int i = myRandom48(numdbnodes);
11587         int nodeid = restarter.getDbNodeId(i);
11588         bool initial = (bool)myRandom48(2);
11589         bool nostart = true;
11590         g_info << "restart node " << nodeid << " initial=" << initial << endl;
11591 
11592         CHK1(restarter.restartOneDbNode(nodeid, initial, nostart) == 0);
11593         CHK1(restarter.waitNodesNoStart(&nodeid, 1) == 0);
11594         g_info << "nostart node " << nodeid << endl;
11595 
11596         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11597         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11598         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11599 
11600         g_info << "start node " << nodeid << endl;
11601         CHK1(restarter.startNodes(&nodeid, 1) == 0);
11602       }
11603 
11604       CHK1(restarter.waitClusterStarted() == 0);
11605       CHK_NDB_READY(pNdb);
11606       g_info << "cluster is started" << endl;
11607 
11608       CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11609       CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11610       CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11611     }
11612     CHK1(result == NDBT_OK);
11613 
11614     if (!d.nodrop)
11615     {
11616       CHK1(fk_drop_all(d, pNdb, false) == NDBT_OK);
11617     }
11618   }
11619   while (0);
11620 
11621   if (result != NDBT_OK)
11622   {
11623     if (!d.nodrop)
11624       (void)fk_drop_all(d, pNdb, true);
11625   }
11626   return result;
11627 }
11628 
11629 int
runFK_TRANS(NDBT_Context * ctx,NDBT_Step * step)11630 runFK_TRANS(NDBT_Context* ctx, NDBT_Step* step)
11631 {
11632   Ndb* pNdb = GETNDB(step);
11633   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11634   const int loops = ctx->getNumLoops();
11635   const int records = ctx->getNumRecords();
11636   int result = NDBT_OK;
11637   const int abort_flag = NdbDictionary::Dictionary::SchemaTransAbort;
11638 
11639   Fkdef d;
11640   d.testcase = ctx->getProperty("testcase", (Uint32)0);
11641   fk_env_options(d);
11642   fk_define_tables(d);
11643   fk_undefine_keys(d);
11644 
11645   do
11646   {
11647     (void)fk_drop_all(d, pNdb, true);
11648     CHK1(fk_create_tables(d, pNdb) == NDBT_OK);
11649     CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11650     CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11651 
11652     // what to do on loop % 3
11653     const int abort_loop[3][2] = { { 1, -1 }, { 0, 1 }, { 0, 0 } };
11654 
11655     for (int loop = 0; loop < loops; loop++)
11656     {
11657       g_info << "loop " << loop << "<" << loops << endl;
11658 
11659       int abort_create = abort_loop[loop % 3][0];
11660       require(abort_create == 0 || abort_create == 1);
11661       g_info << "abort create: " << abort_create << endl;
11662 
11663       fk_define_keys(d);
11664       CHK2(pDic->beginSchemaTrans() == 0, pDic->getNdbError());
11665       CHK1(fk_create_keys(d, pNdb) == 0);
11666       if (!abort_create)
11667       {
11668         g_info << "commit schema trans" << endl;
11669         CHK2(pDic->endSchemaTrans(0) == 0, pDic->getNdbError());
11670         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11671         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11672         CHK1(fk_verify_list(d, pNdb, true) == NDBT_OK);
11673       }
11674       else
11675       {
11676         g_info << "abort schema trans" << endl;
11677         CHK2(pDic->endSchemaTrans(abort_flag) == 0, pDic->getNdbError());
11678         fk_undefine_keys(d);
11679         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11680         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11681         continue; // nothing to drop
11682       }
11683 
11684       int abort_drop = abort_loop[loop % 3][1];
11685       require(abort_drop == 0 || abort_drop == 1);
11686       g_info << "abort drop: " << abort_drop << endl;
11687 
11688       CHK2(pDic->beginSchemaTrans() == 0, pDic->getNdbError());
11689       CHK1(fk_drop_keys(d, pNdb, false) == 0);
11690       if (!abort_drop)
11691       {
11692         g_info << "commit schema trans" << endl;
11693         CHK2(pDic->endSchemaTrans(0) == 0, pDic->getNdbError());
11694         fk_undefine_keys(d);
11695         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11696         CHK1(fk_verify_list(d, pNdb, true) == NDBT_OK);
11697       }
11698       else
11699       {
11700         g_info << "abort schema trans" << endl;
11701         CHK2(pDic->endSchemaTrans(abort_flag) == 0, pDic->getNdbError());
11702         CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11703         CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11704         CHK1(fk_verify_list(d, pNdb, false) == NDBT_OK);
11705         // prepare for next round
11706         CHK1(fk_drop_keys(d, pNdb, false) == NDBT_OK);
11707         fk_undefine_keys(d);
11708       }
11709     }
11710     CHK1(result == NDBT_OK);
11711 
11712     if (!d.nodrop)
11713     {
11714       CHK1(fk_drop_all(d, pNdb, false) == NDBT_OK);
11715     }
11716   }
11717   while (0);
11718 
11719   if (result != NDBT_OK)
11720   {
11721     (void)pDic->endSchemaTrans(abort_flag);
11722     if (!d.nodrop)
11723       (void)fk_drop_all(d, pNdb, true);
11724   }
11725   return result;
11726 }
11727 
11728 int
runFK_Bug18069680(NDBT_Context * ctx,NDBT_Step * step)11729 runFK_Bug18069680(NDBT_Context* ctx, NDBT_Step* step)
11730 {
11731   Ndb* pNdb = GETNDB(step);
11732   const int loops = ctx->getNumLoops();
11733   const int records = ctx->getNumRecords();
11734   int result = NDBT_OK;
11735 
11736   Fkdef d;
11737   d.testcase = ctx->getProperty("testcase", (Uint32)0);
11738   fk_env_options(d);
11739   fk_define_all(d);
11740 
11741   do
11742   {
11743     (void)fk_drop_all(d, pNdb, true);
11744 
11745     for (int loop = 0; loop < loops; loop++)
11746     {
11747       g_info << "loop " << loop << "<" << loops << endl;
11748 
11749       CHK1(fk_create_all_random(d, pNdb) == NDBT_OK);
11750       CHK1(fk_verify_ddl(d, pNdb) == NDBT_OK);
11751       CHK1(fk_verify_dml(d, pNdb, records) == NDBT_OK);
11752 
11753       CHK1(fk_drop_indexes_under(d, pNdb) == NDBT_OK);
11754       CHK1(fk_drop_tables(d, pNdb, false) == NDBT_OK);
11755 
11756       fk_dropped_all(d);
11757     }
11758     CHK1(result == NDBT_OK);
11759   }
11760   while (0);
11761 
11762   if (result != NDBT_OK)
11763   {
11764     if (!d.nodrop)
11765       (void)fk_drop_all(d, pNdb, true);
11766   }
11767   return result;
11768 }
11769 
11770 #undef myRandom48
11771 #undef myRandom48Init
11772 
11773 int
runDictTO_1(NDBT_Context * ctx,NDBT_Step * step)11774 runDictTO_1(NDBT_Context* ctx, NDBT_Step* step)
11775 {
11776   Ndb* pNdb = GETNDB(step);
11777   NdbDictionary::Dictionary* pDic = pNdb->getDictionary();
11778   NdbRestarter restarter;
11779 
11780   if (restarter.getNumDbNodes() < 3)
11781     return NDBT_OK;
11782 
11783   for (int i = 0; i < ctx->getNumLoops(); i++)
11784   {
11785     int master = restarter.getMasterNodeId();
11786     int next = restarter.getNextMasterNodeId(master);
11787     int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
11788 
11789     restarter.dumpStateOneNode(master, val2, 2);
11790     restarter.insertError2InNode(master, 6050, next);
11791 
11792     ndbout_c("master: %d next: %d", master, next);
11793     {
11794       g_info << "save all resource usage" << endl;
11795       int dump1[] = { DumpStateOrd::SchemaResourceSnapshot };
11796       restarter.dumpStateAllNodes(dump1, 1);
11797     }
11798 
11799 
11800     {
11801       if (pDic->beginSchemaTrans() != 0)
11802       {
11803         ndbout << "ERROR: line: " << __LINE__ << endl;
11804         ndbout << pDic->getNdbError();
11805         return NDBT_FAILED;
11806       }
11807       for (int j = 0; j < (i + 1); j++)
11808       {
11809         NdbDictionary::Table pTab(* ctx->getTab());
11810         pTab.setName(BaseString(pTab.getName()).appfmt("_EXTRA_%u", j).c_str());
11811 
11812         if (pDic->createTable(pTab) != 0)
11813         {
11814           ndbout << "ERROR: line: " << __LINE__ << endl;
11815           ndbout << pDic->getNdbError();
11816           return NDBT_FAILED;
11817         }
11818       }
11819 
11820       // this should give master failuer...but trans should rollforward
11821       if (pDic->endSchemaTrans() != 0)
11822       {
11823         ndbout << "ERROR: line: " << __LINE__ << endl;
11824         ndbout << pDic->getNdbError();
11825         return NDBT_FAILED;
11826       }
11827     }
11828 
11829     for (int j = 0; j < (i + 1); j++)
11830     {
11831       pDic->dropTable(BaseString(ctx->getTab()->getName()).appfmt("_EXTRA_%u", j).c_str());
11832     }
11833 
11834     {
11835       g_info << "check all resource usage" << endl;
11836       for (int j = 0; j < restarter.getNumDbNodes(); j++)
11837       {
11838         if (restarter.getDbNodeId(j) == master)
11839           continue;
11840 
11841         int dump1[] = { DumpStateOrd::SchemaResourceCheckLeak };
11842         restarter.dumpStateOneNode(restarter.getDbNodeId(j), dump1, 1);
11843       }
11844     }
11845 
11846     restarter.waitNodesNoStart(&master, 1);
11847     restarter.startNodes(&master, 1);
11848     restarter.waitClusterStarted();
11849     CHK_NDB_READY(pNdb);
11850   }
11851 
11852   return NDBT_OK;
11853 }
11854 
11855 int
runIndexStatTimeout(NDBT_Context * ctx,NDBT_Step * step)11856 runIndexStatTimeout(NDBT_Context* ctx, NDBT_Step* step)
11857 {
11858   Ndb* pNdb = GETNDB(step);
11859   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
11860   const NdbDictionary::Table* pTab = ctx->getTab();
11861   char idxname[20];
11862   sprintf(idxname, "%s_idx", pTab->getName());
11863   NdbRestarter restarter;
11864 
11865   if(pTab == NULL)
11866   {
11867     ndbout << "Failed to get table " << endl;
11868     return NDBT_FAILED;
11869   }
11870   const NdbDictionary::Index* pIdx = pDict->getIndex(idxname, pTab->getName());
11871   if(pIdx == NULL)
11872   {
11873     ndbout << "Failed to get index" << idxname << " error " << pDict->getNdbError() << endl;
11874     return NDBT_FAILED;
11875   }
11876   ndbout << "Inserting error in ndbd to cause dictsignal timeout" << endl;
11877   if(restarter.insertErrorInAllNodes(6221) != 0)
11878   {
11879     ndbout << "Failed to insert error 6221" << endl;
11880     return NDBT_FAILED;
11881   }
11882 
11883   ndbout << "Do error injection in ndbapi to timeout quickly" << endl;
11884   DBUG_SET_INITIAL("+d,ndb_dictsignal_timeout");
11885 
11886   if(pDict->updateIndexStat(*pIdx, *pTab) == 0)
11887   {
11888     ndbout << "Error: updateIndexStat succeeded, should have failed" << endl;
11889     return NDBT_FAILED;
11890   }
11891   ndbout << "Clear error injection from ndbapi" << endl;
11892   DBUG_SET_INITIAL("-d,ndb_dictsignal_timeout");
11893 
11894   ndbout << "Clear error insert in ndbd" << endl;
11895   if(restarter.insertErrorInAllNodes(0) != 0)
11896   {
11897     ndbout << "Failed to clear error 6221" << endl;
11898     return NDBT_FAILED;
11899   }
11900   int errorCode= pDict->getNdbError().code;
11901   if(errorCode != 4008)
11902   {
11903     ndbout << "Error: updateIndexStat failed with wrong error " << errorCode << endl;
11904     return NDBT_FAILED;
11905   }
11906   ndbout << "Success: updateIndexStat failed with expected error 4008" << endl;
11907   return NDBT_OK;
11908 }
11909 
11910 int
runForceGCPWait(NDBT_Context * ctx,NDBT_Step * step)11911 runForceGCPWait(NDBT_Context* ctx, NDBT_Step* step)
11912 {
11913   Ndb* pNdb = GETNDB(step);
11914   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
11915   NdbRestarter restarter;
11916 
11917   ndbout << "Inserting error in ndbd to cause dictsignal timeout" << endl;
11918   if(restarter.insertErrorInAllNodes(7247) != 0)
11919   {
11920     ndbout << "Failed to insert error 7247" << endl;
11921     return NDBT_FAILED;
11922   }
11923 
11924   ndbout << "Do error injection in ndbapi to timeout quickly" << endl;
11925   DBUG_SET_INITIAL("+d,ndb_dictsignal_timeout");
11926 
11927   if(pDict->forceGCPWait(0) == 0)
11928   {
11929     ndbout << "Error: forceGCPWait succeeded, should have failed" << endl;
11930     return NDBT_FAILED;
11931   }
11932   ndbout << "Clear error injection from ndbapi" << endl;
11933   DBUG_SET_INITIAL("-d,ndb_dictsignal_timeout");
11934 
11935   ndbout << "Clear error insert in ndbd" << endl;
11936   if(restarter.insertErrorInAllNodes(0) != 0)
11937   {
11938     ndbout << "Failed to clear error 6222" << endl;
11939     return NDBT_FAILED;
11940   }
11941   int errorCode= pDict->getNdbError().code;
11942   if(errorCode != 4008)
11943   {
11944     ndbout << "Error: forceGCPWait failed with wrong error " << errorCode << endl;
11945     return NDBT_FAILED;
11946   }
11947   ndbout << "Success: forceGCPWait failed with expected error 4008" << endl;
11948   return NDBT_OK;
11949 }
11950 
11951 /**
11952  * Testcase CreateManyDataFiles : Check if error code 1517 is
11953  * returned when DiskPageBufferMemory is exhausted.
11954  *
11955  * Provoke lack of DiskPageBufferMemory when creating data files
11956  * by reconfiguring it to the allowed minimum. Save the original
11957  * config value and reinstate it when runCreateManyDataFiles
11958  * creating many files is finished.
11959  */
11960 static int
changeStartDiskPageBufMem(NDBT_Context * ctx,NDBT_Step * step)11961 changeStartDiskPageBufMem(NDBT_Context *ctx, NDBT_Step *step)
11962 {
11963   Config conf;
11964   NdbRestarter restarter;
11965   Uint64 new_diskpage_buffer = 4 * 1024 * 1024; // Configured minimum value
11966   Uint64 start_disk_page_buffer = ctx->getProperty("STARTDISKPAGEBUFFER",
11967                                                 (Uint64)new_diskpage_buffer);
11968 
11969   NdbMgmd mgmd;
11970   Uint64 saved_old_value = 0;
11971   CHECK3(mgmd.change_config(start_disk_page_buffer, &saved_old_value,
11972                             CFG_SECTION_NODE,
11973                             CFG_DB_DISK_PAGE_BUFFER_MEMORY),
11974          "Change config failed");
11975 
11976   // Save old config value in the test case context
11977   ctx->setProperty("STARTDISKPAGEBUFFER", Uint64(saved_old_value));
11978 
11979   g_err << "Restarting nodes to apply config change from "
11980         << saved_old_value << " to " << start_disk_page_buffer << endl;
11981 
11982   CHECK3(restarter.restartAll() == 0,
11983          "Restart all failed");
11984   CHECK3(restarter.waitClusterStarted(120) == 0,
11985          "Cluster has not started");
11986   g_err << "Nodes restarted with new config." << endl;
11987   return NDBT_OK;
11988 }
11989 
11990 /**
11991  * If not exists, create LogfileGroup DEFAULT-LG and
11992  * create a tablespace DEFAULT-TS.
11993  * Save in test context whether log file group or
11994  * table space is created in this test case.
11995  */
11996 int
runCreateLogFileGroupTableSpace(NDBT_Context * ctx,NDBT_Step * step)11997 runCreateLogFileGroupTableSpace(NDBT_Context* ctx, NDBT_Step* step)
11998 {
11999   Ndb* pNdb = GETNDB(step);
12000   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
12001 
12002   // Create a new LFG, if not exixts already
12003   bool log_file_group_created = false;
12004   NdbDictionary::LogfileGroup lg = pDict->getLogfileGroup("DEFAULT-LG");
12005   if (strcmp(lg.getName(), "DEFAULT-LG") != 0)
12006   {
12007     lg.setName("DEFAULT-LG");
12008     lg.setUndoBufferSize(1*1024*1024);
12009 
12010     CHECK3(pDict->createLogfileGroup(lg) == 0, pDict->getNdbError());
12011     log_file_group_created = true;
12012   }
12013   // Save the info about the test created the log file group
12014   // "DEFAULT-LG" in the test case context.
12015   ctx->setProperty("LOGFILEGROUPCREATED", Uint32(log_file_group_created));
12016 
12017   // Create a tablespace, if not exists
12018   bool ts_created = false;
12019   NdbDictionary::Tablespace ts = pDict->getTablespace("DEFAULT-TS");
12020   if (strcmp(ts.getName(), "DEFAULT-TS") != 0)
12021   {
12022     const char * tsName  = "DEFAULT-TS";
12023     NdbDictionary::Tablespace ts;
12024     ts.setName(tsName);
12025     ts.setExtentSize(1024*1024);
12026     ts.setDefaultLogfileGroup("DEFAULT-LG");
12027 
12028     CHECK3((pDict->createTablespace(ts)) == 0, pNdb->getNdbError());
12029     ts_created = true;
12030   }
12031   // Save the info about the test created the table space
12032   // "DEFAULT-TS" in the test case context.
12033   ctx->setProperty("TABLESPACECREATED", Uint32(ts_created));
12034   return NDBT_OK;
12035 }
12036 
12037 /**
12038  * Drop DEFAULT-TS and DEFAULT-LG if the test case created them.
12039  * This info is saved in the test context.
12040  */
12041 int
runDropTableSpaceLG(NDBT_Context * ctx,NDBT_Step * step)12042 runDropTableSpaceLG(NDBT_Context* ctx, NDBT_Step* step)
12043 {
12044   Ndb* pNdb = GETNDB(step);
12045 
12046   // Read the info about the test created the table space
12047   // "DEFAULT-TS" from the test case context.
12048   Uint32 ts_created =
12049     ctx->getProperty("TABLESPACECREATED", (Uint32)0);
12050 
12051   if (ts_created)
12052   {
12053     // tablespace was created by this test case, remove it.
12054     if (pNdb->getDictionary()->dropTablespace(
12055           pNdb->getDictionary()->getTablespace("DEFAULT-TS")) != 0)
12056     {
12057       g_err << " Dropping table space DEFAULT-TS failed with "
12058             << pNdb->getDictionary()->getNdbError() << endl;
12059       // Don't return NDBT_FAILED, continue clean up log file group
12060     }
12061   }
12062 
12063   // Read the info about the test created the log file group
12064   // "DEFAULT-LG" from the test case context.
12065   Uint32 log_file_group_created =
12066     ctx->getProperty("LOGFILEGROUPCREATED", (Uint32)0);
12067 
12068   if (log_file_group_created)
12069   {
12070     // Log file group was created by this test case, remove it.
12071     CHECK3(pNdb->getDictionary()->dropLogfileGroup(
12072              pNdb->getDictionary()->getLogfileGroup("DEFAULT-LG")) == 0,
12073            pNdb->getDictionary()->getNdbError());
12074   }
12075   return NDBT_OK;
12076 }
12077 
12078 /**
12079  * Create upto the number of data files given in the test case until
12080  * DiskPageBufferMemory gets exhausted, indicated by error code 1517.
12081  *
12082  * Drop data files.
12083  *
12084  * Test succeeds if the DiskPageBufferMemory gets exhausted,
12085  *      fails otherwise.
12086  */
12087 int
runCreateManyDataFiles(NDBT_Context * ctx,NDBT_Step * step)12088 runCreateManyDataFiles(NDBT_Context* ctx, NDBT_Step* step)
12089 {
12090   Ndb* pNdb = GETNDB(step);
12091   NdbDictionary::Dictionary *pDict = pNdb->getDictionary();
12092   int result = NDBT_FAILED;
12093 
12094   // Add many data files until disk page buffer gets filled
12095   Uint32 data_files_to_create = ctx->getProperty("DATAFILES",
12096                                                  (Uint32)200);
12097   NdbDictionary::Datafile df;
12098   uint created_files = 0; // How many files are created so far
12099   char datafilename[256];
12100 
12101   for (Uint32 datafile=0; datafile < data_files_to_create; ++datafile)
12102   {
12103     BaseString::snprintf(datafilename, sizeof(datafilename),
12104                          "datafile%d", datafile);
12105     df.setPath(datafilename);
12106     df.setSize(1*1024*1024);
12107     df.setTablespace("DEFAULT-TS");
12108 
12109     int res = pDict->createDatafile(df);
12110     if(res != 0)
12111     {
12112       int error = pDict->getNdbError().code;
12113       if (error == 1517)
12114       {
12115         // Error 1517 indicates DiskPageBufferMemory exhaustion.
12116         // Stop creating more data files.
12117         result =  NDBT_OK;
12118       }
12119       else
12120       {
12121         g_err << "Failed to create datafile " << datafilename
12122               << endl << pDict->getNdbError() << endl;
12123       }
12124       break;
12125     }
12126     created_files++;
12127   }
12128 
12129   // Clean up : remove the data files created
12130   for (uint datafile=0; datafile < created_files; ++datafile)
12131   {
12132     BaseString::snprintf(datafilename, sizeof(datafilename),
12133                          "datafile%d", datafile);
12134     df.setPath(datafilename);
12135 
12136     if (pNdb->getDictionary()->dropDatafile(
12137           pNdb->getDictionary()->getDatafile(0, datafilename)) != 0)
12138     {
12139         g_err << "Failed to create datafile " << datafilename
12140               << pNdb->getDictionary()->getNdbError() << endl;
12141         // Continue dropping rest of the data files
12142     }
12143   }
12144 
12145   return result;
12146 }
12147 
12148 NDBT_TESTSUITE(testDict);
12149 TESTCASE("testDropDDObjects",
12150          "* 1. start cluster\n"
12151          "* 2. Create LFG\n"
12152          "* 3. create TS\n"
12153          "* 4. run DropDDObjects\n"
12154          "* 5. Verify DropDDObjectsRestart worked\n"){
12155 INITIALIZER(runWaitStarted);
12156 INITIALIZER(runDropDDObjects);
12157 INITIALIZER(testDropDDObjectsSetup);
12158 STEP(runDropDDObjects);
12159 FINALIZER(DropDDObjectsVerify);
12160 }
12161 
12162 TESTCASE("Bug29501",
12163          "* 1. start cluster\n"
12164          "* 2. Restart 1 node -abort -nostart\n"
12165          "* 3. create LFG\n"
12166          "* 4. Restart data node\n"
12167          "* 5. Restart 1 node -nostart\n"
12168          "* 6. Drop LFG\n"){
12169 INITIALIZER(runWaitStarted);
12170 INITIALIZER(runDropDDObjects);
12171 STEP(runBug29501);
12172 FINALIZER(runDropDDObjects);
12173 }
12174 TESTCASE("CreateAndDrop",
12175 	 "Try to create and drop the table loop number of times\n"){
12176   INITIALIZER(runCreateAndDrop);
12177 }
12178 TESTCASE("CreateAndDropAtRandom",
12179 	 "Try to create and drop table at random loop number of times\n"
12180          "Uses all available tables\n"
12181          "Uses error insert 4013 to make TUP verify table descriptor"){
12182   INITIALIZER(runCreateAndDropAtRandom);
12183 }
12184 TESTCASE("CreateAndDropIndexes",
12185 	 "Like CreateAndDropAtRandom but also creates random ordered\n"
12186          "indexes and loads data as a simple check of index operation"){
12187   TC_PROPERTY("CreateIndexes", 1);
12188   TC_PROPERTY("LoadData", 1);
12189   INITIALIZER(runCreateAndDropAtRandom);
12190 }
12191 TESTCASE("CreateAndDropWithData",
12192 	 "Try to create and drop the table when it's filled with data\n"
12193 	 "do this loop number of times\n"){
12194   INITIALIZER(runCreateAndDropWithData);
12195 }
12196 TESTCASE("CreateAndDropDuring",
12197 	 "Try to create and drop the table when other thread is using it\n"
12198 	 "do this loop number of times\n"){
12199   STEP(runCreateAndDropDuring);
12200   STEP(runUseTableUntilStopped);
12201 }
12202 TESTCASE("DropWithTakeover","bug 14190114"){
12203   INITIALIZER(runDropTakeoverTest);
12204 }
12205 TESTCASE("CreateInvalidTables",
12206 	 "Try to create the invalid tables we have defined\n"){
12207   INITIALIZER(runCreateInvalidTables);
12208 }
12209 TESTCASE("DropTableConcurrentLCP",
12210          "Drop a table while LCP is ongoing\n")
12211 {
12212   INITIALIZER(runCreateTheTable);
12213   INITIALIZER(runFillTable);
12214   INITIALIZER(runSetMinTimeBetweenLCP);
12215   INITIALIZER(runSetDropTableConcurrentLCP);
12216   INITIALIZER(runDropTheTable);
12217   FINALIZER(runResetMinTimeBetweenLCP);
12218 }
12219 TESTCASE("DropTableConcurrentLCP2",
12220          "Drop a table while LCP is ongoing\n")
12221 {
12222   INITIALIZER(runCreateTheTable);
12223   INITIALIZER(runFillTable);
12224   INITIALIZER(runSetMinTimeBetweenLCP);
12225   INITIALIZER(runSetDropTableConcurrentLCP2);
12226   INITIALIZER(runDropTheTable);
12227   FINALIZER(runResetMinTimeBetweenLCP);
12228 }
12229 TESTCASE("CreateTableWhenDbIsFull",
12230 	 "Try to create a new table when db already is full\n"){
12231   INITIALIZER(runCreateTheTable);
12232   INITIALIZER(runFillTable);
12233   INITIALIZER(runCreateTableWhenDbIsFull);
12234   INITIALIZER(runDropTableWhenDbIsFull);
12235   FINALIZER(runDropTheTable);
12236 }
12237 TESTCASE("FragmentTypeSingle",
12238 	 "Create the table with fragment type Single\n"){
12239   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragSingle);
12240   INITIALIZER(runTestFragmentTypes);
12241 }
12242 TESTCASE("FragmentTypeAllSmall",
12243 	 "Create the table with fragment type AllSmall\n"){
12244   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllSmall);
12245   INITIALIZER(runTestFragmentTypes);
12246 }
12247 TESTCASE("FragmentTypeAllMedium",
12248 	 "Create the table with fragment type AllMedium\n"){
12249   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllMedium);
12250   INITIALIZER(runTestFragmentTypes);
12251 }
12252 TESTCASE("FragmentTypeAllLarge",
12253 	 "Create the table with fragment type AllLarge\n"){
12254   TC_PROPERTY("FragmentType", NdbDictionary::Table::FragAllLarge);
12255   INITIALIZER(runTestFragmentTypes);
12256 }
12257 TESTCASE("TemporaryTables",
12258 	 "Create the table as temporary and make sure it doesn't\n"
12259 	 "contain any data when system is restarted\n"){
12260   INITIALIZER(runTestTemporaryTables);
12261 }
12262 TESTCASE("CreateMaxTables",
12263 	 "Create tables until db says that it can't create any more\n"){
12264   TC_PROPERTY("tables", 1000);
12265   INITIALIZER(runCreateMaxTables);
12266   INITIALIZER(runDropMaxTables);
12267 }
12268 TESTCASE("BackupMaxTables",
12269 	 "Create max amount of tables and verify backup works\n"){
12270   TC_PROPERTY("tables", 200);
12271   INITIALIZER(runCreateMaxTables);
12272   INITIALIZER(runBackup);
12273   INITIALIZER(runDropMaxTables);
12274 }
12275 TESTCASE("PkSizes",
12276 	 "Create tables with all different primary key sizes.\n"\
12277 	 "Test all data operations insert, update, delete etc.\n"\
12278 	 "Drop table."){
12279   INITIALIZER(runPkSizes);
12280 }
12281 TESTCASE("StoreFrm",
12282 	 "Test that a frm file can be properly stored as part of the\n"
12283 	 "data in Dict."){
12284   INITIALIZER(runStoreFrm);
12285 }
12286 TESTCASE("GetPrimaryKey",
12287 	 "Test the function NdbDictionary::Column::getPrimaryKey\n"
12288 	 "It should return true only if the column is part of \n"
12289 	 "the primary key in the table"){
12290   INITIALIZER(runGetPrimaryKey);
12291 }
12292 TESTCASE("StoreExtraMetadata",
12293          "Test that extra metadata can be stored as part of the\n"
12294          "data in Dict."){
12295   INITIALIZER(runStoreExtraMetada);
12296 }
12297 TESTCASE("StoreExtraMetadataError",
12298          "Test that extra metadata with too long length can't be stored."){
12299   INITIALIZER(runStoreExtraMetadataError);
12300 }
12301 TESTCASE("TableRename",
12302 	 "Test basic table rename"){
12303   INITIALIZER(runTableRename);
12304 }
12305 TESTCASE("TableRenameSR",
12306 	 "Test that table rename can handle system restart"){
12307   INITIALIZER(runTableRenameSR);
12308 }
12309 TESTCASE("ColumnRename",
12310 	 "Test basic column rename"){
12311   INITIALIZER(runColumnRename);
12312 }
12313 TESTCASE("ColumnRenameSR",
12314 	 "Test that column rename can handle system restart"){
12315   INITIALIZER(runColumnRenameSR);
12316 }
12317 TESTCASE("DictionaryPerf",
12318 	 ""){
12319   INITIALIZER(runTestDictionaryPerf);
12320 }
12321 TESTCASE("CreateLogfileGroup", ""){
12322   INITIALIZER(runCreateLogfileGroup);
12323 }
12324 TESTCASE("CreateLogfileGroupWithFailure",
12325          "Create a log file group where a dict participant"
12326          " fails to create log buffer"){
12327   TC_PROPERTY("OneDictParticipantFail", 1);
12328   INITIALIZER(runCreateLogfileGroup);
12329 }
12330 TESTCASE("CreateTablespaceWithFailure",
12331          "Create a log file group where a dict participant"
12332          " fails to create log buffer"){
12333   TC_PROPERTY("OneDictParticipantFail", 1);
12334   STEP(runCreateTablespace);
12335   FINALIZER(runDropTableSpaceLogFileGroup);
12336 }
12337 TESTCASE("CreateTablespace",
12338          "Create a table space where a dict participant"
12339          " fails to create log buffer"){
12340   INITIALIZER(runCreateTablespace);
12341 }
12342 TESTCASE("CreateDiskTable", ""){
12343   INITIALIZER(runCreateDiskTable);
12344 }
12345 TESTCASE("FailAddFragment",
12346          "Fail add fragment or attribute in ACC or TUP or TUX\n"){
12347   INITIALIZER(runFailAddFragment);
12348 }
12349 TESTCASE("Restart_NF1",
12350          "DICT ops during node graceful shutdown (not master)"){
12351   TC_PROPERTY("Restart_NF_ops", 1);
12352   TC_PROPERTY("Restart_NF_type", 1);
12353   STEP(runRestarts);
12354   STEP(runDictOps);
12355 }
12356 TESTCASE("Restart_NF2",
12357          "DICT ops during node shutdown abort (not master)"){
12358   TC_PROPERTY("Restart_NF_ops", 1);
12359   TC_PROPERTY("Restart_NF_type", 2);
12360   STEP(runRestarts);
12361   STEP(runDictOps);
12362 }
12363 TESTCASE("Restart_NR1",
12364          "DICT ops during node startup (not master)"){
12365   TC_PROPERTY("Restart_NR_ops", 1);
12366   STEP(runRestarts);
12367   STEP(runDictOps);
12368 }
12369 TESTCASE("Restart_NR2",
12370          "DICT ops during node startup with crash inserts (not master)"){
12371   TC_PROPERTY("Restart_NR_ops", 1);
12372   TC_PROPERTY("Restart_NR_error", 1);
12373   STEP(runRestarts);
12374   STEP(runDictOps);
12375 }
12376 TESTCASE("TableAddAttrs",
12377 	 "Add attributes to an existing table using alterTable()"){
12378   INITIALIZER(runTableAddAttrs);
12379 }
12380 TESTCASE("TableAddAttrsDuring",
12381 	 "Try to add attributes to the table when other thread is using it\n"
12382 	 "do this loop number of times\n"){
12383   INITIALIZER(runCreateTheTable);
12384   STEP(runTableAddAttrsDuring);
12385   STEP(runUseTableUntilStopped2);
12386   STEP(runUseTableUntilStopped3);
12387   FINALIZER(runDropTheTable);
12388 }
12389 TESTCASE("TableAddAttrsDuringError",
12390 	 "Try to add attributes to the table when other thread is using it\n"
12391 	 "do this loop number of times\n"){
12392   TC_PROPERTY("AbortAlter", 1);
12393   INITIALIZER(runCreateTheTable);
12394   STEP(runTableAddAttrsDuring);
12395   STEP(runUseTableUntilStopped2);
12396   STEP(runUseTableUntilStopped3);
12397   FINALIZER(runDropTheTable);
12398 }
12399 TESTCASE("Bug21755",
12400          ""){
12401   INITIALIZER(runBug21755);
12402 }
12403 TESTCASE("DictRestart",
12404          ""){
12405   INITIALIZER(runDictRestart);
12406 }
12407 TESTCASE("Bug24631",
12408          ""){
12409   INITIALIZER(runBug24631);
12410 }
12411 TESTCASE("Bug36702", "")
12412 {
12413   INITIALIZER(runDropDDObjects);
12414   INITIALIZER(runBug36072);
12415   FINALIZER(restartClusterInitial);
12416 }
12417 TESTCASE("Bug29186",
12418          ""){
12419   INITIALIZER(runBug29186);
12420 }
12421 TESTCASE("Bug48604",
12422          "Online ordered index build.\n"
12423          "Complements testOIBasic -case f"){
12424   STEP(runBug48604);
12425   STEP(runBug48604ops);
12426 #if 0 // for future MT test
12427   STEP(runBug48604ops);
12428   STEP(runBug48604ops);
12429   STEP(runBug48604ops);
12430 #endif
12431 }
12432 TESTCASE("Bug54651", ""){
12433   INITIALIZER(runBug54651);
12434 }
12435 /** telco-6.4 **/
12436 TESTCASE("SchemaTrans",
12437          "Schema transactions"){
12438   ALL_TABLES();
12439   STEP(runSchemaTrans);
12440 }
12441 TESTCASE("FailCreateHashmap",
12442          "Fail create hashmap")
12443 {
12444   INITIALIZER(runFailCreateHashmap);
12445 }
12446 TESTCASE("FailAddPartition",
12447          "Fail add partition")
12448 {
12449   INITIALIZER(runFailAddPartition);
12450 }
12451 TESTCASE("TableAddPartitions",
12452 	 "Add partitions to an existing table using alterTable()"){
12453   INITIALIZER(runTableAddPartition);
12454 }
12455 TESTCASE("Bug41905",
12456 	 ""){
12457   STEP(runBug41905);
12458   STEP(runBug41905getTable);
12459 }
12460 TESTCASE("Bug46552", "")
12461 {
12462   INITIALIZER(runBug46552);
12463 }
12464 TESTCASE("Bug46585", "")
12465 {
12466   INITIALIZER(runWaitStarted);
12467   INITIALIZER(runBug46585);
12468 }
12469 TESTCASE("Bug53944", "")
12470 {
12471   INITIALIZER(runBug53944);
12472 }
12473 TESTCASE("Bug58277",
12474          "Dropping busy ordered index can crash data node.\n"
12475          "Give any tablename as argument (T1)"){
12476   TC_PROPERTY("RSS_CHECK", (Uint32)true);
12477   TC_PROPERTY("RANGE_MAX", (Uint32)5);
12478   INITIALIZER(runBug58277errtest);
12479   STEP(runBug58277);
12480   // sub-steps 2-8 synced with main step
12481   TC_PROPERTY("SubSteps", 7);
12482   STEP(runBug58277drop);
12483   /*
12484    * A single scan update can show the bug but this is not likely.
12485    * Add more scan updates.  Also add PK ops for other asserts.
12486    */
12487   STEP(runBug58277scan);
12488   STEP(runBug58277scan);
12489   STEP(runBug58277scan);
12490   STEP(runBug58277scan);
12491   STEP(runBug58277pk);
12492   STEP(runBug58277pk);
12493   // kernel side scans (eg. LCP) for resource usage check
12494   STEP(runBug58277rand);
12495 }
12496 TESTCASE("Bug57057",
12497          "MRR + delete leaks stored procs (fixed under Bug58277).\n"
12498          "Give any tablename as argument (T1)"){
12499   TC_PROPERTY("RSS_CHECK", (Uint32)true);
12500   TC_PROPERTY("RANGE_MAX", (Uint32)100);
12501   TC_PROPERTY("SCAN_DELETE", (Uint32)1);
12502   STEP(runBug57057);
12503   TC_PROPERTY("SubSteps", 1);
12504   STEP(runBug58277scan);
12505 }
12506 TESTCASE("GetTabInfoRef", "Regression test for bug #14647210 'CAN CRASH ALL "
12507          "NODES EASILY WHEN RESTARTING MORE THAN 6 NODES SIMULTANEOUSLY'"
12508          " (missing handling of GET_TABINFOREF signal).")
12509 {
12510   INITIALIZER(runGetTabInfoRef);
12511 }
12512 TESTCASE("Bug13416603", "")
12513 {
12514   INITIALIZER(runCreateTheTable);
12515   INITIALIZER(runLoadTable);
12516   INITIALIZER(runBug13416603);
12517   FINALIZER(runDropTheTable);
12518 }
12519 TESTCASE("IndexStatCreate", "")
12520 {
12521   STEPS(runIndexStatCreate, 10);
12522 }
12523 TESTCASE("WL946",
12524          "Time types with fractional seconds.\n"
12525          "Give any tablename as argument (T1)"){
12526   INITIALIZER(runWL946);
12527 }
12528 TESTCASE("Bug14645319", "")
12529 {
12530   STEP(runBug14645319);
12531 }
12532 TESTCASE("FK_SRNR1",
12533          "Foreign keys SR/NR, simple case with DDL and DML checks.\n"
12534          "Give any tablename as argument (T1)"){
12535   TC_PROPERTY("testcase", 1);
12536   INITIALIZER(runFK_SRNR);
12537 }
12538 TESTCASE("FK_SRNR2",
12539          "Foreign keys SR/NR, complex case with DDL checks .\n"
12540          "Give any tablename as argument (T1)"){
12541   TC_PROPERTY("testcase", 2);
12542   INITIALIZER(runFK_SRNR);
12543 }
12544 TESTCASE("FK_TRANS1",
12545          "Foreign keys schema trans, simple case with DDL and DML checks.\n"
12546          "Give any tablename as argument (T1)"){
12547   TC_PROPERTY("testcase", 1);
12548   INITIALIZER(runFK_TRANS);
12549 }
12550 TESTCASE("FK_TRANS2",
12551          "Foreign keys schema trans, complex case with DDL checks.\n"
12552          "Give any tablename as argument (T1)"){
12553   TC_PROPERTY("testcase", 2);
12554   INITIALIZER(runFK_TRANS);
12555 }
12556 TESTCASE("FK_Bug18069680",
12557          "NDB API drop table with foreign keys.\n"
12558          "Give any tablename as argument (T1)"){
12559   TC_PROPERTY("testcase", 2);
12560   INITIALIZER(runFK_Bug18069680);
12561 }
12562 TESTCASE("CreateHashmaps",
12563          "Create (default) hashmaps")
12564 {
12565   INITIALIZER(runCreateHashmaps);
12566 }
12567 TESTCASE("DictTakeOver_1", "")
12568 {
12569   INITIALIZER(runDictTO_1);
12570 }
12571 TESTCASE("indexStat", "test dictsignal timeout in INDEX_STAT_REQ")
12572 {
12573   INITIALIZER(runCreateTheTable);
12574   INITIALIZER(runCreateTheIndex);
12575   INITIALIZER(runIndexStatTimeout);
12576   FINALIZER(runDropTheIndex);
12577   FINALIZER(runDropTheTable);
12578 }
12579 TESTCASE("forceGCPWait", "test dictsignal timeout in FORCE_GCP_WAIT")
12580 {
12581   INITIALIZER(runForceGCPWait);
12582 }
12583 TESTCASE("CreateManyDataFiles", "Test lack of DiskPageBufferMemory "
12584          "when creating data files")
12585 {
12586   INITIALIZER(changeStartDiskPageBufMem);
12587   INITIALIZER(runCreateLogFileGroupTableSpace);
12588   TC_PROPERTY("DATAFILES", (Uint32)200);
12589   INITIALIZER(runCreateManyDataFiles);
12590   FINALIZER(runDropTableSpaceLG);
12591   FINALIZER(changeStartDiskPageBufMem);
12592 }
12593 
NDBT_TESTSUITE_END(testDict)12594 NDBT_TESTSUITE_END(testDict)
12595 
12596 int main(int argc, const char** argv){
12597   ndb_init();
12598   NDBT_TESTSUITE_INSTANCE(testDict);
12599   // Tables should not be auto created
12600   testDict.setCreateTable(false);
12601   myRandom48Init((long)NdbTick_CurrentMillisecond());
12602   return testDict.execute(argc, argv);
12603 }
12604