1 /*
2    Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <NDBT_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     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     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