1 /*
2 Copyright (c) 2004, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <NDBT_Test.hpp>
26 #include <NDBT_ReturnCodes.h>
27 #include <HugoTransactions.hpp>
28 #include <UtilTransactions.hpp>
29 #include <NdbRestarter.hpp>
30
31 static Uint32 max_dks = 0;
32 static const Uint32 MAX_FRAGS=48 * 8 * 4; // e.g. 48 nodes, 8 frags/node, 4 replicas
33 static Uint32 frag_ng_mappings[MAX_FRAGS];
34 static const char* DistTabName= "DistTest";
35 static const char* DistTabDKeyCol= "DKey";
36 static const char* DistTabPKey2Col= "PKey2";
37 static const char* DistTabResultCol= "Result";
38 static const char* DistIdxName= "ResultIndex";
39
40 static
41 int
run_drop_table(NDBT_Context * ctx,NDBT_Step * step)42 run_drop_table(NDBT_Context* ctx, NDBT_Step* step)
43 {
44 NdbDictionary::Dictionary* dict = GETNDB(step)->getDictionary();
45 dict->dropTable(ctx->getTab()->getName());
46 return 0;
47 }
48
49 static
50 int
setNativePartitioning(Ndb * ndb,NdbDictionary::Table & tab,int when,void * arg)51 setNativePartitioning(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
52 {
53 switch(when){
54 case 0: // Before
55 break;
56 case 1: // After
57 return 0;
58 default:
59 return 0;
60 }
61
62 /* Use rand to choose one of the native partitioning schemes */
63 const Uint32 rType= rand() % 3;
64 Uint32 fragType= -1;
65 switch(rType)
66 {
67 case 0 :
68 fragType = NdbDictionary::Object::DistrKeyHash;
69 break;
70 case 1 :
71 fragType = NdbDictionary::Object::DistrKeyLin;
72 break;
73 case 2:
74 fragType = NdbDictionary::Object::HashMapPartition;
75 break;
76 }
77
78 ndbout << "Setting fragment type to " << fragType << endl;
79 tab.setFragmentType((NdbDictionary::Object::FragmentType)fragType);
80 return 0;
81 }
82
83
84 static
85 int
add_distribution_key(Ndb * ndb,NdbDictionary::Table & tab,int when,void * arg)86 add_distribution_key(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
87 {
88 switch(when){
89 case 0: // Before
90 break;
91 case 1: // After
92 return 0;
93 default:
94 return 0;
95 }
96
97 /* Choose a partitioning type */
98 setNativePartitioning(ndb, tab, when, arg);
99
100 int keys = tab.getNoOfPrimaryKeys();
101 Uint32 dks = (2 * keys + 2) / 3; dks = (dks > max_dks ? max_dks : dks);
102
103 for(int i = 0; i<tab.getNoOfColumns(); i++)
104 if(tab.getColumn(i)->getPrimaryKey() &&
105 tab.getColumn(i)->getCharset() != 0)
106 keys--;
107
108 Uint32 max = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY - tab.getNoOfPrimaryKeys();
109
110 if(max_dks < max)
111 max = max_dks;
112
113 if(keys <= 1 && max > 0)
114 {
115 dks = 1 + (rand() % max);
116 ndbout_c("%s pks: %d dks: %d", tab.getName(), keys, dks);
117 while(dks--)
118 {
119 NdbDictionary::Column col;
120 BaseString name;
121 name.assfmt("PK_DK_%d", dks);
122 col.setName(name.c_str());
123 if((rand() % 100) > 50)
124 {
125 col.setType(NdbDictionary::Column::Unsigned);
126 col.setLength(1);
127 }
128 else
129 {
130 col.setType(NdbDictionary::Column::Varbinary);
131 col.setLength(1+(rand() % 25));
132 }
133 col.setNullable(false);
134 col.setPrimaryKey(true);
135 col.setDistributionKey(true);
136 tab.addColumn(col);
137 }
138 }
139 else
140 {
141 for(int i = 0; i<tab.getNoOfColumns(); i++)
142 {
143 NdbDictionary::Column* col = tab.getColumn(i);
144 if(col->getPrimaryKey() && col->getCharset() == 0)
145 {
146 if((int)dks >= keys || (rand() % 100) > 50)
147 {
148 col->setDistributionKey(true);
149 dks--;
150 }
151 keys--;
152 }
153 }
154 }
155
156 ndbout << (NDBT_Table&)tab << endl;
157
158 return 0;
159 }
160
161
162 static
163 int
setupUDPartitioning(Ndb * ndb,NdbDictionary::Table & tab)164 setupUDPartitioning(Ndb* ndb, NdbDictionary::Table& tab)
165 {
166 /* Following should really be taken from running test system : */
167 const Uint32 numNodes= ndb->get_ndb_cluster_connection().no_db_nodes();
168 const Uint32 numReplicas= 2; // Assumption
169 const Uint32 guessNumNgs= numNodes/2;
170 const Uint32 numNgs= guessNumNgs?guessNumNgs : 1;
171 const Uint32 numFragsPerNode= 2 + (rand() % 3);
172 const Uint32 numPartitions= numReplicas * numNgs * numFragsPerNode;
173
174 tab.setFragmentType(NdbDictionary::Table::UserDefined);
175 tab.setFragmentCount(numPartitions);
176 for (Uint32 i=0; i<numPartitions; i++)
177 {
178 frag_ng_mappings[i]= i % numNgs;
179 }
180 tab.setFragmentData(frag_ng_mappings, numPartitions);
181
182 return 0;
183 }
184
185 static
186 int
setUserDefPartitioning(Ndb * ndb,NdbDictionary::Table & tab,int when,void * arg)187 setUserDefPartitioning(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
188 {
189 switch(when){
190 case 0: // Before
191 break;
192 case 1: // After
193 return 0;
194 default:
195 return 0;
196 }
197
198 setupUDPartitioning(ndb, tab);
199
200 ndbout << (NDBT_Table&)tab << endl;
201
202 return 0;
203 }
204
205 static
206 int
one_distribution_key(Ndb * ndb,NdbDictionary::Table & tab,int when,void * arg)207 one_distribution_key(Ndb* ndb, NdbDictionary::Table& tab, int when, void* arg)
208 {
209 switch(when){
210 case 0: // Before
211 break;
212 case 1: // After
213 return 0;
214 default:
215 return 0;
216 }
217
218 setNativePartitioning(ndb, tab, when, arg);
219
220 int keys = tab.getNoOfPrimaryKeys();
221 int dist_key_no = rand()% keys;
222
223 for(int i = 0; i<tab.getNoOfColumns(); i++)
224 {
225 if(tab.getColumn(i)->getPrimaryKey())
226 {
227 if (dist_key_no-- == 0)
228 {
229 tab.getColumn(i)->setDistributionKey(true);
230 }
231 else
232 {
233 tab.getColumn(i)->setDistributionKey(false);
234 }
235 }
236 }
237 ndbout << (NDBT_Table&)tab << endl;
238
239 return 0;
240 }
241
242 static
243 const NdbDictionary::Table*
create_dist_table(Ndb * pNdb,bool userDefined)244 create_dist_table(Ndb* pNdb,
245 bool userDefined)
246 {
247 NdbDictionary::Dictionary* dict= pNdb->getDictionary();
248
249 do {
250 NdbDictionary::Table tab;
251 tab.setName(DistTabName);
252
253 if (userDefined)
254 {
255 setupUDPartitioning(pNdb, tab);
256 }
257 else
258 {
259 setNativePartitioning(pNdb, tab, 0, 0);
260 }
261
262 NdbDictionary::Column dk;
263 dk.setName(DistTabDKeyCol);
264 dk.setType(NdbDictionary::Column::Unsigned);
265 dk.setLength(1);
266 dk.setNullable(false);
267 dk.setPrimaryKey(true);
268 dk.setPartitionKey(true);
269 tab.addColumn(dk);
270
271 NdbDictionary::Column pk2;
272 pk2.setName(DistTabPKey2Col);
273 pk2.setType(NdbDictionary::Column::Unsigned);
274 pk2.setLength(1);
275 pk2.setNullable(false);
276 pk2.setPrimaryKey(true);
277 pk2.setPartitionKey(false);
278 tab.addColumn(pk2);
279
280 NdbDictionary::Column result;
281 result.setName(DistTabResultCol);
282 result.setType(NdbDictionary::Column::Unsigned);
283 result.setLength(1);
284 result.setNullable(true);
285 result.setPrimaryKey(false);
286 tab.addColumn(result);
287
288 dict->dropTable(tab.getName());
289 if(dict->createTable(tab) == 0)
290 {
291 ndbout << (NDBT_Table&)tab << endl;
292
293 do {
294 /* Primary key index */
295 NdbDictionary::Index idx;
296 idx.setType(NdbDictionary::Index::OrderedIndex);
297 idx.setLogging(false);
298 idx.setTable(DistTabName);
299 idx.setName("PRIMARY");
300 idx.addColumnName(DistTabDKeyCol);
301 idx.addColumnName(DistTabPKey2Col);
302
303 dict->dropIndex("PRIMARY",
304 tab.getName());
305
306 if (dict->createIndex(idx) == 0)
307 {
308 ndbout << "Primary Index created successfully" << endl;
309 break;
310 }
311 ndbout << "Primary Index create failed with " <<
312 dict->getNdbError().code <<
313 " retrying " << endl;
314 } while (0);
315
316 do {
317 /* Now the index on the result column */
318 NdbDictionary::Index idx;
319 idx.setType(NdbDictionary::Index::OrderedIndex);
320 idx.setLogging(false);
321 idx.setTable(DistTabName);
322 idx.setName(DistIdxName);
323 idx.addColumnName(DistTabResultCol);
324
325 dict->dropIndex(idx.getName(),
326 tab.getName());
327
328 if (dict->createIndex(idx) == 0)
329 {
330 ndbout << "Index on Result created successfully" << endl;
331 return dict->getTable(tab.getName());
332 }
333 ndbout << "Index create failed with " <<
334 dict->getNdbError().code << endl;
335 } while (0);
336 }
337 } while (0);
338 return 0;
339 };
340
341 static int
run_create_table(NDBT_Context * ctx,NDBT_Step * step)342 run_create_table(NDBT_Context* ctx, NDBT_Step* step)
343 {
344 /* Create table, optionally with extra distribution keys
345 * or UserDefined partitioning
346 */
347 max_dks = ctx->getProperty("distributionkey", (unsigned)0);
348 bool userDefined = ctx->getProperty("UserDefined", (unsigned) 0);
349
350 if(NDBT_Tables::createTable(GETNDB(step),
351 ctx->getTab()->getName(),
352 false, false,
353 max_dks?
354 add_distribution_key:
355 userDefined?
356 setUserDefPartitioning :
357 setNativePartitioning) == NDBT_OK)
358 {
359 return NDBT_OK;
360 }
361
362 if(GETNDB(step)->getDictionary()->getNdbError().code == 745)
363 return NDBT_OK;
364
365 return NDBT_FAILED;
366 }
367
368 static int
run_create_table_smart_scan(NDBT_Context * ctx,NDBT_Step * step)369 run_create_table_smart_scan(NDBT_Context* ctx, NDBT_Step* step)
370 {
371 if(NDBT_Tables::createTable(GETNDB(step),
372 ctx->getTab()->getName(),
373 false, false,
374 one_distribution_key) == NDBT_OK)
375 {
376 return NDBT_OK;
377 }
378
379 if(GETNDB(step)->getDictionary()->getNdbError().code == 745)
380 return NDBT_OK;
381
382 return NDBT_FAILED;
383 }
384
385 static int
run_create_pk_index(NDBT_Context * ctx,NDBT_Step * step)386 run_create_pk_index(NDBT_Context* ctx, NDBT_Step* step){
387 bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
388
389 Ndb* pNdb = GETNDB(step);
390 const NdbDictionary::Table *pTab =
391 pNdb->getDictionary()->getTable(ctx->getTab()->getName());
392
393 if(!pTab)
394 return NDBT_OK;
395
396 bool logged = ctx->getProperty("LoggedIndexes", orderedIndex ? 0 : 1);
397
398 BaseString name;
399 name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
400
401 // Create index
402 if (orderedIndex)
403 ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "ordered index "
404 << name.c_str() << " (";
405 else
406 ndbout << "Creating " << ((logged)?"logged ": "temporary ") << "unique index "
407 << name.c_str() << " (";
408
409 NdbDictionary::Index pIdx(name.c_str());
410 pIdx.setTable(pTab->getName());
411 if (orderedIndex)
412 pIdx.setType(NdbDictionary::Index::OrderedIndex);
413 else
414 pIdx.setType(NdbDictionary::Index::UniqueHashIndex);
415 for (int c = 0; c< pTab->getNoOfColumns(); c++){
416 const NdbDictionary::Column * col = pTab->getColumn(c);
417 if(col->getPrimaryKey()){
418 pIdx.addIndexColumn(col->getName());
419 ndbout << col->getName() <<" ";
420 }
421 }
422
423 pIdx.setStoredIndex(logged);
424 ndbout << ") ";
425 if (pNdb->getDictionary()->createIndex(pIdx) != 0){
426 ndbout << "FAILED!" << endl;
427 const NdbError err = pNdb->getDictionary()->getNdbError();
428 NDB_ERR(err);
429 return NDBT_FAILED;
430 }
431
432 ndbout << "OK!" << endl;
433 return NDBT_OK;
434 }
435
run_create_pk_index_drop(NDBT_Context * ctx,NDBT_Step * step)436 static int run_create_pk_index_drop(NDBT_Context* ctx, NDBT_Step* step){
437 bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
438
439 Ndb* pNdb = GETNDB(step);
440 const NdbDictionary::Table *pTab =
441 pNdb->getDictionary()->getTable(ctx->getTab()->getName());
442
443 if(!pTab)
444 return NDBT_OK;
445
446 BaseString name;
447 name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
448
449 ndbout << "Dropping index " << name.c_str() << " ";
450 if (pNdb->getDictionary()->dropIndex(name.c_str(), pTab->getName()) != 0){
451 ndbout << "FAILED!" << endl;
452 NDB_ERR(pNdb->getDictionary()->getNdbError());
453 return NDBT_FAILED;
454 } else {
455 ndbout << "OK!" << endl;
456 }
457
458 return NDBT_OK;
459 }
460
461 static int
run_create_dist_table(NDBT_Context * ctx,NDBT_Step * step)462 run_create_dist_table(NDBT_Context* ctx, NDBT_Step* step)
463 {
464 bool userDefined = ctx->getProperty("UserDefined", (unsigned)0);
465 if(create_dist_table(GETNDB(step),
466 userDefined))
467 return NDBT_OK;
468
469 return NDBT_FAILED;
470 }
471
472 static int
run_drop_dist_table(NDBT_Context * ctx,NDBT_Step * step)473 run_drop_dist_table(NDBT_Context* ctx, NDBT_Step* step)
474 {
475 GETNDB(step)->getDictionary()->dropTable(DistTabName);
476 return NDBT_OK;
477 }
478
479 static int
run_tests(Ndb * p_ndb,HugoTransactions & hugoTrans,int records,Uint32 batchSize=1)480 run_tests(Ndb* p_ndb, HugoTransactions& hugoTrans, int records, Uint32 batchSize = 1)
481 {
482 if (hugoTrans.loadTable(p_ndb, records, batchSize) != 0)
483 {
484 return NDBT_FAILED;
485 }
486
487 if(hugoTrans.pkReadRecords(p_ndb, records, batchSize) != 0)
488 {
489 return NDBT_FAILED;
490 }
491
492 if(hugoTrans.pkUpdateRecords(p_ndb, records, batchSize) != 0)
493 {
494 return NDBT_FAILED;
495 }
496
497 if(hugoTrans.pkDelRecords(p_ndb, records, batchSize) != 0)
498 {
499 return NDBT_FAILED;
500 }
501
502 if (hugoTrans.loadTable(p_ndb, records, batchSize) != 0)
503 {
504 return NDBT_FAILED;
505 }
506
507 if(hugoTrans.scanUpdateRecords(p_ndb, records) != 0)
508 {
509 return NDBT_FAILED;
510 }
511
512 Uint32 abort = 23;
513 for(Uint32 j = 0; j<5; j++){
514 Uint32 parallelism = (j == 1 ? 1 : j * 3);
515 ndbout_c("parallelism: %d", parallelism);
516 if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
517 NdbOperation::LM_Read) != 0)
518 {
519 return NDBT_FAILED;
520 }
521 if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
522 NdbOperation::LM_Exclusive) != 0)
523 {
524 return NDBT_FAILED;
525 }
526 if (hugoTrans.scanReadRecords(p_ndb, records, abort, parallelism,
527 NdbOperation::LM_CommittedRead) != 0)
528 {
529 return NDBT_FAILED;
530 }
531 }
532
533 if(hugoTrans.clearTable(p_ndb, records) != 0)
534 {
535 return NDBT_FAILED;
536 }
537
538 return 0;
539 }
540
541 static int
run_pk_dk(NDBT_Context * ctx,NDBT_Step * step)542 run_pk_dk(NDBT_Context* ctx, NDBT_Step* step)
543 {
544 Ndb* p_ndb = GETNDB(step);
545 int records = ctx->getNumRecords();
546 const NdbDictionary::Table *tab =
547 p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
548
549 if(!tab)
550 return NDBT_OK;
551
552 HugoTransactions hugoTrans(*tab);
553
554 Uint32 batchSize= ctx->getProperty("BatchSize", (unsigned) 1);
555
556 return run_tests(p_ndb, hugoTrans, records, batchSize);
557 }
558
559 int
run_index_dk(NDBT_Context * ctx,NDBT_Step * step)560 run_index_dk(NDBT_Context* ctx, NDBT_Step* step)
561 {
562 Ndb* p_ndb = GETNDB(step);
563 int records = ctx->getNumRecords();
564 const NdbDictionary::Table *pTab =
565 p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
566
567 if(!pTab)
568 return NDBT_OK;
569
570 bool orderedIndex = ctx->getProperty("OrderedIndex", (unsigned)0);
571
572 BaseString name;
573 name.assfmt("IND_%s_PK_%c", pTab->getName(), orderedIndex ? 'O' : 'U');
574
575 const NdbDictionary::Index * idx =
576 p_ndb->getDictionary()->getIndex(name.c_str(), pTab->getName());
577
578 if(!idx)
579 {
580 ndbout << "Failed to retreive index: " << name.c_str() << endl;
581 return NDBT_FAILED;
582 }
583 Uint32 batchSize= ctx->getProperty("BatchSize", (unsigned) 1);
584
585 HugoTransactions hugoTrans(*pTab, idx);
586
587 return run_tests(p_ndb, hugoTrans, records, batchSize);
588 }
589
590 static int
run_startHint(NDBT_Context * ctx,NDBT_Step * step)591 run_startHint(NDBT_Context* ctx, NDBT_Step* step)
592 {
593 Ndb* p_ndb = GETNDB(step);
594 int records = ctx->getNumRecords();
595 const NdbDictionary::Table *tab =
596 p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
597
598 if(!tab)
599 return NDBT_OK;
600
601 HugoTransactions hugoTrans(*tab);
602 if (hugoTrans.loadTable(p_ndb, records) != 0)
603 {
604 return NDBT_FAILED;
605 }
606
607 NdbRestarter restarter;
608 if(restarter.insertErrorInAllNodes(8050) != 0)
609 return NDBT_FAILED;
610
611 HugoCalculator dummy(*tab);
612 int result = NDBT_OK;
613 for(int i = 0; i<records && result == NDBT_OK; i++)
614 {
615 char buffer[NDB_MAX_TUPLE_SIZE];
616 char* start= buffer + (rand() & 7);
617 char* pos= start;
618
619 int k = 0;
620 Ndb::Key_part_ptr ptrs[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY+1];
621 for(int j = 0; j<tab->getNoOfColumns(); j++)
622 {
623 if(tab->getColumn(j)->getPartitionKey())
624 {
625 //ndbout_c(tab->getColumn(j)->getName());
626 int sz = tab->getColumn(j)->getSizeInBytes();
627 Uint32 real_size;
628 dummy.calcValue(i, j, 0, pos, sz, &real_size);
629 ptrs[k].ptr = pos;
630 ptrs[k++].len = real_size;
631 pos += (real_size + 3) & ~3;
632 }
633 }
634 ptrs[k].ptr = 0;
635
636 // Now we have the pk
637 NdbTransaction* pTrans= p_ndb->startTransaction(tab, ptrs);
638 HugoOperations ops(*tab);
639 ops.setTransaction(pTrans);
640 if(ops.pkReadRecord(p_ndb, i, 1) != NDBT_OK)
641 {
642 result = NDBT_FAILED;
643 break;
644 }
645
646 if(ops.execute_Commit(p_ndb) != 0)
647 {
648 result = NDBT_FAILED;
649 break;
650 }
651
652 ops.closeTransaction(p_ndb);
653 }
654 restarter.insertErrorInAllNodes(0);
655 return result;
656 }
657
658 static int
run_startHint_ordered_index(NDBT_Context * ctx,NDBT_Step * step)659 run_startHint_ordered_index(NDBT_Context* ctx, NDBT_Step* step)
660 {
661 Ndb* p_ndb = GETNDB(step);
662 int records = ctx->getNumRecords();
663 const NdbDictionary::Table *tab =
664 p_ndb->getDictionary()->getTable(ctx->getTab()->getName());
665
666 if(!tab)
667 return NDBT_OK;
668
669 BaseString name;
670 name.assfmt("IND_%s_PK_O", tab->getName());
671
672 const NdbDictionary::Index * idx =
673 p_ndb->getDictionary()->getIndex(name.c_str(), tab->getName());
674
675 if(!idx)
676 {
677 ndbout << "Failed to retreive index: " << name.c_str() << endl;
678 return NDBT_FAILED;
679 }
680
681 HugoTransactions hugoTrans(*tab, idx);
682 if (hugoTrans.loadTable(p_ndb, records) != 0)
683 {
684 return NDBT_FAILED;
685 }
686
687 NdbRestarter restarter;
688 if(restarter.insertErrorInAllNodes(8050) != 0)
689 return NDBT_FAILED;
690
691 HugoCalculator dummy(*tab);
692 int result = NDBT_OK;
693 for(int i = 0; i<records && result == NDBT_OK; i++)
694 {
695 char buffer[NDB_MAX_TUPLE_SIZE];
696 NdbTransaction* pTrans= NULL;
697
698 char* start= buffer + (rand() & 7);
699 char* pos= start;
700
701 int k = 0;
702 Ndb::Key_part_ptr ptrs[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY+1];
703 for(int j = 0; j<tab->getNoOfColumns(); j++)
704 {
705 if(tab->getColumn(j)->getPartitionKey())
706 {
707 //ndbout_c(tab->getColumn(j)->getName());
708 int sz = tab->getColumn(j)->getSizeInBytes();
709 Uint32 real_size;
710 dummy.calcValue(i, j, 0, pos, sz, &real_size);
711 ptrs[k].ptr = pos;
712 ptrs[k++].len = real_size;
713 pos += (real_size + 3) & ~3;
714 }
715 }
716 ptrs[k].ptr = 0;
717
718 // Now we have the pk, start a hinted transaction
719 pTrans= p_ndb->startTransaction(tab, ptrs);
720
721 // Because we pass an Ordered index here, pkReadRecord will
722 // use an index scan on the Ordered index
723 HugoOperations ops(*tab, idx);
724 ops.setTransaction(pTrans);
725 /* Despite it's name, it will actually perform index scans
726 * as there is an index.
727 * Error 8050 will cause an NDBD assertion failure in
728 * Dbtc::execDIGETPRIMCONF() if TC needs to scan a fragment
729 * which is not on the TC node
730 * So for this TC to pass with no failures we need transaction
731 * hinting and scan partition pruning on equal() to work
732 * correctly.
733 * TODO : Get coverage of Index scan which is equal on dist
734 * key cols, but has an inequality on some other column.
735 */
736 if(ops.pkReadRecord(p_ndb, i, 1) != NDBT_OK)
737 {
738 result = NDBT_FAILED;
739 break;
740 }
741
742 if(ops.execute_Commit(p_ndb) != 0)
743 {
744 result = NDBT_FAILED;
745 break;
746 }
747
748 ops.closeTransaction(p_ndb);
749 }
750 restarter.insertErrorInAllNodes(0);
751 return result;
752 }
753
754 #define CHECK(x, y) {int res= (x); \
755 if (res != 0) { ndbout << "Assert failed at " \
756 << __LINE__ << endl \
757 << res << endl \
758 << " error : " \
759 << (y)->getNdbError().code \
760 << endl; \
761 return NDBT_FAILED; } }
762
763 #define CHECKNOTNULL(x, y) { \
764 if ((x) == NULL) { ndbout << "Assert failed at line " \
765 << __LINE__ << endl \
766 << " with " \
767 << (y)->getNdbError().code \
768 << endl; \
769 return NDBT_FAILED; } }
770
771
772 static int
load_dist_table(Ndb * pNdb,int records,int parts)773 load_dist_table(Ndb* pNdb, int records, int parts)
774 {
775 const NdbDictionary::Table* tab= pNdb->getDictionary()->getTable(DistTabName);
776 bool userDefined= (tab->getFragmentType() ==
777 NdbDictionary::Object::UserDefined);
778
779 const NdbRecord* distRecord= tab->getDefaultRecord();
780 CHECKNOTNULL(distRecord, pNdb);
781
782 char* buf= (char*) malloc(NdbDictionary::getRecordRowLength(distRecord));
783
784 CHECKNOTNULL(buf, pNdb);
785
786 /* We insert a number of records with a constrained number of
787 * values for the distribution key column
788 */
789 for (int r=0; r < records; r++)
790 {
791 NdbTransaction* trans= pNdb->startTransaction();
792 CHECKNOTNULL(trans, pNdb);
793
794 {
795 const int dKeyVal= r % parts;
796 const Uint32 dKeyAttrid= tab->getColumn(DistTabDKeyCol)->getAttrId();
797 memcpy(NdbDictionary::getValuePtr(distRecord, buf,
798 dKeyAttrid),
799 &dKeyVal, sizeof(dKeyVal));
800 }
801
802 {
803 const int pKey2Val= r;
804 const Uint32 pKey2Attrid= tab->getColumn(DistTabPKey2Col)->getAttrId();
805 memcpy(NdbDictionary::getValuePtr(distRecord, buf,
806 pKey2Attrid),
807 &pKey2Val, sizeof(pKey2Val));
808 }
809
810 {
811 const int resultVal= r*r;
812 const Uint32 resultValAttrid=
813 tab->getColumn(DistTabResultCol)->getAttrId();
814 memcpy(NdbDictionary::getValuePtr(distRecord, buf,
815 resultValAttrid),
816 &resultVal, sizeof(resultVal));
817
818 // set not NULL
819 NdbDictionary::setNull(distRecord, buf, resultValAttrid, false);
820 }
821
822
823 NdbOperation::OperationOptions opts;
824 opts.optionsPresent= 0;
825
826 if (userDefined)
827 {
828 /* For user-defined partitioning, we set the partition id
829 * to be the distribution key value modulo the number
830 * of partitions in the table
831 */
832 opts.optionsPresent= NdbOperation::OperationOptions::OO_PARTITION_ID;
833 opts.partitionId= (r%parts) % tab->getFragmentCount();
834 }
835
836 CHECKNOTNULL(trans->insertTuple(distRecord, buf,
837 NULL, &opts, sizeof(opts)), trans);
838
839 if (trans->execute(NdbTransaction::Commit) != 0)
840 {
841 NdbError err = trans->getNdbError();
842 if (err.status == NdbError::TemporaryError)
843 {
844 ndbout << err << endl;
845 NdbSleep_MilliSleep(50);
846 r--; // just retry
847 }
848 else
849 {
850 CHECK(-1, trans);
851 }
852 }
853 trans->close();
854 }
855
856 free(buf);
857
858 return NDBT_OK;
859 };
860
861 struct PartInfo
862 {
863 NdbTransaction* trans;
864 NdbIndexScanOperation* op;
865 int dKeyVal;
866 int valCount;
867 };
868
869 class Ap
870 {
871 public:
872 void* ptr;
873
Ap(void * _ptr)874 Ap(void* _ptr) : ptr(_ptr)
875 {};
~Ap()876 ~Ap()
877 {
878 if (ptr != 0)
879 {
880 free(ptr);
881 ptr= 0;
882 }
883 }
884 };
885
886 static int
dist_scan_body(Ndb * pNdb,int records,int parts,PartInfo * partInfo,bool usePrimary)887 dist_scan_body(Ndb* pNdb, int records, int parts, PartInfo* partInfo, bool usePrimary)
888 {
889 const NdbDictionary::Table* tab= pNdb->getDictionary()->getTable(DistTabName);
890 CHECKNOTNULL(tab, pNdb->getDictionary());
891 const char* indexName= usePrimary ? "PRIMARY" : DistIdxName;
892 const NdbDictionary::Index* idx= pNdb->getDictionary()->getIndex(indexName,
893 DistTabName);
894 CHECKNOTNULL(idx, pNdb->getDictionary());
895 const NdbRecord* tabRecord= tab->getDefaultRecord();
896 const NdbRecord* idxRecord= idx->getDefaultRecord();
897 bool userDefined= (tab->getFragmentType() ==
898 NdbDictionary::Object::UserDefined);
899
900 char* boundBuf= (char*) malloc(NdbDictionary::getRecordRowLength(idx->getDefaultRecord()));
901
902 if (usePrimary)
903 ndbout << "Checking MRR indexscan distribution awareness when distribution key part of bounds" << endl;
904 else
905 ndbout << "Checking MRR indexscan distribution awareness when distribution key provided explicitly" << endl;
906
907 if (userDefined)
908 ndbout << "User Defined Partitioning scheme" << endl;
909 else
910 ndbout << "Native Partitioning scheme" << endl;
911
912 Ap boundAp(boundBuf);
913
914 for (int r=0; r < records; r++)
915 {
916 int partValue= r % parts;
917 PartInfo& pInfo= partInfo[partValue];
918
919 if (pInfo.trans == NULL)
920 {
921 /* Provide the partition key as a hint for this transaction */
922 if (!userDefined)
923 {
924 Ndb::Key_part_ptr keyParts[2];
925 keyParts[0].ptr= &partValue;
926 keyParts[0].len= sizeof(partValue);
927 keyParts[1].ptr= NULL;
928 keyParts[1].len= 0;
929
930 /* To test that bad hinting causes failure, uncomment */
931 // int badPartVal= partValue+1;
932 // keyParts[0].ptr= &badPartVal;
933
934 CHECKNOTNULL(pInfo.trans= pNdb->startTransaction(tab, keyParts),
935 pNdb);
936 }
937 else
938 {
939 /* User Defined partitioning */
940 Uint32 partId= partValue % tab->getFragmentCount();
941 CHECKNOTNULL(pInfo.trans= pNdb->startTransaction(tab,
942 partId),
943 pNdb);
944 }
945 pInfo.valCount= 0;
946 pInfo.dKeyVal= partValue;
947
948 NdbScanOperation::ScanOptions opts;
949 opts.optionsPresent= NdbScanOperation::ScanOptions::SO_SCANFLAGS;
950 opts.scan_flags= NdbScanOperation::SF_MultiRange;
951
952 // Define the scan operation for this partition.
953 CHECKNOTNULL(pInfo.op= pInfo.trans->scanIndex(idx->getDefaultRecord(),
954 tab->getDefaultRecord(),
955 NdbOperation::LM_Read,
956 NULL,
957 NULL,
958 &opts,
959 sizeof(opts)),
960 pInfo.trans);
961 }
962
963 NdbIndexScanOperation* op= pInfo.op;
964
965 if (usePrimary)
966 {
967 {
968 int dKeyVal= partValue;
969 int pKey2Val= r;
970 /* Scanning the primary index, set bound on the pk */
971 memcpy(NdbDictionary::getValuePtr(idxRecord,
972 boundBuf,
973 tab->getColumn(DistTabDKeyCol)->getAttrId()),
974 &dKeyVal,
975 sizeof(dKeyVal));
976 memcpy(NdbDictionary::getValuePtr(idxRecord,
977 boundBuf,
978 tab->getColumn(DistTabPKey2Col)->getAttrId()),
979 &pKey2Val,
980 sizeof(pKey2Val));
981
982 }
983
984 NdbIndexScanOperation::IndexBound ib;
985 ib.low_key= boundBuf;
986 ib.low_key_count= 2;
987 ib.low_inclusive= true;
988 ib.high_key= ib.low_key;
989 ib.high_key_count= ib.low_key_count;
990 ib.high_inclusive= true;
991 ib.range_no= pInfo.valCount++;
992
993 /* No partitioning info for native, PK index scan
994 * NDBAPI can determine it from PK */
995 Ndb::PartitionSpec pSpec;
996 pSpec.type= Ndb::PartitionSpec::PS_NONE;
997
998 if (userDefined)
999 {
1000 /* We'll provide partition info */
1001 pSpec.type= Ndb::PartitionSpec::PS_USER_DEFINED;
1002 pSpec.UserDefined.partitionId= partValue % tab->getFragmentCount();
1003 }
1004
1005 CHECK(op->setBound(idxRecord,
1006 ib,
1007 &pSpec,
1008 sizeof(pSpec)),
1009 op);
1010 }
1011 else
1012 {
1013 Uint32 resultValAttrId= tab->getColumn(DistTabResultCol)->getAttrId();
1014 /* Scanning the secondary index, set bound on the result */
1015 {
1016 int resultVal= r*r;
1017 memcpy(NdbDictionary::getValuePtr(idxRecord,
1018 boundBuf,
1019 resultValAttrId),
1020 &resultVal,
1021 sizeof(resultVal));
1022 }
1023
1024 NdbDictionary::setNull(idxRecord,
1025 boundBuf,
1026 resultValAttrId,
1027 false);
1028
1029 NdbIndexScanOperation::IndexBound ib;
1030 ib.low_key= boundBuf;
1031 ib.low_key_count= 1;
1032 ib.low_inclusive= true;
1033 ib.high_key= ib.low_key;
1034 ib.high_key_count= ib.low_key_count;
1035 ib.high_inclusive= true;
1036 ib.range_no= pInfo.valCount++;
1037
1038 Ndb::Key_part_ptr keyParts[2];
1039 keyParts[0].ptr= &partValue;
1040 keyParts[0].len= sizeof(partValue);
1041 keyParts[1].ptr= NULL;
1042 keyParts[1].len= 0;
1043
1044 /* To test that bad hinting causes failure, uncomment */
1045 //int badPartVal= partValue+1;
1046 //keyParts[0].ptr= &badPartVal;
1047
1048 Ndb::PartitionSpec pSpec;
1049 char* tabRow= NULL;
1050
1051 if (userDefined)
1052 {
1053 /* We'll provide partition info */
1054 pSpec.type= Ndb::PartitionSpec::PS_USER_DEFINED;
1055 pSpec.UserDefined.partitionId= partValue % tab->getFragmentCount();
1056 }
1057 else
1058 {
1059 /* Can set either using an array of Key parts, or a KeyRecord
1060 * structure. Let's test both
1061 */
1062 if (rand() % 2)
1063 {
1064 //ndbout << "Using Key Parts to set range partition info" << endl;
1065 pSpec.type= Ndb::PartitionSpec::PS_DISTR_KEY_PART_PTR;
1066 pSpec.KeyPartPtr.tableKeyParts= keyParts;
1067 pSpec.KeyPartPtr.xfrmbuf= NULL;
1068 pSpec.KeyPartPtr.xfrmbuflen= 0;
1069 }
1070 else
1071 {
1072 //ndbout << "Using KeyRecord to set range partition info" << endl;
1073
1074 /* Setup a row in NdbRecord format with the distkey value set */
1075 tabRow= (char*)malloc(NdbDictionary::getRecordRowLength(tabRecord));
1076 int& dKeyVal= *((int*) NdbDictionary::getValuePtr(tabRecord,
1077 tabRow,
1078 tab->getColumn(DistTabDKeyCol)->getAttrId()));
1079 dKeyVal= partValue;
1080 // dKeyVal= partValue + 1; // Test failue case
1081
1082 pSpec.type= Ndb::PartitionSpec::PS_DISTR_KEY_RECORD;
1083 pSpec.KeyRecord.keyRecord= tabRecord;
1084 pSpec.KeyRecord.keyRow= tabRow;
1085 pSpec.KeyRecord.xfrmbuf= 0;
1086 pSpec.KeyRecord.xfrmbuflen= 0;
1087 }
1088 }
1089
1090 CHECK(op->setBound(idxRecord,
1091 ib,
1092 &pSpec,
1093 sizeof(pSpec)),
1094 op);
1095
1096 if (tabRow)
1097 free(tabRow);
1098 tabRow= NULL;
1099
1100 }
1101 }
1102
1103 for (int p=0; p < parts; p++)
1104 {
1105 PartInfo& pInfo= partInfo[p];
1106 //ndbout << "D-key val " << p << " has " << pInfo.valCount
1107 // << " ranges specified. " << endl;
1108 //ndbout << "Is Pruned? " << pInfo.op->getPruned() << endl;
1109 if (! pInfo.op->getPruned())
1110 {
1111 ndbout << "MRR Scan Operation should have been pruned, but was not." << endl;
1112 return NDBT_FAILED;
1113 }
1114
1115 CHECK(pInfo.trans->execute(NdbTransaction::NoCommit), pInfo.trans);
1116
1117 int resultCount=0;
1118
1119 const char* resultPtr;
1120 int rc= 0;
1121
1122 while ((rc= pInfo.op->nextResult(&resultPtr, true, true)) == 0)
1123 {
1124 int dKeyVal;
1125 memcpy(&dKeyVal, NdbDictionary::getValuePtr(tabRecord,
1126 resultPtr,
1127 tab->getColumn(DistTabDKeyCol)->getAttrId()),
1128 sizeof(dKeyVal));
1129
1130 int pKey2Val;
1131 memcpy(&pKey2Val, NdbDictionary::getValuePtr(tabRecord,
1132 resultPtr,
1133 tab->getColumn(DistTabPKey2Col)->getAttrId()),
1134 sizeof(pKey2Val));
1135
1136 int resultVal;
1137 memcpy(&resultVal, NdbDictionary::getValuePtr(tabRecord,
1138 resultPtr,
1139 tab->getColumn(DistTabResultCol)->getAttrId()),
1140 sizeof(resultVal));
1141
1142 if ((dKeyVal != pInfo.dKeyVal) ||
1143 (resultVal != (pKey2Val * pKey2Val)))
1144 {
1145 ndbout << "Got bad values. Dkey : " << dKeyVal
1146 << " Pkey2 : " << pKey2Val
1147 << " Result : " << resultVal
1148 << endl;
1149 return NDBT_FAILED;
1150 }
1151 resultCount++;
1152 }
1153
1154 if (rc != 1)
1155 {
1156 ndbout << "Got bad scan rc " << rc << endl;
1157 ndbout << "Error : " << pInfo.op->getNdbError().code << endl;
1158 ndbout << "Trans Error : " << pInfo.trans->getNdbError().code << endl;
1159 return NDBT_FAILED;
1160 }
1161
1162 if (resultCount != pInfo.valCount)
1163 {
1164 ndbout << "Error resultCount was " << resultCount << endl;
1165 return NDBT_FAILED;
1166 }
1167 CHECK(pInfo.trans->execute(NdbTransaction::Commit), pInfo.trans);
1168 pInfo.trans->close();
1169 };
1170
1171 ndbout << "Success" << endl;
1172
1173 return NDBT_OK;
1174 }
1175
1176 static int
dist_scan(Ndb * pNdb,int records,int parts,bool usePk)1177 dist_scan(Ndb* pNdb, int records, int parts, bool usePk)
1178 {
1179 PartInfo* partInfo= new PartInfo[parts];
1180
1181 NdbRestarter restarter;
1182 if(restarter.insertErrorInAllNodes(8050) != 0)
1183 {
1184 delete[] partInfo;
1185 return NDBT_FAILED;
1186 }
1187
1188 for (int p=0; p<parts; p++)
1189 {
1190 partInfo[p].trans= NULL;
1191 partInfo[p].op= NULL;
1192 partInfo[p].dKeyVal= 0;
1193 partInfo[p].valCount= 0;
1194 }
1195
1196 int result= dist_scan_body(pNdb,
1197 records,
1198 parts,
1199 partInfo,
1200 usePk);
1201
1202 restarter.insertErrorInAllNodes(0);
1203 delete[] partInfo;
1204
1205 return result;
1206 }
1207
1208 static int
run_dist_test(NDBT_Context * ctx,NDBT_Step * step)1209 run_dist_test(NDBT_Context* ctx, NDBT_Step* step)
1210 {
1211 int records= ctx->getNumRecords();
1212
1213 /* Choose an interesting number of discrete
1214 * distribution key values to work with
1215 */
1216 int numTabPartitions= GETNDB(step)
1217 ->getDictionary()
1218 ->getTable(DistTabName)
1219 ->getFragmentCount();
1220 int numDkeyValues= 2*numTabPartitions + (rand() % 6);
1221 if (numDkeyValues > records)
1222 {
1223 // limit number of distributions keys to number of records
1224 numDkeyValues = records;
1225 }
1226
1227 ndbout << "Table has " << numTabPartitions
1228 << " physical partitions" << endl;
1229 ndbout << "Testing with " << numDkeyValues
1230 << " discrete distribution key values " << endl;
1231
1232 if (load_dist_table(GETNDB(step), records, numDkeyValues) != NDBT_OK)
1233 return NDBT_FAILED;
1234
1235 /* Test access via PK ordered index (including Dkey) */
1236 if (dist_scan(GETNDB(step), records, numDkeyValues, true) != NDBT_OK)
1237 return NDBT_FAILED;
1238
1239 /* Test access via secondary ordered index (not including Dkey) */
1240 if (dist_scan(GETNDB(step), records, numDkeyValues, false) != NDBT_OK)
1241 return NDBT_FAILED;
1242
1243 return NDBT_OK;
1244 }
1245
1246
1247
1248 NDBT_TESTSUITE(testPartitioning);
1249 TESTCASE("pk_dk",
1250 "Primary key operations with distribution key")
1251 {
1252 TC_PROPERTY("distributionkey", ~0);
1253 INITIALIZER(run_drop_table);
1254 INITIALIZER(run_create_table);
1255 INITIALIZER(run_pk_dk);
1256 INITIALIZER(run_drop_table);
1257 }
1258 TESTCASE("hash_index_dk",
1259 "Unique index operations with distribution key")
1260 {
1261 TC_PROPERTY("distributionkey", ~0);
1262 TC_PROPERTY("OrderedIndex", (unsigned)0);
1263 INITIALIZER(run_drop_table);
1264 INITIALIZER(run_create_table);
1265 INITIALIZER(run_create_pk_index);
1266 INITIALIZER(run_index_dk);
1267 INITIALIZER(run_create_pk_index_drop);
1268 INITIALIZER(run_drop_table);
1269 }
1270 TESTCASE("ordered_index_dk",
1271 "Ordered index operations with distribution key")
1272 {
1273 TC_PROPERTY("distributionkey", (unsigned)1);
1274 TC_PROPERTY("OrderedIndex", (unsigned)1);
1275 INITIALIZER(run_drop_table);
1276 INITIALIZER(run_create_table);
1277 INITIALIZER(run_create_pk_index);
1278 INITIALIZER(run_index_dk);
1279 INITIALIZER(run_create_pk_index_drop);
1280 INITIALIZER(run_drop_table);
1281 }
1282 TESTCASE("smart_scan",
1283 "Ordered index operations with distribution key")
1284 {
1285 TC_PROPERTY("OrderedIndex", (unsigned)1);
1286 INITIALIZER(run_drop_table);
1287 INITIALIZER(run_create_table_smart_scan);
1288 INITIALIZER(run_create_pk_index);
1289 INITIALIZER(run_index_dk);
1290 INITIALIZER(run_create_pk_index_drop);
1291 INITIALIZER(run_drop_table);
1292 }
1293 TESTCASE("startTransactionHint",
1294 "Test startTransactionHint wo/ distribution key")
1295 {
1296 /* If hint is incorrect, node failure occurs */
1297 TC_PROPERTY("distributionkey", (unsigned)0);
1298 INITIALIZER(run_drop_table);
1299 INITIALIZER(run_create_table);
1300 INITIALIZER(run_startHint);
1301 INITIALIZER(run_drop_table);
1302 }
1303 TESTCASE("startTransactionHint_dk",
1304 "Test startTransactionHint with distribution key")
1305 {
1306 /* If hint is incorrect, node failure occurs */
1307 TC_PROPERTY("distributionkey", (unsigned)~0);
1308 INITIALIZER(run_drop_table);
1309 INITIALIZER(run_create_table);
1310 INITIALIZER(run_startHint);
1311 INITIALIZER(run_drop_table);
1312 }
1313 TESTCASE("startTransactionHint_orderedIndex",
1314 "Test startTransactionHint and ordered index reads")
1315 {
1316 /* If hint is incorrect, node failure occurs */
1317 TC_PROPERTY("distributionkey", (unsigned)0);
1318 TC_PROPERTY("OrderedIndex", (unsigned)1);
1319 INITIALIZER(run_drop_table);
1320 INITIALIZER(run_create_table);
1321 INITIALIZER(run_create_pk_index);
1322 INITIALIZER(run_startHint_ordered_index);
1323 INITIALIZER(run_create_pk_index_drop);
1324 INITIALIZER(run_drop_table);
1325 }
1326 TESTCASE("startTransactionHint_orderedIndex_dk",
1327 "Test startTransactionHint and ordered index reads with distribution key")
1328 {
1329 /* If hint is incorrect, node failure occurs */
1330 TC_PROPERTY("distributionkey", (unsigned)~0);
1331 TC_PROPERTY("OrderedIndex", (unsigned)1);
1332 INITIALIZER(run_drop_table);
1333 INITIALIZER(run_create_table);
1334 INITIALIZER(run_create_pk_index);
1335 INITIALIZER(run_startHint_ordered_index);
1336 INITIALIZER(run_create_pk_index_drop);
1337 INITIALIZER(run_drop_table);
1338 }
1339 TESTCASE("startTransactionHint_orderedIndex_mrr_native",
1340 "Test hinting and MRR Ordered Index Scans for native partitioned table")
1341 {
1342 TC_PROPERTY("UserDefined", (unsigned)0);
1343 INITIALIZER(run_create_dist_table);
1344 INITIALIZER(run_dist_test);
1345 INITIALIZER(run_drop_dist_table);
1346 }
1347 TESTCASE("pk_userDefined",
1348 "Test primary key operations on table with user-defined partitioning")
1349 {
1350 /* Check PK ops against user-defined partitioned table */
1351 TC_PROPERTY("UserDefined", (unsigned) 1);
1352 INITIALIZER(run_drop_table);
1353 INITIALIZER(run_create_table);
1354 INITIALIZER(run_create_pk_index);
1355 INITIALIZER(run_pk_dk);
1356 INITIALIZER(run_create_pk_index_drop);
1357 INITIALIZER(run_drop_table);
1358 };
1359 TESTCASE("hash_index_userDefined",
1360 "Unique index operations on table with user-defined partitioning")
1361 {
1362 /* Check hash index ops against user-defined partitioned table */
1363 TC_PROPERTY("OrderedIndex", (unsigned)0);
1364 TC_PROPERTY("UserDefined", (unsigned)1);
1365 INITIALIZER(run_drop_table);
1366 INITIALIZER(run_create_table);
1367 INITIALIZER(run_create_pk_index);
1368 INITIALIZER(run_index_dk);
1369 INITIALIZER(run_create_pk_index_drop);
1370 INITIALIZER(run_drop_table);
1371 }
1372 TESTCASE("ordered_index_userDefined",
1373 "Ordered index operations on table with user-defined partitioning")
1374 {
1375 /* Check ordered index operations against user-defined partitioned table */
1376 TC_PROPERTY("OrderedIndex", (unsigned)1);
1377 TC_PROPERTY("UserDefined", (unsigned)1);
1378 INITIALIZER(run_drop_table);
1379 INITIALIZER(run_create_table);
1380 INITIALIZER(run_create_pk_index);
1381 INITIALIZER(run_index_dk);
1382 INITIALIZER(run_create_pk_index_drop);
1383 INITIALIZER(run_drop_table);
1384 }
1385 TESTCASE("startTransactionHint_orderedIndex_mrr_userDefined",
1386 "Test hinting and MRR Ordered Index Scans for user defined partitioned table")
1387 {
1388 TC_PROPERTY("UserDefined", (unsigned)1);
1389 INITIALIZER(run_create_dist_table);
1390 INITIALIZER(run_dist_test);
1391 INITIALIZER(run_drop_dist_table);
1392 }
1393
1394 NDBT_TESTSUITE_END(testPartitioning);
1395
main(int argc,const char ** argv)1396 int main(int argc, const char** argv){
1397 ndb_init();
1398 NDBT_TESTSUITE_INSTANCE(testPartitioning);
1399 testPartitioning.setCreateTable(false);
1400 return testPartitioning.execute(argc, argv);
1401 }
1402
1403
1404
1405