1 /* Copyright (c) 2006, 2015, Oracle and/or its affiliates.
2    Copyright (c) 2010, 2020, MariaDB Corporation.
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 as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16 
17 /* Some general useful functions */
18 
19 #ifdef USE_PRAGMA_IMPLEMENTATION
20 #pragma implementation
21 #endif
22 
23 #include "mariadb.h"
24 #include <my_global.h>
25 #include <tztime.h>
26 #include "sql_priv.h"
27 // Required to get server definitions for mysql/plugin.h right
28 #include "sql_plugin.h"
29 #include "sql_partition.h"                 // partition_info.h: LIST_PART_ENTRY
30                                            // NOT_A_PARTITION_ID
31 #include "partition_info.h"
32 #include "sql_parse.h"
33 #include "sql_base.h"                         // fill_record
34 #include "lock.h"
35 #include "table.h"
36 #include "sql_class.h"
37 #include "vers_string.h"
38 
39 #ifdef WITH_PARTITION_STORAGE_ENGINE
40 #include "ha_partition.h"
41 
42 
get_clone(THD * thd,bool empty_data_and_index_file)43 partition_info *partition_info::get_clone(THD *thd, bool empty_data_and_index_file)
44 {
45   MEM_ROOT *mem_root= thd->mem_root;
46   DBUG_ENTER("partition_info::get_clone");
47 
48   List_iterator<partition_element> part_it(partitions);
49   partition_element *part;
50   partition_info *clone= new (mem_root) partition_info(*this);
51   if (unlikely(!clone))
52     DBUG_RETURN(NULL);
53 
54   memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions));
55   memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions));
56   clone->bitmaps_are_initialized= FALSE;
57   clone->partitions.empty();
58 
59   while ((part= (part_it++)))
60   {
61     List_iterator<partition_element> subpart_it(part->subpartitions);
62     partition_element *subpart;
63     partition_element *part_clone= new (mem_root) partition_element(*part);
64     if (!part_clone)
65       DBUG_RETURN(NULL);
66     part_clone->subpartitions.empty();
67     while ((subpart= (subpart_it++)))
68     {
69       partition_element *subpart_clone= new (mem_root) partition_element(*subpart);
70       if (!subpart_clone)
71         DBUG_RETURN(NULL);
72       if (empty_data_and_index_file)
73         subpart_clone->data_file_name= subpart_clone->index_file_name= NULL;
74       part_clone->subpartitions.push_back(subpart_clone, mem_root);
75     }
76 
77     if (empty_data_and_index_file)
78       part_clone->data_file_name= part_clone->index_file_name= NULL;
79     clone->partitions.push_back(part_clone, mem_root);
80     part_clone->list_val_list.empty();
81     List_iterator<part_elem_value> list_val_it(part->list_val_list);
82     part_elem_value *new_val_arr=
83       (part_elem_value *)alloc_root(mem_root, sizeof(part_elem_value) *
84                                     part->list_val_list.elements);
85     if (!new_val_arr)
86       DBUG_RETURN(NULL);
87 
88     p_column_list_val *new_colval_arr=
89       (p_column_list_val*)alloc_root(mem_root, sizeof(p_column_list_val) *
90                                      num_columns *
91                                      part->list_val_list.elements);
92     if (!new_colval_arr)
93       DBUG_RETURN(NULL);
94 
95     part_elem_value *val;
96     while ((val= list_val_it++))
97     {
98       part_elem_value *new_val= new_val_arr++;
99       memcpy(new_val, val, sizeof(part_elem_value));
100       if (!val->null_value)
101       {
102         p_column_list_val *new_colval= new_colval_arr;
103         new_colval_arr+= num_columns;
104         memcpy(new_colval, val->col_val_array,
105                sizeof(p_column_list_val) * num_columns);
106         new_val->col_val_array= new_colval;
107       }
108       part_clone->list_val_list.push_back(new_val, mem_root);
109     }
110   }
111   if (part_type == VERSIONING_PARTITION && vers_info)
112   {
113     // clone Vers_part_info; set now_part, hist_part
114     clone->vers_info= new (mem_root) Vers_part_info(*vers_info);
115     List_iterator<partition_element> it(clone->partitions);
116     while ((part= it++))
117     {
118       if (vers_info->now_part && part->id == vers_info->now_part->id)
119         clone->vers_info->now_part= part;
120       else if (vers_info->hist_part && part->id == vers_info->hist_part->id)
121         clone->vers_info->hist_part= part;
122     } // while ((part= it++))
123   } // if (part_type == VERSIONING_PARTITION ...
124   DBUG_RETURN(clone);
125 }
126 
127 /**
128   Mark named [sub]partition to be used/locked.
129 
130   @param part_name  Partition name to match.
131   @param length     Partition name length.
132 
133   @return Success if partition found
134     @retval true  Partition found
135     @retval false Partition not found
136 */
137 
add_named_partition(const char * part_name,size_t length)138 bool partition_info::add_named_partition(const char *part_name, size_t length)
139 {
140   HASH *part_name_hash;
141   PART_NAME_DEF *part_def;
142   Partition_share *part_share;
143   DBUG_ENTER("partition_info::add_named_partition");
144   DBUG_ASSERT(table && table->s && table->s->ha_share);
145   part_share= static_cast<Partition_share*>((table->s->ha_share));
146   DBUG_ASSERT(part_share->partition_name_hash_initialized);
147   part_name_hash= &part_share->partition_name_hash;
148   DBUG_ASSERT(part_name_hash->records);
149 
150   part_def= (PART_NAME_DEF*) my_hash_search(part_name_hash,
151                                             (const uchar*) part_name,
152                                             length);
153   if (!part_def)
154   {
155     my_error(ER_UNKNOWN_PARTITION, MYF(0), part_name, table->alias.c_ptr());
156     DBUG_RETURN(true);
157   }
158 
159   if (part_def->is_subpart)
160   {
161     bitmap_set_bit(&read_partitions, part_def->part_id);
162   }
163   else
164   {
165     if (is_sub_partitioned())
166     {
167       /* Mark all subpartitions in the partition */
168       uint j, start= part_def->part_id;
169       uint end= start + num_subparts;
170       for (j= start; j < end; j++)
171         bitmap_set_bit(&read_partitions, j);
172     }
173     else
174       bitmap_set_bit(&read_partitions, part_def->part_id);
175   }
176   DBUG_PRINT("info", ("Found partition %u is_subpart %d for name %s",
177                       part_def->part_id, part_def->is_subpart,
178                       part_name));
179   DBUG_RETURN(false);
180 }
181 
182 
183 /**
184   Mark named [sub]partition to be used/locked.
185 
186   @param part_elem  Partition element that matched.
187 */
188 
set_named_partition_bitmap(const char * part_name,size_t length)189 bool partition_info::set_named_partition_bitmap(const char *part_name, size_t length)
190 {
191   DBUG_ENTER("partition_info::set_named_partition_bitmap");
192   bitmap_clear_all(&read_partitions);
193   if (add_named_partition(part_name, length))
194     DBUG_RETURN(true);
195   bitmap_copy(&lock_partitions, &read_partitions);
196   DBUG_RETURN(false);
197 }
198 
199 
200 /**
201   Prune away partitions not mentioned in the PARTITION () clause,
202   if used.
203 
204     @param partition_names  list of names of partitions.
205 
206   @return Operation status
207     @retval true  Failure
208     @retval false Success
209 */
prune_partition_bitmaps(List<String> * partition_names)210 bool partition_info::prune_partition_bitmaps(List<String> *partition_names)
211 {
212   List_iterator<String> partition_names_it(*(partition_names));
213   uint num_names= partition_names->elements;
214   uint i= 0;
215   DBUG_ENTER("partition_info::prune_partition_bitmaps");
216 
217   if (num_names < 1)
218     DBUG_RETURN(true);
219 
220   /*
221     TODO: When adding support for FK in partitioned tables, the referenced
222     table must probably lock all partitions for read, and also write depending
223     of ON DELETE/UPDATE.
224   */
225   bitmap_clear_all(&read_partitions);
226 
227   /* No check for duplicate names or overlapping partitions/subpartitions. */
228 
229   DBUG_PRINT("info", ("Searching through partition_name_hash"));
230   do
231   {
232     String *part_name_str= partition_names_it++;
233     if (add_named_partition(part_name_str->c_ptr(), part_name_str->length()))
234       DBUG_RETURN(true);
235   } while (++i < num_names);
236   DBUG_RETURN(false);
237 }
238 
239 
240 /**
241   Set read/lock_partitions bitmap over non pruned partitions
242 
243   @param partition_names   list of partition names to query
244 
245   @return Operation status
246     @retval FALSE  OK
247     @retval TRUE   Failed to allocate memory for bitmap or list of partitions
248                    did not match
249 
250   @note OK to call multiple times without the need for free_bitmaps.
251 */
252 
set_partition_bitmaps(List<String> * partition_names)253 bool partition_info::set_partition_bitmaps(List<String> *partition_names)
254 {
255   DBUG_ENTER("partition_info::set_partition_bitmaps");
256 
257   DBUG_ASSERT(bitmaps_are_initialized);
258   DBUG_ASSERT(table);
259   if (!bitmaps_are_initialized)
260     DBUG_RETURN(TRUE);
261 
262   if (partition_names &&
263       partition_names->elements)
264   {
265     if (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)
266     {
267         my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
268         DBUG_RETURN(true);
269     }
270     if (prune_partition_bitmaps(partition_names))
271       DBUG_RETURN(TRUE);
272   }
273   else
274   {
275     bitmap_set_all(&read_partitions);
276     DBUG_PRINT("info", ("Set all partitions"));
277   }
278   bitmap_copy(&lock_partitions, &read_partitions);
279   DBUG_ASSERT(bitmap_get_first_set(&lock_partitions) != MY_BIT_NONE);
280   DBUG_RETURN(FALSE);
281 }
282 
283 
284 /**
285   Set read/lock_partitions bitmap over non pruned partitions
286 
287   @param table_list   Possible TABLE_LIST which can contain
288                       list of partition names to query
289 
290   @return Operation status
291     @retval FALSE  OK
292     @retval TRUE   Failed to allocate memory for bitmap or list of partitions
293                    did not match
294 
295   @note OK to call multiple times without the need for free_bitmaps.
296 */
set_partition_bitmaps_from_table(TABLE_LIST * table_list)297 bool partition_info::set_partition_bitmaps_from_table(TABLE_LIST *table_list)
298 {
299   List<String> *partition_names= table_list ?
300                                    NULL : table_list->partition_names;
301   return set_partition_bitmaps(partition_names);
302 }
303 
304 
305 /*
306   Create a memory area where default partition names are stored and fill it
307   up with the names.
308 
309   SYNOPSIS
310     create_default_partition_names()
311     part_no                         Partition number for subparts
312     num_parts                       Number of partitions
313     start_no                        Starting partition number
314     subpart                         Is it subpartitions
315 
316   RETURN VALUE
317     A pointer to the memory area of the default partition names
318 
319   DESCRIPTION
320     A support routine for the partition code where default values are
321     generated.
322     The external routine needing this code is check_partition_info
323 */
324 
325 #define MAX_PART_NAME_SIZE 8
326 
create_default_partition_names(THD * thd,uint part_no,uint num_parts_arg,uint start_no)327 char *partition_info::create_default_partition_names(THD *thd, uint part_no,
328                                                      uint num_parts_arg,
329                                                      uint start_no)
330 {
331   char *ptr= (char*) thd->calloc(num_parts_arg * MAX_PART_NAME_SIZE);
332   char *move_ptr= ptr;
333   uint i= 0;
334   DBUG_ENTER("create_default_partition_names");
335 
336   if (likely(ptr != 0))
337   {
338     do
339     {
340       if (make_partition_name(move_ptr, (start_no + i)))
341         DBUG_RETURN(NULL);
342       move_ptr+= MAX_PART_NAME_SIZE;
343     } while (++i < num_parts_arg);
344   }
345   DBUG_RETURN(ptr);
346 }
347 
348 
349 /*
350   Create a unique name for the subpartition as part_name'sp''subpart_no'
351 
352   SYNOPSIS
353     create_default_subpartition_name()
354     subpart_no                  Number of subpartition
355     part_name                   Name of partition
356   RETURN VALUES
357     >0                          A reference to the created name string
358     0                           Memory allocation error
359 */
360 
create_default_subpartition_name(THD * thd,uint subpart_no,const char * part_name)361 char *partition_info::create_default_subpartition_name(THD *thd, uint subpart_no,
362                                                const char *part_name)
363 {
364   size_t size_alloc= strlen(part_name) + MAX_PART_NAME_SIZE;
365   char *ptr= (char*) thd->calloc(size_alloc);
366   DBUG_ENTER("create_default_subpartition_name");
367 
368   if (likely(ptr != NULL))
369     my_snprintf(ptr, size_alloc, "%ssp%u", part_name, subpart_no);
370 
371   DBUG_RETURN(ptr);
372 }
373 
374 
375 /*
376   Set up all the default partitions not set-up by the user in the SQL
377   statement. Also perform a number of checks that the user hasn't tried
378   to use default values where no defaults exists.
379 
380   SYNOPSIS
381     set_up_default_partitions()
382     file                A reference to a handler of the table
383     info                Create info
384     start_no            Starting partition number
385 
386   RETURN VALUE
387     TRUE                Error, attempted default values not possible
388     FALSE               Ok, default partitions set-up
389 
390   DESCRIPTION
391     The routine uses the underlying handler of the partitioning to define
392     the default number of partitions. For some handlers this requires
393     knowledge of the maximum number of rows to be stored in the table.
394     This routine only accepts HASH and KEY partitioning and thus there is
395     no subpartitioning if this routine is successful.
396     The external routine needing this code is check_partition_info
397 */
398 
set_up_default_partitions(THD * thd,handler * file,HA_CREATE_INFO * info,uint start_no)399 bool partition_info::set_up_default_partitions(THD *thd, handler *file,
400                                                HA_CREATE_INFO *info,
401                                                uint start_no)
402 {
403   uint i;
404   char *default_name;
405   bool result= TRUE;
406   DBUG_ENTER("partition_info::set_up_default_partitions");
407 
408   if (part_type == VERSIONING_PARTITION)
409   {
410     if (start_no == 0 && use_default_num_partitions)
411       num_parts= 2;
412     use_default_num_partitions= false;
413   }
414   else if (part_type != HASH_PARTITION)
415   {
416     const char *error_string;
417     if (part_type == RANGE_PARTITION)
418       error_string= "RANGE";
419     else if (part_type == VERSIONING_PARTITION)
420       error_string= "SYSTEM_TIME";
421     else
422       error_string= "LIST";
423     my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
424     goto end;
425   }
426 
427   if ((num_parts == 0) &&
428       ((num_parts= file->get_default_no_partitions(info)) == 0))
429   {
430     my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
431     goto end;
432   }
433 
434   if (unlikely(num_parts > MAX_PARTITIONS))
435   {
436     my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
437     goto end;
438   }
439   if (unlikely((!(default_name= create_default_partition_names(thd, 0,
440                                                                num_parts,
441                                                                start_no)))))
442     goto end;
443   i= 0;
444   do
445   {
446     partition_element *part_elem= new partition_element();
447     if (likely(part_elem != 0 &&
448                (!partitions.push_back(part_elem))))
449     {
450       part_elem->engine_type= default_engine_type;
451       part_elem->partition_name= default_name;
452       part_elem->id= i;
453       default_name+=MAX_PART_NAME_SIZE;
454       if (part_type == VERSIONING_PARTITION)
455       {
456         if (start_no > 0 || i < num_parts - 1) {
457           part_elem->type= partition_element::HISTORY;
458         } else {
459           part_elem->type= partition_element::CURRENT;
460           part_elem->partition_name= "pn";
461         }
462       }
463     }
464     else
465       goto end;
466   } while (++i < num_parts);
467   result= FALSE;
468 end:
469   DBUG_RETURN(result);
470 }
471 
472 
473 /*
474   Set up all the default subpartitions not set-up by the user in the SQL
475   statement. Also perform a number of checks that the default partitioning
476   becomes an allowed partitioning scheme.
477 
478   SYNOPSIS
479     set_up_default_subpartitions()
480     file                A reference to a handler of the table
481     info                Create info
482 
483   RETURN VALUE
484     TRUE                Error, attempted default values not possible
485     FALSE               Ok, default partitions set-up
486 
487   DESCRIPTION
488     The routine uses the underlying handler of the partitioning to define
489     the default number of partitions. For some handlers this requires
490     knowledge of the maximum number of rows to be stored in the table.
491     This routine is only called for RANGE or LIST partitioning and those
492     need to be specified so only subpartitions are specified.
493     The external routine needing this code is check_partition_info
494 */
495 
set_up_default_subpartitions(THD * thd,handler * file,HA_CREATE_INFO * info)496 bool partition_info::set_up_default_subpartitions(THD *thd, handler *file,
497                                                   HA_CREATE_INFO *info)
498 {
499   uint i, j;
500   bool result= TRUE;
501   partition_element *part_elem;
502   List_iterator<partition_element> part_it(partitions);
503   DBUG_ENTER("partition_info::set_up_default_subpartitions");
504 
505   if (num_subparts == 0)
506     num_subparts= file->get_default_no_partitions(info);
507   if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS))
508   {
509     my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
510     goto end;
511   }
512   i= 0;
513   do
514   {
515     part_elem= part_it++;
516     j= 0;
517     do
518     {
519       partition_element *subpart_elem= new partition_element(part_elem);
520       if (likely(subpart_elem != 0 &&
521           (!part_elem->subpartitions.push_back(subpart_elem))))
522       {
523         char *ptr= create_default_subpartition_name(thd, j,
524                                                     part_elem->partition_name);
525         if (!ptr)
526           goto end;
527         subpart_elem->engine_type= default_engine_type;
528         subpart_elem->partition_name= ptr;
529       }
530       else
531         goto end;
532     } while (++j < num_subparts);
533   } while (++i < num_parts);
534   result= FALSE;
535 end:
536   DBUG_RETURN(result);
537 }
538 
539 
540 /*
541   Support routine for check_partition_info
542 
543   SYNOPSIS
544     set_up_defaults_for_partitioning()
545     file                A reference to a handler of the table
546     info                Create info
547     start_no            Starting partition number
548 
549   RETURN VALUE
550     TRUE                Error, attempted default values not possible
551     FALSE               Ok, default partitions set-up
552 
553   DESCRIPTION
554     Set up defaults for partition or subpartition (cannot set-up for both,
555     this will return an error.
556 */
557 
set_up_defaults_for_partitioning(THD * thd,handler * file,HA_CREATE_INFO * info,uint start_no)558 bool partition_info::set_up_defaults_for_partitioning(THD *thd, handler *file,
559                                                       HA_CREATE_INFO *info,
560                                                       uint start_no)
561 {
562   DBUG_ENTER("partition_info::set_up_defaults_for_partitioning");
563 
564   if (!default_partitions_setup)
565   {
566     default_partitions_setup= TRUE;
567     if (use_default_partitions &&
568         set_up_default_partitions(thd, file, info, start_no))
569       DBUG_RETURN(TRUE);
570     if (is_sub_partitioned() &&
571         use_default_subpartitions)
572       DBUG_RETURN(set_up_default_subpartitions(thd, file, info));
573   }
574   DBUG_RETURN(FALSE);
575 }
576 
577 
578 /*
579   Support routine for check_partition_info
580 
581   SYNOPSIS
582     find_duplicate_field
583     no parameters
584 
585   RETURN VALUE
586     Erroneus field name  Error, there are two fields with same name
587     NULL                 Ok, no field defined twice
588 
589   DESCRIPTION
590     Check that the user haven't defined the same field twice in
591     key or column list partitioning.
592 */
593 
find_duplicate_field()594 const char* partition_info::find_duplicate_field()
595 {
596   const char *field_name_outer, *field_name_inner;
597   List_iterator<const char> it_outer(part_field_list);
598   uint num_fields= part_field_list.elements;
599   uint i,j;
600   DBUG_ENTER("partition_info::find_duplicate_field");
601 
602   for (i= 0; i < num_fields; i++)
603   {
604     field_name_outer= it_outer++;
605     List_iterator<const char> it_inner(part_field_list);
606     for (j= 0; j < num_fields; j++)
607     {
608       field_name_inner= it_inner++;
609       if (i >= j)
610         continue;
611       if (!(my_strcasecmp(system_charset_info,
612                           field_name_outer,
613                           field_name_inner)))
614       {
615         DBUG_RETURN(field_name_outer);
616       }
617     }
618   }
619   DBUG_RETURN(NULL);
620 }
621 
622 
623 /**
624   @brief Get part_elem and part_id from partition name
625 
626   @param partition_name Name of partition to search for.
627   @param file_name[out] Partition file name (part after table name,
628                         #P#<part>[#SP#<subpart>]), skipped if NULL.
629   @param part_id[out]   Id of found partition or NOT_A_PARTITION_ID.
630 
631   @retval Pointer to part_elem of [sub]partition, if not found NULL
632 
633   @note Since names of partitions AND subpartitions must be unique,
634   this function searches both partitions and subpartitions and if name of
635   a partition is given for a subpartitioned table, part_elem will be
636   the partition, but part_id will be NOT_A_PARTITION_ID and file_name not set.
637 */
get_part_elem(const char * partition_name,char * file_name,size_t file_name_size,uint32 * part_id)638 partition_element *partition_info::get_part_elem(const char *partition_name,
639                                                  char *file_name,
640                                                  size_t file_name_size,
641                                                  uint32 *part_id)
642 {
643   List_iterator<partition_element> part_it(partitions);
644   uint i= 0;
645   DBUG_ENTER("partition_info::get_part_elem");
646   DBUG_ASSERT(part_id);
647   *part_id= NOT_A_PARTITION_ID;
648   do
649   {
650     partition_element *part_elem= part_it++;
651     if (is_sub_partitioned())
652     {
653       List_iterator<partition_element> sub_part_it(part_elem->subpartitions);
654       uint j= 0;
655       do
656       {
657         partition_element *sub_part_elem= sub_part_it++;
658         if (!my_strcasecmp(system_charset_info,
659                            sub_part_elem->partition_name, partition_name))
660         {
661           if (file_name)
662             if (create_subpartition_name(file_name, file_name_size, "",
663                                          part_elem->partition_name,
664                                          partition_name, NORMAL_PART_NAME))
665               DBUG_RETURN(NULL);
666           *part_id= j + (i * num_subparts);
667           DBUG_RETURN(sub_part_elem);
668         }
669       } while (++j < num_subparts);
670 
671       /* Naming a partition (first level) on a subpartitioned table. */
672       if (!my_strcasecmp(system_charset_info,
673                             part_elem->partition_name, partition_name))
674         DBUG_RETURN(part_elem);
675     }
676     else if (!my_strcasecmp(system_charset_info,
677                             part_elem->partition_name, partition_name))
678     {
679       if (file_name)
680         if (create_partition_name(file_name, file_name_size, "",
681                                   partition_name, NORMAL_PART_NAME, TRUE))
682           DBUG_RETURN(NULL);
683       *part_id= i;
684       DBUG_RETURN(part_elem);
685     }
686   } while (++i < num_parts);
687   DBUG_RETURN(NULL);
688 }
689 
690 
691 /**
692   Helper function to find_duplicate_name.
693 */
694 
get_part_name_from_elem(const char * name,size_t * length,my_bool not_used)695 static const char *get_part_name_from_elem(const char *name, size_t *length,
696                                       my_bool not_used __attribute__((unused)))
697 {
698   *length= strlen(name);
699   return name;
700 }
701 
702 /*
703   A support function to check partition names for duplication in a
704   partitioned table
705 
706   SYNOPSIS
707     find_duplicate_name()
708 
709   RETURN VALUES
710     NULL               Has unique part and subpart names
711     !NULL              Pointer to duplicated name
712 
713   DESCRIPTION
714     Checks that the list of names in the partitions doesn't contain any
715     duplicated names.
716 */
717 
find_duplicate_name()718 char *partition_info::find_duplicate_name()
719 {
720   HASH partition_names;
721   uint max_names;
722   const uchar *curr_name= NULL;
723   List_iterator<partition_element> parts_it(partitions);
724   partition_element *p_elem;
725 
726   DBUG_ENTER("partition_info::find_duplicate_name");
727 
728   /*
729     TODO: If table->s->ha_part_data->partition_name_hash.elements is > 0,
730     then we could just return NULL, but that has not been verified.
731     And this only happens when in ALTER TABLE with full table copy.
732   */
733 
734   max_names= num_parts;
735   if (is_sub_partitioned())
736     max_names+= num_parts * num_subparts;
737   if (my_hash_init(PSI_INSTRUMENT_ME, &partition_names, system_charset_info, max_names, 0, 0,
738                    (my_hash_get_key) get_part_name_from_elem, 0, HASH_UNIQUE))
739   {
740     DBUG_ASSERT(0);
741     curr_name= (const uchar*) "Internal failure";
742     goto error;
743   }
744   while ((p_elem= (parts_it++)))
745   {
746     curr_name= (const uchar*) p_elem->partition_name;
747     if (my_hash_insert(&partition_names, curr_name))
748       goto error;
749 
750     if (!p_elem->subpartitions.is_empty())
751     {
752       List_iterator<partition_element> subparts_it(p_elem->subpartitions);
753       partition_element *subp_elem;
754       while ((subp_elem= (subparts_it++)))
755       {
756         curr_name= (const uchar*) subp_elem->partition_name;
757         if (my_hash_insert(&partition_names, curr_name))
758           goto error;
759       }
760     }
761   }
762   my_hash_free(&partition_names);
763   DBUG_RETURN(NULL);
764 error:
765   my_hash_free(&partition_names);
766   DBUG_RETURN((char*) curr_name);
767 }
768 
769 
770 /*
771   A support function to check if a partition element's name is unique
772 
773   SYNOPSIS
774     has_unique_name()
775     partition_element  element to check
776 
777   RETURN VALUES
778     TRUE               Has unique name
779     FALSE              Doesn't
780 */
781 
has_unique_name(partition_element * element)782 bool partition_info::has_unique_name(partition_element *element)
783 {
784   DBUG_ENTER("partition_info::has_unique_name");
785 
786   const char *name_to_check= element->partition_name;
787   List_iterator<partition_element> parts_it(partitions);
788 
789   partition_element *el;
790   while ((el= (parts_it++)))
791   {
792     if (!(my_strcasecmp(system_charset_info, el->partition_name,
793                         name_to_check)) && el != element)
794         DBUG_RETURN(FALSE);
795 
796     if (!el->subpartitions.is_empty())
797     {
798       partition_element *sub_el;
799       List_iterator<partition_element> subparts_it(el->subpartitions);
800       while ((sub_el= (subparts_it++)))
801       {
802         if (!(my_strcasecmp(system_charset_info, sub_el->partition_name,
803                             name_to_check)) && sub_el != element)
804             DBUG_RETURN(FALSE);
805       }
806     }
807   }
808   DBUG_RETURN(TRUE);
809 }
810 
811 
812 /**
813   @brief Switch history partition according limit or interval
814 
815   @note
816     vers_info->limit      Limit by number of partition records
817     vers_info->interval   Limit by fixed time interval
818     vers_info->hist_part  (out) Working history partition
819 */
vers_set_hist_part(THD * thd)820 int partition_info::vers_set_hist_part(THD *thd)
821 {
822   if (table->pos_in_table_list &&
823       table->pos_in_table_list->partition_names)
824   {
825     return HA_ERR_PARTITION_LIST;
826   }
827   if (vers_info->limit)
828   {
829     ha_partition *hp= (ha_partition*)(table->file);
830     partition_element *next= NULL;
831     List_iterator<partition_element> it(partitions);
832     while (next != vers_info->hist_part)
833       next= it++;
834     DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
835     ha_rows records= hp->part_records(next);
836     while ((next= it++) != vers_info->now_part)
837     {
838       DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
839       ha_rows next_records= hp->part_records(next);
840       if (next_records == 0)
841         break;
842       vers_info->hist_part= next;
843       records= next_records;
844     }
845     if (records >= vers_info->limit)
846     {
847       if (next == vers_info->now_part)
848       {
849         my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
850                 table->s->db.str, table->s->table_name.str,
851                 vers_info->hist_part->partition_name, "LIMIT");
852       }
853       else
854         vers_info->hist_part= next;
855     }
856     return 0;
857   }
858 
859   if (vers_info->interval.is_set())
860   {
861     if (vers_info->hist_part->range_value > thd->query_start())
862       return 0;
863 
864     partition_element *next= NULL;
865     List_iterator<partition_element> it(partitions);
866     while (next != vers_info->hist_part)
867       next= it++;
868 
869     while ((next= it++) != vers_info->now_part)
870     {
871       vers_info->hist_part= next;
872       if (next->range_value > thd->query_start())
873         return 0;
874     }
875   }
876   return 0;
877 }
878 
879 
880 /*
881   Check that the partition/subpartition is setup to use the correct
882   storage engine
883   SYNOPSIS
884     check_engine_condition()
885     p_elem                   Partition element
886     table_engine_set         Have user specified engine on table level
887     inout::engine_type       Current engine used
888     inout::first             Is it first partition
889   RETURN VALUE
890     TRUE                     Failed check
891     FALSE                    Ok
892   DESCRIPTION
893     Specified engine for table and partitions p0 and pn
894     Must be correct both on CREATE and ALTER commands
895     table p0 pn res (0 - OK, 1 - FAIL)
896         -  -  - 0
897         -  -  x 1
898         -  x  - 1
899         -  x  x 0
900         x  -  - 0
901         x  -  x 0
902         x  x  - 0
903         x  x  x 0
904     i.e:
905     - All subpartitions must use the same engine
906       AND it must be the same as the partition.
907     - All partitions must use the same engine
908       AND it must be the same as the table.
909     - if one does NOT specify an engine on the table level
910       then one must either NOT specify any engine on any
911       partition/subpartition OR for ALL partitions/subpartitions
912     Note:
913     When ALTER a table, the engines are already set for all levels
914     (table, all partitions and subpartitions). So if one want to
915     change the storage engine, one must specify it on the table level
916 
917 */
918 
check_engine_condition(partition_element * p_elem,bool table_engine_set,handlerton ** engine_type,bool * first)919 static bool check_engine_condition(partition_element *p_elem,
920                                    bool table_engine_set,
921                                    handlerton **engine_type,
922                                    bool *first)
923 {
924   DBUG_ENTER("check_engine_condition");
925 
926   DBUG_PRINT("enter", ("p_eng %s t_eng %s t_eng_set %u first %u state %u",
927                        ha_resolve_storage_engine_name(p_elem->engine_type),
928                        ha_resolve_storage_engine_name(*engine_type),
929                        table_engine_set, *first, p_elem->part_state));
930   if (*first && !table_engine_set)
931   {
932     *engine_type= p_elem->engine_type;
933     DBUG_PRINT("info", ("setting table_engine = %s",
934                          ha_resolve_storage_engine_name(*engine_type)));
935   }
936   *first= FALSE;
937   if ((table_engine_set &&
938       (p_elem->engine_type != (*engine_type) &&
939        p_elem->engine_type)) ||
940       (!table_engine_set &&
941        p_elem->engine_type != (*engine_type)))
942   {
943     DBUG_RETURN(TRUE);
944   }
945 
946   DBUG_RETURN(FALSE);
947 }
948 
949 
950 /*
951   Check engine mix that it is correct
952   Current limitation is that all partitions and subpartitions
953   must use the same storage engine.
954   SYNOPSIS
955     check_engine_mix()
956     inout::engine_type       Current engine used
957     table_engine_set         Have user specified engine on table level
958   RETURN VALUE
959     TRUE                     Error, mixed engines
960     FALSE                    Ok, no mixed engines
961   DESCRIPTION
962     Current check verifies only that all handlers are the same.
963     Later this check will be more sophisticated.
964     (specified partition handler ) specified table handler
965     (MYISAM, MYISAM) -       OK
966     (MYISAM, -)      -       NOT OK
967     (MYISAM, -)    MYISAM    OK
968     (- , MYISAM)   -         NOT OK
969     (- , -)        MYISAM    OK
970     (-,-)          -         OK
971 */
972 
check_engine_mix(handlerton * engine_type,bool table_engine_set)973 bool partition_info::check_engine_mix(handlerton *engine_type,
974                                       bool table_engine_set)
975 {
976   handlerton *old_engine_type= engine_type;
977   bool first= TRUE;
978   uint n_parts= partitions.elements;
979   DBUG_ENTER("partition_info::check_engine_mix");
980   DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u",
981                        ha_resolve_storage_engine_name(engine_type),
982                        table_engine_set));
983   if (n_parts)
984   {
985     List_iterator<partition_element> part_it(partitions);
986     uint i= 0;
987     do
988     {
989       partition_element *part_elem= part_it++;
990       DBUG_PRINT("info", ("part = %d engine = %s table_engine_set %u",
991                  i, ha_resolve_storage_engine_name(part_elem->engine_type),
992                  table_engine_set));
993       if (is_sub_partitioned() &&
994           part_elem->subpartitions.elements)
995       {
996         uint n_subparts= part_elem->subpartitions.elements;
997         uint j= 0;
998         List_iterator<partition_element> sub_it(part_elem->subpartitions);
999         do
1000         {
1001           partition_element *sub_elem= sub_it++;
1002           DBUG_PRINT("info", ("sub = %d engine = %s table_engie_set %u",
1003                      j, ha_resolve_storage_engine_name(sub_elem->engine_type),
1004                      table_engine_set));
1005           if (check_engine_condition(sub_elem, table_engine_set,
1006                                      &engine_type, &first))
1007             goto error;
1008         } while (++j < n_subparts);
1009         /* ensure that the partition also has correct engine */
1010         if (check_engine_condition(part_elem, table_engine_set,
1011                                    &engine_type, &first))
1012           goto error;
1013       }
1014       else if (check_engine_condition(part_elem, table_engine_set,
1015                                       &engine_type, &first))
1016         goto error;
1017     } while (++i < n_parts);
1018   }
1019   DBUG_PRINT("info", ("engine_type = %s",
1020                        ha_resolve_storage_engine_name(engine_type)));
1021   if (!engine_type)
1022     engine_type= old_engine_type;
1023   if (engine_type->flags & HTON_NO_PARTITION)
1024   {
1025     my_error(ER_PARTITION_MERGE_ERROR, MYF(0));
1026     DBUG_RETURN(TRUE);
1027   }
1028   DBUG_PRINT("info", ("out: engine_type = %s",
1029                        ha_resolve_storage_engine_name(engine_type)));
1030   DBUG_ASSERT(engine_type != partition_hton);
1031   DBUG_RETURN(FALSE);
1032 error:
1033   /*
1034     Mixed engines not yet supported but when supported it will need
1035     the partition handler
1036   */
1037   DBUG_RETURN(TRUE);
1038 }
1039 
1040 
1041 /**
1042   Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL.
1043 
1044   @param thd  THD also containing sql_mode (looks from MODE_NO_DIR_IN_CREATE).
1045   @param part_elem partition_element to check.
1046 */
warn_if_dir_in_part_elem(THD * thd,partition_element * part_elem)1047 static void warn_if_dir_in_part_elem(THD *thd, partition_element *part_elem)
1048 {
1049   if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
1050   {
1051     if (part_elem->data_file_name)
1052       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1053                           WARN_OPTION_IGNORED,
1054                           ER_THD(thd, WARN_OPTION_IGNORED),
1055                           "DATA DIRECTORY");
1056     if (part_elem->index_file_name)
1057       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1058                           WARN_OPTION_IGNORED,
1059                           ER_THD(thd, WARN_OPTION_IGNORED),
1060                           "INDEX DIRECTORY");
1061     part_elem->data_file_name= part_elem->index_file_name= NULL;
1062   }
1063 }
1064 
1065 
1066 /*
1067   This code is used early in the CREATE TABLE and ALTER TABLE process.
1068 
1069   SYNOPSIS
1070     check_partition_info()
1071     thd                 Thread object
1072     eng_type            Return value for used engine in partitions
1073     file                A reference to a handler of the table
1074     info                Create info
1075     add_or_reorg_part   Is it ALTER TABLE ADD/REORGANIZE command
1076 
1077   RETURN VALUE
1078     TRUE                 Error, something went wrong
1079     FALSE                Ok, full partition data structures are now generated
1080 
1081   DESCRIPTION
1082     We will check that the partition info requested is possible to set-up in
1083     this version. This routine is an extension of the parser one could say.
1084     If defaults were used we will generate default data structures for all
1085     partitions.
1086 
1087 */
1088 
check_partition_info(THD * thd,handlerton ** eng_type,handler * file,HA_CREATE_INFO * info,partition_info * add_or_reorg_part)1089 bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
1090                                           handler *file, HA_CREATE_INFO *info,
1091                                           partition_info *add_or_reorg_part)
1092 {
1093   handlerton *table_engine= default_engine_type;
1094   uint i, tot_partitions;
1095   bool result= TRUE, table_engine_set;
1096   const char *same_name;
1097   uint32 hist_parts= 0;
1098   uint32 now_parts= 0;
1099   DBUG_ENTER("partition_info::check_partition_info");
1100   DBUG_ASSERT(default_engine_type != partition_hton);
1101 
1102   DBUG_PRINT("info", ("default table_engine = %s",
1103                       ha_resolve_storage_engine_name(table_engine)));
1104   if (!add_or_reorg_part)
1105   {
1106     int err= 0;
1107 
1108     /* Check for partition expression. */
1109     if (!list_of_part_fields)
1110     {
1111       DBUG_ASSERT(part_expr);
1112       err= part_expr->walk(&Item::check_partition_func_processor, 0, NULL);
1113     }
1114 
1115     /* Check for sub partition expression. */
1116     if (!err && is_sub_partitioned() && !list_of_subpart_fields)
1117     {
1118       DBUG_ASSERT(subpart_expr);
1119       err= subpart_expr->walk(&Item::check_partition_func_processor, 0,
1120                               NULL);
1121     }
1122 
1123     if (err)
1124     {
1125       my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1126       goto end;
1127     }
1128     if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
1129         fix_parser_data(thd))
1130       goto end;
1131   }
1132   if (unlikely(!is_sub_partitioned() &&
1133                !(use_default_subpartitions && use_default_num_subpartitions)))
1134   {
1135     my_error(ER_SUBPARTITION_ERROR, MYF(0));
1136     goto end;
1137   }
1138   if (unlikely(is_sub_partitioned() &&
1139               (!(part_type == RANGE_PARTITION ||
1140                  part_type == LIST_PARTITION ||
1141                  part_type == VERSIONING_PARTITION))))
1142   {
1143     /* Only RANGE, LIST and SYSTEM_TIME partitioning can be subpartitioned */
1144     my_error(ER_SUBPARTITION_ERROR, MYF(0));
1145     goto end;
1146   }
1147   if (unlikely(set_up_defaults_for_partitioning(thd, file, info, (uint)0)))
1148     goto end;
1149   if (!(tot_partitions= get_tot_partitions()))
1150   {
1151     my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
1152     goto end;
1153   }
1154   if (unlikely(tot_partitions > MAX_PARTITIONS))
1155   {
1156     my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
1157     goto end;
1158   }
1159   /*
1160     if NOT specified ENGINE = <engine>:
1161       If Create, always use create_info->db_type
1162       else, use previous tables db_type
1163       either ALL or NONE partition should be set to
1164       default_engine_type when not table_engine_set
1165       Note: after a table is created its storage engines for
1166       the table and all partitions/subpartitions are set.
1167       So when ALTER it is already set on table level
1168   */
1169   if (info && info->used_fields & HA_CREATE_USED_ENGINE)
1170   {
1171     table_engine_set= TRUE;
1172     table_engine= info->db_type;
1173     /* if partition_hton, use thd->lex->create_info */
1174     if (table_engine == partition_hton)
1175       table_engine= thd->lex->create_info.db_type;
1176     DBUG_ASSERT(table_engine != partition_hton);
1177     DBUG_PRINT("info", ("Using table_engine = %s",
1178                         ha_resolve_storage_engine_name(table_engine)));
1179   }
1180   else
1181   {
1182     table_engine_set= FALSE;
1183     if (thd->lex->sql_command != SQLCOM_CREATE_TABLE)
1184     {
1185       table_engine_set= TRUE;
1186       DBUG_PRINT("info", ("No create, table_engine = %s",
1187                           ha_resolve_storage_engine_name(table_engine)));
1188       DBUG_ASSERT(table_engine && table_engine != partition_hton);
1189     }
1190   }
1191 
1192   if (part_field_list.elements > 0 &&
1193       (same_name= find_duplicate_field()))
1194   {
1195     my_error(ER_SAME_NAME_PARTITION_FIELD, MYF(0), same_name);
1196     goto end;
1197   }
1198   if ((same_name= find_duplicate_name()))
1199   {
1200     my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
1201     goto end;
1202   }
1203 
1204   if (part_type == VERSIONING_PARTITION)
1205   {
1206     DBUG_ASSERT(vers_info);
1207     if (num_parts < 2 || !(use_default_partitions || vers_info->now_part))
1208     {
1209       DBUG_ASSERT(info);
1210       DBUG_ASSERT(info->alias.str);
1211       my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias.str);
1212       goto end;
1213     }
1214     DBUG_ASSERT(num_parts == partitions.elements);
1215   }
1216   i= 0;
1217   {
1218     List_iterator<partition_element> part_it(partitions);
1219     uint num_parts_not_set= 0;
1220     uint prev_num_subparts_not_set= num_subparts + 1;
1221     do
1222     {
1223       partition_element *part_elem= part_it++;
1224       warn_if_dir_in_part_elem(thd, part_elem);
1225       if (!is_sub_partitioned())
1226       {
1227         if (part_elem->engine_type == NULL)
1228         {
1229           num_parts_not_set++;
1230           part_elem->engine_type= default_engine_type;
1231         }
1232         if (check_table_name(part_elem->partition_name,
1233                              strlen(part_elem->partition_name), FALSE))
1234         {
1235           my_error(ER_WRONG_PARTITION_NAME, MYF(0));
1236           goto end;
1237         }
1238         DBUG_PRINT("info", ("part = %d engine = %s",
1239                    i, ha_resolve_storage_engine_name(part_elem->engine_type)));
1240       }
1241       else
1242       {
1243         uint j= 0;
1244         uint num_subparts_not_set= 0;
1245         List_iterator<partition_element> sub_it(part_elem->subpartitions);
1246         partition_element *sub_elem;
1247         do
1248         {
1249           sub_elem= sub_it++;
1250           warn_if_dir_in_part_elem(thd, sub_elem);
1251           if (check_table_name(sub_elem->partition_name,
1252                                strlen(sub_elem->partition_name), FALSE))
1253           {
1254             my_error(ER_WRONG_PARTITION_NAME, MYF(0));
1255             goto end;
1256           }
1257           if (sub_elem->engine_type == NULL)
1258           {
1259             if (part_elem->engine_type != NULL)
1260               sub_elem->engine_type= part_elem->engine_type;
1261             else
1262             {
1263               sub_elem->engine_type= default_engine_type;
1264               num_subparts_not_set++;
1265             }
1266           }
1267           DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j,
1268                      ha_resolve_storage_engine_name(sub_elem->engine_type)));
1269         } while (++j < num_subparts);
1270 
1271         if (prev_num_subparts_not_set == (num_subparts + 1) &&
1272             (num_subparts_not_set == 0 ||
1273              num_subparts_not_set == num_subparts))
1274           prev_num_subparts_not_set= num_subparts_not_set;
1275 
1276         if (!table_engine_set &&
1277             prev_num_subparts_not_set != num_subparts_not_set)
1278         {
1279           DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u",
1280                      num_subparts_not_set, num_subparts));
1281           my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1282           goto end;
1283         }
1284 
1285         if (part_elem->engine_type == NULL)
1286         {
1287           if (num_subparts_not_set == 0)
1288             part_elem->engine_type= sub_elem->engine_type;
1289           else
1290           {
1291             num_parts_not_set++;
1292             part_elem->engine_type= default_engine_type;
1293           }
1294         }
1295       }
1296       if (part_type == VERSIONING_PARTITION)
1297       {
1298         if (part_elem->type == partition_element::HISTORY)
1299         {
1300           hist_parts++;
1301         }
1302         else
1303         {
1304           DBUG_ASSERT(part_elem->type == partition_element::CURRENT);
1305           now_parts++;
1306         }
1307       }
1308     } while (++i < num_parts);
1309     if (!table_engine_set &&
1310         num_parts_not_set != 0 &&
1311         num_parts_not_set != num_parts)
1312     {
1313       DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u",
1314                  num_parts_not_set, num_subparts));
1315       my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1316       goto end;
1317     }
1318   }
1319   if (unlikely(check_engine_mix(table_engine, table_engine_set)))
1320   {
1321     my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1322     goto end;
1323   }
1324 
1325   if (hist_parts > 1)
1326   {
1327     if (vers_info->limit == 0 && !vers_info->interval.is_set())
1328     {
1329       push_warning_printf(thd,
1330         Sql_condition::WARN_LEVEL_WARN,
1331         WARN_VERS_PARAMETERS,
1332         ER_THD(thd, WARN_VERS_PARAMETERS),
1333         "no rotation condition for multiple HISTORY partitions.");
1334     }
1335   }
1336   if (unlikely(now_parts > 1))
1337   {
1338     my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias.str);
1339     goto end;
1340   }
1341 
1342 
1343   DBUG_ASSERT(table_engine != partition_hton &&
1344               default_engine_type == table_engine);
1345   if (eng_type)
1346     *eng_type= table_engine;
1347 
1348 
1349   /*
1350     We need to check all constant expressions that they are of the correct
1351     type and that they are increasing for ranges and not overlapping for
1352     list constants.
1353   */
1354 
1355   if (add_or_reorg_part)
1356   {
1357     if (part_type == VERSIONING_PARTITION && add_or_reorg_part->partitions.elements)
1358       vers_update_el_ids();
1359     if (check_constants(thd, this))
1360       goto end;
1361   }
1362 
1363   result= FALSE;
1364 end:
1365   DBUG_RETURN(result);
1366 }
1367 
1368 
1369 /*
1370   Print error for no partition found
1371 
1372   SYNOPSIS
1373     print_no_partition_found()
1374     table                        Table object
1375 
1376   RETURN VALUES
1377 */
1378 
print_no_partition_found(TABLE * table_arg,myf errflag)1379 void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag)
1380 {
1381   char buf[100];
1382   char *buf_ptr= (char*)&buf;
1383   TABLE_LIST table_list;
1384   THD *thd= current_thd;
1385 
1386   table_list.reset();
1387   table_list.db= table_arg->s->db;
1388   table_list.table_name= table_arg->s->table_name;
1389 
1390   if (check_single_table_access(thd, SELECT_ACL, &table_list, TRUE))
1391   {
1392     my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
1393                ER_THD(thd, ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), errflag);
1394   }
1395   else
1396   {
1397     if (column_list)
1398       buf_ptr= (char*)"from column_list";
1399     else
1400     {
1401       MY_BITMAP *old_map= dbug_tmp_use_all_columns(table_arg, &table_arg->read_set);
1402       if (part_expr->null_value)
1403         buf_ptr= (char*)"NULL";
1404       else
1405         longlong10_to_str(err_value, buf,
1406                      part_expr->unsigned_flag ? 10 : -10);
1407       dbug_tmp_restore_column_map(&table_arg->read_set, old_map);
1408     }
1409     my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, errflag, buf_ptr);
1410   }
1411 }
1412 
1413 
1414 /*
1415   Set fields related to partition expression
1416   SYNOPSIS
1417     set_part_expr()
1418     start_token               Start of partition function string
1419     item_ptr                  Pointer to item tree
1420     end_token                 End of partition function string
1421     is_subpart                Subpartition indicator
1422   RETURN VALUES
1423     TRUE                      Memory allocation error
1424     FALSE                     Success
1425 */
1426 
set_part_expr(THD * thd,Item * item_ptr,bool is_subpart)1427 bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
1428 {
1429   if (is_subpart)
1430   {
1431     list_of_subpart_fields= FALSE;
1432     subpart_expr= item_ptr;
1433   }
1434   else
1435   {
1436     list_of_part_fields= FALSE;
1437     part_expr= item_ptr;
1438   }
1439   return FALSE;
1440 }
1441 
1442 
1443 /*
1444   Check that partition fields and subpartition fields are not too long
1445 
1446   SYNOPSIS
1447     check_partition_field_length()
1448 
1449   RETURN VALUES
1450     TRUE                             Total length was too big
1451     FALSE                            Length is ok
1452 */
1453 
check_partition_field_length()1454 bool partition_info::check_partition_field_length()
1455 {
1456   uint store_length= 0;
1457   uint i;
1458   DBUG_ENTER("partition_info::check_partition_field_length");
1459 
1460   for (i= 0; i < num_part_fields; i++)
1461     store_length+= get_partition_field_store_length(part_field_array[i]);
1462   if (store_length > MAX_DATA_LENGTH_FOR_KEY)
1463     DBUG_RETURN(TRUE);
1464   store_length= 0;
1465   for (i= 0; i < num_subpart_fields; i++)
1466     store_length+= get_partition_field_store_length(subpart_field_array[i]);
1467   if (store_length > MAX_DATA_LENGTH_FOR_KEY)
1468     DBUG_RETURN(TRUE);
1469   DBUG_RETURN(FALSE);
1470 }
1471 
1472 
1473 /*
1474   Set up buffers and arrays for fields requiring preparation
1475   SYNOPSIS
1476     set_up_charset_field_preps()
1477 
1478   RETURN VALUES
1479     TRUE                             Memory Allocation error
1480     FALSE                            Success
1481 
1482   DESCRIPTION
1483     Set up arrays and buffers for fields that require special care for
1484     calculation of partition id. This is used for string fields with
1485     variable length or string fields with fixed length that isn't using
1486     the binary collation.
1487 */
1488 
set_up_charset_field_preps(THD * thd)1489 bool partition_info::set_up_charset_field_preps(THD *thd)
1490 {
1491   Field *field, **ptr;
1492   uchar **char_ptrs;
1493   unsigned i;
1494   size_t size;
1495   uint tot_fields= 0;
1496   uint tot_part_fields= 0;
1497   uint tot_subpart_fields= 0;
1498   DBUG_ENTER("set_up_charset_field_preps");
1499 
1500   if (!(part_type == HASH_PARTITION &&
1501         list_of_part_fields) &&
1502         check_part_func_fields(part_field_array, FALSE))
1503   {
1504     ptr= part_field_array;
1505     /* Set up arrays and buffers for those fields */
1506     while ((field= *(ptr++)))
1507     {
1508       if (field_is_partition_charset(field))
1509       {
1510         tot_part_fields++;
1511         tot_fields++;
1512       }
1513     }
1514     size= tot_part_fields * sizeof(char*);
1515     if (!(char_ptrs= (uchar**)thd->calloc(size)))
1516       goto error;
1517     part_field_buffers= char_ptrs;
1518     if (!(char_ptrs= (uchar**)thd->calloc(size)))
1519       goto error;
1520     restore_part_field_ptrs= char_ptrs;
1521     size= (tot_part_fields + 1) * sizeof(Field*);
1522     if (!(char_ptrs= (uchar**)thd->alloc(size)))
1523       goto error;
1524     part_charset_field_array= (Field**)char_ptrs;
1525     ptr= part_field_array;
1526     i= 0;
1527     while ((field= *(ptr++)))
1528     {
1529       if (field_is_partition_charset(field))
1530       {
1531         uchar *field_buf;
1532         size= field->pack_length();
1533         if (!(field_buf= (uchar*) thd->calloc(size)))
1534           goto error;
1535         part_charset_field_array[i]= field;
1536         part_field_buffers[i++]= field_buf;
1537       }
1538     }
1539     part_charset_field_array[i]= NULL;
1540   }
1541   if (is_sub_partitioned() && !list_of_subpart_fields &&
1542       check_part_func_fields(subpart_field_array, FALSE))
1543   {
1544     /* Set up arrays and buffers for those fields */
1545     ptr= subpart_field_array;
1546     while ((field= *(ptr++)))
1547     {
1548       if (field_is_partition_charset(field))
1549       {
1550         tot_subpart_fields++;
1551         tot_fields++;
1552       }
1553     }
1554     size= tot_subpart_fields * sizeof(char*);
1555     if (!(char_ptrs= (uchar**) thd->calloc(size)))
1556       goto error;
1557     subpart_field_buffers= char_ptrs;
1558     if (!(char_ptrs= (uchar**) thd->calloc(size)))
1559       goto error;
1560     restore_subpart_field_ptrs= char_ptrs;
1561     size= (tot_subpart_fields + 1) * sizeof(Field*);
1562     if (!(char_ptrs= (uchar**) thd->alloc(size)))
1563       goto error;
1564     subpart_charset_field_array= (Field**)char_ptrs;
1565     ptr= subpart_field_array;
1566     i= 0;
1567     while ((field= *(ptr++)))
1568     {
1569       uchar *UNINIT_VAR(field_buf);
1570 
1571       if (!field_is_partition_charset(field))
1572         continue;
1573       size= field->pack_length();
1574       if (!(field_buf= (uchar*) thd->calloc(size)))
1575         goto error;
1576       subpart_charset_field_array[i]= field;
1577       subpart_field_buffers[i++]= field_buf;
1578     }
1579     subpart_charset_field_array[i]= NULL;
1580   }
1581   DBUG_RETURN(FALSE);
1582 error:
1583   DBUG_RETURN(TRUE);
1584 }
1585 
1586 
1587 /*
1588   Check if path does not contain mysql data home directory
1589   for partition elements with data directory and index directory
1590 
1591   SYNOPSIS
1592     check_partition_dirs()
1593     part_info               partition_info struct
1594 
1595   RETURN VALUES
1596     0	ok
1597     1	error
1598 */
1599 
check_partition_dirs(partition_info * part_info)1600 bool check_partition_dirs(partition_info *part_info)
1601 {
1602   if (!part_info)
1603     return 0;
1604 
1605   partition_element *part_elem;
1606   List_iterator<partition_element> part_it(part_info->partitions);
1607   while ((part_elem= part_it++))
1608   {
1609     if (part_elem->subpartitions.elements)
1610     {
1611       List_iterator<partition_element> sub_it(part_elem->subpartitions);
1612       partition_element *subpart_elem;
1613       while ((subpart_elem= sub_it++))
1614       {
1615         if (unlikely(error_if_data_home_dir(subpart_elem->data_file_name,
1616                                             "DATA DIRECTORY")) ||
1617             unlikely(error_if_data_home_dir(subpart_elem->index_file_name,
1618                                             "INDEX DIRECTORY")))
1619         return 1;
1620       }
1621     }
1622     else
1623     {
1624       if (unlikely(error_if_data_home_dir(part_elem->data_file_name,
1625                                           "DATA DIRECTORY")) ||
1626           unlikely(error_if_data_home_dir(part_elem->index_file_name,
1627                                           "INDEX DIRECTORY")))
1628         return 1;
1629     }
1630   }
1631   return 0;
1632 }
1633 
1634 
1635 /**
1636   Check what kind of error to report
1637 
1638   @param use_subpart_expr Use the subpart_expr instead of part_expr
1639   @param part_str         Name of partition to report error (or NULL)
1640 */
report_part_expr_error(bool use_subpart_expr)1641 void partition_info::report_part_expr_error(bool use_subpart_expr)
1642 {
1643   Item *expr= part_expr;
1644   DBUG_ENTER("partition_info::report_part_expr_error");
1645   if (use_subpart_expr)
1646     expr= subpart_expr;
1647 
1648   if (expr->type() == Item::FIELD_ITEM)
1649   {
1650     partition_type type= part_type;
1651     bool list_of_fields= list_of_part_fields;
1652     Item_field *item_field= (Item_field*) expr;
1653     /*
1654       The expression consists of a single field.
1655       It must be of integer type unless KEY or COLUMNS partitioning.
1656     */
1657     if (use_subpart_expr)
1658     {
1659       type= subpart_type;
1660       list_of_fields= list_of_subpart_fields;
1661     }
1662     if (!column_list &&
1663         item_field->field &&
1664         item_field->field->result_type() != INT_RESULT &&
1665         !(type == HASH_PARTITION && list_of_fields))
1666     {
1667       my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
1668                item_field->name.str);
1669       DBUG_VOID_RETURN;
1670     }
1671   }
1672   if (use_subpart_expr)
1673     my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "SUBPARTITION");
1674   else
1675     my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "PARTITION");
1676   DBUG_VOID_RETURN;
1677 }
1678 
1679 
1680 /*
1681   Create a new column value in current list with maxvalue
1682   Called from parser
1683 
1684   SYNOPSIS
1685     add_max_value()
1686   RETURN
1687     TRUE               Error
1688     FALSE              Success
1689 */
1690 
add_max_value(THD * thd)1691 int partition_info::add_max_value(THD *thd)
1692 {
1693   DBUG_ENTER("partition_info::add_max_value");
1694 
1695   part_column_list_val *col_val;
1696   /*
1697     Makes for LIST COLUMNS 'num_columns' DEFAULT tuples, 1 tuple for RANGEs
1698   */
1699   uint max_val= (num_columns && part_type == LIST_PARTITION) ?
1700                  num_columns : 1;
1701   for (uint i= 0; i < max_val; i++)
1702   {
1703     if (!(col_val= add_column_value(thd)))
1704     {
1705       DBUG_RETURN(TRUE);
1706     }
1707     col_val->max_value= TRUE;
1708   }
1709   DBUG_RETURN(FALSE);
1710 }
1711 
1712 /*
1713   Create a new column value in current list
1714   Called from parser
1715 
1716   SYNOPSIS
1717     add_column_value()
1718   RETURN
1719     >0                 A part_column_list_val object which have been
1720                        inserted into its list
1721     0                  Memory allocation failure
1722 */
1723 
add_column_value(THD * thd)1724 part_column_list_val *partition_info::add_column_value(THD *thd)
1725 {
1726   uint max_val= num_columns ? num_columns : MAX_REF_PARTS;
1727   DBUG_ENTER("add_column_value");
1728   DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u",
1729                         num_columns, curr_list_object, max_val));
1730   if (curr_list_object < max_val)
1731   {
1732     curr_list_val->added_items++;
1733     DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]);
1734   }
1735   if (!num_columns && part_type == LIST_PARTITION)
1736   {
1737     /*
1738       We're trying to add more than MAX_REF_PARTS, this can happen
1739       in ALTER TABLE using List partitions where the first partition
1740       uses VALUES IN (1,2,3...,17) where the number of fields in
1741       the list is more than MAX_REF_PARTS, in this case we know
1742       that the number of columns must be 1 and we thus reorganize
1743       into the structure used for 1 column. After this we call
1744       ourselves recursively which should always succeed.
1745     */
1746     num_columns= curr_list_object;
1747     if (!reorganize_into_single_field_col_val(thd))
1748     {
1749       if (!init_column_part(thd))
1750         DBUG_RETURN(add_column_value(thd));
1751     }
1752     DBUG_RETURN(NULL);
1753   }
1754   if (column_list)
1755   {
1756     my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
1757   }
1758   else
1759   {
1760     if (part_type == RANGE_PARTITION)
1761       my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "RANGE");
1762     else
1763       my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "LIST");
1764   }
1765   DBUG_RETURN(NULL);
1766 }
1767 
1768 
1769 /*
1770   Initialise part_elem_value object at setting of a new object
1771   (Helper functions to functions called by parser)
1772 
1773   SYNOPSIS
1774     init_col_val
1775     col_val                  Column value object to be initialised
1776     item                     Item object representing column value
1777 
1778   RETURN VALUES
1779     TRUE                     Failure
1780     FALSE                    Success
1781 */
init_col_val(part_column_list_val * col_val,Item * item)1782 void partition_info::init_col_val(part_column_list_val *col_val, Item *item)
1783 {
1784   DBUG_ENTER("partition_info::init_col_val");
1785 
1786   col_val->item_expression= item;
1787   col_val->null_value= item->null_value;
1788   if (item->result_type() == INT_RESULT)
1789   {
1790     /*
1791       This could be both column_list partitioning and function
1792       partitioning, but it doesn't hurt to set the function
1793       partitioning flags about unsignedness.
1794     */
1795     curr_list_val->value= item->val_int();
1796     curr_list_val->unsigned_flag= TRUE;
1797     if (!item->unsigned_flag &&
1798         curr_list_val->value < 0)
1799       curr_list_val->unsigned_flag= FALSE;
1800     if (!curr_list_val->unsigned_flag)
1801       curr_part_elem->signed_flag= TRUE;
1802   }
1803   col_val->part_info= NULL;
1804   DBUG_VOID_RETURN;
1805 }
1806 /*
1807   Add a column value in VALUES LESS THAN or VALUES IN
1808   (Called from parser)
1809 
1810   SYNOPSIS
1811     add_column_list_value()
1812     lex                      Parser's lex object
1813     thd                      Thread object
1814     item                     Item object representing column value
1815 
1816   RETURN VALUES
1817     TRUE                     Failure
1818     FALSE                    Success
1819 */
add_column_list_value(THD * thd,Item * item)1820 bool partition_info::add_column_list_value(THD *thd, Item *item)
1821 {
1822   part_column_list_val *col_val;
1823   Name_resolution_context *context= &thd->lex->current_select->context;
1824   TABLE_LIST *save_list= context->table_list;
1825   const char *save_where= thd->where;
1826   DBUG_ENTER("partition_info::add_column_list_value");
1827 
1828   if (part_type == LIST_PARTITION &&
1829       num_columns == 1U)
1830   {
1831     if (init_column_part(thd))
1832     {
1833       DBUG_RETURN(TRUE);
1834     }
1835   }
1836 
1837   context->table_list= 0;
1838   if (column_list)
1839     thd->where= "field list";
1840   else
1841     thd->where= "partition function";
1842 
1843   if (item->walk(&Item::check_partition_func_processor, 0, NULL))
1844   {
1845     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1846     DBUG_RETURN(TRUE);
1847   }
1848   if (item->fix_fields(thd, (Item**)0) ||
1849       ((context->table_list= save_list), FALSE) ||
1850       (!item->const_item()))
1851   {
1852     context->table_list= save_list;
1853     thd->where= save_where;
1854     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1855     DBUG_RETURN(TRUE);
1856   }
1857   thd->where= save_where;
1858 
1859   if (!(col_val= add_column_value(thd)))
1860   {
1861     DBUG_RETURN(TRUE);
1862   }
1863   init_col_val(col_val, item);
1864   DBUG_RETURN(FALSE);
1865 }
1866 
1867 /*
1868   Initialise part_info object for receiving a set of column values
1869   for a partition, called when parser reaches VALUES LESS THAN or
1870   VALUES IN.
1871 
1872   SYNOPSIS
1873     init_column_part()
1874     lex                    Parser's lex object
1875 
1876   RETURN VALUES
1877     TRUE                     Failure
1878     FALSE                    Success
1879 */
init_column_part(THD * thd)1880 bool partition_info::init_column_part(THD *thd)
1881 {
1882   partition_element *p_elem= curr_part_elem;
1883   part_column_list_val *col_val_array;
1884   part_elem_value *list_val;
1885   uint loc_num_columns;
1886   DBUG_ENTER("partition_info::init_column_part");
1887 
1888   if (!(list_val=
1889       (part_elem_value*) thd->calloc(sizeof(part_elem_value))) ||
1890       p_elem->list_val_list.push_back(list_val, thd->mem_root))
1891     DBUG_RETURN(TRUE);
1892 
1893   if (num_columns)
1894     loc_num_columns= num_columns;
1895   else
1896     loc_num_columns= MAX_REF_PARTS;
1897   if (!(col_val_array=
1898         (part_column_list_val*) thd->calloc(loc_num_columns *
1899                                             sizeof(part_column_list_val))))
1900     DBUG_RETURN(TRUE);
1901 
1902   list_val->col_val_array= col_val_array;
1903   list_val->added_items= 0;
1904   curr_list_val= list_val;
1905   curr_list_object= 0;
1906   DBUG_RETURN(FALSE);
1907 }
1908 
1909 /*
1910   In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST
1911   partitions we can specify list values as:
1912   VALUES IN (v1, v2,,,, v17) if we're using the first partitioning
1913   variant with a function or a column list partitioned table with
1914   one partition field. In this case the parser knows not the
1915   number of columns start with and allocates MAX_REF_PARTS in the
1916   array. If we try to allocate something beyond MAX_REF_PARTS we
1917   will call this function to reorganize into a structure with
1918   num_columns = 1. Also when the parser knows that we used LIST
1919   partitioning and we used a VALUES IN like above where number of
1920   values was smaller than MAX_REF_PARTS or equal, then we will
1921   reorganize after discovering this in the parser.
1922 
1923   SYNOPSIS
1924     reorganize_into_single_field_col_val()
1925 
1926   RETURN VALUES
1927     TRUE                     Failure
1928     FALSE                    Success
1929 */
1930 
reorganize_into_single_field_col_val(THD * thd)1931 int partition_info::reorganize_into_single_field_col_val(THD *thd)
1932 {
1933   part_column_list_val *col_val, *new_col_val;
1934   part_elem_value *val= curr_list_val;
1935   uint loc_num_columns= num_columns;
1936   uint i;
1937   DBUG_ENTER("partition_info::reorganize_into_single_field_col_val");
1938 
1939   num_columns= 1;
1940   val->added_items= 1U;
1941   col_val= &val->col_val_array[0];
1942   init_col_val(col_val, col_val->item_expression);
1943   for (i= 1; i < loc_num_columns; i++)
1944   {
1945     col_val= &val->col_val_array[i];
1946     DBUG_ASSERT(part_type == LIST_PARTITION);
1947     if (init_column_part(thd))
1948     {
1949       DBUG_RETURN(TRUE);
1950     }
1951     if (!(new_col_val= add_column_value(thd)))
1952     {
1953       DBUG_RETURN(TRUE);
1954     }
1955     memcpy(new_col_val, col_val, sizeof(*col_val));
1956     init_col_val(new_col_val, col_val->item_expression);
1957   }
1958   curr_list_val= val;
1959   DBUG_RETURN(FALSE);
1960 }
1961 
1962 /*
1963   This function handles the case of function-based partitioning.
1964   It fixes some data structures created in the parser and puts
1965   them in the format required by the rest of the partitioning
1966   code.
1967 
1968   SYNOPSIS
1969   fix_partition_values()
1970   thd                             Thread object
1971   col_val                         Array of one value
1972   part_elem                       The partition instance
1973   part_id                         Id of partition instance
1974 
1975   RETURN VALUES
1976     TRUE                     Failure
1977     FALSE                    Success
1978 */
fix_partition_values(THD * thd,part_elem_value * val,partition_element * part_elem)1979 int partition_info::fix_partition_values(THD *thd,
1980                                          part_elem_value *val,
1981                                          partition_element *part_elem)
1982 {
1983   part_column_list_val *col_val= val->col_val_array;
1984   DBUG_ENTER("partition_info::fix_partition_values");
1985 
1986   if (col_val->fixed)
1987   {
1988     DBUG_RETURN(FALSE);
1989   }
1990 
1991   Item *item_expr= col_val->item_expression;
1992   if ((val->null_value= item_expr->null_value))
1993   {
1994     if (part_elem->has_null_value)
1995     {
1996       my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
1997       DBUG_RETURN(TRUE);
1998     }
1999     part_elem->has_null_value= TRUE;
2000   }
2001   else if (item_expr->result_type() != INT_RESULT)
2002   {
2003     my_error(ER_VALUES_IS_NOT_INT_TYPE_ERROR, MYF(0),
2004              part_elem->partition_name);
2005     DBUG_RETURN(TRUE);
2006   }
2007   if (part_type == RANGE_PARTITION)
2008   {
2009     if (part_elem->has_null_value)
2010     {
2011       my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
2012       DBUG_RETURN(TRUE);
2013     }
2014     part_elem->range_value= val->value;
2015   }
2016   col_val->fixed= 2;
2017   DBUG_RETURN(FALSE);
2018 }
2019 
2020 /*
2021   Get column item with a proper character set according to the field
2022 
2023   SYNOPSIS
2024     get_column_item()
2025     item                     Item object to start with
2026     field                    Field for which the item will be compared to
2027 
2028   RETURN VALUES
2029     NULL                     Error
2030     item                     Returned item
2031 */
2032 
get_column_item(Item * item,Field * field)2033 Item* partition_info::get_column_item(Item *item, Field *field)
2034 {
2035   if (field->result_type() == STRING_RESULT &&
2036       item->collation.collation != field->charset())
2037   {
2038     if (!(item= convert_charset_partition_constant(item,
2039                                                    field->charset())))
2040     {
2041       my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2042       return NULL;
2043     }
2044   }
2045   return item;
2046 }
2047 
2048 
2049 /*
2050   Evaluate VALUES functions for column list values
2051   SYNOPSIS
2052     fix_column_value_functions()
2053     thd                              Thread object
2054     col_val                          List of column values
2055     part_id                          Partition id we are fixing
2056 
2057   RETURN VALUES
2058     TRUE                             Error
2059     FALSE                            Success
2060   DESCRIPTION
2061     Fix column VALUES and store in memory array adapted to the data type
2062 */
2063 
fix_column_value_functions(THD * thd,part_elem_value * val,uint part_id)2064 bool partition_info::fix_column_value_functions(THD *thd,
2065                                                 part_elem_value *val,
2066                                                 uint part_id)
2067 {
2068   uint n_columns= part_field_list.elements;
2069   bool result= FALSE;
2070   uint i;
2071   part_column_list_val *col_val= val->col_val_array;
2072   DBUG_ENTER("partition_info::fix_column_value_functions");
2073 
2074   if (col_val->fixed > 1)
2075   {
2076     DBUG_RETURN(FALSE);
2077   }
2078   for (i= 0; i < n_columns; col_val++, i++)
2079   {
2080     Item *column_item= col_val->item_expression;
2081     Field *field= part_field_array[i];
2082     col_val->part_info= this;
2083     col_val->partition_id= part_id;
2084     if (col_val->max_value)
2085       col_val->column_value= NULL;
2086     else
2087     {
2088       col_val->column_value= NULL;
2089       if (!col_val->null_value)
2090       {
2091         uchar *val_ptr;
2092         uint len= field->pack_length();
2093         bool save_got_warning;
2094 
2095         if (!(column_item= get_column_item(column_item, field)))
2096         {
2097           result= TRUE;
2098           goto end;
2099         }
2100         Sql_mode_instant_set sms(thd, 0);
2101         save_got_warning= thd->got_warning;
2102         thd->got_warning= 0;
2103         if (column_item->save_in_field(field, TRUE) ||
2104             thd->got_warning)
2105         {
2106           my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
2107           result= TRUE;
2108           goto end;
2109         }
2110         thd->got_warning= save_got_warning;
2111         if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len)))
2112         {
2113           result= TRUE;
2114           goto end;
2115         }
2116         col_val->column_value= val_ptr;
2117       }
2118     }
2119     col_val->fixed= 2;
2120   }
2121 end:
2122   DBUG_RETURN(result);
2123 }
2124 
2125 
2126 /**
2127   Fix partition data from parser.
2128 
2129   @details The parser generates generic data structures, we need to set them
2130   up as the rest of the code expects to find them. This is in reality part
2131   of the syntax check of the parser code.
2132 
2133   It is necessary to call this function in the case of a CREATE TABLE
2134   statement, in this case we do it early in the check_partition_info
2135   function.
2136 
2137   It is necessary to call this function for ALTER TABLE where we
2138   assign a completely new partition structure, in this case we do it
2139   in prep_alter_part_table after discovering that the partition
2140   structure is entirely redefined.
2141 
2142   It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE
2143   of partitions, in this we call it in prep_alter_part_table after
2144   making some initial checks but before going deep to check the partition
2145   info, we also assign the column_list variable before calling this function
2146   here.
2147 
2148   Finally we also call it immediately after returning from parsing the
2149   partitioning text found in the frm file.
2150 
2151   This function mainly fixes the VALUES parts, these are handled differently
2152   whether or not we use column list partitioning. Since the parser doesn't
2153   know which we are using we need to set-up the old data structures after
2154   the parser is complete when we know if what type of partitioning the
2155   base table is using.
2156 
2157   For column lists we will handle this in the fix_column_value_function.
2158   For column lists it is sufficient to verify that the number of columns
2159   and number of elements are in synch with each other. So only partitioning
2160   using functions need to be set-up to their data structures.
2161 
2162   @param thd  Thread object
2163 
2164   @return Operation status
2165     @retval TRUE   Failure
2166     @retval FALSE  Success
2167 */
2168 
fix_parser_data(THD * thd)2169 bool partition_info::fix_parser_data(THD *thd)
2170 {
2171   List_iterator<partition_element> it(partitions);
2172   partition_element *part_elem;
2173   uint num_elements;
2174   uint i= 0, j, k;
2175   DBUG_ENTER("partition_info::fix_parser_data");
2176 
2177   if (!(part_type == RANGE_PARTITION ||
2178         part_type == LIST_PARTITION))
2179   {
2180     if (part_type == HASH_PARTITION && list_of_part_fields)
2181     {
2182       /* KEY partitioning, check ALGORITHM = N. Should not pass the parser! */
2183       if (key_algorithm > KEY_ALGORITHM_55)
2184       {
2185         my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2186         DBUG_RETURN(true);
2187       }
2188       /* If not set, use DEFAULT = 2 for CREATE and ALTER! */
2189       if ((thd_sql_command(thd) == SQLCOM_CREATE_TABLE ||
2190            thd_sql_command(thd) == SQLCOM_ALTER_TABLE) &&
2191           key_algorithm == KEY_ALGORITHM_NONE)
2192         key_algorithm= KEY_ALGORITHM_55;
2193     }
2194     DBUG_RETURN(FALSE);
2195   }
2196   if (is_sub_partitioned() && list_of_subpart_fields)
2197   {
2198     /* KEY subpartitioning, check ALGORITHM = N. Should not pass the parser! */
2199     if (key_algorithm > KEY_ALGORITHM_55)
2200     {
2201       my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2202       DBUG_RETURN(true);
2203     }
2204     /* If not set, use DEFAULT = 2 for CREATE and ALTER! */
2205     if ((thd_sql_command(thd) == SQLCOM_CREATE_TABLE ||
2206          thd_sql_command(thd) == SQLCOM_ALTER_TABLE) &&
2207         key_algorithm == KEY_ALGORITHM_NONE)
2208       key_algorithm= KEY_ALGORITHM_55;
2209   }
2210   defined_max_value= FALSE; // in case it already set (CREATE TABLE LIKE)
2211   do
2212   {
2213     part_elem= it++;
2214     List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
2215     num_elements= part_elem->list_val_list.elements;
2216     if (unlikely(!num_elements && error_if_requires_values()))
2217       DBUG_RETURN(true);
2218     DBUG_ASSERT(part_type == RANGE_PARTITION ?
2219                 num_elements == 1U : TRUE);
2220 
2221     for (j= 0; j < num_elements; j++)
2222     {
2223       part_elem_value *val= list_val_it++;
2224 
2225       if (val->added_items != (column_list ? num_columns : 1))
2226       {
2227         my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
2228         DBUG_RETURN(TRUE);
2229       }
2230 
2231       /*
2232         Check the last MAX_VALUE for range partitions and DEFAULT value
2233         for LIST partitions.
2234         Both values are marked with defined_max_value and
2235         default_partition_id.
2236 
2237         This is a max_value/default is max_value is set and this is
2238         a normal RANGE (no column list) or if it's a LIST partition:
2239 
2240         PARTITION p3 VALUES LESS THAN MAXVALUE
2241         or
2242         PARTITION p3 VALUES DEFAULT
2243       */
2244       if (val->added_items && val->col_val_array[0].max_value &&
2245           (!column_list || part_type == LIST_PARTITION))
2246       {
2247         DBUG_ASSERT(part_type == RANGE_PARTITION ||
2248                     part_type == LIST_PARTITION);
2249         if (defined_max_value)
2250         {
2251           my_error((part_type == RANGE_PARTITION) ?
2252                    ER_PARTITION_MAXVALUE_ERROR :
2253                    ER_PARTITION_DEFAULT_ERROR, MYF(0));
2254           DBUG_RETURN(TRUE);
2255         }
2256 
2257         /* For RANGE PARTITION MAX_VALUE must be last */
2258         if (i != (num_parts - 1) &&
2259             part_type != LIST_PARTITION)
2260         {
2261           my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
2262           DBUG_RETURN(TRUE);
2263         }
2264 
2265         defined_max_value= TRUE;
2266         default_partition_id= i;
2267         part_elem->max_value= TRUE;
2268         part_elem->range_value= LONGLONG_MAX;
2269         continue;
2270       }
2271 
2272       if (column_list)
2273       {
2274         for (k= 0; k < num_columns; k++)
2275         {
2276           part_column_list_val *col_val= &val->col_val_array[k];
2277           if (col_val->null_value && part_type == RANGE_PARTITION)
2278           {
2279             my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
2280             DBUG_RETURN(TRUE);
2281           }
2282         }
2283       }
2284       else
2285       {
2286         if (fix_partition_values(thd, val, part_elem))
2287           DBUG_RETURN(TRUE);
2288         if (val->null_value)
2289         {
2290           /*
2291             Null values aren't required in the value part, they are kept per
2292             partition instance, only LIST partitions have NULL values.
2293           */
2294           list_val_it.remove();
2295         }
2296       }
2297     }
2298   } while (++i < num_parts);
2299   DBUG_RETURN(FALSE);
2300 }
2301 
2302 
2303 /**
2304   helper function to compare strings that can also be
2305   a NULL pointer.
2306 
2307   @param a  char pointer (can be NULL).
2308   @param b  char pointer (can be NULL).
2309 
2310   @return false if equal
2311     @retval true  strings differs
2312     @retval false strings is equal
2313 */
2314 
strcmp_null(const char * a,const char * b)2315 static bool strcmp_null(const char *a, const char *b)
2316 {
2317   if (!a && !b)
2318     return false;
2319   if (a && b && !strcmp(a, b))
2320     return false;
2321   return true;
2322 }
2323 
2324 
2325 /**
2326   Check if the new part_info has the same partitioning.
2327 
2328   @param new_part_info  New partition definition to compare with.
2329 
2330   @return True if not considered to have changed the partitioning.
2331     @retval true  Allowed change (only .frm change, compatible distribution).
2332     @retval false Different partitioning, will need redistribution of rows.
2333 
2334   @note Currently only used to allow changing from non-set key_algorithm
2335   to a specified key_algorithm, to avoid rebuild when upgrading from 5.1 of
2336   such partitioned tables using numeric colums in the partitioning expression.
2337   For more info see bug#14521864.
2338   Does not check if columns etc has changed, i.e. only for
2339   alter_info->partition_flags == ALTER_PARTITION_INFO.
2340 */
2341 
has_same_partitioning(partition_info * new_part_info)2342 bool partition_info::has_same_partitioning(partition_info *new_part_info)
2343 {
2344   DBUG_ENTER("partition_info::has_same_partitioning");
2345 
2346   DBUG_ASSERT(part_field_array && part_field_array[0]);
2347 
2348   /*
2349     Only consider pre 5.5.3 .frm's to have same partitioning as
2350     a new one with KEY ALGORITHM = 1 ().
2351   */
2352 
2353   if (part_field_array[0]->table->s->mysql_version >= 50503)
2354     DBUG_RETURN(false);
2355 
2356   if (!new_part_info ||
2357       part_type != new_part_info->part_type ||
2358       num_parts != new_part_info->num_parts ||
2359       use_default_partitions != new_part_info->use_default_partitions ||
2360       new_part_info->is_sub_partitioned() != is_sub_partitioned())
2361     DBUG_RETURN(false);
2362 
2363   if (part_type != HASH_PARTITION)
2364   {
2365     /*
2366       RANGE or LIST partitioning, check if KEY subpartitioned.
2367       Also COLUMNS partitioning was added in 5.5, so treat that as different.
2368     */
2369     if (!is_sub_partitioned() ||
2370         !new_part_info->is_sub_partitioned() ||
2371         column_list ||
2372         new_part_info->column_list ||
2373         !list_of_subpart_fields ||
2374         !new_part_info->list_of_subpart_fields ||
2375         new_part_info->num_subparts != num_subparts ||
2376         new_part_info->subpart_field_list.elements !=
2377           subpart_field_list.elements ||
2378         new_part_info->use_default_subpartitions !=
2379           use_default_subpartitions)
2380       DBUG_RETURN(false);
2381   }
2382   else
2383   {
2384     /* Check if KEY partitioned. */
2385     if (!new_part_info->list_of_part_fields ||
2386         !list_of_part_fields ||
2387         new_part_info->part_field_list.elements != part_field_list.elements)
2388       DBUG_RETURN(false);
2389   }
2390 
2391   /* Check that it will use the same fields in KEY (fields) list. */
2392   List_iterator<const char> old_field_name_it(part_field_list);
2393   List_iterator<const char> new_field_name_it(new_part_info->part_field_list);
2394   const char *old_name, *new_name;
2395   while ((old_name= old_field_name_it++))
2396   {
2397     new_name= new_field_name_it++;
2398     if (!new_name || my_strcasecmp(system_charset_info,
2399                                    new_name,
2400                                    old_name))
2401       DBUG_RETURN(false);
2402   }
2403 
2404   if (is_sub_partitioned())
2405   {
2406     /* Check that it will use the same fields in KEY subpart fields list. */
2407     List_iterator<const char> old_field_name_it(subpart_field_list);
2408     List_iterator<const char> new_field_name_it(new_part_info->subpart_field_list);
2409     const char *old_name, *new_name;
2410     while ((old_name= old_field_name_it++))
2411     {
2412       new_name= new_field_name_it++;
2413       if (!new_name || my_strcasecmp(system_charset_info,
2414                                      new_name,
2415                                      old_name))
2416         DBUG_RETURN(false);
2417     }
2418   }
2419 
2420   if (!use_default_partitions)
2421   {
2422     /*
2423       Loop over partitions/subpartition to verify that they are
2424       the same, including state and name.
2425     */
2426     List_iterator<partition_element> part_it(partitions);
2427     List_iterator<partition_element> new_part_it(new_part_info->partitions);
2428     uint i= 0;
2429     do
2430     {
2431       partition_element *part_elem= part_it++;
2432       partition_element *new_part_elem= new_part_it++;
2433       /*
2434         The following must match:
2435         partition_name, tablespace_name, data_file_name, index_file_name,
2436         engine_type, part_max_rows, part_min_rows, nodegroup_id.
2437         (max_value, signed_flag, has_null_value only on partition level,
2438         RANGE/LIST)
2439         The following can differ:
2440           - part_comment
2441         part_state must be PART_NORMAL!
2442       */
2443       if (!part_elem || !new_part_elem ||
2444           strcmp(part_elem->partition_name,
2445                  new_part_elem->partition_name) ||
2446           part_elem->part_state != PART_NORMAL ||
2447           new_part_elem->part_state != PART_NORMAL ||
2448           part_elem->max_value != new_part_elem->max_value ||
2449           part_elem->signed_flag != new_part_elem->signed_flag ||
2450           part_elem->has_null_value != new_part_elem->has_null_value)
2451         DBUG_RETURN(false);
2452 
2453       /* new_part_elem may not have engine_type set! */
2454       if (new_part_elem->engine_type &&
2455           part_elem->engine_type != new_part_elem->engine_type)
2456         DBUG_RETURN(false);
2457 
2458       if (is_sub_partitioned())
2459       {
2460         /*
2461           Check that both old and new partition has the same definition
2462           (VALUES IN/VALUES LESS THAN) (No COLUMNS partitioning, see above)
2463         */
2464         if (part_type == LIST_PARTITION)
2465         {
2466           List_iterator<part_elem_value> list_vals(part_elem->list_val_list);
2467           List_iterator<part_elem_value>
2468             new_list_vals(new_part_elem->list_val_list);
2469           part_elem_value *val;
2470           part_elem_value *new_val;
2471           while ((val= list_vals++))
2472           {
2473             new_val= new_list_vals++;
2474             if (!new_val)
2475               DBUG_RETURN(false);
2476             if ((!val->null_value && !new_val->null_value) &&
2477                 val->value != new_val->value)
2478               DBUG_RETURN(false);
2479           }
2480           if (new_list_vals++)
2481             DBUG_RETURN(false);
2482         }
2483         else
2484         {
2485           DBUG_ASSERT(part_type == RANGE_PARTITION);
2486           if (new_part_elem->range_value != part_elem->range_value)
2487             DBUG_RETURN(false);
2488         }
2489 
2490         if (!use_default_subpartitions)
2491         {
2492           List_iterator<partition_element>
2493             sub_part_it(part_elem->subpartitions);
2494           List_iterator<partition_element>
2495             new_sub_part_it(new_part_elem->subpartitions);
2496           uint j= 0;
2497           do
2498           {
2499             partition_element *sub_part_elem= sub_part_it++;
2500             partition_element *new_sub_part_elem= new_sub_part_it++;
2501             /* new_part_elem may not have engine_type set! */
2502             if (new_sub_part_elem->engine_type &&
2503                 sub_part_elem->engine_type != new_sub_part_elem->engine_type)
2504               DBUG_RETURN(false);
2505 
2506             if (strcmp(sub_part_elem->partition_name,
2507                        new_sub_part_elem->partition_name) ||
2508                 sub_part_elem->part_state != PART_NORMAL ||
2509                 new_sub_part_elem->part_state != PART_NORMAL ||
2510                 sub_part_elem->part_min_rows !=
2511                   new_sub_part_elem->part_min_rows ||
2512                 sub_part_elem->part_max_rows !=
2513                   new_sub_part_elem->part_max_rows ||
2514                 sub_part_elem->nodegroup_id !=
2515                   new_sub_part_elem->nodegroup_id)
2516               DBUG_RETURN(false);
2517 
2518             if (strcmp_null(sub_part_elem->data_file_name,
2519                             new_sub_part_elem->data_file_name) ||
2520                 strcmp_null(sub_part_elem->index_file_name,
2521                             new_sub_part_elem->index_file_name) ||
2522                 strcmp_null(sub_part_elem->tablespace_name,
2523                             new_sub_part_elem->tablespace_name))
2524               DBUG_RETURN(false);
2525 
2526           } while (++j < num_subparts);
2527         }
2528       }
2529       else
2530       {
2531         if (part_elem->part_min_rows != new_part_elem->part_min_rows ||
2532             part_elem->part_max_rows != new_part_elem->part_max_rows ||
2533             part_elem->nodegroup_id != new_part_elem->nodegroup_id)
2534           DBUG_RETURN(false);
2535 
2536         if (strcmp_null(part_elem->data_file_name,
2537                         new_part_elem->data_file_name) ||
2538             strcmp_null(part_elem->index_file_name,
2539                         new_part_elem->index_file_name) ||
2540             strcmp_null(part_elem->tablespace_name,
2541                         new_part_elem->tablespace_name))
2542           DBUG_RETURN(false);
2543       }
2544     } while (++i < num_parts);
2545   }
2546 
2547   /*
2548     Only if key_algorithm was not specified before and it is now set,
2549     consider this as nothing was changed, and allow change without rebuild!
2550   */
2551   if (key_algorithm != partition_info::KEY_ALGORITHM_NONE ||
2552       new_part_info->key_algorithm == partition_info::KEY_ALGORITHM_NONE)
2553     DBUG_RETURN(false);
2554 
2555   DBUG_RETURN(true);
2556 }
2557 
2558 
print_debug(const char * str,uint * value)2559 void partition_info::print_debug(const char *str, uint *value)
2560 {
2561   DBUG_ENTER("print_debug");
2562   if (value)
2563     DBUG_PRINT("info", ("parser: %s, val = %u", str, *value));
2564   else
2565     DBUG_PRINT("info", ("parser: %s", str));
2566   DBUG_VOID_RETURN;
2567 }
2568 
field_in_partition_expr(Field * field) const2569 bool partition_info::field_in_partition_expr(Field *field) const
2570 {
2571   uint i;
2572   for (i= 0; i < num_part_fields; i++)
2573   {
2574     if (field->eq(part_field_array[i]))
2575       return TRUE;
2576   }
2577   for (i= 0; i < num_subpart_fields; i++)
2578   {
2579     if (field->eq(subpart_field_array[i]))
2580       return TRUE;
2581   }
2582   return FALSE;
2583 }
2584 
2585 #else /* WITH_PARTITION_STORAGE_ENGINE */
2586  /*
2587    For builds without partitioning we need to define these functions
2588    since we they are called from the parser. The parser cannot
2589    remove code parts using ifdef, but the code parts cannot be called
2590    so we simply need to add empty functions to make the linker happy.
2591  */
add_column_value(THD * thd)2592 part_column_list_val *partition_info::add_column_value(THD *thd)
2593 {
2594   return NULL;
2595 }
2596 
set_part_expr(THD * thd,Item * item_ptr,bool is_subpart)2597 bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
2598 {
2599   (void)item_ptr;
2600   (void)is_subpart;
2601   return FALSE;
2602 }
2603 
reorganize_into_single_field_col_val(THD * thd)2604 int partition_info::reorganize_into_single_field_col_val(THD *thd)
2605 {
2606   return 0;
2607 }
2608 
init_column_part(THD * thd)2609 bool partition_info::init_column_part(THD *thd)
2610 {
2611   return FALSE;
2612 }
2613 
add_column_list_value(THD * thd,Item * item)2614 bool partition_info::add_column_list_value(THD *thd, Item *item)
2615 {
2616   return FALSE;
2617 }
add_max_value(THD * thd)2618 int partition_info::add_max_value(THD *thd)
2619 {
2620   return 0;
2621 }
2622 
print_debug(const char * str,uint * value)2623 void partition_info::print_debug(const char *str, uint *value)
2624 {
2625 }
2626 
check_partition_dirs(partition_info * part_info)2627 bool check_partition_dirs(partition_info *part_info)
2628 {
2629   return 0;
2630 }
2631 
2632 #endif /* WITH_PARTITION_STORAGE_ENGINE */
2633 
vers_init_info(THD * thd)2634 bool partition_info::vers_init_info(THD * thd)
2635 {
2636   part_type= VERSIONING_PARTITION;
2637   list_of_part_fields= true;
2638   column_list= false;
2639   vers_info= new (thd->mem_root) Vers_part_info;
2640   if (unlikely(!vers_info))
2641     return true;
2642 
2643   return false;
2644 }
2645 
2646 
2647 /**
2648   Assign INTERVAL and STARTS for SYSTEM_TIME partitions.
2649 
2650   @return true on error
2651 */
2652 
vers_set_interval(THD * thd,Item * interval,interval_type int_type,Item * starts,const char * table_name)2653 bool partition_info::vers_set_interval(THD* thd, Item* interval,
2654                                        interval_type int_type, Item* starts,
2655                                        const char *table_name)
2656 {
2657   DBUG_ASSERT(part_type == VERSIONING_PARTITION);
2658 
2659   MYSQL_TIME ltime;
2660   uint err;
2661   vers_info->interval.type= int_type;
2662 
2663   /* 1. assign INTERVAL to interval.step */
2664   if (interval->fix_fields_if_needed_for_scalar(thd, &interval))
2665     return true;
2666   bool error= get_interval_value(thd, interval, int_type, &vers_info->interval.step) ||
2667           vers_info->interval.step.neg || vers_info->interval.step.second_part ||
2668         !(vers_info->interval.step.year || vers_info->interval.step.month ||
2669           vers_info->interval.step.day || vers_info->interval.step.hour ||
2670           vers_info->interval.step.minute || vers_info->interval.step.second);
2671   if (error)
2672   {
2673     my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "INTERVAL");
2674     return true;
2675   }
2676 
2677   /* 2. assign STARTS to interval.start */
2678   if (starts)
2679   {
2680     if (starts->fix_fields_if_needed_for_scalar(thd, &starts))
2681       return true;
2682     switch (starts->result_type())
2683     {
2684       case INT_RESULT:
2685       case DECIMAL_RESULT:
2686       case REAL_RESULT:
2687         /* When table member is defined, we are inside mysql_unpack_partition(). */
2688         if (!table || starts->val_int() > TIMESTAMP_MAX_VALUE)
2689           goto interval_starts_error;
2690         vers_info->interval.start= (my_time_t) starts->val_int();
2691         break;
2692       case STRING_RESULT:
2693       case TIME_RESULT:
2694       {
2695         Datetime::Options opt(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, thd);
2696         starts->get_date(thd, &ltime, opt);
2697         vers_info->interval.start= TIME_to_timestamp(thd, &ltime, &err);
2698         if (err)
2699           goto interval_starts_error;
2700         break;
2701       }
2702       case ROW_RESULT:
2703       default:
2704         goto interval_starts_error;
2705     }
2706     if (!table)
2707     {
2708       if (thd->query_start() < vers_info->interval.start) {
2709         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
2710                             ER_PART_STARTS_BEYOND_INTERVAL,
2711                             ER_THD(thd, ER_PART_STARTS_BEYOND_INTERVAL),
2712                             table_name);
2713       }
2714     }
2715   }
2716   else // calculate default STARTS depending on INTERVAL
2717   {
2718     thd->variables.time_zone->gmt_sec_to_TIME(&ltime, thd->query_start());
2719     if (vers_info->interval.step.second)
2720       goto interval_set_starts;
2721     ltime.second= 0;
2722     if (vers_info->interval.step.minute)
2723       goto interval_set_starts;
2724     ltime.minute= 0;
2725     if (vers_info->interval.step.hour)
2726       goto interval_set_starts;
2727     ltime.hour= 0;
2728 
2729 interval_set_starts:
2730     vers_info->interval.start= TIME_to_timestamp(thd, &ltime, &err);
2731     if (err)
2732       goto interval_starts_error;
2733   }
2734 
2735   return false;
2736 
2737 interval_starts_error:
2738   my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "STARTS");
2739   return true;
2740 }
2741 
2742 
error_if_requires_values() const2743 bool partition_info::error_if_requires_values() const
2744 {
2745   switch (part_type) {
2746   case NOT_A_PARTITION:
2747   case HASH_PARTITION:
2748   case VERSIONING_PARTITION:
2749     break;
2750   case RANGE_PARTITION:
2751     my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
2752     return true;
2753   case LIST_PARTITION:
2754     my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
2755     return true;
2756   }
2757   return false;
2758 }
2759