1 /* Copyright (c) 2005, 2017, Oracle and/or its affiliates.
2    Copyright (c) 2009, 2018, MariaDB
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 Street, Fifth Floor, Boston, MA  02110-1335  USA */
16 
17 /*
18   This file is a container for general functionality related
19   to partitioning introduced in MySQL version 5.1. It contains functionality
20   used by all handlers that support partitioning, such as
21   the partitioning handler itself and the NDB handler.
22   (Much of the code in this file has been split into partition_info.cc and
23    the header files partition_info.h + partition_element.h + sql_partition.h)
24 
25   The first version was written by Mikael Ronstrom 2004-2006.
26   Various parts of the optimizer code was written by Sergey Petrunia.
27   Code have been maintained by Mattias Jonsson.
28   The second version was written by Mikael Ronstrom 2006-2007 with some
29   final fixes for partition pruning in 2008-2009 with assistance from Sergey
30   Petrunia and Mattias Jonsson.
31 
32   The first version supports RANGE partitioning, LIST partitioning, HASH
33   partitioning and composite partitioning (hereafter called subpartitioning)
34   where each RANGE/LIST partitioning is HASH partitioned. The hash function
35   can either be supplied by the user or by only a list of fields (also
36   called KEY partitioning), where the MySQL server will use an internal
37   hash function.
38   There are quite a few defaults that can be used as well.
39 
40   The second version introduces a new variant of RANGE and LIST partitioning
41   which is often referred to as column lists in the code variables. This
42   enables a user to specify a set of columns and their concatenated value
43   as the partition value. By comparing the concatenation of these values
44   the proper partition can be choosen.
45 */
46 
47 /* Some general useful functions */
48 
49 #define MYSQL_LEX 1
50 #include "mariadb.h"
51 #include "sql_priv.h"
52 #include "sql_partition.h"
53 #include "key.h"                            // key_restore
54 #include "sql_parse.h"                      // parse_sql
55 #include "sql_cache.h"                      // query_cache_invalidate3
56 #include "lock.h"                           // mysql_lock_remove
57 #include "sql_show.h"                       // append_identifier
58 #include <m_ctype.h>
59 #include "transaction.h"
60 #include "debug_sync.h"
61 
62 #include "sql_base.h"                   // close_all_tables_for_name
63 #include "sql_table.h"                  // build_table_filename,
64                                         // build_table_shadow_filename,
65                                         // table_to_filename
66                                         // mysql_*_alter_copy_data
67 #include "opt_range.h"                  // store_key_image_to_rec
68 #include "sql_alter.h"                  // Alter_table_ctx
69 #include "sql_select.h"
70 #include "sql_tablespace.h"             // check_tablespace_name
71 #include "tztime.h"                     // my_tz_OFFSET0
72 
73 #include <algorithm>
74 using std::max;
75 using std::min;
76 
77 #ifdef WITH_PARTITION_STORAGE_ENGINE
78 #include "ha_partition.h"
79 
80 #define ERROR_INJECT_CRASH(code) \
81   DBUG_EVALUATE_IF(code, (DBUG_SUICIDE(), 0), 0)
82 #define ERROR_INJECT_ERROR(code) \
83   DBUG_EVALUATE_IF(code, (my_error(ER_UNKNOWN_ERROR, MYF(0)), TRUE), 0)
84 
85 /*
86   Partition related functions declarations and some static constants;
87 */
88 static int get_partition_id_list_col(partition_info *, uint32 *, longlong *);
89 static int get_partition_id_list(partition_info *, uint32 *, longlong *);
90 static int get_partition_id_range_col(partition_info *, uint32 *, longlong *);
91 static int get_partition_id_range(partition_info *, uint32 *, longlong *);
92 static int vers_get_partition_id(partition_info *, uint32 *, longlong *);
93 static int get_part_id_charset_func_part(partition_info *, uint32 *, longlong *);
94 static int get_part_id_charset_func_subpart(partition_info *, uint32 *);
95 static int get_partition_id_hash_nosub(partition_info *, uint32 *, longlong *);
96 static int get_partition_id_key_nosub(partition_info *, uint32 *, longlong *);
97 static int get_partition_id_linear_hash_nosub(partition_info *, uint32 *, longlong *);
98 static int get_partition_id_linear_key_nosub(partition_info *, uint32 *, longlong *);
99 static int get_partition_id_with_sub(partition_info *, uint32 *, longlong *);
100 static int get_partition_id_hash_sub(partition_info *part_info, uint32 *part_id);
101 static int get_partition_id_key_sub(partition_info *part_info, uint32 *part_id);
102 static int get_partition_id_linear_hash_sub(partition_info *part_info, uint32 *part_id);
103 static int get_partition_id_linear_key_sub(partition_info *part_info, uint32 *part_id);
104 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR*);
105 static void set_up_range_analysis_info(partition_info *part_info);
106 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR*);
107 #endif
108 
109 uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter);
110 uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter);
111 
112 #ifdef WITH_PARTITION_STORAGE_ENGINE
113 static int get_part_iter_for_interval_via_mapping(partition_info *, bool,
114           uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *);
115 static int get_part_iter_for_interval_cols_via_map(partition_info *, bool,
116           uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *);
117 static int get_part_iter_for_interval_via_walking(partition_info *, bool,
118           uint32 *, uchar *, uchar *, uint, uint, uint, PARTITION_ITERATOR *);
119 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
120 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
121                                    uint32 n_vals_in_rec,
122                                    bool is_left_endpoint,
123                                    bool include_endpoint);
124 
125 /*
126   Convert constants in VALUES definition to the character set the
127   corresponding field uses.
128 
129   SYNOPSIS
130     convert_charset_partition_constant()
131     item                                Item to convert
132     cs                                  Character set to convert to
133 
134   RETURN VALUE
135     NULL                                Error
136     item                                New converted item
137 */
138 
convert_charset_partition_constant(Item * item,CHARSET_INFO * cs)139 Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs)
140 {
141   THD *thd= current_thd;
142   Name_resolution_context *context= &thd->lex->current_select->context;
143   TABLE_LIST *save_list= context->table_list;
144   const char *save_where= thd->where;
145 
146   item= item->safe_charset_converter(thd, cs);
147   context->table_list= NULL;
148   thd->where= "convert character set partition constant";
149   if (item && item->fix_fields_if_needed(thd, (Item**)NULL))
150     item= NULL;
151   thd->where= save_where;
152   context->table_list= save_list;
153   return item;
154 }
155 
156 
157 /**
158   A support function to check if a name is in a list of strings.
159 
160   @param name        String searched for
161   @param list_names  A list of names searched in
162 
163   @return True if if the name is in the list.
164     @retval true   String found
165     @retval false  String not found
166 */
167 
is_name_in_list(const char * name,List<const char> list_names)168 static bool is_name_in_list(const char *name, List<const char> list_names)
169 {
170   List_iterator<const char> names_it(list_names);
171   uint num_names= list_names.elements;
172   uint i= 0;
173 
174   do
175   {
176     const char *list_name= names_it++;
177     if (!(my_strcasecmp(system_charset_info, name, list_name)))
178       return TRUE;
179   } while (++i < num_names);
180   return FALSE;
181 }
182 
183 
184 
185 /*
186   Set-up defaults for partitions.
187 
188   SYNOPSIS
189     partition_default_handling()
190     table                         Table object
191     part_info                     Partition info to set up
192     is_create_table_ind           Is this part of a table creation
193     normalized_path               Normalized path name of table and database
194 
195   RETURN VALUES
196     TRUE                          Error
197     FALSE                         Success
198 */
199 
partition_default_handling(THD * thd,TABLE * table,partition_info * part_info,bool is_create_table_ind,const char * normalized_path)200 bool partition_default_handling(THD *thd, TABLE *table, partition_info *part_info,
201                                 bool is_create_table_ind,
202                                 const char *normalized_path)
203 {
204   DBUG_ENTER("partition_default_handling");
205 
206   if (!is_create_table_ind)
207   {
208     if (part_info->use_default_num_partitions)
209     {
210       if (table->file->get_no_parts(normalized_path, &part_info->num_parts))
211       {
212         DBUG_RETURN(TRUE);
213       }
214     }
215     else if (part_info->is_sub_partitioned() &&
216              part_info->use_default_num_subpartitions)
217     {
218       uint num_parts;
219       if (table->file->get_no_parts(normalized_path, &num_parts))
220       {
221         DBUG_RETURN(TRUE);
222       }
223       DBUG_ASSERT(part_info->num_parts > 0);
224       DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
225       part_info->num_subparts= num_parts / part_info->num_parts;
226     }
227   }
228   part_info->set_up_defaults_for_partitioning(thd, table->file,
229                                               NULL, 0U);
230   DBUG_RETURN(FALSE);
231 }
232 
233 
234 /*
235   A useful routine used by update/delete_row for partition handlers to
236   calculate the partition id.
237 
238   SYNOPSIS
239     get_part_for_buf()
240     buf                     Buffer of old record
241     rec0                    Reference to table->record[0]
242     part_info               Reference to partition information
243     out:part_id             The returned partition id to delete from
244 
245   RETURN VALUE
246     0                       Success
247     > 0                     Error code
248 
249   DESCRIPTION
250     Dependent on whether buf is not record[0] we need to prepare the
251     fields. Then we call the function pointer get_partition_id to
252     calculate the partition id.
253 */
254 
get_part_for_buf(const uchar * buf,const uchar * rec0,partition_info * part_info,uint32 * part_id)255 int get_part_for_buf(const uchar *buf, const uchar *rec0,
256                      partition_info *part_info, uint32 *part_id)
257 {
258   int error;
259   longlong func_value;
260   DBUG_ENTER("get_part_for_buf");
261 
262   if (buf == rec0)
263   {
264     error= part_info->get_partition_id(part_info, part_id, &func_value);
265     if (unlikely((error)))
266       goto err;
267     DBUG_PRINT("info", ("Partition %d", *part_id));
268   }
269   else
270   {
271     Field **part_field_array= part_info->full_part_field_array;
272     part_info->table->move_fields(part_field_array, buf, rec0);
273     error= part_info->get_partition_id(part_info, part_id, &func_value);
274     part_info->table->move_fields(part_field_array, rec0, buf);
275     if (unlikely(error))
276       goto err;
277     DBUG_PRINT("info", ("Partition %d (path2)", *part_id));
278   }
279   DBUG_RETURN(0);
280 err:
281   part_info->err_value= func_value;
282   DBUG_RETURN(error);
283 }
284 
285 
286 /*
287   This method is used to set-up both partition and subpartitioning
288   field array and used for all types of partitioning.
289   It is part of the logic around fix_partition_func.
290 
291   SYNOPSIS
292     set_up_field_array()
293     table                TABLE object for which partition fields are set-up
294     sub_part             Is the table subpartitioned as well
295 
296   RETURN VALUE
297     TRUE                 Error, some field didn't meet requirements
298     FALSE                Ok, partition field array set-up
299 
300   DESCRIPTION
301 
302     A great number of functions below here is part of the fix_partition_func
303     method. It is used to set up the partition structures for execution from
304     openfrm. It is called at the end of the openfrm when the table struct has
305     been set-up apart from the partition information.
306     It involves:
307     1) Setting arrays of fields for the partition functions.
308     2) Setting up binary search array for LIST partitioning
309     3) Setting up array for binary search for RANGE partitioning
310     4) Setting up key_map's to assist in quick evaluation whether one
311        can deduce anything from a given index of what partition to use
312     5) Checking whether a set of partitions can be derived from a range on
313        a field in the partition function.
314     As part of doing this there is also a great number of error controls.
315     This is actually the place where most of the things are checked for
316     partition information when creating a table.
317     Things that are checked includes
318     1) All fields of partition function in Primary keys and unique indexes
319        (if not supported)
320 
321 
322     Create an array of partition fields (NULL terminated). Before this method
323     is called fix_fields or find_table_in_sef has been called to set
324     GET_FIXED_FIELDS_FLAG on all fields that are part of the partition
325     function.
326 */
327 
set_up_field_array(THD * thd,TABLE * table,bool is_sub_part)328 static bool set_up_field_array(THD *thd, TABLE *table,
329                               bool is_sub_part)
330 {
331   Field **ptr, *field, **field_array;
332   uint num_fields= 0;
333   uint size_field_array;
334   uint i= 0;
335   uint inx;
336   partition_info *part_info= table->part_info;
337   int result= FALSE;
338   DBUG_ENTER("set_up_field_array");
339 
340   ptr= table->field;
341   while ((field= *(ptr++)))
342   {
343     if (field->flags & GET_FIXED_FIELDS_FLAG)
344     {
345       if (table->versioned(VERS_TRX_ID)
346           && unlikely(field->flags & VERS_SYSTEM_FIELD))
347       {
348         my_error(ER_VERS_TRX_PART_HISTORIC_ROW_NOT_SUPPORTED, MYF(0));
349         DBUG_RETURN(TRUE);
350       }
351       num_fields++;
352     }
353   }
354   if (unlikely(num_fields > MAX_REF_PARTS))
355   {
356     char *err_str;
357     if (is_sub_part)
358       err_str= (char*)"subpartition function";
359     else
360       err_str= (char*)"partition function";
361     my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), err_str);
362     DBUG_RETURN(TRUE);
363   }
364   if (num_fields == 0)
365   {
366     /*
367       We are using hidden key as partitioning field
368     */
369     DBUG_ASSERT(!is_sub_part);
370     DBUG_RETURN(FALSE);
371   }
372   size_field_array= (num_fields+1)*sizeof(Field*);
373   field_array= (Field**) thd->calloc(size_field_array);
374   if (unlikely(!field_array))
375     DBUG_RETURN(TRUE);
376 
377   ptr= table->field;
378   while ((field= *(ptr++)))
379   {
380     if (field->flags & GET_FIXED_FIELDS_FLAG)
381     {
382       field->flags&= ~GET_FIXED_FIELDS_FLAG;
383       field->flags|= FIELD_IN_PART_FUNC_FLAG;
384       if (likely(!result))
385       {
386         if (!is_sub_part && part_info->column_list)
387         {
388           List_iterator<const char> it(part_info->part_field_list);
389           const char *field_name;
390 
391           DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
392           inx= 0;
393           do
394           {
395             field_name= it++;
396             if (!my_strcasecmp(system_charset_info,
397                                field_name,
398                                field->field_name.str))
399               break;
400           } while (++inx < num_fields);
401           if (inx == num_fields)
402           {
403             /*
404               Should not occur since it should already been checked in either
405               add_column_list_values, handle_list_of_fields,
406               check_partition_info etc.
407             */
408             DBUG_ASSERT(0);
409             my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
410             result= TRUE;
411             continue;
412           }
413         }
414         else
415           inx= i;
416         field_array[inx]= field;
417         i++;
418 
419         /*
420           We check that the fields are proper. It is required for each
421           field in a partition function to:
422           1) Not be a BLOB of any type
423             A BLOB takes too long time to evaluate so we don't want it for
424             performance reasons.
425         */
426 
427         if (unlikely(field->flags & BLOB_FLAG))
428         {
429           my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
430           result= TRUE;
431         }
432       }
433     }
434   }
435   field_array[num_fields]= 0;
436   if (!is_sub_part)
437   {
438     part_info->part_field_array= field_array;
439     part_info->num_part_fields= num_fields;
440   }
441   else
442   {
443     part_info->subpart_field_array= field_array;
444     part_info->num_subpart_fields= num_fields;
445   }
446   DBUG_RETURN(result);
447 }
448 
449 
450 
451 /*
452   Create a field array including all fields of both the partitioning and the
453   subpartitioning functions.
454 
455   SYNOPSIS
456     create_full_part_field_array()
457     thd                  Thread handle
458     table                TABLE object for which partition fields are set-up
459     part_info            Reference to partitioning data structure
460 
461   RETURN VALUE
462     TRUE                 Memory allocation of field array failed
463     FALSE                Ok
464 
465   DESCRIPTION
466     If there is no subpartitioning then the same array is used as for the
467     partitioning. Otherwise a new array is built up using the flag
468     FIELD_IN_PART_FUNC in the field object.
469     This function is called from fix_partition_func
470 */
471 
create_full_part_field_array(THD * thd,TABLE * table,partition_info * part_info)472 static bool create_full_part_field_array(THD *thd, TABLE *table,
473                                          partition_info *part_info)
474 {
475   bool result= FALSE;
476   Field **ptr;
477   my_bitmap_map *bitmap_buf;
478   DBUG_ENTER("create_full_part_field_array");
479 
480   if (!part_info->is_sub_partitioned())
481   {
482     part_info->full_part_field_array= part_info->part_field_array;
483     part_info->num_full_part_fields= part_info->num_part_fields;
484   }
485   else
486   {
487     Field *field, **field_array;
488     uint num_part_fields=0, size_field_array;
489     ptr= table->field;
490     while ((field= *(ptr++)))
491     {
492       if (field->flags & FIELD_IN_PART_FUNC_FLAG)
493         num_part_fields++;
494     }
495     size_field_array= (num_part_fields+1)*sizeof(Field*);
496     field_array= (Field**) thd->calloc(size_field_array);
497     if (unlikely(!field_array))
498     {
499       result= TRUE;
500       goto end;
501     }
502     num_part_fields= 0;
503     ptr= table->field;
504     while ((field= *(ptr++)))
505     {
506       if (field->flags & FIELD_IN_PART_FUNC_FLAG)
507         field_array[num_part_fields++]= field;
508     }
509     field_array[num_part_fields]=0;
510     part_info->full_part_field_array= field_array;
511     part_info->num_full_part_fields= num_part_fields;
512   }
513 
514   /*
515     Initialize the set of all fields used in partition and subpartition
516     expression. Required for testing of partition fields in write_set
517     when updating. We need to set all bits in read_set because the row
518     may need to be inserted in a different [sub]partition.
519   */
520   if (!(bitmap_buf= (my_bitmap_map*)
521         thd->alloc(bitmap_buffer_size(table->s->fields))))
522   {
523     result= TRUE;
524     goto end;
525   }
526   if (unlikely(my_bitmap_init(&part_info->full_part_field_set, bitmap_buf,
527                               table->s->fields, FALSE)))
528   {
529     result= TRUE;
530     goto end;
531   }
532   /*
533     full_part_field_array may be NULL if storage engine supports native
534     partitioning.
535   */
536   table->vcol_set= table->read_set= &part_info->full_part_field_set;
537   if ((ptr= part_info->full_part_field_array))
538     for (; *ptr; ptr++)
539     {
540       if ((*ptr)->vcol_info)
541         table->mark_virtual_col(*ptr);
542       else
543         bitmap_fast_test_and_set(table->read_set, (*ptr)->field_index);
544     }
545   table->default_column_bitmaps();
546 
547 end:
548   DBUG_RETURN(result);
549 }
550 
551 
552 /*
553 
554   Clear flag GET_FIXED_FIELDS_FLAG in all fields of a key previously set by
555   set_indicator_in_key_fields (always used in pairs).
556 
557   SYNOPSIS
558     clear_indicator_in_key_fields()
559     key_info                  Reference to find the key fields
560 
561   RETURN VALUE
562     NONE
563 
564   DESCRIPTION
565     These support routines is used to set/reset an indicator of all fields
566     in a certain key. It is used in conjunction with another support routine
567     that traverse all fields in the PF to find if all or some fields in the
568     PF is part of the key. This is used to check primary keys and unique
569     keys involve all fields in PF (unless supported) and to derive the
570     key_map's used to quickly decide whether the index can be used to
571     derive which partitions are needed to scan.
572 */
573 
clear_indicator_in_key_fields(KEY * key_info)574 static void clear_indicator_in_key_fields(KEY *key_info)
575 {
576   KEY_PART_INFO *key_part;
577   uint key_parts= key_info->user_defined_key_parts, i;
578   for (i= 0, key_part=key_info->key_part; i < key_parts; i++, key_part++)
579     key_part->field->flags&= (~GET_FIXED_FIELDS_FLAG);
580 }
581 
582 
583 /*
584   Set flag GET_FIXED_FIELDS_FLAG in all fields of a key.
585 
586   SYNOPSIS
587     set_indicator_in_key_fields
588     key_info                  Reference to find the key fields
589 
590   RETURN VALUE
591     NONE
592 */
593 
set_indicator_in_key_fields(KEY * key_info)594 static void set_indicator_in_key_fields(KEY *key_info)
595 {
596   KEY_PART_INFO *key_part;
597   uint key_parts= key_info->user_defined_key_parts, i;
598   for (i= 0, key_part=key_info->key_part; i < key_parts; i++, key_part++)
599     key_part->field->flags|= GET_FIXED_FIELDS_FLAG;
600 }
601 
602 
603 /*
604   Check if all or some fields in partition field array is part of a key
605   previously used to tag key fields.
606 
607   SYNOPSIS
608     check_fields_in_PF()
609     ptr                  Partition field array
610     out:all_fields       Is all fields of partition field array used in key
611     out:some_fields      Is some fields of partition field array used in key
612 
613   RETURN VALUE
614     all_fields, some_fields
615 */
616 
check_fields_in_PF(Field ** ptr,bool * all_fields,bool * some_fields)617 static void check_fields_in_PF(Field **ptr, bool *all_fields,
618                                bool *some_fields)
619 {
620   DBUG_ENTER("check_fields_in_PF");
621 
622   *all_fields= TRUE;
623   *some_fields= FALSE;
624   if ((!ptr) || !(*ptr))
625   {
626     *all_fields= FALSE;
627     DBUG_VOID_RETURN;
628   }
629   do
630   {
631   /* Check if the field of the PF is part of the current key investigated */
632     if ((*ptr)->flags & GET_FIXED_FIELDS_FLAG)
633       *some_fields= TRUE;
634     else
635       *all_fields= FALSE;
636   } while (*(++ptr));
637   DBUG_VOID_RETURN;
638 }
639 
640 
641 /*
642   Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
643   This routine is used for error handling purposes.
644 
645   SYNOPSIS
646     clear_field_flag()
647     table                TABLE object for which partition fields are set-up
648 
649   RETURN VALUE
650     NONE
651 */
652 
clear_field_flag(TABLE * table)653 static void clear_field_flag(TABLE *table)
654 {
655   Field **ptr;
656   DBUG_ENTER("clear_field_flag");
657 
658   for (ptr= table->field; *ptr; ptr++)
659     (*ptr)->flags&= (~GET_FIXED_FIELDS_FLAG);
660   DBUG_VOID_RETURN;
661 }
662 
663 
664 /*
665   find_field_in_table_sef finds the field given its name. All fields get
666   GET_FIXED_FIELDS_FLAG set.
667 
668   SYNOPSIS
669     handle_list_of_fields()
670     it                   A list of field names for the partition function
671     table                TABLE object for which partition fields are set-up
672     part_info            Reference to partitioning data structure
673     sub_part             Is the table subpartitioned as well
674 
675   RETURN VALUE
676     TRUE                 Fields in list of fields not part of table
677     FALSE                All fields ok and array created
678 
679   DESCRIPTION
680     This routine sets-up the partition field array for KEY partitioning, it
681     also verifies that all fields in the list of fields is actually a part of
682     the table.
683 
684 */
685 
686 
handle_list_of_fields(THD * thd,List_iterator<const char> it,TABLE * table,partition_info * part_info,bool is_sub_part)687 static bool handle_list_of_fields(THD *thd, List_iterator<const char> it,
688                                   TABLE *table,
689                                   partition_info *part_info,
690                                   bool is_sub_part)
691 {
692   Field *field;
693   bool result;
694   const char *field_name;
695   bool is_list_empty= TRUE;
696   DBUG_ENTER("handle_list_of_fields");
697 
698   while ((field_name= it++))
699   {
700     is_list_empty= FALSE;
701     field= find_field_in_table_sef(table, field_name);
702     if (likely(field != 0))
703       field->flags|= GET_FIXED_FIELDS_FLAG;
704     else
705     {
706       my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
707       clear_field_flag(table);
708       result= TRUE;
709       goto end;
710     }
711   }
712   if (is_list_empty && part_info->part_type == HASH_PARTITION)
713   {
714     uint primary_key= table->s->primary_key;
715     if (primary_key != MAX_KEY)
716     {
717       uint num_key_parts= table->key_info[primary_key].user_defined_key_parts, i;
718       /*
719         In the case of an empty list we use primary key as partition key.
720       */
721       for (i= 0; i < num_key_parts; i++)
722       {
723         Field *field= table->key_info[primary_key].key_part[i].field;
724         field->flags|= GET_FIXED_FIELDS_FLAG;
725       }
726     }
727     else
728     {
729       if (table->s->db_type()->partition_flags &&
730           (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
731           (table->s->db_type()->partition_flags() & HA_CAN_PARTITION))
732       {
733         /*
734           This engine can handle automatic partitioning and there is no
735           primary key. In this case we rely on that the engine handles
736           partitioning based on a hidden key. Thus we allocate no
737           array for partitioning fields.
738         */
739         DBUG_RETURN(FALSE);
740       }
741       else
742       {
743         my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
744         DBUG_RETURN(TRUE);
745       }
746     }
747   }
748   result= set_up_field_array(thd, table, is_sub_part);
749 end:
750   DBUG_RETURN(result);
751 }
752 
753 
754 /*
755   Support function to check if all VALUES * (expression) is of the
756   right sign (no signed constants when unsigned partition function)
757 
758   SYNOPSIS
759     check_signed_flag()
760     part_info                Partition info object
761 
762   RETURN VALUES
763     0                        No errors due to sign errors
764     >0                       Sign error
765 */
766 
check_signed_flag(partition_info * part_info)767 int check_signed_flag(partition_info *part_info)
768 {
769   int error= 0;
770   uint i= 0;
771   if (part_info->part_type != HASH_PARTITION &&
772       part_info->part_expr->unsigned_flag)
773   {
774     List_iterator<partition_element> part_it(part_info->partitions);
775     do
776     {
777       partition_element *part_elem= part_it++;
778 
779       if (part_elem->signed_flag)
780       {
781         my_error(ER_PARTITION_CONST_DOMAIN_ERROR, MYF(0));
782         error= ER_PARTITION_CONST_DOMAIN_ERROR;
783         break;
784       }
785     } while (++i < part_info->num_parts);
786   }
787   return error;
788 }
789 
790 /*
791   init_lex_with_single_table and end_lex_with_single_table
792   are now in sql_lex.cc
793 */
794 
795 /*
796   The function uses a new feature in fix_fields where the flag
797   GET_FIXED_FIELDS_FLAG is set for all fields in the item tree.
798   This field must always be reset before returning from the function
799   since it is used for other purposes as well.
800 
801   SYNOPSIS
802     fix_fields_part_func()
803     thd                  The thread object
804     func_expr            The item tree reference of the partition function
805     table                The table object
806     part_info            Reference to partitioning data structure
807     is_sub_part          Is the table subpartitioned as well
808     is_create_table_ind  Indicator of whether openfrm was called as part of
809                          CREATE or ALTER TABLE
810 
811   RETURN VALUE
812     TRUE                 An error occurred, something was wrong with the
813                          partition function.
814     FALSE                Ok, a partition field array was created
815 
816   DESCRIPTION
817     This function is used to build an array of partition fields for the
818     partitioning function and subpartitioning function. The partitioning
819     function is an item tree that must reference at least one field in the
820     table. This is checked first in the parser that the function doesn't
821     contain non-cacheable parts (like a random function) and by checking
822     here that the function isn't a constant function.
823 
824     Calculate the number of fields in the partition function.
825     Use it allocate memory for array of Field pointers.
826     Initialise array of field pointers. Use information set when
827     calling fix_fields and reset it immediately after.
828     The get_fields_in_item_tree activates setting of bit in flags
829     on the field object.
830 */
831 
fix_fields_part_func(THD * thd,Item * func_expr,TABLE * table,bool is_sub_part,bool is_create_table_ind)832 static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
833                                  bool is_sub_part, bool is_create_table_ind)
834 {
835   partition_info *part_info= table->part_info;
836   bool result= TRUE;
837   int error;
838   LEX *old_lex= thd->lex;
839   LEX lex;
840   DBUG_ENTER("fix_fields_part_func");
841 
842   if (init_lex_with_single_table(thd, table, &lex))
843     goto end;
844   table->get_fields_in_item_tree= true;
845 
846   func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context);
847   thd->where= "partition function";
848   /*
849     In execution we must avoid the use of thd->change_item_tree since
850     we might release memory before statement is completed. We do this
851     by temporarily setting the stmt_arena->mem_root to be the mem_root
852     of the table object, this also ensures that any memory allocated
853     during fix_fields will not be released at end of execution of this
854     statement. Thus the item tree will remain valid also in subsequent
855     executions of this table object. We do however not at the moment
856     support allocations during execution of val_int so any item class
857     that does this during val_int must be disallowed as partition
858     function.
859     SEE Bug #21658
860 
861     This is a tricky call to prepare for since it can have a large number
862     of interesting side effects, both desirable and undesirable.
863   */
864   {
865     const bool save_agg_field= thd->lex->current_select->non_agg_field_used();
866     const bool save_agg_func=  thd->lex->current_select->agg_func_used();
867     const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func;
868     thd->lex->allow_sum_func.clear_all();
869 
870     if (likely(!(error= func_expr->fix_fields_if_needed(thd, (Item**)&func_expr))))
871       func_expr->walk(&Item::post_fix_fields_part_expr_processor, 0, NULL);
872 
873     /*
874       Restore agg_field/agg_func  and allow_sum_func,
875       fix_fields should not affect mysql_select later, see Bug#46923.
876     */
877     thd->lex->current_select->set_non_agg_field_used(save_agg_field);
878     thd->lex->current_select->set_agg_func_used(save_agg_func);
879     thd->lex->allow_sum_func= saved_allow_sum_func;
880   }
881   if (unlikely(error))
882   {
883     DBUG_PRINT("info", ("Field in partition function not part of table"));
884     clear_field_flag(table);
885     goto end;
886   }
887   if (unlikely(func_expr->const_item()))
888   {
889     my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
890     clear_field_flag(table);
891     goto end;
892   }
893 
894   /*
895     We don't allow creating partitions with expressions with non matching
896     arguments as a (sub)partitioning function,
897     but we want to allow such expressions when opening existing tables for
898     easier maintenance. This exception should be deprecated at some point
899     in future so that we always throw an error.
900   */
901   if (func_expr->walk(&Item::check_valid_arguments_processor, 0, NULL))
902   {
903     if (is_create_table_ind)
904     {
905       my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
906       goto end;
907     }
908     else
909       push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
910                    ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
911                    ER_THD(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
912   }
913 
914   if (unlikely((!is_sub_part) && (error= check_signed_flag(part_info))))
915     goto end;
916   result= set_up_field_array(thd, table, is_sub_part);
917 end:
918   end_lex_with_single_table(thd, table, old_lex);
919   func_expr->walk(&Item::change_context_processor, 0, 0);
920   DBUG_RETURN(result);
921 }
922 
923 
924 /*
925   Check that the primary key contains all partition fields if defined
926 
927   SYNOPSIS
928     check_primary_key()
929     table                TABLE object for which partition fields are set-up
930 
931   RETURN VALUES
932     TRUE                 Not all fields in partitioning function was part
933                          of primary key
934     FALSE                Ok, all fields of partitioning function were part
935                          of primary key
936 
937   DESCRIPTION
938     This function verifies that if there is a primary key that it contains
939     all the fields of the partition function.
940     This is a temporary limitation that will hopefully be removed after a
941     while.
942 */
943 
check_primary_key(TABLE * table)944 static bool check_primary_key(TABLE *table)
945 {
946   uint primary_key= table->s->primary_key;
947   bool all_fields, some_fields;
948   bool result= FALSE;
949   DBUG_ENTER("check_primary_key");
950 
951   if (primary_key < MAX_KEY)
952   {
953     set_indicator_in_key_fields(table->key_info+primary_key);
954     check_fields_in_PF(table->part_info->full_part_field_array,
955                         &all_fields, &some_fields);
956     clear_indicator_in_key_fields(table->key_info+primary_key);
957     if (unlikely(!all_fields))
958     {
959       my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF,MYF(0),"PRIMARY KEY");
960       result= TRUE;
961     }
962   }
963   DBUG_RETURN(result);
964 }
965 
966 
967 /*
968   Check that unique keys contains all partition fields
969 
970   SYNOPSIS
971     check_unique_keys()
972     table                TABLE object for which partition fields are set-up
973 
974   RETURN VALUES
975     TRUE                 Not all fields in partitioning function was part
976                          of all unique keys
977     FALSE                Ok, all fields of partitioning function were part
978                          of unique keys
979 
980   DESCRIPTION
981     This function verifies that if there is a unique index that it contains
982     all the fields of the partition function.
983     This is a temporary limitation that will hopefully be removed after a
984     while.
985 */
986 
check_unique_keys(TABLE * table)987 static bool check_unique_keys(TABLE *table)
988 {
989   bool all_fields, some_fields;
990   bool result= FALSE;
991   uint keys= table->s->keys;
992   uint i;
993   DBUG_ENTER("check_unique_keys");
994 
995   for (i= 0; i < keys; i++)
996   {
997     if (table->key_info[i].flags & HA_NOSAME) //Unique index
998     {
999       set_indicator_in_key_fields(table->key_info+i);
1000       check_fields_in_PF(table->part_info->full_part_field_array,
1001                          &all_fields, &some_fields);
1002       clear_indicator_in_key_fields(table->key_info+i);
1003       if (unlikely(!all_fields))
1004       {
1005         my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF,MYF(0),"UNIQUE INDEX");
1006         result= TRUE;
1007         break;
1008       }
1009     }
1010   }
1011   DBUG_RETURN(result);
1012 }
1013 
1014 
1015 /*
1016   An important optimisation is whether a range on a field can select a subset
1017   of the partitions.
1018   A prerequisite for this to happen is that the PF is a growing function OR
1019   a shrinking function.
1020   This can never happen for a multi-dimensional PF. Thus this can only happen
1021   with PF with at most one field involved in the PF.
1022   The idea is that if the function is a growing function and you know that
1023   the field of the PF is 4 <= A <= 6 then we can convert this to a range
1024   in the PF instead by setting the range to PF(4) <= PF(A) <= PF(6). In the
1025   case of RANGE PARTITIONING and LIST PARTITIONING this can be used to
1026   calculate a set of partitions rather than scanning all of them.
1027   Thus the following prerequisites are there to check if sets of partitions
1028   can be found.
1029   1) Only possible for RANGE and LIST partitioning (not for subpartitioning)
1030   2) Only possible if PF only contains 1 field
1031   3) Possible if PF is a growing function of the field
1032   4) Possible if PF is a shrinking function of the field
1033   OBSERVATION:
1034   1) IF f1(A) is a growing function AND f2(A) is a growing function THEN
1035      f1(A) + f2(A) is a growing function
1036      f1(A) * f2(A) is a growing function if f1(A) >= 0 and f2(A) >= 0
1037   2) IF f1(A) is a growing function and f2(A) is a shrinking function THEN
1038      f1(A) / f2(A) is a growing function if f1(A) >= 0 and f2(A) > 0
1039   3) IF A is a growing function then a function f(A) that removes the
1040      least significant portion of A is a growing function
1041      E.g. DATE(datetime) is a growing function
1042      MONTH(datetime) is not a growing/shrinking function
1043   4) IF f1(A) is a growing function and f2(A) is a growing function THEN
1044      f1(f2(A)) and f2(f1(A)) are also growing functions
1045   5) IF f1(A) is a shrinking function and f2(A) is a growing function THEN
1046      f1(f2(A)) is a shrinking function and f2(f1(A)) is a shrinking function
1047   6) f1(A) = A is a growing function
1048   7) f1(A) = A*a + b (where a and b are constants) is a growing function
1049 
1050   By analysing the item tree of the PF we can use these deducements and
1051   derive whether the PF is a growing function or a shrinking function or
1052   neither of it.
1053 
1054   If the PF is range capable then a flag is set on the table object
1055   indicating this to notify that we can use also ranges on the field
1056   of the PF to deduce a set of partitions if the fields of the PF were
1057   not all fully bound.
1058 
1059   SYNOPSIS
1060     check_range_capable_PF()
1061     table                TABLE object for which partition fields are set-up
1062 
1063   DESCRIPTION
1064     Support for this is not implemented yet.
1065 */
1066 
check_range_capable_PF(TABLE * table)1067 void check_range_capable_PF(TABLE *table)
1068 {
1069   DBUG_ENTER("check_range_capable_PF");
1070 
1071   DBUG_VOID_RETURN;
1072 }
1073 
1074 
1075 /**
1076   Set up partition bitmaps
1077 
1078     @param thd           Thread object
1079     @param part_info     Reference to partitioning data structure
1080 
1081   @return Operation status
1082     @retval TRUE         Memory allocation failure
1083     @retval FALSE        Success
1084 
1085     Allocate memory for bitmaps of the partitioned table
1086     and initialise it.
1087 */
1088 
set_up_partition_bitmaps(THD * thd,partition_info * part_info)1089 static bool set_up_partition_bitmaps(THD *thd, partition_info *part_info)
1090 {
1091   uint32 *bitmap_buf;
1092   uint bitmap_bits= part_info->num_subparts?
1093                      (part_info->num_subparts* part_info->num_parts):
1094                       part_info->num_parts;
1095   uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
1096   DBUG_ENTER("set_up_partition_bitmaps");
1097 
1098   DBUG_ASSERT(!part_info->bitmaps_are_initialized);
1099 
1100   /* Allocate for both read and lock_partitions */
1101   if (unlikely(!(bitmap_buf=
1102                  (uint32*) alloc_root(&part_info->table->mem_root,
1103                                       bitmap_bytes * 2))))
1104     DBUG_RETURN(TRUE);
1105 
1106   my_bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits, FALSE);
1107   /* Use the second half of the allocated buffer for lock_partitions */
1108   my_bitmap_init(&part_info->lock_partitions, bitmap_buf + (bitmap_bytes / 4),
1109               bitmap_bits, FALSE);
1110   part_info->bitmaps_are_initialized= TRUE;
1111   part_info->set_partition_bitmaps(NULL);
1112   DBUG_RETURN(FALSE);
1113 }
1114 
1115 
1116 /*
1117   Set up partition key maps
1118 
1119   SYNOPSIS
1120     set_up_partition_key_maps()
1121     table                TABLE object for which partition fields are set-up
1122     part_info            Reference to partitioning data structure
1123 
1124   RETURN VALUES
1125     None
1126 
1127   DESCRIPTION
1128     This function sets up a couple of key maps to be able to quickly check
1129     if an index ever can be used to deduce the partition fields or even
1130     a part of the fields of the  partition function.
1131     We set up the following key_map's.
1132     PF = Partition Function
1133     1) All fields of the PF is set even by equal on the first fields in the
1134        key
1135     2) All fields of the PF is set if all fields of the key is set
1136     3) At least one field in the PF is set if all fields is set
1137     4) At least one field in the PF is part of the key
1138 */
1139 
set_up_partition_key_maps(TABLE * table,partition_info * part_info)1140 static void set_up_partition_key_maps(TABLE *table,
1141                                       partition_info *part_info)
1142 {
1143   uint keys= table->s->keys;
1144   uint i;
1145   bool all_fields, some_fields;
1146   DBUG_ENTER("set_up_partition_key_maps");
1147 
1148   part_info->all_fields_in_PF.clear_all();
1149   part_info->all_fields_in_PPF.clear_all();
1150   part_info->all_fields_in_SPF.clear_all();
1151   part_info->some_fields_in_PF.clear_all();
1152   for (i= 0; i < keys; i++)
1153   {
1154     set_indicator_in_key_fields(table->key_info+i);
1155     check_fields_in_PF(part_info->full_part_field_array,
1156                        &all_fields, &some_fields);
1157     if (all_fields)
1158       part_info->all_fields_in_PF.set_bit(i);
1159     if (some_fields)
1160       part_info->some_fields_in_PF.set_bit(i);
1161     if (part_info->is_sub_partitioned())
1162     {
1163       check_fields_in_PF(part_info->part_field_array,
1164                          &all_fields, &some_fields);
1165       if (all_fields)
1166         part_info->all_fields_in_PPF.set_bit(i);
1167       check_fields_in_PF(part_info->subpart_field_array,
1168                          &all_fields, &some_fields);
1169       if (all_fields)
1170         part_info->all_fields_in_SPF.set_bit(i);
1171     }
1172     clear_indicator_in_key_fields(table->key_info+i);
1173   }
1174   DBUG_VOID_RETURN;
1175 }
1176 
check_no_constants(THD *,partition_info *)1177 static bool check_no_constants(THD *, partition_info*)
1178 {
1179   return FALSE;
1180 }
1181 
1182 /*
1183   Support routines for check_list_constants used by qsort to sort the
1184   constant list expressions. One routine for integers and one for
1185   column lists.
1186 
1187   SYNOPSIS
1188     list_part_cmp()
1189       a                First list constant to compare with
1190       b                Second list constant to compare with
1191 
1192   RETURN VALUE
1193     +1                 a > b
1194     0                  a  == b
1195     -1                 a < b
1196 */
1197 
1198 extern "C"
partition_info_list_part_cmp(const void * a,const void * b)1199 int partition_info_list_part_cmp(const void* a, const void* b)
1200 {
1201   longlong a1= ((LIST_PART_ENTRY*)a)->list_value;
1202   longlong b1= ((LIST_PART_ENTRY*)b)->list_value;
1203   if (a1 < b1)
1204     return -1;
1205   else if (a1 > b1)
1206     return +1;
1207   else
1208     return 0;
1209 }
1210 
1211 
1212 /*
1213   Compare two lists of column values in RANGE/LIST partitioning
1214   SYNOPSIS
1215     partition_info_compare_column_values()
1216     first                    First column list argument
1217     second                   Second column list argument
1218   RETURN VALUES
1219     0                        Equal
1220     -1                       First argument is smaller
1221     +1                       First argument is larger
1222 */
1223 
1224 extern "C"
partition_info_compare_column_values(const void * first_arg,const void * second_arg)1225 int partition_info_compare_column_values(const void *first_arg,
1226                                          const void *second_arg)
1227 {
1228   const part_column_list_val *first= (part_column_list_val*)first_arg;
1229   const part_column_list_val *second= (part_column_list_val*)second_arg;
1230   partition_info *part_info= first->part_info;
1231   Field **field;
1232 
1233   for (field= part_info->part_field_array; *field;
1234        field++, first++, second++)
1235   {
1236     if (first->max_value || second->max_value)
1237     {
1238       if (first->max_value && second->max_value)
1239         return 0;
1240       if (second->max_value)
1241         return -1;
1242       else
1243         return +1;
1244     }
1245     if (first->null_value || second->null_value)
1246     {
1247       if (first->null_value && second->null_value)
1248         continue;
1249       if (second->null_value)
1250         return +1;
1251       else
1252         return -1;
1253     }
1254     int res= (*field)->cmp((const uchar*)first->column_value,
1255                            (const uchar*)second->column_value);
1256     if (res)
1257       return res;
1258   }
1259   return 0;
1260 }
1261 
1262 
1263 /*
1264   This routine allocates an array for all range constants to achieve a fast
1265   check what partition a certain value belongs to. At the same time it does
1266   also check that the range constants are defined in increasing order and
1267   that the expressions are constant integer expressions.
1268 
1269   SYNOPSIS
1270     check_range_constants()
1271     thd                          Thread object
1272 
1273   RETURN VALUE
1274     TRUE                An error occurred during creation of range constants
1275     FALSE               Successful creation of range constant mapping
1276 
1277   DESCRIPTION
1278     This routine is called from check_partition_info to get a quick error
1279     before we came too far into the CREATE TABLE process. It is also called
1280     from fix_partition_func every time we open the .frm file. It is only
1281     called for RANGE PARTITIONed tables.
1282 */
1283 
check_range_constants(THD * thd,partition_info * part_info)1284 static bool check_range_constants(THD *thd, partition_info *part_info)
1285 {
1286   partition_element* part_def;
1287   bool first= TRUE;
1288   uint i;
1289   List_iterator<partition_element> it(part_info->partitions);
1290   bool result= TRUE;
1291   DBUG_ENTER("check_range_constants");
1292   DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u",
1293                        part_info->num_parts, part_info->column_list));
1294 
1295   if (part_info->column_list)
1296   {
1297     part_column_list_val *loc_range_col_array;
1298     part_column_list_val *UNINIT_VAR(current_largest_col_val);
1299     uint num_column_values= part_info->part_field_list.elements;
1300     uint size_entries= sizeof(part_column_list_val) * num_column_values;
1301     part_info->range_col_array= (part_column_list_val*)
1302       thd->calloc(part_info->num_parts * size_entries);
1303     if (unlikely(part_info->range_col_array == NULL))
1304       goto end;
1305 
1306     loc_range_col_array= part_info->range_col_array;
1307     i= 0;
1308     do
1309     {
1310       part_def= it++;
1311       {
1312         List_iterator<part_elem_value> list_val_it(part_def->list_val_list);
1313         part_elem_value *range_val= list_val_it++;
1314         part_column_list_val *col_val= range_val->col_val_array;
1315 
1316         if (part_info->fix_column_value_functions(thd, range_val, i))
1317           goto end;
1318         memcpy(loc_range_col_array, (const void*)col_val, size_entries);
1319         loc_range_col_array+= num_column_values;
1320         if (!first)
1321         {
1322           if (partition_info_compare_column_values(current_largest_col_val,
1323                                                     col_val) >= 0)
1324             goto range_not_increasing_error;
1325         }
1326         current_largest_col_val= col_val;
1327       }
1328       first= FALSE;
1329     } while (++i < part_info->num_parts);
1330   }
1331   else
1332   {
1333     longlong UNINIT_VAR(current_largest);
1334     longlong part_range_value;
1335     bool signed_flag= !part_info->part_expr->unsigned_flag;
1336 
1337     part_info->range_int_array= (longlong*)
1338       thd->alloc(part_info->num_parts * sizeof(longlong));
1339     if (unlikely(part_info->range_int_array == NULL))
1340       goto end;
1341 
1342     i= 0;
1343     do
1344     {
1345       part_def= it++;
1346       if ((i != part_info->num_parts - 1) || !part_info->defined_max_value)
1347       {
1348         part_range_value= part_def->range_value;
1349         if (!signed_flag)
1350           part_range_value-= 0x8000000000000000ULL;
1351       }
1352       else
1353         part_range_value= LONGLONG_MAX;
1354 
1355       if (!first)
1356       {
1357         if (current_largest > part_range_value ||
1358             (current_largest == part_range_value &&
1359             (part_range_value < LONGLONG_MAX ||
1360              i != part_info->num_parts - 1 ||
1361              !part_info->defined_max_value)))
1362           goto range_not_increasing_error;
1363       }
1364       part_info->range_int_array[i]= part_range_value;
1365       current_largest= part_range_value;
1366       first= FALSE;
1367     } while (++i < part_info->num_parts);
1368   }
1369   result= FALSE;
1370 end:
1371   DBUG_RETURN(result);
1372 
1373 range_not_increasing_error:
1374   my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
1375   goto end;
1376 }
1377 
1378 
1379 /*
1380   This routine allocates an array for all list constants to achieve a fast
1381   check what partition a certain value belongs to. At the same time it does
1382   also check that there are no duplicates among the list constants and that
1383   that the list expressions are constant integer expressions.
1384 
1385   SYNOPSIS
1386     check_list_constants()
1387     thd                            Thread object
1388 
1389   RETURN VALUE
1390     TRUE                  An error occurred during creation of list constants
1391     FALSE                 Successful creation of list constant mapping
1392 
1393   DESCRIPTION
1394     This routine is called from check_partition_info to get a quick error
1395     before we came too far into the CREATE TABLE process. It is also called
1396     from fix_partition_func every time we open the .frm file. It is only
1397     called for LIST PARTITIONed tables.
1398 */
1399 
check_list_constants(THD * thd,partition_info * part_info)1400 static bool check_list_constants(THD *thd, partition_info *part_info)
1401 {
1402   uint i, size_entries, num_column_values;
1403   uint list_index= 0;
1404   part_elem_value *list_value;
1405   bool result= TRUE;
1406   longlong type_add, calc_value;
1407   void *curr_value;
1408   void *UNINIT_VAR(prev_value);
1409   partition_element* part_def;
1410   bool found_null= FALSE;
1411   qsort_cmp compare_func;
1412   void *ptr;
1413   List_iterator<partition_element> list_func_it(part_info->partitions);
1414   DBUG_ENTER("check_list_constants");
1415 
1416   DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
1417 
1418   part_info->num_list_values= 0;
1419   /*
1420     We begin by calculating the number of list values that have been
1421     defined in the first step.
1422 
1423     We use this number to allocate a properly sized array of structs
1424     to keep the partition id and the value to use in that partition.
1425     In the second traversal we assign them values in the struct array.
1426 
1427     Finally we sort the array of structs in order of values to enable
1428     a quick binary search for the proper value to discover the
1429     partition id.
1430     After sorting the array we check that there are no duplicates in the
1431     list.
1432   */
1433 
1434   i= 0;
1435   do
1436   {
1437     part_def= list_func_it++;
1438     if (part_def->has_null_value)
1439     {
1440       if (found_null)
1441       {
1442         my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
1443         goto end;
1444       }
1445       part_info->has_null_value= TRUE;
1446       part_info->has_null_part_id= i;
1447       found_null= TRUE;
1448     }
1449     part_info->num_list_values+= part_def->list_val_list.elements;
1450   } while (++i < part_info->num_parts);
1451   list_func_it.rewind();
1452   num_column_values= part_info->part_field_list.elements;
1453   size_entries= part_info->column_list ?
1454         (num_column_values * sizeof(part_column_list_val)) :
1455         sizeof(LIST_PART_ENTRY);
1456   if (!(ptr= thd->calloc((part_info->num_list_values+1) * size_entries)))
1457     goto end;
1458   if (part_info->column_list)
1459   {
1460     part_column_list_val *loc_list_col_array;
1461     loc_list_col_array= (part_column_list_val*)ptr;
1462     part_info->list_col_array= (part_column_list_val*)ptr;
1463     compare_func= partition_info_compare_column_values;
1464     i= 0;
1465     do
1466     {
1467       part_def= list_func_it++;
1468       if (part_def->max_value)
1469       {
1470         // DEFAULT is not a real value so let's exclude it from sorting.
1471         DBUG_ASSERT(part_info->num_list_values);
1472         part_info->num_list_values--;
1473         continue;
1474       }
1475       List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
1476       while ((list_value= list_val_it2++))
1477       {
1478         part_column_list_val *col_val= list_value->col_val_array;
1479         if (part_info->fix_column_value_functions(thd, list_value, i))
1480           DBUG_RETURN(result);
1481         memcpy(loc_list_col_array, (const void*)col_val, size_entries);
1482         loc_list_col_array+= num_column_values;
1483       }
1484     } while (++i < part_info->num_parts);
1485   }
1486   else
1487   {
1488     compare_func= partition_info_list_part_cmp;
1489     part_info->list_array= (LIST_PART_ENTRY*)ptr;
1490     i= 0;
1491     /*
1492       Fix to be able to reuse signed sort functions also for unsigned
1493       partition functions.
1494     */
1495     type_add= (longlong)(part_info->part_expr->unsigned_flag ?
1496                                        0x8000000000000000ULL :
1497                                        0ULL);
1498 
1499     do
1500     {
1501       part_def= list_func_it++;
1502       if (part_def->max_value)
1503       {
1504         // DEFAULT is not a real value so let's exclude it from sorting.
1505         DBUG_ASSERT(part_info->num_list_values);
1506         part_info->num_list_values--;
1507         continue;
1508       }
1509       List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
1510       while ((list_value= list_val_it2++))
1511       {
1512         calc_value= list_value->value - type_add;
1513         part_info->list_array[list_index].list_value= calc_value;
1514         part_info->list_array[list_index++].partition_id= i;
1515       }
1516     } while (++i < part_info->num_parts);
1517   }
1518   DBUG_ASSERT(part_info->fixed);
1519   if (part_info->num_list_values)
1520   {
1521     bool first= TRUE;
1522     /*
1523       list_array and list_col_array are unions, so this works for both
1524       variants of LIST partitioning.
1525     */
1526     my_qsort(part_info->list_array, part_info->num_list_values, size_entries,
1527              compare_func);
1528 
1529     i= 0;
1530     do
1531     {
1532       DBUG_ASSERT(i < part_info->num_list_values);
1533       curr_value= part_info->column_list
1534                   ? (void*)&part_info->list_col_array[num_column_values * i]
1535                   : (void*)&part_info->list_array[i];
1536       if (likely(first || compare_func(curr_value, prev_value)))
1537       {
1538         prev_value= curr_value;
1539         first= FALSE;
1540       }
1541       else
1542       {
1543         my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
1544         goto end;
1545       }
1546     } while (++i < part_info->num_list_values);
1547   }
1548   result= FALSE;
1549 end:
1550   DBUG_RETURN(result);
1551 }
1552 
1553 
1554 /* Set partition boundaries when rotating by INTERVAL */
check_vers_constants(THD * thd,partition_info * part_info)1555 static bool check_vers_constants(THD *thd, partition_info *part_info)
1556 {
1557   uint hist_parts= part_info->num_parts - 1;
1558   Vers_part_info *vers_info= part_info->vers_info;
1559   vers_info->hist_part= part_info->partitions.head();
1560   vers_info->now_part= part_info->partitions.elem(hist_parts);
1561 
1562   if (!vers_info->interval.is_set())
1563     return 0;
1564 
1565   part_info->range_int_array=
1566     (longlong*) thd->alloc(part_info->num_parts * sizeof(longlong));
1567 
1568   MYSQL_TIME ltime;
1569   List_iterator<partition_element> it(part_info->partitions);
1570   partition_element *el;
1571   my_tz_OFFSET0->gmt_sec_to_TIME(&ltime, vers_info->interval.start);
1572   while ((el= it++)->id < hist_parts)
1573   {
1574     if (date_add_interval(&ltime, vers_info->interval.type,
1575                           vers_info->interval.step))
1576       goto err;
1577     uint error= 0;
1578     part_info->range_int_array[el->id]= el->range_value=
1579       my_tz_OFFSET0->TIME_to_gmt_sec(&ltime, &error);
1580     if (error)
1581       goto err;
1582     if (vers_info->hist_part->range_value <= thd->query_start())
1583       vers_info->hist_part= el;
1584   }
1585   DBUG_ASSERT(el == vers_info->now_part);
1586   el->max_value= true;
1587   part_info->range_int_array[el->id]= el->range_value= LONGLONG_MAX;
1588   return 0;
1589 err:
1590   my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "TIMESTAMP", "INTERVAL");
1591   return 1;
1592 }
1593 
1594 
1595 /*
1596   Set up function pointers for partition function
1597 
1598   SYNOPSIS
1599     set_up_partition_func_pointers()
1600     part_info            Reference to partitioning data structure
1601 
1602   RETURN VALUE
1603     NONE
1604 
1605   DESCRIPTION
1606     Set-up all function pointers for calculation of partition id,
1607     subpartition id and the upper part in subpartitioning. This is to speed up
1608     execution of get_partition_id which is executed once every record to be
1609     written and deleted and twice for updates.
1610 */
1611 
set_up_partition_func_pointers(partition_info * part_info)1612 static void set_up_partition_func_pointers(partition_info *part_info)
1613 {
1614   DBUG_ENTER("set_up_partition_func_pointers");
1615 
1616   if (part_info->is_sub_partitioned())
1617   {
1618     part_info->get_partition_id= get_partition_id_with_sub;
1619     if (part_info->part_type == RANGE_PARTITION)
1620     {
1621       if (part_info->column_list)
1622         part_info->get_part_partition_id= get_partition_id_range_col;
1623       else
1624         part_info->get_part_partition_id= get_partition_id_range;
1625       if (part_info->list_of_subpart_fields)
1626       {
1627         if (part_info->linear_hash_ind)
1628           part_info->get_subpartition_id= get_partition_id_linear_key_sub;
1629         else
1630           part_info->get_subpartition_id= get_partition_id_key_sub;
1631       }
1632       else
1633       {
1634         if (part_info->linear_hash_ind)
1635           part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
1636         else
1637           part_info->get_subpartition_id= get_partition_id_hash_sub;
1638       }
1639     }
1640     else if (part_info->part_type == VERSIONING_PARTITION)
1641     {
1642       part_info->get_part_partition_id= vers_get_partition_id;
1643       if (part_info->list_of_subpart_fields)
1644       {
1645         if (part_info->linear_hash_ind)
1646           part_info->get_subpartition_id= get_partition_id_linear_key_sub;
1647         else
1648           part_info->get_subpartition_id= get_partition_id_key_sub;
1649       }
1650       else
1651       {
1652         if (part_info->linear_hash_ind)
1653           part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
1654         else
1655           part_info->get_subpartition_id= get_partition_id_hash_sub;
1656       }
1657     }
1658     else /* LIST Partitioning */
1659     {
1660       if (part_info->column_list)
1661         part_info->get_part_partition_id= get_partition_id_list_col;
1662       else
1663         part_info->get_part_partition_id= get_partition_id_list;
1664       if (part_info->list_of_subpart_fields)
1665       {
1666         if (part_info->linear_hash_ind)
1667           part_info->get_subpartition_id= get_partition_id_linear_key_sub;
1668         else
1669           part_info->get_subpartition_id= get_partition_id_key_sub;
1670       }
1671       else
1672       {
1673         if (part_info->linear_hash_ind)
1674           part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
1675         else
1676           part_info->get_subpartition_id= get_partition_id_hash_sub;
1677       }
1678     }
1679   }
1680   else /* No subpartitioning */
1681   {
1682     part_info->get_part_partition_id= NULL;
1683     part_info->get_subpartition_id= NULL;
1684     if (part_info->part_type == RANGE_PARTITION)
1685     {
1686       if (part_info->column_list)
1687         part_info->get_partition_id= get_partition_id_range_col;
1688       else
1689         part_info->get_partition_id= get_partition_id_range;
1690     }
1691     else if (part_info->part_type == LIST_PARTITION)
1692     {
1693       if (part_info->column_list)
1694         part_info->get_partition_id= get_partition_id_list_col;
1695       else
1696         part_info->get_partition_id= get_partition_id_list;
1697     }
1698     else if (part_info->part_type == VERSIONING_PARTITION)
1699     {
1700       part_info->get_partition_id= vers_get_partition_id;
1701     }
1702     else /* HASH partitioning */
1703     {
1704       if (part_info->list_of_part_fields)
1705       {
1706         if (part_info->linear_hash_ind)
1707           part_info->get_partition_id= get_partition_id_linear_key_nosub;
1708         else
1709           part_info->get_partition_id= get_partition_id_key_nosub;
1710       }
1711       else
1712       {
1713         if (part_info->linear_hash_ind)
1714           part_info->get_partition_id= get_partition_id_linear_hash_nosub;
1715         else
1716           part_info->get_partition_id= get_partition_id_hash_nosub;
1717       }
1718     }
1719   }
1720   /*
1721     We need special functions to handle character sets since they require copy
1722     of field pointers and restore afterwards. For subpartitioned tables we do
1723     the copy and restore individually on the part and subpart parts. For non-
1724     subpartitioned tables we use the same functions as used for the parts part
1725     of subpartioning.
1726     Thus for subpartitioned tables the get_partition_id is always
1727     get_partition_id_with_sub, even when character sets exists.
1728   */
1729   if (part_info->part_charset_field_array)
1730   {
1731     if (part_info->is_sub_partitioned())
1732     {
1733       DBUG_ASSERT(part_info->get_part_partition_id);
1734       if (!part_info->column_list)
1735       {
1736         part_info->get_part_partition_id_charset=
1737           part_info->get_part_partition_id;
1738         part_info->get_part_partition_id= get_part_id_charset_func_part;
1739       }
1740     }
1741     else
1742     {
1743       DBUG_ASSERT(part_info->get_partition_id);
1744       if (!part_info->column_list)
1745       {
1746         part_info->get_part_partition_id_charset= part_info->get_partition_id;
1747         part_info->get_part_partition_id= get_part_id_charset_func_part;
1748       }
1749     }
1750   }
1751   if (part_info->subpart_charset_field_array)
1752   {
1753     DBUG_ASSERT(part_info->get_subpartition_id);
1754     part_info->get_subpartition_id_charset=
1755           part_info->get_subpartition_id;
1756     part_info->get_subpartition_id= get_part_id_charset_func_subpart;
1757   }
1758   if (part_info->part_type == RANGE_PARTITION)
1759     part_info->check_constants= check_range_constants;
1760   else if (part_info->part_type == LIST_PARTITION)
1761     part_info->check_constants= check_list_constants;
1762   else if (part_info->part_type == VERSIONING_PARTITION)
1763     part_info->check_constants= check_vers_constants;
1764   else
1765     part_info->check_constants= check_no_constants;
1766   DBUG_VOID_RETURN;
1767 }
1768 
1769 
1770 /*
1771   For linear hashing we need a mask which is on the form 2**n - 1 where
1772   2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
1773 
1774   SYNOPSIS
1775     set_linear_hash_mask()
1776     part_info            Reference to partitioning data structure
1777     num_parts            Number of parts in linear hash partitioning
1778 
1779   RETURN VALUE
1780     NONE
1781 */
1782 
set_linear_hash_mask(partition_info * part_info,uint num_parts)1783 void set_linear_hash_mask(partition_info *part_info, uint num_parts)
1784 {
1785   uint mask;
1786 
1787   for (mask= 1; mask < num_parts; mask<<=1)
1788     ;
1789   part_info->linear_hash_mask= mask - 1;
1790 }
1791 
1792 
1793 /*
1794   This function calculates the partition id provided the result of the hash
1795   function using linear hashing parameters, mask and number of partitions.
1796 
1797   SYNOPSIS
1798     get_part_id_from_linear_hash()
1799     hash_value          Hash value calculated by HASH function or KEY function
1800     mask                Mask calculated previously by set_linear_hash_mask
1801     num_parts           Number of partitions in HASH partitioned part
1802 
1803   RETURN VALUE
1804     part_id             The calculated partition identity (starting at 0)
1805 
1806   DESCRIPTION
1807     The partition is calculated according to the theory of linear hashing.
1808     See e.g. Linear hashing: a new tool for file and table addressing,
1809     Reprinted from VLDB-80 in Readings Database Systems, 2nd ed, M. Stonebraker
1810     (ed.), Morgan Kaufmann 1994.
1811 */
1812 
get_part_id_from_linear_hash(longlong hash_value,uint mask,uint num_parts)1813 static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
1814                                            uint num_parts)
1815 {
1816   uint32 part_id= (uint32)(hash_value & mask);
1817 
1818   if (part_id >= num_parts)
1819   {
1820     uint new_mask= ((mask + 1) >> 1) - 1;
1821     part_id= (uint32)(hash_value & new_mask);
1822   }
1823   return part_id;
1824 }
1825 
1826 
1827 /*
1828   Check if a particular field is in need of character set
1829   handling for partition functions.
1830 
1831   SYNOPSIS
1832     field_is_partition_charset()
1833     field                         The field to check
1834 
1835   RETURN VALUES
1836     FALSE                        Not in need of character set handling
1837     TRUE                         In need of character set handling
1838 */
1839 
field_is_partition_charset(Field * field)1840 bool field_is_partition_charset(Field *field)
1841 {
1842   if (!(field->type() == MYSQL_TYPE_STRING) &&
1843       !(field->type() == MYSQL_TYPE_VARCHAR))
1844     return FALSE;
1845   {
1846     CHARSET_INFO *cs= field->charset();
1847     if (!(field->type() == MYSQL_TYPE_STRING) ||
1848         !(cs->state & MY_CS_BINSORT))
1849       return TRUE;
1850     return FALSE;
1851   }
1852 }
1853 
1854 
1855 /*
1856   Check that partition function doesn't contain any forbidden
1857   character sets and collations.
1858 
1859   SYNOPSIS
1860     check_part_func_fields()
1861     ptr                                 Array of Field pointers
1862     ok_with_charsets                    Will we report allowed charset
1863                                         fields as ok
1864   RETURN VALUES
1865     FALSE                               Success
1866     TRUE                                Error
1867 
1868   DESCRIPTION
1869     We will check in this routine that the fields of the partition functions
1870     do not contain unallowed parts. It can also be used to check if there
1871     are fields that require special care by calling my_strnxfrm before
1872     calling the functions to calculate partition id.
1873 */
1874 
check_part_func_fields(Field ** ptr,bool ok_with_charsets)1875 bool check_part_func_fields(Field **ptr, bool ok_with_charsets)
1876 {
1877   Field *field;
1878   DBUG_ENTER("check_part_func_fields");
1879 
1880   while ((field= *(ptr++)))
1881   {
1882     /*
1883       For CHAR/VARCHAR fields we need to take special precautions.
1884       Binary collation with CHAR is automatically supported. Other
1885       types need some kind of standardisation function handling
1886     */
1887     if (field_is_partition_charset(field))
1888     {
1889       CHARSET_INFO *cs= field->charset();
1890       if (!ok_with_charsets ||
1891           cs->mbmaxlen > 1 ||
1892           cs->strxfrm_multiply > 1)
1893       {
1894         DBUG_RETURN(TRUE);
1895       }
1896     }
1897   }
1898   DBUG_RETURN(FALSE);
1899 }
1900 
1901 
1902 /*
1903   fix partition functions
1904 
1905   SYNOPSIS
1906     fix_partition_func()
1907     thd                  The thread object
1908     table                TABLE object for which partition fields are set-up
1909     is_create_table_ind  Indicator of whether openfrm was called as part of
1910                          CREATE or ALTER TABLE
1911 
1912   RETURN VALUE
1913     TRUE                 Error
1914     FALSE                Success
1915 
1916   DESCRIPTION
1917     The name parameter contains the full table name and is used to get the
1918     database name of the table which is used to set-up a correct
1919     TABLE_LIST object for use in fix_fields.
1920 
1921 NOTES
1922     This function is called as part of opening the table by opening the .frm
1923     file. It is a part of CREATE TABLE to do this so it is quite permissible
1924     that errors due to erroneus syntax isn't found until we come here.
1925     If the user has used a non-existing field in the table is one such example
1926     of an error that is not discovered until here.
1927 */
1928 
fix_partition_func(THD * thd,TABLE * table,bool is_create_table_ind)1929 bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind)
1930 {
1931   bool result= TRUE;
1932   partition_info *part_info= table->part_info;
1933   enum_column_usage saved_column_usage= thd->column_usage;
1934   DBUG_ENTER("fix_partition_func");
1935 
1936   if (part_info->fixed)
1937   {
1938     DBUG_RETURN(FALSE);
1939   }
1940   thd->column_usage= COLUMNS_WRITE;
1941   DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage));
1942 
1943   if (!is_create_table_ind ||
1944        thd->lex->sql_command != SQLCOM_CREATE_TABLE)
1945   {
1946     if (partition_default_handling(thd, table, part_info,
1947                                    is_create_table_ind,
1948                                    table->s->normalized_path.str))
1949     {
1950       DBUG_RETURN(TRUE);
1951     }
1952   }
1953   if (part_info->is_sub_partitioned())
1954   {
1955     DBUG_ASSERT(part_info->subpart_type == HASH_PARTITION);
1956     /*
1957       Subpartition is defined. We need to verify that subpartitioning
1958       function is correct.
1959     */
1960     if (part_info->linear_hash_ind)
1961       set_linear_hash_mask(part_info, part_info->num_subparts);
1962     if (part_info->list_of_subpart_fields)
1963     {
1964       List_iterator<const char> it(part_info->subpart_field_list);
1965       if (unlikely(handle_list_of_fields(thd, it, table, part_info, TRUE)))
1966         goto end;
1967     }
1968     else
1969     {
1970       if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
1971                                         table, TRUE, is_create_table_ind)))
1972         goto end;
1973       if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
1974       {
1975         part_info->report_part_expr_error(TRUE);
1976         goto end;
1977       }
1978     }
1979   }
1980   DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION);
1981   /*
1982     Partition is defined. We need to verify that partitioning
1983     function is correct.
1984   */
1985   set_up_partition_func_pointers(part_info);
1986   if (part_info->part_type == HASH_PARTITION)
1987   {
1988     if (part_info->linear_hash_ind)
1989       set_linear_hash_mask(part_info, part_info->num_parts);
1990     if (part_info->list_of_part_fields)
1991     {
1992       List_iterator<const char> it(part_info->part_field_list);
1993       if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE)))
1994         goto end;
1995     }
1996     else
1997     {
1998       if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
1999                                         table, FALSE, is_create_table_ind)))
2000         goto end;
2001       if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
2002       {
2003         part_info->report_part_expr_error(FALSE);
2004         goto end;
2005       }
2006     }
2007     part_info->fixed= TRUE;
2008   }
2009   else
2010   {
2011     if (part_info->column_list)
2012     {
2013       List_iterator<const char> it(part_info->part_field_list);
2014       if (unlikely(handle_list_of_fields(thd, it, table, part_info, FALSE)))
2015         goto end;
2016     }
2017     else
2018     {
2019       if (part_info->part_type == VERSIONING_PARTITION &&
2020         part_info->vers_setup_expression(thd))
2021         goto end;
2022       if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
2023                                         table, FALSE, is_create_table_ind)))
2024         goto end;
2025     }
2026     part_info->fixed= TRUE;
2027     if (part_info->check_constants(thd, part_info))
2028       goto end;
2029     if (unlikely(part_info->num_parts < 1))
2030     {
2031       const char *error_str= part_info->part_type == LIST_PARTITION
2032                              ? "LIST" : "RANGE";
2033       my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
2034       goto end;
2035     }
2036     if (unlikely(!part_info->column_list &&
2037                   part_info->part_expr->result_type() != INT_RESULT &&
2038                   part_info->part_expr->result_type() != DECIMAL_RESULT))
2039     {
2040       part_info->report_part_expr_error(FALSE);
2041       goto end;
2042     }
2043   }
2044   if (((part_info->part_type != HASH_PARTITION ||
2045         part_info->list_of_part_fields == FALSE) &&
2046        !part_info->column_list &&
2047        check_part_func_fields(part_info->part_field_array, TRUE)) ||
2048       (part_info->list_of_subpart_fields == FALSE &&
2049        part_info->is_sub_partitioned() &&
2050        check_part_func_fields(part_info->subpart_field_array, TRUE)))
2051   {
2052     /*
2053       Range/List/HASH (but not KEY) and not COLUMNS or HASH subpartitioning
2054       with columns in the partitioning expression using unallowed charset.
2055     */
2056     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2057     goto end;
2058   }
2059   if (unlikely(create_full_part_field_array(thd, table, part_info)))
2060     goto end;
2061   if (unlikely(check_primary_key(table)))
2062     goto end;
2063   if (unlikely((!(table->s->db_type()->partition_flags &&
2064       (table->s->db_type()->partition_flags() & HA_CAN_PARTITION_UNIQUE))) &&
2065                check_unique_keys(table)))
2066     goto end;
2067   if (unlikely(set_up_partition_bitmaps(thd, part_info)))
2068     goto end;
2069   if (unlikely(part_info->set_up_charset_field_preps(thd)))
2070   {
2071     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2072     goto end;
2073   }
2074   if (unlikely(part_info->check_partition_field_length()))
2075   {
2076     my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
2077     goto end;
2078   }
2079   check_range_capable_PF(table);
2080   set_up_partition_key_maps(table, part_info);
2081   set_up_range_analysis_info(part_info);
2082   table->file->set_part_info(part_info);
2083   result= FALSE;
2084 end:
2085   thd->column_usage= saved_column_usage;
2086   DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage));
2087   DBUG_RETURN(result);
2088 }
2089 
2090 
2091 /*
2092   The code below is support routines for the reverse parsing of the
2093   partitioning syntax. This feature is very useful to generate syntax for
2094   all default values to avoid all default checking when opening the frm
2095   file. It is also used when altering the partitioning by use of various
2096   ALTER TABLE commands. Finally it is used for SHOW CREATE TABLES.
2097 */
2098 
add_part_field_list(THD * thd,String * str,List<const char> field_list)2099 static int add_part_field_list(THD *thd, String *str, List<const char> field_list)
2100 {
2101   int err= 0;
2102   const char *field_name;
2103   List_iterator<const char> part_it(field_list);
2104 
2105   err+= str->append('(');
2106   while ((field_name= part_it++))
2107   {
2108     err+= append_identifier(thd, str, field_name, strlen(field_name));
2109     err+= str->append(',');
2110   }
2111   if (field_list.elements)
2112     str->length(str->length()-1);
2113   err+= str->append(')');
2114   return err;
2115 }
2116 
2117 /*
2118    Must escape strings in partitioned tables frm-files,
2119    parsing it later with mysql_unpack_partition will fail otherwise.
2120 */
2121 
add_keyword_string(String * str,const char * keyword,bool quoted,const char * keystr)2122 static int add_keyword_string(String *str, const char *keyword,
2123                               bool quoted, const char *keystr)
2124 {
2125   int err= str->append(' ');
2126   err+= str->append(keyword);
2127 
2128   str->append(STRING_WITH_LEN(" = "));
2129   if (quoted)
2130   {
2131     err+= str->append('\'');
2132     err+= str->append_for_single_quote(keystr);
2133     err+= str->append('\'');
2134   }
2135   else
2136     err+= str->append(keystr);
2137   return err;
2138 }
2139 
2140 
2141 /**
2142   @brief  Truncate the partition file name from a path it it exists.
2143 
2144   @note  A partition file name will contian one or more '#' characters.
2145 One of the occurances of '#' will be either "#P#" or "#p#" depending
2146 on whether the storage engine has converted the filename to lower case.
2147 */
truncate_partition_filename(char * path)2148 void truncate_partition_filename(char *path)
2149 {
2150   if (path)
2151   {
2152     char* last_slash= strrchr(path, FN_LIBCHAR);
2153 
2154     if (!last_slash)
2155       last_slash= strrchr(path, FN_LIBCHAR2);
2156 
2157     if (last_slash)
2158     {
2159       /* Look for a partition-type filename */
2160       for (char* pound= strchr(last_slash, '#');
2161            pound; pound = strchr(pound + 1, '#'))
2162       {
2163         if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#')
2164         {
2165           last_slash[0] = '\0';	/* truncate the file name */
2166           break;
2167         }
2168       }
2169     }
2170   }
2171 }
2172 
2173 /**
2174   @brief  Output a filepath.  Similar to add_keyword_string except it
2175 also converts \ to / on Windows and skips the partition file name at
2176 the end if found.
2177 
2178   @note  When Mysql sends a DATA DIRECTORY from SQL for partitions it does
2179 not use a file name, but it does for DATA DIRECTORY on a non-partitioned
2180 table.  So when the storage engine is asked for the DATA DIRECTORY string
2181 after a restart through Handler::update_create_options(), the storage
2182 engine may include the filename.
2183 */
add_keyword_path(String * str,const char * keyword,const char * path)2184 static int add_keyword_path(String *str, const char *keyword,
2185                             const char *path)
2186 {
2187   char temp_path[FN_REFLEN];
2188   strcpy(temp_path, path);
2189 #ifdef __WIN__
2190   /* Convert \ to / to be able to create table on unix */
2191   char *pos, *end;
2192   size_t length= strlen(temp_path);
2193   for (pos= temp_path, end= pos+length ; pos < end ; pos++)
2194   {
2195     if (*pos == '\\')
2196       *pos = '/';
2197   }
2198 #endif
2199 
2200   /*
2201   If the partition file name with its "#P#" identifier
2202   is found after the last slash, truncate that filename.
2203   */
2204   truncate_partition_filename(temp_path);
2205 
2206   return add_keyword_string(str, keyword, true, temp_path);
2207 }
2208 
add_keyword_int(String * str,const char * keyword,longlong num)2209 static int add_keyword_int(String *str, const char *keyword, longlong num)
2210 {
2211   int err= str->append(' ');
2212   err+= str->append(keyword);
2213   str->append(STRING_WITH_LEN(" = "));
2214   return err + str->append_longlong(num);
2215 }
2216 
add_partition_options(String * str,partition_element * p_elem)2217 static int add_partition_options(String *str, partition_element *p_elem)
2218 {
2219   int err= 0;
2220 
2221   if (p_elem->tablespace_name)
2222     err+= add_keyword_string(str,"TABLESPACE", false, p_elem->tablespace_name);
2223   if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
2224     err+= add_keyword_int(str,"NODEGROUP",(longlong)p_elem->nodegroup_id);
2225   if (p_elem->part_max_rows)
2226     err+= add_keyword_int(str,"MAX_ROWS",(longlong)p_elem->part_max_rows);
2227   if (p_elem->part_min_rows)
2228     err+= add_keyword_int(str,"MIN_ROWS",(longlong)p_elem->part_min_rows);
2229   if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
2230   {
2231     if (p_elem->data_file_name)
2232       err+= add_keyword_path(str, "DATA DIRECTORY", p_elem->data_file_name);
2233     if (p_elem->index_file_name)
2234       err+= add_keyword_path(str, "INDEX DIRECTORY", p_elem->index_file_name);
2235   }
2236   if (p_elem->part_comment)
2237     err+= add_keyword_string(str, "COMMENT", true, p_elem->part_comment);
2238   if (p_elem->connect_string.length)
2239     err+= add_keyword_string(str, "CONNECTION", true,
2240                              p_elem->connect_string.str);
2241   err += add_keyword_string(str, "ENGINE", false,
2242                          ha_resolve_storage_engine_name(p_elem->engine_type));
2243   return err;
2244 }
2245 
2246 
2247 /*
2248   Check partition fields for result type and if they need
2249   to check the character set.
2250 
2251   SYNOPSIS
2252     check_part_field()
2253     sql_type              Type provided by user
2254     field_name            Name of field, used for error handling
2255     result_type           Out value: Result type of field
2256     need_cs_check         Out value: Do we need character set check
2257 
2258   RETURN VALUES
2259     TRUE                  Error
2260     FALSE                 Ok
2261 */
2262 
check_part_field(enum_field_types sql_type,const char * field_name,Item_result * result_type,bool * need_cs_check)2263 static int check_part_field(enum_field_types sql_type,
2264                             const char *field_name,
2265                             Item_result *result_type,
2266                             bool *need_cs_check)
2267 {
2268   if (sql_type >= MYSQL_TYPE_TINY_BLOB &&
2269       sql_type <= MYSQL_TYPE_BLOB)
2270   {
2271     my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
2272     return TRUE;
2273   }
2274   switch (sql_type)
2275   {
2276     case MYSQL_TYPE_TINY:
2277     case MYSQL_TYPE_SHORT:
2278     case MYSQL_TYPE_LONG:
2279     case MYSQL_TYPE_LONGLONG:
2280     case MYSQL_TYPE_INT24:
2281       *result_type= INT_RESULT;
2282       *need_cs_check= FALSE;
2283       return FALSE;
2284     case MYSQL_TYPE_NEWDATE:
2285     case MYSQL_TYPE_DATE:
2286     case MYSQL_TYPE_TIME:
2287     case MYSQL_TYPE_DATETIME:
2288     case MYSQL_TYPE_TIME2:
2289     case MYSQL_TYPE_DATETIME2:
2290       *result_type= STRING_RESULT;
2291       *need_cs_check= TRUE;
2292       return FALSE;
2293     case MYSQL_TYPE_VARCHAR:
2294     case MYSQL_TYPE_STRING:
2295     case MYSQL_TYPE_VAR_STRING:
2296       *result_type= STRING_RESULT;
2297       *need_cs_check= TRUE;
2298       return FALSE;
2299     case MYSQL_TYPE_NEWDECIMAL:
2300     case MYSQL_TYPE_DECIMAL:
2301     case MYSQL_TYPE_TIMESTAMP:
2302     case MYSQL_TYPE_TIMESTAMP2:
2303     case MYSQL_TYPE_NULL:
2304     case MYSQL_TYPE_FLOAT:
2305     case MYSQL_TYPE_DOUBLE:
2306     case MYSQL_TYPE_BIT:
2307     case MYSQL_TYPE_ENUM:
2308     case MYSQL_TYPE_SET:
2309     case MYSQL_TYPE_GEOMETRY:
2310       goto error;
2311     default:
2312       goto error;
2313   }
2314 error:
2315   my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
2316            field_name);
2317   return TRUE;
2318 }
2319 
2320 
2321 /*
2322   Find the given field's Create_field object using name of field
2323 
2324   SYNOPSIS
2325     get_sql_field()
2326     field_name                   Field name
2327     alter_info                   Info from ALTER TABLE/CREATE TABLE
2328 
2329   RETURN VALUE
2330     sql_field                    Object filled in by parser about field
2331     NULL                         No field found
2332 */
2333 
get_sql_field(const char * field_name,Alter_info * alter_info)2334 static Create_field* get_sql_field(const char *field_name,
2335                                    Alter_info *alter_info)
2336 {
2337   List_iterator<Create_field> it(alter_info->create_list);
2338   Create_field *sql_field;
2339   DBUG_ENTER("get_sql_field");
2340 
2341   while ((sql_field= it++))
2342   {
2343     if (!(my_strcasecmp(system_charset_info,
2344                         sql_field->field_name.str,
2345                         field_name)))
2346     {
2347       DBUG_RETURN(sql_field);
2348     }
2349   }
2350   DBUG_RETURN(NULL);
2351 }
2352 
2353 
add_column_list_values(String * str,partition_info * part_info,part_elem_value * list_value,HA_CREATE_INFO * create_info,Alter_info * alter_info)2354 static int add_column_list_values(String *str, partition_info *part_info,
2355                                   part_elem_value *list_value,
2356                                   HA_CREATE_INFO *create_info,
2357                                   Alter_info *alter_info)
2358 {
2359   int err= 0;
2360   uint i;
2361   List_iterator<const char> it(part_info->part_field_list);
2362   uint num_elements= part_info->part_field_list.elements;
2363   bool use_parenthesis= (part_info->part_type == LIST_PARTITION &&
2364                          part_info->num_columns > 1U);
2365 
2366   if (use_parenthesis)
2367     err+= str->append('(');
2368   for (i= 0; i < num_elements; i++)
2369   {
2370     part_column_list_val *col_val= &list_value->col_val_array[i];
2371     const char *field_name= it++;
2372     if (col_val->max_value)
2373       err+= str->append(STRING_WITH_LEN("MAXVALUE"));
2374     else if (col_val->null_value)
2375       err+= str->append(STRING_WITH_LEN("NULL"));
2376     else
2377     {
2378       Item *item_expr= col_val->item_expression;
2379       if (item_expr->null_value)
2380         err+= str->append(STRING_WITH_LEN("NULL"));
2381       else
2382       {
2383         CHARSET_INFO *field_cs;
2384         bool need_cs_check= FALSE;
2385         Item_result result_type= STRING_RESULT;
2386 
2387         /*
2388           This function is called at a very early stage, even before
2389           we have prepared the sql_field objects. Thus we have to
2390           find the proper sql_field object and get the character set
2391           from that object.
2392         */
2393         if (create_info)
2394         {
2395           Create_field *sql_field;
2396 
2397           if (!(sql_field= get_sql_field(field_name,
2398                                          alter_info)))
2399           {
2400             my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
2401             return 1;
2402           }
2403           if (check_part_field(sql_field->real_field_type(),
2404                                sql_field->field_name.str,
2405                                &result_type,
2406                                &need_cs_check))
2407             return 1;
2408           if (need_cs_check)
2409             field_cs= get_sql_field_charset(sql_field, create_info);
2410           else
2411             field_cs= NULL;
2412         }
2413         else
2414         {
2415           Field *field= part_info->part_field_array[i];
2416           result_type= field->result_type();
2417           if (check_part_field(field->real_type(),
2418                                field->field_name.str,
2419                                &result_type,
2420                                &need_cs_check))
2421             return 1;
2422           DBUG_ASSERT(result_type == field->result_type());
2423           if (need_cs_check)
2424             field_cs= field->charset();
2425           else
2426             field_cs= NULL;
2427         }
2428         if (result_type != item_expr->result_type())
2429         {
2430           my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
2431           return 1;
2432         }
2433         if (field_cs && field_cs != item_expr->collation.collation)
2434         {
2435           if (!(item_expr= convert_charset_partition_constant(item_expr,
2436                                                               field_cs)))
2437           {
2438             my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2439             return 1;
2440           }
2441         }
2442         {
2443           StringBuffer<MAX_KEY_LENGTH> buf;
2444           String val_conv, *res;
2445           val_conv.set_charset(system_charset_info);
2446           res= item_expr->val_str(&buf);
2447           if (get_cs_converted_part_value_from_string(current_thd,
2448                                                       item_expr, res,
2449                                                       &val_conv, field_cs,
2450                                                    (bool)(alter_info != NULL)))
2451             return 1;
2452           err+= str->append(val_conv);
2453         }
2454       }
2455     }
2456     if (i != (num_elements - 1))
2457       err+= str->append(',');
2458   }
2459   if (use_parenthesis)
2460     err+= str->append(')');
2461   return err;
2462 }
2463 
add_partition_values(String * str,partition_info * part_info,partition_element * p_elem,HA_CREATE_INFO * create_info,Alter_info * alter_info)2464 static int add_partition_values(String *str, partition_info *part_info,
2465                                 partition_element *p_elem,
2466                                 HA_CREATE_INFO *create_info,
2467                                 Alter_info *alter_info)
2468 {
2469   int err= 0;
2470 
2471   if (part_info->part_type == RANGE_PARTITION)
2472   {
2473     err+= str->append(STRING_WITH_LEN(" VALUES LESS THAN "));
2474     if (part_info->column_list)
2475     {
2476       List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2477       part_elem_value *list_value= list_val_it++;
2478       err+= str->append('(');
2479       err+= add_column_list_values(str, part_info, list_value,
2480                                    create_info, alter_info);
2481       err+= str->append(')');
2482     }
2483     else
2484     {
2485       if (!p_elem->max_value)
2486       {
2487         err+= str->append('(');
2488         if (p_elem->signed_flag)
2489           err+= str->append_longlong(p_elem->range_value);
2490         else
2491           err+= str->append_ulonglong(p_elem->range_value);
2492         err+= str->append(')');
2493       }
2494       else
2495         err+= str->append(STRING_WITH_LEN("MAXVALUE"));
2496     }
2497   }
2498   else if (part_info->part_type == LIST_PARTITION)
2499   {
2500     uint i;
2501     List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2502 
2503     if (p_elem->max_value)
2504     {
2505       DBUG_ASSERT(part_info->defined_max_value ||
2506                   current_thd->lex->sql_command == SQLCOM_ALTER_TABLE);
2507       err+= str->append(STRING_WITH_LEN(" DEFAULT"));
2508       return err;
2509     }
2510 
2511     err+= str->append(STRING_WITH_LEN(" VALUES IN "));
2512     uint num_items= p_elem->list_val_list.elements;
2513 
2514     err+= str->append('(');
2515     if (p_elem->has_null_value)
2516     {
2517       err+= str->append(STRING_WITH_LEN("NULL"));
2518       if (num_items == 0)
2519       {
2520         err+= str->append(')');
2521         goto end;
2522       }
2523       err+= str->append(',');
2524     }
2525     i= 0;
2526     do
2527     {
2528       part_elem_value *list_value= list_val_it++;
2529 
2530       if (part_info->column_list)
2531         err+= add_column_list_values(str, part_info, list_value,
2532                                      create_info, alter_info);
2533       else
2534       {
2535         if (!list_value->unsigned_flag)
2536           err+= str->append_longlong(list_value->value);
2537         else
2538           err+= str->append_ulonglong(list_value->value);
2539       }
2540       if (i != (num_items-1))
2541         err+= str->append(',');
2542     } while (++i < num_items);
2543     err+= str->append(')');
2544   }
2545   else if (part_info->part_type == VERSIONING_PARTITION)
2546   {
2547     switch (p_elem->type)
2548     {
2549     case partition_element::CURRENT:
2550       err+= str->append(STRING_WITH_LEN(" CURRENT"));
2551       break;
2552     case partition_element::HISTORY:
2553       err+= str->append(STRING_WITH_LEN(" HISTORY"));
2554       break;
2555     default:
2556       DBUG_ASSERT(0 && "wrong p_elem->type");
2557     }
2558   }
2559 end:
2560   return err;
2561 }
2562 
2563 
2564 /**
2565   Add 'KEY' word, with optional 'ALGORTIHM = N'.
2566 
2567   @param str                    String to write to.
2568   @param part_info              partition_info holding the used key_algorithm
2569 
2570   @return Operation status.
2571     @retval 0    Success
2572     @retval != 0 Failure
2573 */
2574 
add_key_with_algorithm(String * str,partition_info * part_info)2575 static int add_key_with_algorithm(String *str, partition_info *part_info)
2576 {
2577   int err= 0;
2578   err+= str->append(STRING_WITH_LEN("KEY "));
2579 
2580   if (part_info->key_algorithm == partition_info::KEY_ALGORITHM_51)
2581   {
2582     err+= str->append(STRING_WITH_LEN("ALGORITHM = "));
2583     err+= str->append_longlong(part_info->key_algorithm);
2584     err+= str->append(' ');
2585   }
2586   return err;
2587 }
2588 
generate_partition_syntax_for_frm(THD * thd,partition_info * part_info,uint * buf_length,HA_CREATE_INFO * create_info,Alter_info * alter_info)2589 char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
2590                                         uint *buf_length,
2591                                         HA_CREATE_INFO *create_info,
2592                                         Alter_info *alter_info)
2593 {
2594   sql_mode_t old_mode= thd->variables.sql_mode;
2595   thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
2596   char *res= generate_partition_syntax(thd, part_info, buf_length,
2597                                              true, create_info, alter_info);
2598   thd->variables.sql_mode= old_mode;
2599   return res;
2600 }
2601 
2602 /*
2603   Generate the partition syntax from the partition data structure.
2604   Useful for support of generating defaults, SHOW CREATE TABLES
2605   and easy partition management.
2606 
2607   SYNOPSIS
2608     generate_partition_syntax()
2609     part_info                  The partitioning data structure
2610     buf_length                 A pointer to the returned buffer length
2611     show_partition_options     Should we display partition options
2612     create_info                Info generated by parser
2613     alter_info                 Info generated by parser
2614 
2615   RETURN VALUES
2616     NULL error
2617     buf, buf_length            Buffer and its length
2618 
2619   DESCRIPTION
2620   Here we will generate the full syntax for the given command where all
2621   defaults have been expanded. By so doing the it is also possible to
2622   make lots of checks of correctness while at it.
2623   This could will also be reused for SHOW CREATE TABLES and also for all
2624   type ALTER TABLE commands focusing on changing the PARTITION structure
2625   in any fashion.
2626 
2627   The code is optimised for minimal code size since it is not used in any
2628   common queries.
2629 */
2630 
generate_partition_syntax(THD * thd,partition_info * part_info,uint * buf_length,bool show_partition_options,HA_CREATE_INFO * create_info,Alter_info * alter_info)2631 char *generate_partition_syntax(THD *thd, partition_info *part_info,
2632                                 uint *buf_length,
2633                                 bool show_partition_options,
2634                                 HA_CREATE_INFO *create_info,
2635                                 Alter_info *alter_info)
2636 {
2637   uint i,j, tot_num_parts, num_subparts;
2638   partition_element *part_elem;
2639   int err= 0;
2640   List_iterator<partition_element> part_it(part_info->partitions);
2641   StringBuffer<1024> str;
2642   DBUG_ENTER("generate_partition_syntax");
2643 
2644   err+= str.append(STRING_WITH_LEN(" PARTITION BY "));
2645   switch (part_info->part_type)
2646   {
2647     case RANGE_PARTITION:
2648       err+= str.append(STRING_WITH_LEN("RANGE "));
2649       break;
2650     case LIST_PARTITION:
2651       err+= str.append(STRING_WITH_LEN("LIST "));
2652       break;
2653     case HASH_PARTITION:
2654       if (part_info->linear_hash_ind)
2655         err+= str.append(STRING_WITH_LEN("LINEAR "));
2656       if (part_info->list_of_part_fields)
2657       {
2658         err+= add_key_with_algorithm(&str, part_info);
2659         err+= add_part_field_list(thd, &str, part_info->part_field_list);
2660       }
2661       else
2662         err+= str.append(STRING_WITH_LEN("HASH "));
2663       break;
2664     case VERSIONING_PARTITION:
2665       err+= str.append(STRING_WITH_LEN("SYSTEM_TIME "));
2666       break;
2667     default:
2668       DBUG_ASSERT(0);
2669       /* We really shouldn't get here, no use in continuing from here */
2670       my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
2671       DBUG_RETURN(NULL);
2672   }
2673   if (part_info->part_type == VERSIONING_PARTITION)
2674   {
2675     Vers_part_info *vers_info= part_info->vers_info;
2676     DBUG_ASSERT(vers_info);
2677     if (vers_info->interval.is_set())
2678     {
2679       err+= str.append(STRING_WITH_LEN("INTERVAL "));
2680       err+= append_interval(&str, vers_info->interval.type,
2681                                   vers_info->interval.step);
2682       if (create_info) // not SHOW CREATE
2683       {
2684         err+= str.append(STRING_WITH_LEN(" STARTS "));
2685         err+= str.append_ulonglong(vers_info->interval.start);
2686       }
2687     }
2688     if (vers_info->limit)
2689     {
2690       err+= str.append(STRING_WITH_LEN("LIMIT "));
2691       err+= str.append_ulonglong(vers_info->limit);
2692     }
2693   }
2694   else if (part_info->part_expr)
2695   {
2696     err+= str.append('(');
2697     part_info->part_expr->print_for_table_def(&str);
2698     err+= str.append(')');
2699   }
2700   else if (part_info->column_list)
2701   {
2702     err+= str.append(STRING_WITH_LEN(" COLUMNS"));
2703     err+= add_part_field_list(thd, &str, part_info->part_field_list);
2704   }
2705   if ((!part_info->use_default_num_partitions) &&
2706        part_info->use_default_partitions)
2707   {
2708     err+= str.append(STRING_WITH_LEN("\nPARTITIONS "));
2709     err+= str.append_ulonglong(part_info->num_parts);
2710   }
2711   if (part_info->is_sub_partitioned())
2712   {
2713     err+= str.append(STRING_WITH_LEN("\nSUBPARTITION BY "));
2714     /* Must be hash partitioning for subpartitioning */
2715     if (part_info->linear_hash_ind)
2716       err+= str.append(STRING_WITH_LEN("LINEAR "));
2717     if (part_info->list_of_subpart_fields)
2718     {
2719       err+= add_key_with_algorithm(&str, part_info);
2720       err+= add_part_field_list(thd, &str, part_info->subpart_field_list);
2721     }
2722     else
2723       err+= str.append(STRING_WITH_LEN("HASH "));
2724     if (part_info->subpart_expr)
2725     {
2726       err+= str.append('(');
2727       part_info->subpart_expr->print_for_table_def(&str);
2728       err+= str.append(')');
2729     }
2730     if ((!part_info->use_default_num_subpartitions) &&
2731           part_info->use_default_subpartitions)
2732     {
2733       err+= str.append(STRING_WITH_LEN("\nSUBPARTITIONS "));
2734       err+= str.append_ulonglong(part_info->num_subparts);
2735     }
2736   }
2737   tot_num_parts= part_info->partitions.elements;
2738   num_subparts= part_info->num_subparts;
2739 
2740   if (!part_info->use_default_partitions)
2741   {
2742     bool first= TRUE;
2743     err+= str.append(STRING_WITH_LEN("\n("));
2744     i= 0;
2745     do
2746     {
2747       part_elem= part_it++;
2748       if (part_elem->part_state != PART_TO_BE_DROPPED &&
2749           part_elem->part_state != PART_REORGED_DROPPED)
2750       {
2751         if (!first)
2752           err+= str.append(STRING_WITH_LEN(",\n "));
2753         first= FALSE;
2754         err+= str.append(STRING_WITH_LEN("PARTITION "));
2755         err+= append_identifier(thd, &str, part_elem->partition_name,
2756                                            strlen(part_elem->partition_name));
2757         err+= add_partition_values(&str, part_info, part_elem,
2758                                    create_info, alter_info);
2759         if (!part_info->is_sub_partitioned() ||
2760             part_info->use_default_subpartitions)
2761         {
2762           if (show_partition_options)
2763             err+= add_partition_options(&str, part_elem);
2764         }
2765         else
2766         {
2767           err+= str.append(STRING_WITH_LEN("\n ("));
2768           List_iterator<partition_element> sub_it(part_elem->subpartitions);
2769           j= 0;
2770           do
2771           {
2772             part_elem= sub_it++;
2773             err+= str.append(STRING_WITH_LEN("SUBPARTITION "));
2774             err+= append_identifier(thd, &str, part_elem->partition_name,
2775                                                strlen(part_elem->partition_name));
2776             if (show_partition_options)
2777               err+= add_partition_options(&str, part_elem);
2778             if (j != (num_subparts-1))
2779               err+= str.append(STRING_WITH_LEN(",\n  "));
2780             else
2781               err+= str.append(')');
2782           } while (++j < num_subparts);
2783         }
2784       }
2785       if (i == (tot_num_parts-1))
2786         err+= str.append(')');
2787     } while (++i < tot_num_parts);
2788   }
2789   if (err)
2790     DBUG_RETURN(NULL);
2791   *buf_length= str.length();
2792   DBUG_RETURN(thd->strmake(str.ptr(), str.length()));
2793 }
2794 
2795 
2796 /*
2797   Check if partition key fields are modified and if it can be handled by the
2798   underlying storage engine.
2799 
2800   SYNOPSIS
2801     partition_key_modified
2802     table                TABLE object for which partition fields are set-up
2803     fields               Bitmap representing fields to be modified
2804 
2805   RETURN VALUES
2806     TRUE                 Need special handling of UPDATE
2807     FALSE                Normal UPDATE handling is ok
2808 */
2809 
partition_key_modified(TABLE * table,const MY_BITMAP * fields)2810 bool partition_key_modified(TABLE *table, const MY_BITMAP *fields)
2811 {
2812   Field **fld;
2813   partition_info *part_info= table->part_info;
2814   DBUG_ENTER("partition_key_modified");
2815 
2816   if (!part_info)
2817     DBUG_RETURN(FALSE);
2818   if (table->s->db_type()->partition_flags &&
2819       (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
2820     DBUG_RETURN(FALSE);
2821   for (fld= part_info->full_part_field_array; *fld; fld++)
2822     if (bitmap_is_set(fields, (*fld)->field_index))
2823       DBUG_RETURN(TRUE);
2824   DBUG_RETURN(FALSE);
2825 }
2826 
2827 
2828 /*
2829   A function to handle correct handling of NULL values in partition
2830   functions.
2831   SYNOPSIS
2832     part_val_int()
2833     item_expr                 The item expression to evaluate
2834     out:result                The value of the partition function,
2835                                 LONGLONG_MIN if any null value in function
2836   RETURN VALUES
2837     TRUE      Error in val_int()
2838     FALSE     ok
2839 */
2840 
part_val_int(Item * item_expr,longlong * result)2841 static inline int part_val_int(Item *item_expr, longlong *result)
2842 {
2843   switch (item_expr->cmp_type())
2844   {
2845   case DECIMAL_RESULT:
2846   {
2847     my_decimal buf;
2848     my_decimal *val= item_expr->val_decimal(&buf);
2849     if (val && my_decimal2int(E_DEC_FATAL_ERROR, val, item_expr->unsigned_flag,
2850                               result, FLOOR) != E_DEC_OK)
2851       return true;
2852     break;
2853   }
2854   case INT_RESULT:
2855     *result= item_expr->val_int();
2856     break;
2857   case STRING_RESULT:
2858   case REAL_RESULT:
2859   case ROW_RESULT:
2860   case TIME_RESULT:
2861     DBUG_ASSERT(0);
2862     break;
2863   }
2864   if (item_expr->null_value)
2865   {
2866     if (unlikely(current_thd->is_error()))
2867       return true;
2868     *result= LONGLONG_MIN;
2869   }
2870   return false;
2871 }
2872 
2873 
2874 /*
2875   The next set of functions are used to calculate the partition identity.
2876   A handler sets up a variable that corresponds to one of these functions
2877   to be able to quickly call it whenever the partition id needs to calculated
2878   based on the record in table->record[0] (or set up to fake that).
2879   There are 4 functions for hash partitioning and 2 for RANGE/LIST partitions.
2880   In addition there are 4 variants for RANGE subpartitioning and 4 variants
2881   for LIST subpartitioning thus in total there are 14 variants of this
2882   function.
2883 
2884   We have a set of support functions for these 14 variants. There are 4
2885   variants of hash functions and there is a function for each. The KEY
2886   partitioning uses the function calculate_key_hash_value to calculate the hash
2887   value based on an array of fields. The linear hash variants uses the
2888   method get_part_id_from_linear_hash to get the partition id using the
2889   hash value and some parameters calculated from the number of partitions.
2890 */
2891 
2892 /*
2893   A simple support function to calculate part_id given local part and
2894   sub part.
2895 
2896   SYNOPSIS
2897     get_part_id_for_sub()
2898     loc_part_id             Local partition id
2899     sub_part_id             Subpartition id
2900     num_subparts            Number of subparts
2901 */
2902 
2903 inline
get_part_id_for_sub(uint32 loc_part_id,uint32 sub_part_id,uint num_subparts)2904 static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
2905                                   uint num_subparts)
2906 {
2907   return (uint32)((loc_part_id * num_subparts) + sub_part_id);
2908 }
2909 
2910 
2911 /*
2912   Calculate part_id for (SUB)PARTITION BY HASH
2913 
2914   SYNOPSIS
2915     get_part_id_hash()
2916     num_parts                Number of hash partitions
2917     part_expr                Item tree of hash function
2918     out:part_id              The returned partition id
2919     out:func_value           Value of hash function
2920 
2921   RETURN VALUE
2922     != 0                          Error code
2923     FALSE                         Success
2924 */
2925 
get_part_id_hash(uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2926 static int get_part_id_hash(uint num_parts,
2927                             Item *part_expr,
2928                             uint32 *part_id,
2929                             longlong *func_value)
2930 {
2931   longlong int_hash_id;
2932   DBUG_ENTER("get_part_id_hash");
2933 
2934   if (part_val_int(part_expr, func_value))
2935     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2936 
2937   int_hash_id= *func_value % num_parts;
2938 
2939   *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
2940   DBUG_RETURN(FALSE);
2941 }
2942 
2943 
2944 /*
2945   Calculate part_id for (SUB)PARTITION BY LINEAR HASH
2946 
2947   SYNOPSIS
2948     get_part_id_linear_hash()
2949     part_info           A reference to the partition_info struct where all the
2950                         desired information is given
2951     num_parts           Number of hash partitions
2952     part_expr           Item tree of hash function
2953     out:part_id         The returned partition id
2954     out:func_value      Value of hash function
2955 
2956   RETURN VALUE
2957     != 0     Error code
2958     0        OK
2959 */
2960 
get_part_id_linear_hash(partition_info * part_info,uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2961 static int get_part_id_linear_hash(partition_info *part_info,
2962                                    uint num_parts,
2963                                    Item *part_expr,
2964                                    uint32 *part_id,
2965                                    longlong *func_value)
2966 {
2967   DBUG_ENTER("get_part_id_linear_hash");
2968 
2969   if (part_val_int(part_expr, func_value))
2970     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2971 
2972   *part_id= get_part_id_from_linear_hash(*func_value,
2973                                          part_info->linear_hash_mask,
2974                                          num_parts);
2975   DBUG_RETURN(FALSE);
2976 }
2977 
2978 
2979 /**
2980   Calculate part_id for (SUB)PARTITION BY KEY
2981 
2982   @param file                Handler to storage engine
2983   @param field_array         Array of fields for PARTTION KEY
2984   @param num_parts           Number of KEY partitions
2985   @param func_value[out]     Returns calculated hash value
2986 
2987   @return Calculated partition id
2988 */
2989 
2990 inline
get_part_id_key(handler * file,Field ** field_array,uint num_parts,longlong * func_value)2991 static uint32 get_part_id_key(handler *file,
2992                               Field **field_array,
2993                               uint num_parts,
2994                               longlong *func_value)
2995 {
2996   DBUG_ENTER("get_part_id_key");
2997   *func_value= ha_partition::calculate_key_hash_value(field_array);
2998   DBUG_RETURN((uint32) (*func_value % num_parts));
2999 }
3000 
3001 
3002 /*
3003   Calculate part_id for (SUB)PARTITION BY LINEAR KEY
3004 
3005   SYNOPSIS
3006     get_part_id_linear_key()
3007     part_info           A reference to the partition_info struct where all the
3008                         desired information is given
3009     field_array         Array of fields for PARTTION KEY
3010     num_parts            Number of KEY partitions
3011 
3012   RETURN VALUE
3013     Calculated partition id
3014 */
3015 
3016 inline
get_part_id_linear_key(partition_info * part_info,Field ** field_array,uint num_parts,longlong * func_value)3017 static uint32 get_part_id_linear_key(partition_info *part_info,
3018                                      Field **field_array,
3019                                      uint num_parts,
3020                                      longlong *func_value)
3021 {
3022   DBUG_ENTER("get_part_id_linear_key");
3023 
3024   *func_value= ha_partition::calculate_key_hash_value(field_array);
3025   DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
3026                                            part_info->linear_hash_mask,
3027                                            num_parts));
3028 }
3029 
3030 /*
3031   Copy to field buffers and set up field pointers
3032 
3033   SYNOPSIS
3034     copy_to_part_field_buffers()
3035     ptr                          Array of fields to copy
3036     field_bufs                   Array of field buffers to copy to
3037     restore_ptr                  Array of pointers to restore to
3038 
3039   RETURN VALUES
3040     NONE
3041   DESCRIPTION
3042     This routine is used to take the data from field pointer, convert
3043     it to a standard format and store this format in a field buffer
3044     allocated for this purpose. Next the field pointers are moved to
3045     point to the field buffers. There is a separate to restore the
3046     field pointers after this call.
3047 */
3048 
copy_to_part_field_buffers(Field ** ptr,uchar ** field_bufs,uchar ** restore_ptr)3049 static void copy_to_part_field_buffers(Field **ptr,
3050                                        uchar **field_bufs,
3051                                        uchar **restore_ptr)
3052 {
3053   Field *field;
3054   while ((field= *(ptr++)))
3055   {
3056     *restore_ptr= field->ptr;
3057     restore_ptr++;
3058     if (!field->maybe_null() || !field->is_null())
3059     {
3060       CHARSET_INFO *cs= field->charset();
3061       uint max_len= field->pack_length();
3062       uint data_len= field->data_length();
3063       uchar *field_buf= *field_bufs;
3064       /*
3065          We only use the field buffer for VARCHAR and CHAR strings
3066          which isn't of a binary collation. We also only use the
3067          field buffer for fields which are not currently NULL.
3068          The field buffer will store a normalised string. We use
3069          the strnxfrm method to normalise the string.
3070        */
3071       if (field->type() == MYSQL_TYPE_VARCHAR)
3072       {
3073         uint len_bytes= ((Field_varstring*)field)->length_bytes;
3074         my_strnxfrm(cs, field_buf + len_bytes, max_len,
3075                     field->ptr + len_bytes, data_len);
3076         if (len_bytes == 1)
3077           *field_buf= (uchar) data_len;
3078         else
3079           int2store(field_buf, data_len);
3080       }
3081       else
3082       {
3083         my_strnxfrm(cs, field_buf, max_len,
3084                     field->ptr, max_len);
3085       }
3086       field->ptr= field_buf;
3087     }
3088     field_bufs++;
3089   }
3090   return;
3091 }
3092 
3093 /*
3094   Restore field pointers
3095   SYNOPSIS
3096     restore_part_field_pointers()
3097     ptr                            Array of fields to restore
3098     restore_ptr                    Array of field pointers to restore to
3099 
3100   RETURN VALUES
3101 */
3102 
restore_part_field_pointers(Field ** ptr,uchar ** restore_ptr)3103 static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
3104 {
3105   Field *field;
3106   while ((field= *(ptr++)))
3107   {
3108     field->ptr= *restore_ptr;
3109     restore_ptr++;
3110   }
3111   return;
3112 }
3113 
3114 /*
3115   This function is used to calculate the partition id where all partition
3116   fields have been prepared to point to a record where the partition field
3117   values are bound.
3118 
3119   SYNOPSIS
3120     get_partition_id()
3121     part_info           A reference to the partition_info struct where all the
3122                         desired information is given
3123     out:part_id         The partition id is returned through this pointer
3124     out:func_value      Value of partition function (longlong)
3125 
3126   RETURN VALUE
3127     part_id                     Partition id of partition that would contain
3128                                 row with given values of PF-fields
3129     HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
3130                                 fit into any partition and thus the values of
3131                                 the PF-fields are not allowed.
3132 
3133   DESCRIPTION
3134     A routine used from write_row, update_row and delete_row from any
3135     handler supporting partitioning. It is also a support routine for
3136     get_partition_set used to find the set of partitions needed to scan
3137     for a certain index scan or full table scan.
3138 
3139     It is actually 9 different variants of this function which are called
3140     through a function pointer.
3141 
3142     get_partition_id_list
3143     get_partition_id_list_col
3144     get_partition_id_range
3145     get_partition_id_range_col
3146     get_partition_id_hash_nosub
3147     get_partition_id_key_nosub
3148     get_partition_id_linear_hash_nosub
3149     get_partition_id_linear_key_nosub
3150     get_partition_id_with_sub
3151 */
3152 
3153 /*
3154   This function is used to calculate the main partition to use in the case of
3155   subpartitioning and we don't know enough to get the partition identity in
3156   total.
3157 
3158   SYNOPSIS
3159     get_part_partition_id()
3160     part_info           A reference to the partition_info struct where all the
3161                         desired information is given
3162     out:part_id         The partition id is returned through this pointer
3163     out:func_value      The value calculated by partition function
3164 
3165   RETURN VALUE
3166     HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
3167                                 fit into any partition and thus the values of
3168                                 the PF-fields are not allowed.
3169     0                           OK
3170 
3171   DESCRIPTION
3172 
3173     It is actually 8 different variants of this function which are called
3174     through a function pointer.
3175 
3176     get_partition_id_list
3177     get_partition_id_list_col
3178     get_partition_id_range
3179     get_partition_id_range_col
3180     get_partition_id_hash_nosub
3181     get_partition_id_key_nosub
3182     get_partition_id_linear_hash_nosub
3183     get_partition_id_linear_key_nosub
3184 */
3185 
get_part_id_charset_func_part(partition_info * part_info,uint32 * part_id,longlong * func_value)3186 static int get_part_id_charset_func_part(partition_info *part_info,
3187                                          uint32 *part_id,
3188                                          longlong *func_value)
3189 {
3190   int res;
3191   DBUG_ENTER("get_part_id_charset_func_part");
3192 
3193   copy_to_part_field_buffers(part_info->part_charset_field_array,
3194                              part_info->part_field_buffers,
3195                              part_info->restore_part_field_ptrs);
3196   res= part_info->get_part_partition_id_charset(part_info,
3197                                                 part_id, func_value);
3198   restore_part_field_pointers(part_info->part_charset_field_array,
3199                               part_info->restore_part_field_ptrs);
3200   DBUG_RETURN(res);
3201 }
3202 
3203 
get_part_id_charset_func_subpart(partition_info * part_info,uint32 * part_id)3204 static int get_part_id_charset_func_subpart(partition_info *part_info,
3205                                             uint32 *part_id)
3206 {
3207   int res;
3208   DBUG_ENTER("get_part_id_charset_func_subpart");
3209 
3210   copy_to_part_field_buffers(part_info->subpart_charset_field_array,
3211                              part_info->subpart_field_buffers,
3212                              part_info->restore_subpart_field_ptrs);
3213   res= part_info->get_subpartition_id_charset(part_info, part_id);
3214   restore_part_field_pointers(part_info->subpart_charset_field_array,
3215                               part_info->restore_subpart_field_ptrs);
3216   DBUG_RETURN(res);
3217 }
3218 
get_partition_id_list_col(partition_info * part_info,uint32 * part_id,longlong * func_value)3219 int get_partition_id_list_col(partition_info *part_info,
3220                               uint32 *part_id,
3221                               longlong *func_value)
3222 {
3223   part_column_list_val *list_col_array= part_info->list_col_array;
3224   uint num_columns= part_info->part_field_list.elements;
3225   int list_index, cmp;
3226   int min_list_index= 0;
3227   int max_list_index= part_info->num_list_values - 1;
3228   DBUG_ENTER("get_partition_id_list_col");
3229 
3230   while (max_list_index >= min_list_index)
3231   {
3232     list_index= (max_list_index + min_list_index) >> 1;
3233     cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns,
3234                           num_columns);
3235     if (cmp > 0)
3236       min_list_index= list_index + 1;
3237     else if (cmp < 0)
3238     {
3239       if (!list_index)
3240         goto notfound;
3241       max_list_index= list_index - 1;
3242     }
3243     else
3244     {
3245       *part_id= (uint32)list_col_array[list_index*num_columns].partition_id;
3246       DBUG_RETURN(0);
3247     }
3248   }
3249 notfound:
3250   if (part_info->defined_max_value)
3251   {
3252     *part_id= part_info->default_partition_id;
3253     DBUG_RETURN(0);
3254   }
3255   *part_id= 0;
3256   DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
3257 }
3258 
3259 
get_partition_id_list(partition_info * part_info,uint32 * part_id,longlong * func_value)3260 int get_partition_id_list(partition_info *part_info,
3261                           uint32 *part_id,
3262                           longlong *func_value)
3263 {
3264   LIST_PART_ENTRY *list_array= part_info->list_array;
3265   int list_index;
3266   int min_list_index= 0;
3267   int max_list_index= part_info->num_list_values - 1;
3268   longlong part_func_value;
3269   int error= part_val_int(part_info->part_expr, &part_func_value);
3270   longlong list_value;
3271   bool unsigned_flag= part_info->part_expr->unsigned_flag;
3272   DBUG_ENTER("get_partition_id_list");
3273 
3274   if (error)
3275     goto notfound;
3276 
3277   if (part_info->part_expr->null_value)
3278   {
3279     if (part_info->has_null_value)
3280     {
3281       *part_id= part_info->has_null_part_id;
3282       DBUG_RETURN(0);
3283     }
3284     goto notfound;
3285   }
3286   *func_value= part_func_value;
3287   if (unsigned_flag)
3288     part_func_value-= 0x8000000000000000ULL;
3289   while (max_list_index >= min_list_index)
3290   {
3291     list_index= (max_list_index + min_list_index) >> 1;
3292     list_value= list_array[list_index].list_value;
3293     if (list_value < part_func_value)
3294       min_list_index= list_index + 1;
3295     else if (list_value > part_func_value)
3296     {
3297       if (!list_index)
3298         goto notfound;
3299       max_list_index= list_index - 1;
3300     }
3301     else
3302     {
3303       *part_id= (uint32)list_array[list_index].partition_id;
3304       DBUG_RETURN(0);
3305     }
3306   }
3307 notfound:
3308   if (part_info->defined_max_value)
3309   {
3310     *part_id= part_info->default_partition_id;
3311     DBUG_RETURN(0);
3312   }
3313   *part_id= 0;
3314   DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
3315 }
3316 
3317 
get_partition_id_cols_list_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint,uint32 nparts)3318 uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
3319                                                bool left_endpoint,
3320                                                bool include_endpoint,
3321                                                uint32 nparts)
3322 {
3323   part_column_list_val *list_col_array= part_info->list_col_array;
3324   uint num_columns= part_info->part_field_list.elements;
3325   uint list_index;
3326   uint min_list_index= 0;
3327   int cmp;
3328   /* Notice that max_list_index = last_index + 1 here! */
3329   uint max_list_index= part_info->num_list_values;
3330   DBUG_ENTER("get_partition_id_cols_list_for_endpoint");
3331 
3332   /* Find the matching partition (including taking endpoint into account). */
3333   do
3334   {
3335     /* Midpoint, adjusted down, so it can never be >= max_list_index. */
3336     list_index= (max_list_index + min_list_index) >> 1;
3337     cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns,
3338                                  nparts, left_endpoint, include_endpoint);
3339     if (cmp > 0)
3340     {
3341       min_list_index= list_index + 1;
3342     }
3343     else
3344     {
3345       max_list_index= list_index;
3346       if (cmp == 0)
3347         break;
3348     }
3349   } while (max_list_index > min_list_index);
3350   list_index= max_list_index;
3351 
3352   /* Given value must be LESS THAN or EQUAL to the found partition. */
3353   DBUG_ASSERT(list_index == part_info->num_list_values ||
3354               (0 >= cmp_rec_and_tuple_prune(list_col_array +
3355                                               list_index*num_columns,
3356                                             nparts, left_endpoint,
3357                                             include_endpoint)));
3358   /* Given value must be GREATER THAN the previous partition. */
3359   DBUG_ASSERT(list_index == 0 ||
3360               (0 < cmp_rec_and_tuple_prune(list_col_array +
3361                                             (list_index - 1)*num_columns,
3362                                            nparts, left_endpoint,
3363                                            include_endpoint)));
3364 
3365   /* Include the right endpoint if not already passed end of array. */
3366   if (!left_endpoint && include_endpoint && cmp == 0 &&
3367       list_index < part_info->num_list_values)
3368     list_index++;
3369 
3370   DBUG_RETURN(list_index);
3371 }
3372 
3373 
3374 /**
3375   Find the sub-array part_info->list_array that corresponds to given interval.
3376 
3377   @param part_info         Partitioning info (partitioning type must be LIST)
3378   @param left_endpoint     TRUE  - the interval is [a; +inf) or (a; +inf)
3379                            FALSE - the interval is (-inf; a] or (-inf; a)
3380   @param include_endpoint  TRUE iff the interval includes the endpoint
3381 
3382   This function finds the sub-array of part_info->list_array where values of
3383   list_array[idx].list_value are contained within the specifed interval.
3384   list_array is ordered by list_value, so
3385   1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
3386      sought sub-array starts at some index idx and continues till array end.
3387      The function returns first number idx, such that
3388      list_array[idx].list_value is contained within the passed interval.
3389 
3390   2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
3391      sought sub-array starts at array start and continues till some last
3392      index idx.
3393      The function returns first number idx, such that
3394      list_array[idx].list_value is NOT contained within the passed interval.
3395      If all array elements are contained, part_info->num_list_values is
3396      returned.
3397 
3398   @note The caller will call this function and then will run along the
3399   sub-array of list_array to collect partition ids. If the number of list
3400   values is significantly higher then number of partitions, this could be slow
3401   and we could invent some other approach. The "run over list array" part is
3402   already wrapped in a get_next()-like function.
3403 
3404   @return The index of corresponding sub-array of part_info->list_array.
3405 */
3406 
get_list_array_idx_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)3407 uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
3408                                                bool left_endpoint,
3409                                                bool include_endpoint)
3410 {
3411   uint32 res;
3412   copy_to_part_field_buffers(part_info->part_field_array,
3413                              part_info->part_field_buffers,
3414                              part_info->restore_part_field_ptrs);
3415   res= get_list_array_idx_for_endpoint(part_info, left_endpoint,
3416                                        include_endpoint);
3417   restore_part_field_pointers(part_info->part_field_array,
3418                               part_info->restore_part_field_ptrs);
3419   return res;
3420 }
3421 
get_list_array_idx_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)3422 uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
3423                                        bool left_endpoint,
3424                                        bool include_endpoint)
3425 {
3426   LIST_PART_ENTRY *list_array= part_info->list_array;
3427   uint list_index;
3428   uint min_list_index= 0, max_list_index= part_info->num_list_values - 1;
3429   longlong list_value;
3430   /* Get the partitioning function value for the endpoint */
3431   longlong part_func_value=
3432     part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3433   bool unsigned_flag= part_info->part_expr->unsigned_flag;
3434   DBUG_ENTER("get_list_array_idx_for_endpoint");
3435 
3436   if (part_info->part_expr->null_value)
3437   {
3438     /*
3439       Special handling for MONOTONIC functions that can return NULL for
3440       values that are comparable. I.e.
3441       '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3442       returns NULL which cannot be compared used <, >, <=, >= etc.
3443 
3444       Otherwise, just return the the first index (lowest value).
3445     */
3446     enum_monotonicity_info monotonic;
3447     monotonic= part_info->part_expr->get_monotonicity_info();
3448     if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3449         monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL)
3450     {
3451       /* F(col) can not return NULL, return index with lowest value */
3452       DBUG_RETURN(0);
3453     }
3454   }
3455 
3456   if (unsigned_flag)
3457     part_func_value-= 0x8000000000000000ULL;
3458   DBUG_ASSERT(part_info->num_list_values);
3459   do
3460   {
3461     list_index= (max_list_index + min_list_index) >> 1;
3462     list_value= list_array[list_index].list_value;
3463     if (list_value < part_func_value)
3464       min_list_index= list_index + 1;
3465     else if (list_value > part_func_value)
3466     {
3467       if (!list_index)
3468         goto notfound;
3469       max_list_index= list_index - 1;
3470     }
3471     else
3472     {
3473       DBUG_RETURN(list_index + MY_TEST(left_endpoint ^ include_endpoint));
3474     }
3475   } while (max_list_index >= min_list_index);
3476 notfound:
3477   if (list_value < part_func_value)
3478     list_index++;
3479   DBUG_RETURN(list_index);
3480 }
3481 
3482 
get_partition_id_range_col(partition_info * part_info,uint32 * part_id,longlong * func_value)3483 int get_partition_id_range_col(partition_info *part_info,
3484                                uint32 *part_id,
3485                                longlong *func_value)
3486 {
3487   part_column_list_val *range_col_array= part_info->range_col_array;
3488   uint num_columns= part_info->part_field_list.elements;
3489   uint max_partition= part_info->num_parts - 1;
3490   uint min_part_id= 0;
3491   uint max_part_id= max_partition;
3492   uint loc_part_id;
3493   DBUG_ENTER("get_partition_id_range_col");
3494 
3495   while (max_part_id > min_part_id)
3496   {
3497     loc_part_id= (max_part_id + min_part_id + 1) >> 1;
3498     if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
3499                           num_columns) >= 0)
3500       min_part_id= loc_part_id + 1;
3501     else
3502       max_part_id= loc_part_id - 1;
3503   }
3504   loc_part_id= max_part_id;
3505   if (loc_part_id != max_partition)
3506     if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
3507                           num_columns) >= 0)
3508       loc_part_id++;
3509   *part_id= (uint32)loc_part_id;
3510   if (loc_part_id == max_partition &&
3511       (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns,
3512                          num_columns) >= 0))
3513     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
3514 
3515   DBUG_PRINT("exit",("partition: %d", *part_id));
3516   DBUG_RETURN(0);
3517 }
3518 
3519 
vers_get_partition_id(partition_info * part_info,uint32 * part_id,longlong * func_value)3520 int vers_get_partition_id(partition_info *part_info, uint32 *part_id,
3521                           longlong *func_value)
3522 {
3523   DBUG_ENTER("vers_get_partition_id");
3524   Field *row_end= part_info->part_field_array[STAT_TRX_END];
3525   Vers_part_info *vers_info= part_info->vers_info;
3526 
3527   if (row_end->is_max() || row_end->is_null())
3528     *part_id= vers_info->now_part->id;
3529   else // row is historical
3530   {
3531     longlong *range_value= part_info->range_int_array;
3532     uint max_hist_id= part_info->num_parts - 2;
3533     uint min_hist_id= 0, loc_hist_id= vers_info->hist_part->id;
3534     ulong unused;
3535     my_time_t ts;
3536 
3537     if (!range_value)
3538       goto done; // fastpath
3539 
3540     ts= row_end->get_timestamp(&unused);
3541     if ((loc_hist_id == 0 || range_value[loc_hist_id - 1] < ts) &&
3542         (loc_hist_id == max_hist_id || range_value[loc_hist_id] >= ts))
3543       goto done; // fastpath
3544 
3545     while (max_hist_id > min_hist_id)
3546     {
3547       loc_hist_id= (max_hist_id + min_hist_id) / 2;
3548       if (range_value[loc_hist_id] <= ts)
3549         min_hist_id= loc_hist_id + 1;
3550       else
3551         max_hist_id= loc_hist_id;
3552     }
3553     loc_hist_id= max_hist_id;
3554 done:
3555     *part_id= (uint32)loc_hist_id;
3556   }
3557   DBUG_PRINT("exit",("partition: %d", *part_id));
3558   DBUG_RETURN(0);
3559 }
3560 
3561 
get_partition_id_range(partition_info * part_info,uint32 * part_id,longlong * func_value)3562 int get_partition_id_range(partition_info *part_info,
3563                            uint32 *part_id,
3564                            longlong *func_value)
3565 {
3566   longlong *range_array= part_info->range_int_array;
3567   uint max_partition= part_info->num_parts - 1;
3568   uint min_part_id= 0;
3569   uint max_part_id= max_partition;
3570   uint loc_part_id;
3571   longlong part_func_value;
3572   int error= part_val_int(part_info->part_expr, &part_func_value);
3573   bool unsigned_flag= part_info->part_expr->unsigned_flag;
3574   DBUG_ENTER("get_partition_id_range");
3575 
3576   if (unlikely(error))
3577     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
3578 
3579   if (part_info->part_expr->null_value)
3580   {
3581     *part_id= 0;
3582     DBUG_RETURN(0);
3583   }
3584   *func_value= part_func_value;
3585   if (unsigned_flag)
3586     part_func_value-= 0x8000000000000000ULL;
3587   /* Search for the partition containing part_func_value */
3588   while (max_part_id > min_part_id)
3589   {
3590     loc_part_id= (max_part_id + min_part_id) / 2;
3591     if (range_array[loc_part_id] <= part_func_value)
3592       min_part_id= loc_part_id + 1;
3593     else
3594       max_part_id= loc_part_id;
3595   }
3596   loc_part_id= max_part_id;
3597   *part_id= (uint32)loc_part_id;
3598   if (loc_part_id == max_partition &&
3599       part_func_value >= range_array[loc_part_id] &&
3600       !part_info->defined_max_value)
3601     DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
3602 
3603   DBUG_PRINT("exit",("partition: %d", *part_id));
3604   DBUG_RETURN(0);
3605 }
3606 
3607 
3608 /*
3609   Find the sub-array of part_info->range_int_array that covers given interval
3610 
3611   SYNOPSIS
3612     get_partition_id_range_for_endpoint()
3613       part_info         Partitioning info (partitioning type must be RANGE)
3614       left_endpoint     TRUE  - the interval is [a; +inf) or (a; +inf)
3615                         FALSE - the interval is (-inf; a] or (-inf; a).
3616       include_endpoint  TRUE <=> the endpoint itself is included in the
3617                         interval
3618 
3619   DESCRIPTION
3620     This function finds the sub-array of part_info->range_int_array where the
3621     elements have non-empty intersections with the given interval.
3622 
3623     A range_int_array element at index idx represents the interval
3624 
3625       [range_int_array[idx-1], range_int_array[idx]),
3626 
3627     intervals are disjoint and ordered by their right bound, so
3628 
3629     1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
3630        sought sub-array starts at some index idx and continues till array end.
3631        The function returns first number idx, such that the interval
3632        represented by range_int_array[idx] has non empty intersection with
3633        the passed interval.
3634 
3635     2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
3636        sought sub-array starts at array start and continues till some last
3637        index idx.
3638        The function returns first number idx, such that the interval
3639        represented by range_int_array[idx] has EMPTY intersection with the
3640        passed interval.
3641        If the interval represented by the last array element has non-empty
3642        intersection with the passed interval, part_info->num_parts is
3643        returned.
3644 
3645   RETURN
3646     The edge of corresponding part_info->range_int_array sub-array.
3647 */
3648 
3649 static uint32
get_partition_id_range_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)3650 get_partition_id_range_for_endpoint_charset(partition_info *part_info,
3651                                             bool left_endpoint,
3652                                             bool include_endpoint)
3653 {
3654   uint32 res;
3655   copy_to_part_field_buffers(part_info->part_field_array,
3656                              part_info->part_field_buffers,
3657                              part_info->restore_part_field_ptrs);
3658   res= get_partition_id_range_for_endpoint(part_info, left_endpoint,
3659                                            include_endpoint);
3660   restore_part_field_pointers(part_info->part_field_array,
3661                               part_info->restore_part_field_ptrs);
3662   return res;
3663 }
3664 
get_partition_id_range_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)3665 uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
3666                                            bool left_endpoint,
3667                                            bool include_endpoint)
3668 {
3669   longlong *range_array= part_info->range_int_array;
3670   longlong part_end_val;
3671   uint max_partition= part_info->num_parts - 1;
3672   uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
3673   /* Get the partitioning function value for the endpoint */
3674   longlong part_func_value=
3675     part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3676 
3677   bool unsigned_flag= part_info->part_expr->unsigned_flag;
3678   DBUG_ENTER("get_partition_id_range_for_endpoint");
3679 
3680   if (part_info->part_expr->null_value)
3681   {
3682     /*
3683       Special handling for MONOTONIC functions that can return NULL for
3684       values that are comparable. I.e.
3685       '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3686       returns NULL which cannot be compared used <, >, <=, >= etc.
3687 
3688       Otherwise, just return the first partition
3689       (may be included if not left endpoint)
3690     */
3691     enum_monotonicity_info monotonic;
3692     monotonic= part_info->part_expr->get_monotonicity_info();
3693     if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3694         monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL)
3695     {
3696       /* F(col) can not return NULL, return partition with lowest value */
3697       if (!left_endpoint && include_endpoint)
3698         DBUG_RETURN(1);
3699       DBUG_RETURN(0);
3700 
3701     }
3702   }
3703 
3704   if (unsigned_flag)
3705     part_func_value-= 0x8000000000000000ULL;
3706   if (left_endpoint && !include_endpoint)
3707     part_func_value++;
3708 
3709   /*
3710     Search for the partition containing part_func_value
3711     (including the right endpoint).
3712   */
3713   while (max_part_id > min_part_id)
3714   {
3715     loc_part_id= (max_part_id + min_part_id) / 2;
3716     if (range_array[loc_part_id] < part_func_value)
3717       min_part_id= loc_part_id + 1;
3718     else
3719       max_part_id= loc_part_id;
3720   }
3721   loc_part_id= max_part_id;
3722 
3723   /* Adjust for endpoints */
3724   part_end_val= range_array[loc_part_id];
3725   if (left_endpoint)
3726   {
3727     DBUG_ASSERT(part_func_value > part_end_val ?
3728                 (loc_part_id == max_partition &&
3729                  !part_info->defined_max_value) :
3730                 1);
3731     /*
3732       In case of PARTITION p VALUES LESS THAN MAXVALUE
3733       the maximum value is in the current (last) partition.
3734       If value is equal or greater than the endpoint,
3735       the range starts from the next partition.
3736     */
3737     if (part_func_value >= part_end_val &&
3738         (loc_part_id < max_partition || !part_info->defined_max_value))
3739       loc_part_id++;
3740     if (part_info->part_type == VERSIONING_PARTITION &&
3741         part_func_value < INT_MAX32 &&
3742         loc_part_id > part_info->vers_info->hist_part->id)
3743     {
3744       /*
3745         Historical query with AS OF point after the last history partition must
3746         include last history partition because it can be overflown (contain
3747         history rows out of right endpoint).
3748       */
3749       loc_part_id= part_info->vers_info->hist_part->id;
3750     }
3751   }
3752   else
3753   {
3754     /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */
3755     if (include_endpoint && loc_part_id < max_partition &&
3756         part_func_value == part_end_val)
3757       loc_part_id++;
3758 
3759     /* Right endpoint, set end after correct partition */
3760     loc_part_id++;
3761   }
3762   DBUG_RETURN(loc_part_id);
3763 }
3764 
3765 
get_partition_id_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3766 int get_partition_id_hash_nosub(partition_info *part_info,
3767                                  uint32 *part_id,
3768                                  longlong *func_value)
3769 {
3770   return get_part_id_hash(part_info->num_parts, part_info->part_expr,
3771                           part_id, func_value);
3772 }
3773 
3774 
get_partition_id_linear_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3775 int get_partition_id_linear_hash_nosub(partition_info *part_info,
3776                                         uint32 *part_id,
3777                                         longlong *func_value)
3778 {
3779   return get_part_id_linear_hash(part_info, part_info->num_parts,
3780                                  part_info->part_expr, part_id, func_value);
3781 }
3782 
3783 
get_partition_id_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3784 int get_partition_id_key_nosub(partition_info *part_info,
3785                                 uint32 *part_id,
3786                                 longlong *func_value)
3787 {
3788   *part_id= get_part_id_key(part_info->table->file,
3789                             part_info->part_field_array,
3790                             part_info->num_parts, func_value);
3791   return 0;
3792 }
3793 
3794 
get_partition_id_linear_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3795 int get_partition_id_linear_key_nosub(partition_info *part_info,
3796                                       uint32 *part_id,
3797                                       longlong *func_value)
3798 {
3799   *part_id= get_part_id_linear_key(part_info,
3800                                    part_info->part_field_array,
3801                                    part_info->num_parts, func_value);
3802   return 0;
3803 }
3804 
3805 
get_partition_id_with_sub(partition_info * part_info,uint32 * part_id,longlong * func_value)3806 int get_partition_id_with_sub(partition_info *part_info,
3807                               uint32 *part_id,
3808                               longlong *func_value)
3809 {
3810   uint32 loc_part_id, sub_part_id;
3811   uint num_subparts;
3812   int error;
3813   DBUG_ENTER("get_partition_id_with_sub");
3814 
3815   if (unlikely((error= part_info->get_part_partition_id(part_info,
3816                                                         &loc_part_id,
3817                                                         func_value))))
3818   {
3819     DBUG_RETURN(error);
3820   }
3821   num_subparts= part_info->num_subparts;
3822   if (unlikely((error= part_info->get_subpartition_id(part_info,
3823                                                       &sub_part_id))))
3824   {
3825     DBUG_RETURN(error);
3826   }
3827   *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
3828   DBUG_RETURN(0);
3829 }
3830 
3831 
3832 /*
3833   This function is used to calculate the subpartition id
3834 
3835   SYNOPSIS
3836     get_subpartition_id()
3837     part_info           A reference to the partition_info struct where all the
3838                         desired information is given
3839 
3840   RETURN VALUE
3841     part_id             The subpartition identity
3842 
3843   DESCRIPTION
3844     A routine used in some SELECT's when only partial knowledge of the
3845     partitions is known.
3846 
3847     It is actually 4 different variants of this function which are called
3848     through a function pointer.
3849 
3850     get_partition_id_hash_sub
3851     get_partition_id_key_sub
3852     get_partition_id_linear_hash_sub
3853     get_partition_id_linear_key_sub
3854 */
3855 
get_partition_id_hash_sub(partition_info * part_info,uint32 * part_id)3856 int get_partition_id_hash_sub(partition_info *part_info,
3857                               uint32 *part_id)
3858 {
3859   longlong func_value;
3860   return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
3861                           part_id, &func_value);
3862 }
3863 
3864 
get_partition_id_linear_hash_sub(partition_info * part_info,uint32 * part_id)3865 int get_partition_id_linear_hash_sub(partition_info *part_info,
3866                                      uint32 *part_id)
3867 {
3868   longlong func_value;
3869   return get_part_id_linear_hash(part_info, part_info->num_subparts,
3870                                  part_info->subpart_expr, part_id,
3871                                  &func_value);
3872 }
3873 
3874 
get_partition_id_key_sub(partition_info * part_info,uint32 * part_id)3875 int get_partition_id_key_sub(partition_info *part_info,
3876                              uint32 *part_id)
3877 {
3878   longlong func_value;
3879   *part_id= get_part_id_key(part_info->table->file,
3880                             part_info->subpart_field_array,
3881                             part_info->num_subparts, &func_value);
3882   return FALSE;
3883 }
3884 
3885 
get_partition_id_linear_key_sub(partition_info * part_info,uint32 * part_id)3886 int get_partition_id_linear_key_sub(partition_info *part_info,
3887                                        uint32 *part_id)
3888 {
3889   longlong func_value;
3890   *part_id= get_part_id_linear_key(part_info,
3891                                    part_info->subpart_field_array,
3892                                    part_info->num_subparts, &func_value);
3893   return FALSE;
3894 }
3895 
3896 
3897 /*
3898   Set an indicator on all partition fields that are set by the key
3899 
3900   SYNOPSIS
3901     set_PF_fields_in_key()
3902     key_info                   Information about the index
3903     key_length                 Length of key
3904 
3905   RETURN VALUE
3906     TRUE                       Found partition field set by key
3907     FALSE                      No partition field set by key
3908 */
3909 
set_PF_fields_in_key(KEY * key_info,uint key_length)3910 static bool set_PF_fields_in_key(KEY *key_info, uint key_length)
3911 {
3912   KEY_PART_INFO *key_part;
3913   bool found_part_field= FALSE;
3914   DBUG_ENTER("set_PF_fields_in_key");
3915 
3916   for (key_part= key_info->key_part; (int)key_length > 0; key_part++)
3917   {
3918     if (key_part->null_bit)
3919       key_length--;
3920     if (key_part->type == HA_KEYTYPE_BIT)
3921     {
3922       if (((Field_bit*)key_part->field)->bit_len)
3923         key_length--;
3924     }
3925     if (key_part->key_part_flag & (HA_BLOB_PART + HA_VAR_LENGTH_PART))
3926     {
3927       key_length-= HA_KEY_BLOB_LENGTH;
3928     }
3929     if (key_length < key_part->length)
3930       break;
3931     key_length-= key_part->length;
3932     if (key_part->field->flags & FIELD_IN_PART_FUNC_FLAG)
3933     {
3934       found_part_field= TRUE;
3935       key_part->field->flags|= GET_FIXED_FIELDS_FLAG;
3936     }
3937   }
3938   DBUG_RETURN(found_part_field);
3939 }
3940 
3941 
3942 /*
3943   We have found that at least one partition field was set by a key, now
3944   check if a partition function has all its fields bound or not.
3945 
3946   SYNOPSIS
3947     check_part_func_bound()
3948     ptr                     Array of fields NULL terminated (partition fields)
3949 
3950   RETURN VALUE
3951     TRUE                    All fields in partition function are set
3952     FALSE                   Not all fields in partition function are set
3953 */
3954 
check_part_func_bound(Field ** ptr)3955 static bool check_part_func_bound(Field **ptr)
3956 {
3957   bool result= TRUE;
3958   DBUG_ENTER("check_part_func_bound");
3959 
3960   for (; *ptr; ptr++)
3961   {
3962     if (!((*ptr)->flags & GET_FIXED_FIELDS_FLAG))
3963     {
3964       result= FALSE;
3965       break;
3966     }
3967   }
3968   DBUG_RETURN(result);
3969 }
3970 
3971 
3972 /*
3973   Get the id of the subpartitioning part by using the key buffer of the
3974   index scan.
3975 
3976   SYNOPSIS
3977     get_sub_part_id_from_key()
3978     table         The table object
3979     buf           A buffer that can be used to evaluate the partition function
3980     key_info      The index object
3981     key_spec      A key_range containing key and key length
3982     out:part_id   The returned partition id
3983 
3984   RETURN VALUES
3985     TRUE                    All fields in partition function are set
3986     FALSE                   Not all fields in partition function are set
3987 
3988   DESCRIPTION
3989     Use key buffer to set-up record in buf, move field pointers and
3990     get the partition identity and restore field pointers afterwards.
3991 */
3992 
get_sub_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)3993 static int get_sub_part_id_from_key(const TABLE *table,uchar *buf,
3994                                     KEY *key_info,
3995                                     const key_range *key_spec,
3996                                     uint32 *part_id)
3997 {
3998   uchar *rec0= table->record[0];
3999   partition_info *part_info= table->part_info;
4000   int res;
4001   DBUG_ENTER("get_sub_part_id_from_key");
4002 
4003   key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
4004   if (likely(rec0 == buf))
4005   {
4006     res= part_info->get_subpartition_id(part_info, part_id);
4007   }
4008   else
4009   {
4010     Field **part_field_array= part_info->subpart_field_array;
4011     part_info->table->move_fields(part_field_array, buf, rec0);
4012     res= part_info->get_subpartition_id(part_info, part_id);
4013     part_info->table->move_fields(part_field_array, rec0, buf);
4014   }
4015   DBUG_RETURN(res);
4016 }
4017 
4018 /*
4019   Get the id of the partitioning part by using the key buffer of the
4020   index scan.
4021 
4022   SYNOPSIS
4023     get_part_id_from_key()
4024     table         The table object
4025     buf           A buffer that can be used to evaluate the partition function
4026     key_info      The index object
4027     key_spec      A key_range containing key and key length
4028     out:part_id   Partition to use
4029 
4030   RETURN VALUES
4031     TRUE          Partition to use not found
4032     FALSE         Ok, part_id indicates partition to use
4033 
4034   DESCRIPTION
4035     Use key buffer to set-up record in buf, move field pointers and
4036     get the partition identity and restore field pointers afterwards.
4037 */
4038 
get_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)4039 bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
4040                           const key_range *key_spec, uint32 *part_id)
4041 {
4042   bool result;
4043   uchar *rec0= table->record[0];
4044   partition_info *part_info= table->part_info;
4045   longlong func_value;
4046   DBUG_ENTER("get_part_id_from_key");
4047 
4048   key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
4049   if (likely(rec0 == buf))
4050   {
4051     result= part_info->get_part_partition_id(part_info, part_id,
4052                                              &func_value);
4053   }
4054   else
4055   {
4056     Field **part_field_array= part_info->part_field_array;
4057     part_info->table->move_fields(part_field_array, buf, rec0);
4058     result= part_info->get_part_partition_id(part_info, part_id,
4059                                              &func_value);
4060     part_info->table->move_fields(part_field_array, rec0, buf);
4061   }
4062   DBUG_RETURN(result);
4063 }
4064 
4065 /*
4066   Get the partitioning id of the full PF by using the key buffer of the
4067   index scan.
4068 
4069   SYNOPSIS
4070     get_full_part_id_from_key()
4071     table         The table object
4072     buf           A buffer that is used to evaluate the partition function
4073     key_info      The index object
4074     key_spec      A key_range containing key and key length
4075     out:part_spec A partition id containing start part and end part
4076 
4077   RETURN VALUES
4078     part_spec
4079     No partitions to scan is indicated by end_part > start_part when returning
4080 
4081   DESCRIPTION
4082     Use key buffer to set-up record in buf, move field pointers if needed and
4083     get the partition identity and restore field pointers afterwards.
4084 */
4085 
get_full_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,part_id_range * part_spec)4086 void get_full_part_id_from_key(const TABLE *table, uchar *buf,
4087                                KEY *key_info,
4088                                const key_range *key_spec,
4089                                part_id_range *part_spec)
4090 {
4091   bool result;
4092   partition_info *part_info= table->part_info;
4093   uchar *rec0= table->record[0];
4094   longlong func_value;
4095   DBUG_ENTER("get_full_part_id_from_key");
4096 
4097   key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
4098   if (likely(rec0 == buf))
4099   {
4100     result= part_info->get_partition_id(part_info, &part_spec->start_part,
4101                                         &func_value);
4102   }
4103   else
4104   {
4105     Field **part_field_array= part_info->full_part_field_array;
4106     part_info->table->move_fields(part_field_array, buf, rec0);
4107     result= part_info->get_partition_id(part_info, &part_spec->start_part,
4108                                         &func_value);
4109     part_info->table->move_fields(part_field_array, rec0, buf);
4110   }
4111   part_spec->end_part= part_spec->start_part;
4112   if (unlikely(result))
4113     part_spec->start_part++;
4114   DBUG_VOID_RETURN;
4115 }
4116 
4117 
4118 /**
4119   @brief Verify that all rows in a table is in the given partition
4120 
4121   @param table      Table which contains the data that will be checked if
4122                     it is matching the partition definition.
4123   @param part_table Partitioned table containing the partition to check.
4124   @param part_id    Which partition to match with.
4125 
4126   @return Operation status
4127     @retval TRUE                Not all rows match the given partition
4128     @retval FALSE               OK
4129 */
verify_data_with_partition(TABLE * table,TABLE * part_table,uint32 part_id)4130 bool verify_data_with_partition(TABLE *table, TABLE *part_table,
4131                                 uint32 part_id)
4132 {
4133   uint32 found_part_id;
4134   longlong func_value;                     /* Unused */
4135   handler *file;
4136   int error;
4137   uchar *old_rec;
4138   partition_info *part_info;
4139   DBUG_ENTER("verify_data_with_partition");
4140   DBUG_ASSERT(table && table->file && part_table && part_table->part_info &&
4141               part_table->file);
4142 
4143   /*
4144     Verify all table rows.
4145     First implementation uses full scan + evaluates partition functions for
4146     every row. TODO: add optimization to use index if possible, see WL#5397.
4147 
4148     1) Open both tables (already done) and set the row buffers to use
4149        the same buffer (to avoid copy).
4150     2) Init rnd on table.
4151     3) loop over all rows.
4152       3.1) verify that partition_id on the row is correct. Break if error.
4153   */
4154   file= table->file;
4155   part_info= part_table->part_info;
4156   bitmap_union(table->read_set, &part_info->full_part_field_set);
4157   old_rec= part_table->record[0];
4158   part_table->record[0]= table->record[0];
4159   part_info->table->move_fields(part_info->full_part_field_array, table->record[0], old_rec);
4160   if (unlikely(error= file->ha_rnd_init_with_error(TRUE)))
4161     goto err;
4162 
4163   do
4164   {
4165     if (unlikely((error= file->ha_rnd_next(table->record[0]))))
4166     {
4167       if (error == HA_ERR_END_OF_FILE)
4168         error= 0;
4169       else
4170         file->print_error(error, MYF(0));
4171       break;
4172     }
4173     if (unlikely((error= part_info->get_partition_id(part_info, &found_part_id,
4174                                                      &func_value))))
4175     {
4176       part_table->file->print_error(error, MYF(0));
4177       break;
4178     }
4179     DEBUG_SYNC(current_thd, "swap_partition_first_row_read");
4180     if (found_part_id != part_id)
4181     {
4182       my_error(ER_ROW_DOES_NOT_MATCH_PARTITION, MYF(0));
4183       error= 1;
4184       break;
4185     }
4186   } while (TRUE);
4187   (void) file->ha_rnd_end();
4188 err:
4189   part_info->table->move_fields(part_info->full_part_field_array, old_rec,
4190                 table->record[0]);
4191   part_table->record[0]= old_rec;
4192   DBUG_RETURN(unlikely(error) ? TRUE : FALSE);
4193 }
4194 
4195 
4196 /*
4197   Prune the set of partitions to use in query
4198 
4199   SYNOPSIS
4200     prune_partition_set()
4201     table         The table object
4202     out:part_spec Contains start part, end part
4203 
4204   DESCRIPTION
4205     This function is called to prune the range of partitions to scan by
4206     checking the read_partitions bitmap.
4207     If start_part > end_part at return it means no partition needs to be
4208     scanned. If start_part == end_part it always means a single partition
4209     needs to be scanned.
4210 
4211   RETURN VALUE
4212     part_spec
4213 */
prune_partition_set(const TABLE * table,part_id_range * part_spec)4214 void prune_partition_set(const TABLE *table, part_id_range *part_spec)
4215 {
4216   int last_partition= -1;
4217   uint i;
4218   partition_info *part_info= table->part_info;
4219 
4220   DBUG_ENTER("prune_partition_set");
4221   for (i= part_spec->start_part; i <= part_spec->end_part; i++)
4222   {
4223     if (bitmap_is_set(&(part_info->read_partitions), i))
4224     {
4225       DBUG_PRINT("info", ("Partition %d is set", i));
4226       if (last_partition == -1)
4227         /* First partition found in set and pruned bitmap */
4228         part_spec->start_part= i;
4229       last_partition= i;
4230     }
4231   }
4232   if (last_partition == -1)
4233     /* No partition found in pruned bitmap */
4234     part_spec->start_part= part_spec->end_part + 1;
4235   else //if (last_partition != -1)
4236     part_spec->end_part= last_partition;
4237 
4238   DBUG_VOID_RETURN;
4239 }
4240 
4241 /*
4242   Get the set of partitions to use in query.
4243 
4244   SYNOPSIS
4245     get_partition_set()
4246     table         The table object
4247     buf           A buffer that can be used to evaluate the partition function
4248     index         The index of the key used, if MAX_KEY no index used
4249     key_spec      A key_range containing key and key length
4250     out:part_spec Contains start part, end part and indicator if bitmap is
4251                   used for which partitions to scan
4252 
4253   DESCRIPTION
4254     This function is called to discover which partitions to use in an index
4255     scan or a full table scan.
4256     It returns a range of partitions to scan. If there are holes in this
4257     range with partitions that are not needed to scan a bit array is used
4258     to signal which partitions to use and which not to use.
4259     If start_part > end_part at return it means no partition needs to be
4260     scanned. If start_part == end_part it always means a single partition
4261     needs to be scanned.
4262 
4263   RETURN VALUE
4264     part_spec
4265 */
get_partition_set(const TABLE * table,uchar * buf,const uint index,const key_range * key_spec,part_id_range * part_spec)4266 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
4267                        const key_range *key_spec, part_id_range *part_spec)
4268 {
4269   partition_info *part_info= table->part_info;
4270   uint num_parts= part_info->get_tot_partitions();
4271   uint i, part_id;
4272   uint sub_part= num_parts;
4273   uint32 part_part= num_parts;
4274   KEY *key_info= NULL;
4275   bool found_part_field= FALSE;
4276   DBUG_ENTER("get_partition_set");
4277 
4278   part_spec->start_part= 0;
4279   part_spec->end_part= num_parts - 1;
4280   if ((index < MAX_KEY) &&
4281        key_spec && key_spec->flag == (uint)HA_READ_KEY_EXACT &&
4282        part_info->some_fields_in_PF.is_set(index))
4283   {
4284     key_info= table->key_info+index;
4285     /*
4286       The index can potentially provide at least one PF-field (field in the
4287       partition function). Thus it is interesting to continue our probe.
4288     */
4289     if (key_spec->length == key_info->key_length)
4290     {
4291       /*
4292         The entire key is set so we can check whether we can immediately
4293         derive either the complete PF or if we can derive either
4294         the top PF or the subpartitioning PF. This can be established by
4295         checking precalculated bits on each index.
4296       */
4297       if (part_info->all_fields_in_PF.is_set(index))
4298       {
4299         /*
4300           We can derive the exact partition to use, no more than this one
4301           is needed.
4302         */
4303         get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
4304         /*
4305           Check if range can be adjusted by looking in read_partitions
4306         */
4307         prune_partition_set(table, part_spec);
4308         DBUG_VOID_RETURN;
4309       }
4310       else if (part_info->is_sub_partitioned())
4311       {
4312         if (part_info->all_fields_in_SPF.is_set(index))
4313         {
4314           if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
4315           {
4316             part_spec->start_part= num_parts;
4317             DBUG_VOID_RETURN;
4318           }
4319         }
4320         else if (part_info->all_fields_in_PPF.is_set(index))
4321         {
4322           if (get_part_id_from_key(table,buf,key_info,
4323                                    key_spec,(uint32*)&part_part))
4324           {
4325             /*
4326               The value of the RANGE or LIST partitioning was outside of
4327               allowed values. Thus it is certain that the result of this
4328               scan will be empty.
4329             */
4330             part_spec->start_part= num_parts;
4331             DBUG_VOID_RETURN;
4332           }
4333         }
4334       }
4335     }
4336     else
4337     {
4338       /*
4339         Set an indicator on all partition fields that are bound.
4340         If at least one PF-field was bound it pays off to check whether
4341         the PF or PPF or SPF has been bound.
4342         (PF = Partition Function, SPF = Subpartition Function and
4343          PPF = Partition Function part of subpartitioning)
4344       */
4345       if ((found_part_field= set_PF_fields_in_key(key_info,
4346                                                   key_spec->length)))
4347       {
4348         if (check_part_func_bound(part_info->full_part_field_array))
4349         {
4350           /*
4351             We were able to bind all fields in the partition function even
4352             by using only a part of the key. Calculate the partition to use.
4353           */
4354           get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
4355           clear_indicator_in_key_fields(key_info);
4356           /*
4357             Check if range can be adjusted by looking in read_partitions
4358           */
4359           prune_partition_set(table, part_spec);
4360           DBUG_VOID_RETURN;
4361         }
4362         else if (part_info->is_sub_partitioned())
4363         {
4364           if (check_part_func_bound(part_info->subpart_field_array))
4365           {
4366             if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
4367             {
4368               part_spec->start_part= num_parts;
4369               clear_indicator_in_key_fields(key_info);
4370               DBUG_VOID_RETURN;
4371             }
4372           }
4373           else if (check_part_func_bound(part_info->part_field_array))
4374           {
4375             if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
4376             {
4377               part_spec->start_part= num_parts;
4378               clear_indicator_in_key_fields(key_info);
4379               DBUG_VOID_RETURN;
4380             }
4381           }
4382         }
4383       }
4384     }
4385   }
4386   {
4387     /*
4388       The next step is to analyse the table condition to see whether any
4389       information about which partitions to scan can be derived from there.
4390       Currently not implemented.
4391     */
4392   }
4393   /*
4394     If we come here we have found a range of sorts we have either discovered
4395     nothing or we have discovered a range of partitions with possible holes
4396     in it. We need a bitvector to further the work here.
4397   */
4398   if (!(part_part == num_parts && sub_part == num_parts))
4399   {
4400     /*
4401       We can only arrive here if we are using subpartitioning.
4402     */
4403     if (part_part != num_parts)
4404     {
4405       /*
4406         We know the top partition and need to scan all underlying
4407         subpartitions. This is a range without holes.
4408       */
4409       DBUG_ASSERT(sub_part == num_parts);
4410       part_spec->start_part= part_part * part_info->num_subparts;
4411       part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1;
4412     }
4413     else
4414     {
4415       DBUG_ASSERT(sub_part != num_parts);
4416       part_spec->start_part= sub_part;
4417       part_spec->end_part=sub_part+
4418                            (part_info->num_subparts*(part_info->num_parts-1));
4419       for (i= 0, part_id= sub_part; i < part_info->num_parts;
4420            i++, part_id+= part_info->num_subparts)
4421         ; //Set bit part_id in bit array
4422     }
4423   }
4424   if (found_part_field)
4425     clear_indicator_in_key_fields(key_info);
4426   /*
4427     Check if range can be adjusted by looking in read_partitions
4428   */
4429   prune_partition_set(table, part_spec);
4430   DBUG_VOID_RETURN;
4431 }
4432 
4433 /*
4434    If the table is partitioned we will read the partition info into the
4435    .frm file here.
4436    -------------------------------
4437    |  Fileinfo     64 bytes      |
4438    -------------------------------
4439    | Formnames     7 bytes       |
4440    -------------------------------
4441    | Not used    4021 bytes      |
4442    -------------------------------
4443    | Keyinfo + record            |
4444    -------------------------------
4445    | Padded to next multiple     |
4446    | of IO_SIZE                  |
4447    -------------------------------
4448    | Forminfo     288 bytes      |
4449    -------------------------------
4450    | Screen buffer, to make      |
4451    |field names readable        |
4452    -------------------------------
4453    | Packed field info           |
4454    |17 + 1 + strlen(field_name) |
4455    | + 1 end of file character   |
4456    -------------------------------
4457    | Partition info              |
4458    -------------------------------
4459    We provide the length of partition length in Fileinfo[55-58].
4460 
4461    Read the partition syntax from the frm file and parse it to get the
4462    data structures of the partitioning.
4463 
4464    SYNOPSIS
4465      mysql_unpack_partition()
4466      thd                           Thread object
4467      part_buf                      Partition info from frm file
4468      part_info_len                 Length of partition syntax
4469      table                         Table object of partitioned table
4470      create_table_ind              Is it called from CREATE TABLE
4471      default_db_type               What is the default engine of the table
4472      work_part_info_used           Flag is raised if we don't create new
4473                                    part_info, but used thd->work_part_info
4474 
4475    RETURN VALUE
4476      TRUE                          Error
4477      FALSE                         Sucess
4478 
4479    DESCRIPTION
4480      Read the partition syntax from the current position in the frm file.
4481      Initiate a LEX object, save the list of item tree objects to free after
4482      the query is done. Set-up partition info object such that parser knows
4483      it is called from internally. Call parser to create data structures
4484      (best possible recreation of item trees and so forth since there is no
4485      serialisation of these objects other than in parseable text format).
4486      We need to save the text of the partition functions since it is not
4487      possible to retrace this given an item tree.
4488 */
4489 
mysql_unpack_partition(THD * thd,char * part_buf,uint part_info_len,TABLE * table,bool is_create_table_ind,handlerton * default_db_type,bool * work_part_info_used)4490 bool mysql_unpack_partition(THD *thd,
4491                             char *part_buf, uint part_info_len,
4492                             TABLE* table, bool is_create_table_ind,
4493                             handlerton *default_db_type,
4494                             bool *work_part_info_used)
4495 {
4496   bool result= TRUE;
4497   partition_info *part_info;
4498   CHARSET_INFO *old_character_set_client= thd->variables.character_set_client;
4499   LEX *old_lex= thd->lex;
4500   LEX lex;
4501   PSI_statement_locker *parent_locker= thd->m_statement_psi;
4502   DBUG_ENTER("mysql_unpack_partition");
4503 
4504   thd->variables.character_set_client= system_charset_info;
4505 
4506   Parser_state parser_state;
4507   if (unlikely(parser_state.init(thd, part_buf, part_info_len)))
4508     goto end;
4509 
4510   if (unlikely(init_lex_with_single_table(thd, table, &lex)))
4511     goto end;
4512 
4513   *work_part_info_used= FALSE;
4514 
4515   if (unlikely(!(lex.part_info= new partition_info())))
4516     goto end;
4517 
4518   lex.part_info->table= table;       /* Indicates MYSQLparse from this place */
4519   part_info= lex.part_info;
4520   DBUG_PRINT("info", ("Parse: %s", part_buf));
4521 
4522   thd->m_statement_psi= NULL;
4523   if (unlikely(parse_sql(thd, & parser_state, NULL)) ||
4524       unlikely(part_info->fix_parser_data(thd)))
4525   {
4526     thd->free_items();
4527     thd->m_statement_psi= parent_locker;
4528     goto end;
4529   }
4530   thd->m_statement_psi= parent_locker;
4531   /*
4532     The parsed syntax residing in the frm file can still contain defaults.
4533     The reason is that the frm file is sometimes saved outside of this
4534     MySQL Server and used in backup and restore of clusters or partitioned
4535     tables. It is not certain that the restore will restore exactly the
4536     same default partitioning.
4537 
4538     The easiest manner of handling this is to simply continue using the
4539     part_info we already built up during mysql_create_table if we are
4540     in the process of creating a table. If the table already exists we
4541     need to discover the number of partitions for the default parts. Since
4542     the handler object hasn't been created here yet we need to postpone this
4543     to the fix_partition_func method.
4544   */
4545 
4546   DBUG_PRINT("info", ("Successful parse"));
4547   DBUG_PRINT("info", ("default engine = %s, default_db_type = %s",
4548              ha_resolve_storage_engine_name(part_info->default_engine_type),
4549              ha_resolve_storage_engine_name(default_db_type)));
4550   if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
4551   {
4552     /*
4553       When we come here we are doing a create table. In this case we
4554       have already done some preparatory work on the old part_info
4555       object. We don't really need this new partition_info object.
4556       Thus we go back to the old partition info object.
4557       We need to free any memory objects allocated on item_free_list
4558       by the parser since we are keeping the old info from the first
4559       parser call in CREATE TABLE.
4560 
4561       This table object can not be used any more. However, since
4562       this is CREATE TABLE, we know that it will be destroyed by the
4563       caller, and rely on that.
4564     */
4565     thd->free_items();
4566     part_info= thd->work_part_info;
4567     *work_part_info_used= true;
4568   }
4569   table->part_info= part_info;
4570   part_info->table= table;
4571   table->file->set_part_info(part_info);
4572   if (!part_info->default_engine_type)
4573     part_info->default_engine_type= default_db_type;
4574   DBUG_ASSERT(part_info->default_engine_type == default_db_type);
4575   DBUG_ASSERT(part_info->default_engine_type->db_type != DB_TYPE_UNKNOWN);
4576   DBUG_ASSERT(part_info->default_engine_type != partition_hton);
4577   result= FALSE;
4578 end:
4579   end_lex_with_single_table(thd, table, old_lex);
4580   thd->variables.character_set_client= old_character_set_client;
4581   DBUG_RETURN(result);
4582 }
4583 
4584 
4585 /*
4586   Set engine type on all partition element objects
4587   SYNOPSIS
4588     set_engine_all_partitions()
4589     part_info                  Partition info
4590     engine_type                Handlerton reference of engine
4591   RETURN VALUES
4592     NONE
4593 */
4594 
4595 static
4596 void
set_engine_all_partitions(partition_info * part_info,handlerton * engine_type)4597 set_engine_all_partitions(partition_info *part_info,
4598                           handlerton *engine_type)
4599 {
4600   uint i= 0;
4601   List_iterator<partition_element> part_it(part_info->partitions);
4602   do
4603   {
4604     partition_element *part_elem= part_it++;
4605 
4606     part_elem->engine_type= engine_type;
4607     if (part_info->is_sub_partitioned())
4608     {
4609       List_iterator<partition_element> sub_it(part_elem->subpartitions);
4610       uint j= 0;
4611 
4612       do
4613       {
4614         partition_element *sub_elem= sub_it++;
4615 
4616         sub_elem->engine_type= engine_type;
4617       } while (++j < part_info->num_subparts);
4618     }
4619   } while (++i < part_info->num_parts);
4620 }
4621 
4622 
4623 /**
4624   Support routine to handle the successful cases for partition management.
4625 
4626   @param thd               Thread object
4627   @param copied            Number of records copied
4628   @param deleted           Number of records deleted
4629   @param table_list        Table list with the one table in it
4630 
4631   @return Operation status
4632     @retval FALSE          Success
4633     @retval TRUE           Failure
4634 */
4635 
fast_end_partition(THD * thd,ulonglong copied,ulonglong deleted,TABLE_LIST * table_list)4636 static int fast_end_partition(THD *thd, ulonglong copied,
4637                               ulonglong deleted,
4638                               TABLE_LIST *table_list)
4639 {
4640   char tmp_name[80];
4641   DBUG_ENTER("fast_end_partition");
4642 
4643   thd->proc_info="end";
4644 
4645   query_cache_invalidate3(thd, table_list, 0);
4646 
4647   my_snprintf(tmp_name, sizeof(tmp_name), ER_THD(thd, ER_INSERT_INFO),
4648               (ulong) (copied + deleted),
4649               (ulong) deleted,
4650               (ulong) 0);
4651   my_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name);
4652   DBUG_RETURN(FALSE);
4653 }
4654 
4655 
4656 /*
4657   We need to check if engine used by all partitions can handle
4658   partitioning natively.
4659 
4660   SYNOPSIS
4661     check_native_partitioned()
4662     create_info            Create info in CREATE TABLE
4663     out:ret_val            Return value
4664     part_info              Partition info
4665     thd                    Thread object
4666 
4667   RETURN VALUES
4668   Value returned in bool ret_value
4669     TRUE                   Native partitioning supported by engine
4670     FALSE                  Need to use partition handler
4671 
4672   Return value from function
4673     TRUE                   Error
4674     FALSE                  Success
4675 */
4676 
check_native_partitioned(HA_CREATE_INFO * create_info,bool * ret_val,partition_info * part_info,THD * thd)4677 static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val,
4678                                      partition_info *part_info, THD *thd)
4679 {
4680   bool table_engine_set;
4681   handlerton *engine_type= part_info->default_engine_type;
4682   handlerton *old_engine_type= engine_type;
4683   DBUG_ENTER("check_native_partitioned");
4684 
4685   if (create_info->used_fields & HA_CREATE_USED_ENGINE)
4686   {
4687     table_engine_set= TRUE;
4688     engine_type= create_info->db_type;
4689   }
4690   else
4691   {
4692     table_engine_set= FALSE;
4693     if (thd->lex->sql_command != SQLCOM_CREATE_TABLE)
4694     {
4695       table_engine_set= TRUE;
4696       DBUG_ASSERT(engine_type && engine_type != partition_hton);
4697     }
4698   }
4699   DBUG_PRINT("info", ("engine_type = %s, table_engine_set = %u",
4700                        ha_resolve_storage_engine_name(engine_type),
4701                        table_engine_set));
4702   if (part_info->check_engine_mix(engine_type, table_engine_set))
4703     goto error;
4704 
4705   /*
4706     All engines are of the same type. Check if this engine supports
4707     native partitioning.
4708   */
4709 
4710   if (!engine_type)
4711     engine_type= old_engine_type;
4712   DBUG_PRINT("info", ("engine_type = %s",
4713               ha_resolve_storage_engine_name(engine_type)));
4714   if (engine_type->partition_flags &&
4715       (engine_type->partition_flags() & HA_CAN_PARTITION))
4716   {
4717     create_info->db_type= engine_type;
4718     DBUG_PRINT("info", ("Changed to native partitioning"));
4719     *ret_val= TRUE;
4720   }
4721   DBUG_RETURN(FALSE);
4722 error:
4723   /*
4724     Mixed engines not yet supported but when supported it will need
4725     the partition handler
4726   */
4727   my_error(ER_MIX_HANDLER_ERROR, MYF(0));
4728   *ret_val= FALSE;
4729   DBUG_RETURN(TRUE);
4730 }
4731 
4732 
4733 /**
4734   Sets which partitions to be used in the command.
4735 
4736   @param alter_info     Alter_info pointer holding partition names and flags.
4737   @param tab_part_info  partition_info holding all partitions.
4738   @param part_state     Which state to set for the named partitions.
4739 
4740   @return Operation status
4741     @retval false  Success
4742     @retval true   Failure
4743 */
4744 
set_part_state(Alter_info * alter_info,partition_info * tab_part_info,enum partition_state part_state)4745 bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
4746                     enum partition_state part_state)
4747 {
4748   uint part_count= 0;
4749   uint num_parts_found= 0;
4750   List_iterator<partition_element> part_it(tab_part_info->partitions);
4751 
4752   do
4753   {
4754     partition_element *part_elem= part_it++;
4755     if ((alter_info->partition_flags & ALTER_PARTITION_ALL) ||
4756          (is_name_in_list(part_elem->partition_name,
4757           alter_info->partition_names)))
4758     {
4759       /*
4760         Mark the partition.
4761         I.e mark the partition as a partition to be "changed" by
4762         analyzing/optimizing/rebuilding/checking/repairing/...
4763       */
4764       num_parts_found++;
4765       part_elem->part_state= part_state;
4766       DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
4767                           part_state, part_elem->partition_name));
4768     }
4769     else
4770       part_elem->part_state= PART_NORMAL;
4771   } while (++part_count < tab_part_info->num_parts);
4772 
4773   if (num_parts_found != alter_info->partition_names.elements &&
4774       !(alter_info->partition_flags & ALTER_PARTITION_ALL))
4775   {
4776     /* Not all given partitions found, revert and return failure */
4777     part_it.rewind();
4778     part_count= 0;
4779     do
4780     {
4781       partition_element *part_elem= part_it++;
4782       part_elem->part_state= PART_NORMAL;
4783     } while (++part_count < tab_part_info->num_parts);
4784     return true;
4785   }
4786   return false;
4787 }
4788 
4789 
4790 /**
4791   @brief Check if partition is exchangable with table by checking table options
4792 
4793   @param table_create_info Table options from table.
4794   @param part_elem         All the info of the partition.
4795 
4796   @retval FALSE if they are equal, otherwise TRUE.
4797 
4798   @note Any differens that would cause a change in the frm file is prohibited.
4799   Such options as data_file_name, index_file_name, min_rows, max_rows etc. are
4800   not allowed to differ. But comment is allowed to differ.
4801 */
compare_partition_options(HA_CREATE_INFO * table_create_info,partition_element * part_elem)4802 bool compare_partition_options(HA_CREATE_INFO *table_create_info,
4803                                partition_element *part_elem)
4804 {
4805 #define MAX_COMPARE_PARTITION_OPTION_ERRORS 5
4806   const char *option_diffs[MAX_COMPARE_PARTITION_OPTION_ERRORS + 1];
4807   int i, errors= 0;
4808   DBUG_ENTER("compare_partition_options");
4809 
4810   /*
4811     Note that there are not yet any engine supporting tablespace together
4812     with partitioning. TODO: when there are, add compare.
4813   */
4814   if (part_elem->tablespace_name || table_create_info->tablespace)
4815     option_diffs[errors++]= "TABLESPACE";
4816   if (part_elem->part_max_rows != table_create_info->max_rows)
4817     option_diffs[errors++]= "MAX_ROWS";
4818   if (part_elem->part_min_rows != table_create_info->min_rows)
4819     option_diffs[errors++]= "MIN_ROWS";
4820 
4821   for (i= 0; i < errors; i++)
4822     my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
4823              option_diffs[i]);
4824   DBUG_RETURN(errors != 0);
4825 }
4826 
4827 
4828 /**
4829   Check if the ALTER command tries to change DATA DIRECTORY
4830   or INDEX DIRECTORY for its partitions and warn if so.
4831   @param thd  THD
4832   @param part_elem partition_element to check
4833  */
warn_if_datadir_altered(THD * thd,const partition_element * part_elem)4834 static void warn_if_datadir_altered(THD *thd,
4835     const partition_element *part_elem)
4836 {
4837   DBUG_ASSERT(part_elem);
4838 
4839   if (part_elem->engine_type &&
4840       part_elem->engine_type->db_type != DB_TYPE_INNODB)
4841     return;
4842 
4843   if (part_elem->data_file_name)
4844   {
4845     push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4846         WARN_INNODB_PARTITION_OPTION_IGNORED,
4847         ER(WARN_INNODB_PARTITION_OPTION_IGNORED),
4848         "DATA DIRECTORY");
4849   }
4850   if (part_elem->index_file_name)
4851   {
4852     push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4853         WARN_INNODB_PARTITION_OPTION_IGNORED,
4854         ER(WARN_INNODB_PARTITION_OPTION_IGNORED),
4855         "INDEX DIRECTORY");
4856   }
4857 }
4858 
4859 
4860 /**
4861   Currently changing DATA DIRECTORY and INDEX DIRECTORY for InnoDB partitions is
4862   not possible. This function checks it and warns on that case.
4863   @param thd THD
4864   @param tab_part_info old partition info
4865   @param alt_part_info new partition info
4866  */
check_datadir_altered_for_innodb(THD * thd,partition_info * tab_part_info,partition_info * alt_part_info)4867 static void check_datadir_altered_for_innodb(THD *thd,
4868     partition_info *tab_part_info,
4869     partition_info *alt_part_info)
4870 {
4871   if (tab_part_info->default_engine_type->db_type != DB_TYPE_INNODB)
4872     return;
4873 
4874   for (List_iterator_fast<partition_element> it(alt_part_info->partitions);
4875        partition_element *part_elem= it++;)
4876   {
4877     if (alt_part_info->is_sub_partitioned())
4878     {
4879       for (List_iterator_fast<partition_element> it2(part_elem->subpartitions);
4880            const partition_element *sub_part_elem= it2++;)
4881       {
4882         warn_if_datadir_altered(thd, sub_part_elem);
4883       }
4884     }
4885     else
4886       warn_if_datadir_altered(thd, part_elem);
4887   }
4888 }
4889 
4890 
4891 /*
4892   Prepare for ALTER TABLE of partition structure
4893 
4894   @param[in] thd                 Thread object
4895   @param[in] table               Table object
4896   @param[in,out] alter_info      Alter information
4897   @param[in,out] create_info     Create info for CREATE TABLE
4898   @param[in]  alter_ctx          ALTER TABLE runtime context
4899   @param[out] partition_changed  Boolean indicating whether partition changed
4900   @param[out] fast_alter_table   Boolean indicating if fast partition alter is
4901                                  possible.
4902 
4903   @return Operation status
4904     @retval TRUE                 Error
4905     @retval FALSE                Success
4906 
4907   @note
4908     This method handles all preparations for ALTER TABLE for partitioned
4909     tables.
4910     We need to handle both partition management command such as Add Partition
4911     and others here as well as an ALTER TABLE that completely changes the
4912     partitioning and yet others that don't change anything at all. We start
4913     by checking the partition management variants and then check the general
4914     change patterns.
4915 */
4916 
prep_alter_part_table(THD * thd,TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,Alter_table_ctx * alter_ctx,bool * partition_changed,bool * fast_alter_table)4917 uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
4918                            HA_CREATE_INFO *create_info,
4919                            Alter_table_ctx *alter_ctx,
4920                            bool *partition_changed,
4921                            bool *fast_alter_table)
4922 {
4923   DBUG_ENTER("prep_alter_part_table");
4924 
4925   /* Foreign keys on partitioned tables are not supported, waits for WL#148 */
4926   if (table->part_info && (alter_info->flags & (ALTER_ADD_FOREIGN_KEY |
4927                                                 ALTER_DROP_FOREIGN_KEY)))
4928   {
4929     my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
4930     DBUG_RETURN(TRUE);
4931   }
4932   /* Remove partitioning on a not partitioned table is not possible */
4933   if (!table->part_info && (alter_info->partition_flags &
4934                             ALTER_PARTITION_REMOVE))
4935   {
4936     my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4937     DBUG_RETURN(TRUE);
4938   }
4939 
4940   partition_info *alt_part_info= thd->lex->part_info;
4941   /*
4942     This variable is TRUE in very special case when we add only DEFAULT
4943     partition to the existing table
4944   */
4945   bool only_default_value_added=
4946     (alt_part_info &&
4947      alt_part_info->current_partition &&
4948      alt_part_info->current_partition->list_val_list.elements == 1 &&
4949      alt_part_info->current_partition->list_val_list.head()->
4950      added_items >= 1 &&
4951      alt_part_info->current_partition->list_val_list.head()->
4952      col_val_array[0].max_value) &&
4953     alt_part_info->part_type == LIST_PARTITION &&
4954     (alter_info->partition_flags & ALTER_PARTITION_ADD);
4955   if (only_default_value_added &&
4956       !thd->lex->part_info->num_columns)
4957     thd->lex->part_info->num_columns= 1; // to make correct clone
4958 
4959   /*
4960     One of these is done in handle_if_exists_option():
4961         thd->work_part_info= thd->lex->part_info;
4962       or
4963         thd->work_part_info= NULL;
4964   */
4965   if (thd->work_part_info &&
4966       !(thd->work_part_info= thd->work_part_info->get_clone(thd)))
4967     DBUG_RETURN(TRUE);
4968 
4969   /* ALTER_PARTITION_ADMIN is handled in mysql_admin_table */
4970   DBUG_ASSERT(!(alter_info->partition_flags & ALTER_PARTITION_ADMIN));
4971 
4972   partition_info *saved_part_info= NULL;
4973 
4974   if (alter_info->partition_flags &
4975       (ALTER_PARTITION_ADD |
4976        ALTER_PARTITION_DROP |
4977        ALTER_PARTITION_COALESCE |
4978        ALTER_PARTITION_REORGANIZE |
4979        ALTER_PARTITION_TABLE_REORG |
4980        ALTER_PARTITION_REBUILD))
4981   {
4982     /*
4983       You can't add column when we are doing alter related to partition
4984     */
4985     DBUG_EXECUTE_IF("test_pseudo_invisible", {
4986          my_error(ER_INTERNAL_ERROR, MYF(0), "Don't to it with test_pseudo_invisible");
4987          DBUG_RETURN(1);
4988          });
4989     DBUG_EXECUTE_IF("test_completely_invisible", {
4990          my_error(ER_INTERNAL_ERROR, MYF(0), "Don't to it with test_completely_invisible");
4991          DBUG_RETURN(1);
4992          });
4993     partition_info *tab_part_info;
4994     ulonglong flags= 0;
4995     bool is_last_partition_reorged= FALSE;
4996     part_elem_value *tab_max_elem_val= NULL;
4997     part_elem_value *alt_max_elem_val= NULL;
4998     longlong tab_max_range= 0, alt_max_range= 0;
4999     alt_part_info= thd->work_part_info;
5000 
5001     if (!table->part_info)
5002     {
5003       my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
5004       DBUG_RETURN(TRUE);
5005     }
5006 
5007     /*
5008       Open our intermediate table, we will operate on a temporary instance
5009       of the original table, to be able to skip copying all partitions.
5010       Open it as a copy of the original table, and modify its partition_info
5011       object to allow fast_alter_partition_table to perform the changes.
5012     */
5013     DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
5014                                                alter_ctx->db.str,
5015                                                alter_ctx->table_name.str,
5016                                                MDL_INTENTION_EXCLUSIVE));
5017 
5018     tab_part_info= table->part_info;
5019 
5020     if (alter_info->partition_flags & ALTER_PARTITION_TABLE_REORG)
5021     {
5022       uint new_part_no, curr_part_no;
5023       /*
5024         'ALTER TABLE t REORG PARTITION' only allowed with auto partition
5025          if default partitioning is used.
5026       */
5027 
5028       if (tab_part_info->part_type != HASH_PARTITION ||
5029           ((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
5030            !tab_part_info->use_default_num_partitions) ||
5031           ((!(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)) &&
5032            tab_part_info->use_default_num_partitions))
5033       {
5034         my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
5035         goto err;
5036       }
5037       new_part_no= table->file->get_default_no_partitions(create_info);
5038       curr_part_no= tab_part_info->num_parts;
5039       if (new_part_no == curr_part_no)
5040       {
5041         /*
5042           No change is needed, we will have the same number of partitions
5043           after the change as before. Thus we can reply ok immediately
5044           without any changes at all.
5045         */
5046         flags= table->file->alter_table_flags(alter_info->flags);
5047         if (flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE))
5048         {
5049           *fast_alter_table= true;
5050           /* Force table re-open for consistency with the main case. */
5051           table->mark_table_for_reopen();
5052         }
5053         else
5054         {
5055           /*
5056             Create copy of partition_info to avoid modifying original
5057             TABLE::part_info, to keep it safe for later use.
5058           */
5059           if (!(tab_part_info= tab_part_info->get_clone(thd)))
5060             DBUG_RETURN(TRUE);
5061         }
5062 
5063         thd->work_part_info= tab_part_info;
5064         DBUG_RETURN(FALSE);
5065       }
5066       else if (new_part_no > curr_part_no)
5067       {
5068         /*
5069           We will add more partitions, we use the ADD PARTITION without
5070           setting the flag for no default number of partitions
5071         */
5072         alter_info->partition_flags|= ALTER_PARTITION_ADD;
5073         thd->work_part_info->num_parts= new_part_no - curr_part_no;
5074       }
5075       else
5076       {
5077         /*
5078           We will remove hash partitions, we use the COALESCE PARTITION
5079           without setting the flag for no default number of partitions
5080         */
5081         alter_info->partition_flags|= ALTER_PARTITION_COALESCE;
5082         alter_info->num_parts= curr_part_no - new_part_no;
5083       }
5084     }
5085     if (!(flags= table->file->alter_table_flags(alter_info->flags)))
5086     {
5087       my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
5088       goto err;
5089     }
5090     if ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0)
5091     {
5092       /*
5093         "Fast" change of partitioning is supported in this case.
5094         We will change TABLE::part_info (as this is how we pass
5095         information to storage engine in this case), so the table
5096         must be reopened.
5097       */
5098       *fast_alter_table= true;
5099       table->mark_table_for_reopen();
5100     }
5101     else
5102     {
5103       /*
5104         "Fast" changing of partitioning is not supported. Create
5105         a copy of TABLE::part_info object, so we can modify it safely.
5106         Modifying original TABLE::part_info will cause problems when
5107         we read data from old version of table using this TABLE object
5108         while copying them to new version of table.
5109       */
5110       if (!(tab_part_info= tab_part_info->get_clone(thd)))
5111         DBUG_RETURN(TRUE);
5112     }
5113     DBUG_PRINT("info", ("*fast_alter_table flags: 0x%llx", flags));
5114     if ((alter_info->partition_flags & ALTER_PARTITION_ADD) ||
5115         (alter_info->partition_flags & ALTER_PARTITION_REORGANIZE))
5116     {
5117       if (thd->work_part_info->part_type != tab_part_info->part_type)
5118       {
5119         if (thd->work_part_info->part_type == NOT_A_PARTITION)
5120         {
5121           if (tab_part_info->part_type == RANGE_PARTITION)
5122           {
5123             my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
5124             goto err;
5125           }
5126           else if (tab_part_info->part_type == LIST_PARTITION)
5127           {
5128             my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
5129             goto err;
5130           }
5131           /*
5132             Hash partitions can be altered without parser finds out about
5133             that it is HASH partitioned. So no error here.
5134           */
5135         }
5136         else
5137         {
5138           if (thd->work_part_info->part_type == RANGE_PARTITION)
5139           {
5140             my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
5141                      "RANGE", "LESS THAN");
5142           }
5143           else if (thd->work_part_info->part_type == LIST_PARTITION)
5144           {
5145             DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
5146             my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
5147                      "LIST", "IN");
5148           }
5149           else if (thd->work_part_info->part_type == VERSIONING_PARTITION ||
5150                    tab_part_info->part_type == VERSIONING_PARTITION)
5151           {
5152             my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
5153           }
5154           else
5155           {
5156             DBUG_ASSERT(tab_part_info->part_type == RANGE_PARTITION ||
5157                         tab_part_info->part_type == LIST_PARTITION);
5158             (void) tab_part_info->error_if_requires_values();
5159           }
5160           goto err;
5161         }
5162       }
5163       if ((tab_part_info->column_list &&
5164           alt_part_info->num_columns != tab_part_info->num_columns &&
5165           !only_default_value_added) ||
5166           (!tab_part_info->column_list &&
5167             (tab_part_info->part_type == RANGE_PARTITION ||
5168              tab_part_info->part_type == LIST_PARTITION) &&
5169             alt_part_info->num_columns != 1U &&
5170              !only_default_value_added) ||
5171           (!tab_part_info->column_list &&
5172             tab_part_info->part_type == HASH_PARTITION &&
5173             (alt_part_info->num_columns != 0)))
5174       {
5175         my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
5176         goto err;
5177       }
5178       alt_part_info->column_list= tab_part_info->column_list;
5179       if (alt_part_info->fix_parser_data(thd))
5180       {
5181         goto err;
5182       }
5183     }
5184     if (alter_info->partition_flags & ALTER_PARTITION_ADD)
5185     {
5186       if (*fast_alter_table && thd->locked_tables_mode)
5187       {
5188         MEM_ROOT *old_root= thd->mem_root;
5189         thd->mem_root= &thd->locked_tables_list.m_locked_tables_root;
5190         saved_part_info= tab_part_info->get_clone(thd);
5191         thd->mem_root= old_root;
5192         saved_part_info->read_partitions= tab_part_info->read_partitions;
5193         saved_part_info->lock_partitions= tab_part_info->lock_partitions;
5194         saved_part_info->bitmaps_are_initialized= tab_part_info->bitmaps_are_initialized;
5195       }
5196       /*
5197         We start by moving the new partitions to the list of temporary
5198         partitions. We will then check that the new partitions fit in the
5199         partitioning scheme as currently set-up.
5200         Partitions are always added at the end in ADD PARTITION.
5201       */
5202       uint num_new_partitions= alt_part_info->num_parts;
5203       uint num_orig_partitions= tab_part_info->num_parts;
5204       uint check_total_partitions= num_new_partitions + num_orig_partitions;
5205       uint new_total_partitions= check_total_partitions;
5206       /*
5207         We allow quite a lot of values to be supplied by defaults, however we
5208         must know the number of new partitions in this case.
5209       */
5210       if (thd->lex->no_write_to_binlog &&
5211           tab_part_info->part_type != HASH_PARTITION &&
5212           tab_part_info->part_type != VERSIONING_PARTITION)
5213       {
5214         my_error(ER_NO_BINLOG_ERROR, MYF(0));
5215         goto err;
5216       }
5217       if (tab_part_info->defined_max_value &&
5218           (tab_part_info->part_type == RANGE_PARTITION ||
5219            alt_part_info->defined_max_value))
5220       {
5221         my_error((tab_part_info->part_type == RANGE_PARTITION ?
5222                   ER_PARTITION_MAXVALUE_ERROR :
5223                   ER_PARTITION_DEFAULT_ERROR), MYF(0));
5224         goto err;
5225       }
5226       if (num_new_partitions == 0)
5227       {
5228         my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
5229         goto err;
5230       }
5231       if (tab_part_info->is_sub_partitioned())
5232       {
5233         if (alt_part_info->num_subparts == 0)
5234           alt_part_info->num_subparts= tab_part_info->num_subparts;
5235         else if (alt_part_info->num_subparts != tab_part_info->num_subparts)
5236         {
5237           my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
5238           goto err;
5239         }
5240         check_total_partitions= new_total_partitions*
5241                                 alt_part_info->num_subparts;
5242       }
5243       if (check_total_partitions > MAX_PARTITIONS)
5244       {
5245         my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
5246         goto err;
5247       }
5248       alt_part_info->part_type= tab_part_info->part_type;
5249       alt_part_info->subpart_type= tab_part_info->subpart_type;
5250       if (alt_part_info->set_up_defaults_for_partitioning(thd, table->file, 0,
5251                                                     tab_part_info->num_parts))
5252       {
5253         goto err;
5254       }
5255 /*
5256 Handling of on-line cases:
5257 
5258 ADD PARTITION for RANGE/LIST PARTITIONING:
5259 ------------------------------------------
5260 For range and list partitions add partition is simply adding a
5261 new empty partition to the table. If the handler support this we
5262 will use the simple method of doing this. The figure below shows
5263 an example of this and the states involved in making this change.
5264 
5265 Existing partitions                                     New added partitions
5266 ------       ------        ------        ------      |  ------    ------
5267 |    |       |    |        |    |        |    |      |  |    |    |    |
5268 | p0 |       | p1 |        | p2 |        | p3 |      |  | p4 |    | p5 |
5269 ------       ------        ------        ------      |  ------    ------
5270 PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_TO_BE_ADDED*2
5271 PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_IS_ADDED*2
5272 
5273 The first line is the states before adding the new partitions and the
5274 second line is after the new partitions are added. All the partitions are
5275 in the partitions list, no partitions are placed in the temp_partitions
5276 list.
5277 
5278 ADD PARTITION for HASH PARTITIONING
5279 -----------------------------------
5280 This little figure tries to show the various partitions involved when
5281 adding two new partitions to a linear hash based partitioned table with
5282 four partitions to start with, which lists are used and the states they
5283 pass through. Adding partitions to a normal hash based is similar except
5284 that it is always all the existing partitions that are reorganised not
5285 only a subset of them.
5286 
5287 Existing partitions                                     New added partitions
5288 ------       ------        ------        ------      |  ------    ------
5289 |    |       |    |        |    |        |    |      |  |    |    |    |
5290 | p0 |       | p1 |        | p2 |        | p3 |      |  | p4 |    | p5 |
5291 ------       ------        ------        ------      |  ------    ------
5292 PART_CHANGED PART_CHANGED  PART_NORMAL   PART_NORMAL    PART_TO_BE_ADDED
5293 PART_IS_CHANGED*2          PART_NORMAL   PART_NORMAL    PART_IS_ADDED
5294 PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_IS_ADDED
5295 
5296 Reorganised existing partitions
5297 ------      ------
5298 |    |      |    |
5299 | p0'|      | p1'|
5300 ------      ------
5301 
5302 p0 - p5 will be in the partitions list of partitions.
5303 p0' and p1' will actually not exist as separate objects, there presence can
5304 be deduced from the state of the partition and also the names of those
5305 partitions can be deduced this way.
5306 
5307 After adding the partitions and copying the partition data to p0', p1',
5308 p4 and p5 from p0 and p1 the states change to adapt for the new situation
5309 where p0 and p1 is dropped and replaced by p0' and p1' and the new p4 and
5310 p5 are in the table again.
5311 
5312 The first line above shows the states of the partitions before we start
5313 adding and copying partitions, the second after completing the adding
5314 and copying and finally the third line after also dropping the partitions
5315 that are reorganised.
5316 */
5317       if (*fast_alter_table && tab_part_info->part_type == HASH_PARTITION)
5318       {
5319         uint part_no= 0, start_part= 1, start_sec_part= 1;
5320         uint end_part= 0, end_sec_part= 0;
5321         uint upper_2n= tab_part_info->linear_hash_mask + 1;
5322         uint lower_2n= upper_2n >> 1;
5323         bool all_parts= TRUE;
5324         if (tab_part_info->linear_hash_ind && num_new_partitions < upper_2n)
5325         {
5326           /*
5327             An analysis of which parts needs reorganisation shows that it is
5328             divided into two intervals. The first interval is those parts
5329             that are reorganised up until upper_2n - 1. From upper_2n and
5330             onwards it starts again from partition 0 and goes on until
5331             it reaches p(upper_2n - 1). If the last new partition reaches
5332             beyond upper_2n - 1 then the first interval will end with
5333             p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
5334             If lower_2n partitions are added then p0 to p(lower_2n - 1) will
5335             be reorganised which means that the two interval becomes one
5336             interval at this point. Thus only when adding less than
5337             lower_2n partitions and going beyond a total of upper_2n we
5338             actually get two intervals.
5339 
5340             To exemplify this assume we have 6 partitions to start with and
5341             add 1, 2, 3, 5, 6, 7, 8, 9 partitions.
5342             The first to add after p5 is p6 = 110 in bit numbers. Thus we
5343             can see that 10 = p2 will be partition to reorganise if only one
5344             partition.
5345             If 2 partitions are added we reorganise [p2, p3]. Those two
5346             cases are covered by the second if part below.
5347             If 3 partitions are added we reorganise [p2, p3] U [p0,p0]. This
5348             part is covered by the else part below.
5349             If 5 partitions are added we get [p2,p3] U [p0, p2] = [p0, p3].
5350             This is covered by the first if part where we need the max check
5351             to here use lower_2n - 1.
5352             If 7 partitions are added we get [p2,p3] U [p0, p4] = [p0, p4].
5353             This is covered by the first if part but here we use the first
5354             calculated end_part.
5355             Finally with 9 new partitions we would also reorganise p6 if we
5356             used the method below but we cannot reorganise more partitions
5357             than what we had from the start and thus we simply set all_parts
5358             to TRUE. In this case we don't get into this if-part at all.
5359           */
5360           all_parts= FALSE;
5361           if (num_new_partitions >= lower_2n)
5362           {
5363             /*
5364               In this case there is only one interval since the two intervals
5365               overlap and this starts from zero to last_part_no - upper_2n
5366             */
5367             start_part= 0;
5368             end_part= new_total_partitions - (upper_2n + 1);
5369             end_part= max(lower_2n - 1, end_part);
5370           }
5371           else if (new_total_partitions <= upper_2n)
5372           {
5373             /*
5374               Also in this case there is only one interval since we are not
5375               going over a 2**n boundary
5376             */
5377             start_part= num_orig_partitions - lower_2n;
5378             end_part= start_part + (num_new_partitions - 1);
5379           }
5380           else
5381           {
5382             /* We have two non-overlapping intervals since we are not
5383                passing a 2**n border and we have not at least lower_2n
5384                new parts that would ensure that the intervals become
5385                overlapping.
5386             */
5387             start_part= num_orig_partitions - lower_2n;
5388             end_part= upper_2n - 1;
5389             start_sec_part= 0;
5390             end_sec_part= new_total_partitions - (upper_2n + 1);
5391           }
5392         }
5393         List_iterator<partition_element> tab_it(tab_part_info->partitions);
5394         part_no= 0;
5395         do
5396         {
5397           partition_element *p_elem= tab_it++;
5398           if (all_parts ||
5399               (part_no >= start_part && part_no <= end_part) ||
5400               (part_no >= start_sec_part && part_no <= end_sec_part))
5401           {
5402             p_elem->part_state= PART_CHANGED;
5403           }
5404         } while (++part_no < num_orig_partitions);
5405       }
5406       /*
5407         Need to concatenate the lists here to make it possible to check the
5408         partition info for correctness using check_partition_info.
5409         For on-line add partition we set the state of this partition to
5410         PART_TO_BE_ADDED to ensure that it is known that it is not yet
5411         usable (becomes usable when partition is created and the switch of
5412         partition configuration is made.
5413       */
5414       {
5415         partition_element *now_part= NULL;
5416         if (tab_part_info->part_type == VERSIONING_PARTITION)
5417         {
5418           List_iterator<partition_element> it(tab_part_info->partitions);
5419           partition_element *el;
5420           while ((el= it++))
5421           {
5422             if (el->type == partition_element::CURRENT)
5423             {
5424               it.remove();
5425               now_part= el;
5426             }
5427           }
5428           if (*fast_alter_table && tab_part_info->vers_info->interval.is_set())
5429           {
5430             partition_element *hist_part= tab_part_info->vers_info->hist_part;
5431             if (hist_part->range_value <= thd->query_start())
5432               hist_part->part_state= PART_CHANGED;
5433           }
5434         }
5435         List_iterator<partition_element> alt_it(alt_part_info->partitions);
5436         uint part_count= 0;
5437         do
5438         {
5439           partition_element *part_elem= alt_it++;
5440           if (*fast_alter_table)
5441             part_elem->part_state= PART_TO_BE_ADDED;
5442           if (unlikely(tab_part_info->partitions.push_back(part_elem,
5443                                                            thd->mem_root)))
5444             goto err;
5445         } while (++part_count < num_new_partitions);
5446         tab_part_info->num_parts+= num_new_partitions;
5447         if (tab_part_info->part_type == VERSIONING_PARTITION)
5448         {
5449           DBUG_ASSERT(now_part);
5450           if (unlikely(tab_part_info->partitions.push_back(now_part,
5451                                                            thd->mem_root)))
5452             goto err;
5453         }
5454       }
5455       /*
5456         If we specify partitions explicitly we don't use defaults anymore.
5457         Using ADD PARTITION also means that we don't have the default number
5458         of partitions anymore. We use this code also for Table reorganisations
5459         and here we don't set any default flags to FALSE.
5460       */
5461       if (!(alter_info->partition_flags & ALTER_PARTITION_TABLE_REORG))
5462       {
5463         if (!alt_part_info->use_default_partitions)
5464         {
5465           DBUG_PRINT("info", ("part_info: %p", tab_part_info));
5466           tab_part_info->use_default_partitions= FALSE;
5467         }
5468         tab_part_info->use_default_num_partitions= FALSE;
5469         tab_part_info->is_auto_partitioned= FALSE;
5470       }
5471     }
5472     else if (alter_info->partition_flags & ALTER_PARTITION_DROP)
5473     {
5474       /*
5475         Drop a partition from a range partition and list partitioning is
5476         always safe and can be made more or less immediate. It is necessary
5477         however to ensure that the partition to be removed is safely removed
5478         and that REPAIR TABLE can remove the partition if for some reason the
5479         command to drop the partition failed in the middle.
5480       */
5481       uint part_count= 0;
5482       uint num_parts_dropped= alter_info->partition_names.elements;
5483       uint num_parts_found= 0;
5484       List_iterator<partition_element> part_it(tab_part_info->partitions);
5485 
5486       tab_part_info->is_auto_partitioned= FALSE;
5487       if (tab_part_info->part_type == VERSIONING_PARTITION)
5488       {
5489         if (num_parts_dropped >= tab_part_info->num_parts - 1)
5490         {
5491           DBUG_ASSERT(table && table->s && table->s->table_name.str);
5492           my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str);
5493           goto err;
5494         }
5495       }
5496       else
5497       {
5498         if (!(tab_part_info->part_type == RANGE_PARTITION ||
5499               tab_part_info->part_type == LIST_PARTITION))
5500         {
5501           my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
5502           goto err;
5503         }
5504         if (num_parts_dropped >= tab_part_info->num_parts)
5505         {
5506           my_error(ER_DROP_LAST_PARTITION, MYF(0));
5507           goto err;
5508         }
5509       }
5510       do
5511       {
5512         partition_element *part_elem= part_it++;
5513         if (is_name_in_list(part_elem->partition_name,
5514                             alter_info->partition_names))
5515         {
5516           if (tab_part_info->part_type == VERSIONING_PARTITION)
5517           {
5518             if (part_elem->type == partition_element::CURRENT)
5519             {
5520               my_error(ER_VERS_WRONG_PARTS, MYF(0), table->s->table_name.str);
5521               goto err;
5522             }
5523             if (tab_part_info->vers_info->interval.is_set())
5524             {
5525               if (num_parts_found < part_count)
5526               {
5527                 my_error(ER_VERS_DROP_PARTITION_INTERVAL, MYF(0));
5528                 goto err;
5529               }
5530               tab_part_info->vers_info->interval.start=
5531                 (my_time_t)part_elem->range_value;
5532             }
5533           }
5534           /*
5535             Set state to indicate that the partition is to be dropped.
5536           */
5537           num_parts_found++;
5538           part_elem->part_state= PART_TO_BE_DROPPED;
5539         }
5540       } while (++part_count < tab_part_info->num_parts);
5541       if (num_parts_found != num_parts_dropped)
5542       {
5543         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
5544         goto err;
5545       }
5546       if (table->file->is_fk_defined_on_table_or_index(MAX_KEY))
5547       {
5548         my_error(ER_ROW_IS_REFERENCED, MYF(0));
5549         goto err;
5550       }
5551       tab_part_info->num_parts-= num_parts_dropped;
5552     }
5553     else if (alter_info->partition_flags & ALTER_PARTITION_REBUILD)
5554     {
5555       set_engine_all_partitions(tab_part_info,
5556                                 tab_part_info->default_engine_type);
5557       if (set_part_state(alter_info, tab_part_info, PART_CHANGED))
5558       {
5559         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
5560         goto err;
5561       }
5562       if (!(*fast_alter_table))
5563       {
5564         table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
5565         goto err;
5566       }
5567     }
5568     else if (alter_info->partition_flags & ALTER_PARTITION_COALESCE)
5569     {
5570       uint num_parts_coalesced= alter_info->num_parts;
5571       uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced;
5572       List_iterator<partition_element> part_it(tab_part_info->partitions);
5573       if (tab_part_info->part_type != HASH_PARTITION)
5574       {
5575         my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
5576         goto err;
5577       }
5578       if (num_parts_coalesced == 0)
5579       {
5580         my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
5581         goto err;
5582       }
5583       if (num_parts_coalesced >= tab_part_info->num_parts)
5584       {
5585         my_error(ER_DROP_LAST_PARTITION, MYF(0));
5586         goto err;
5587       }
5588 /*
5589 Online handling:
5590 COALESCE PARTITION:
5591 -------------------
5592 The figure below shows the manner in which partitions are handled when
5593 performing an on-line coalesce partition and which states they go through
5594 at start, after adding and copying partitions and finally after dropping
5595 the partitions to drop. The figure shows an example using four partitions
5596 to start with, using linear hash and coalescing one partition (always the
5597 last partition).
5598 
5599 Using linear hash then all remaining partitions will have a new reorganised
5600 part.
5601 
5602 Existing partitions                     Coalesced partition
5603 ------       ------              ------   |      ------
5604 |    |       |    |              |    |   |      |    |
5605 | p0 |       | p1 |              | p2 |   |      | p3 |
5606 ------       ------              ------   |      ------
5607 PART_NORMAL  PART_CHANGED        PART_NORMAL     PART_REORGED_DROPPED
5608 PART_NORMAL  PART_IS_CHANGED     PART_NORMAL     PART_TO_BE_DROPPED
5609 PART_NORMAL  PART_NORMAL         PART_NORMAL     PART_IS_DROPPED
5610 
5611 Reorganised existing partitions
5612             ------
5613             |    |
5614             | p1'|
5615             ------
5616 
5617 p0 - p3 is in the partitions list.
5618 The p1' partition will actually not be in any list it is deduced from the
5619 state of p1.
5620 */
5621       {
5622         uint part_count= 0, start_part= 1, start_sec_part= 1;
5623         uint end_part= 0, end_sec_part= 0;
5624         bool all_parts= TRUE;
5625         if (*fast_alter_table &&
5626             tab_part_info->linear_hash_ind)
5627         {
5628           uint upper_2n= tab_part_info->linear_hash_mask + 1;
5629           uint lower_2n= upper_2n >> 1;
5630           all_parts= FALSE;
5631           if (num_parts_coalesced >= lower_2n)
5632           {
5633             all_parts= TRUE;
5634           }
5635           else if (num_parts_remain >= lower_2n)
5636           {
5637             end_part= tab_part_info->num_parts - (lower_2n + 1);
5638             start_part= num_parts_remain - lower_2n;
5639           }
5640           else
5641           {
5642             start_part= 0;
5643             end_part= tab_part_info->num_parts - (lower_2n + 1);
5644             end_sec_part= (lower_2n >> 1) - 1;
5645             start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1));
5646           }
5647         }
5648         do
5649         {
5650           partition_element *p_elem= part_it++;
5651           if (*fast_alter_table &&
5652               (all_parts ||
5653               (part_count >= start_part && part_count <= end_part) ||
5654               (part_count >= start_sec_part && part_count <= end_sec_part)))
5655             p_elem->part_state= PART_CHANGED;
5656           if (++part_count > num_parts_remain)
5657           {
5658             if (*fast_alter_table)
5659               p_elem->part_state= PART_REORGED_DROPPED;
5660             else
5661               part_it.remove();
5662           }
5663         } while (part_count < tab_part_info->num_parts);
5664         tab_part_info->num_parts= num_parts_remain;
5665       }
5666       if (!(alter_info->partition_flags & ALTER_PARTITION_TABLE_REORG))
5667       {
5668         tab_part_info->use_default_num_partitions= FALSE;
5669         tab_part_info->is_auto_partitioned= FALSE;
5670       }
5671     }
5672     else if (alter_info->partition_flags & ALTER_PARTITION_REORGANIZE)
5673     {
5674       /*
5675         Reorganise partitions takes a number of partitions that are next
5676         to each other (at least for RANGE PARTITIONS) and then uses those
5677         to create a set of new partitions. So data is copied from those
5678         partitions into the new set of partitions. Those new partitions
5679         can have more values in the LIST value specifications or less both
5680         are allowed. The ranges can be different but since they are
5681         changing a set of consecutive partitions they must cover the same
5682         range as those changed from.
5683         This command can be used on RANGE and LIST partitions.
5684       */
5685       uint num_parts_reorged= alter_info->partition_names.elements;
5686       uint num_parts_new= thd->work_part_info->partitions.elements;
5687       uint check_total_partitions;
5688 
5689       tab_part_info->is_auto_partitioned= FALSE;
5690       if (num_parts_reorged > tab_part_info->num_parts)
5691       {
5692         my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
5693         goto err;
5694       }
5695       if (!(tab_part_info->part_type == RANGE_PARTITION ||
5696             tab_part_info->part_type == LIST_PARTITION) &&
5697            (num_parts_new != num_parts_reorged))
5698       {
5699         my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
5700         goto err;
5701       }
5702       if (tab_part_info->is_sub_partitioned() &&
5703           alt_part_info->num_subparts &&
5704           alt_part_info->num_subparts != tab_part_info->num_subparts)
5705       {
5706         my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
5707         goto err;
5708       }
5709       check_total_partitions= tab_part_info->num_parts + num_parts_new;
5710       check_total_partitions-= num_parts_reorged;
5711       if (check_total_partitions > MAX_PARTITIONS)
5712       {
5713         my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
5714         goto err;
5715       }
5716       alt_part_info->part_type= tab_part_info->part_type;
5717       alt_part_info->subpart_type= tab_part_info->subpart_type;
5718       alt_part_info->num_subparts= tab_part_info->num_subparts;
5719       DBUG_ASSERT(!alt_part_info->use_default_partitions);
5720       /* We specified partitions explicitly so don't use defaults anymore. */
5721       tab_part_info->use_default_partitions= FALSE;
5722       if (alt_part_info->set_up_defaults_for_partitioning(thd, table->file, 0,
5723                                                           0))
5724       {
5725         goto err;
5726       }
5727       check_datadir_altered_for_innodb(thd, tab_part_info, alt_part_info);
5728 
5729 /*
5730 Online handling:
5731 REORGANIZE PARTITION:
5732 ---------------------
5733 The figure exemplifies the handling of partitions, their state changes and
5734 how they are organised. It exemplifies four partitions where two of the
5735 partitions are reorganised (p1 and p2) into two new partitions (p4 and p5).
5736 The reason of this change could be to change range limits, change list
5737 values or for hash partitions simply reorganise the partition which could
5738 also involve moving them to new disks or new node groups (MySQL Cluster).
5739 
5740 Existing partitions
5741 ------       ------        ------        ------
5742 |    |       |    |        |    |        |    |
5743 | p0 |       | p1 |        | p2 |        | p3 |
5744 ------       ------        ------        ------
5745 PART_NORMAL  PART_TO_BE_REORGED          PART_NORMAL
5746 PART_NORMAL  PART_TO_BE_DROPPED          PART_NORMAL
5747 PART_NORMAL  PART_IS_DROPPED             PART_NORMAL
5748 
5749 Reorganised new partitions (replacing p1 and p2)
5750 ------      ------
5751 |    |      |    |
5752 | p4 |      | p5 |
5753 ------      ------
5754 PART_TO_BE_ADDED
5755 PART_IS_ADDED
5756 PART_IS_ADDED
5757 
5758 All unchanged partitions and the new partitions are in the partitions list
5759 in the order they will have when the change is completed. The reorganised
5760 partitions are placed in the temp_partitions list. PART_IS_ADDED is only a
5761 temporary state not written in the frm file. It is used to ensure we write
5762 the generated partition syntax in a correct manner.
5763 */
5764       {
5765         List_iterator<partition_element> tab_it(tab_part_info->partitions);
5766         uint part_count= 0;
5767         bool found_first= FALSE;
5768         bool found_last= FALSE;
5769         uint drop_count= 0;
5770         do
5771         {
5772           partition_element *part_elem= tab_it++;
5773           is_last_partition_reorged= FALSE;
5774           if (is_name_in_list(part_elem->partition_name,
5775                               alter_info->partition_names))
5776           {
5777             is_last_partition_reorged= TRUE;
5778             drop_count++;
5779             if (tab_part_info->column_list)
5780             {
5781               List_iterator<part_elem_value> p(part_elem->list_val_list);
5782               tab_max_elem_val= p++;
5783             }
5784             else
5785               tab_max_range= part_elem->range_value;
5786             if (*fast_alter_table &&
5787                 unlikely(tab_part_info->temp_partitions.
5788                          push_back(part_elem, thd->mem_root)))
5789               goto err;
5790 
5791             if (*fast_alter_table)
5792               part_elem->part_state= PART_TO_BE_REORGED;
5793             if (!found_first)
5794             {
5795               uint alt_part_count= 0;
5796               partition_element *alt_part_elem;
5797               List_iterator<partition_element>
5798                                  alt_it(alt_part_info->partitions);
5799               found_first= TRUE;
5800               do
5801               {
5802                 alt_part_elem= alt_it++;
5803                 if (tab_part_info->column_list)
5804                 {
5805                   List_iterator<part_elem_value> p(alt_part_elem->list_val_list);
5806                   alt_max_elem_val= p++;
5807                 }
5808                 else
5809                   alt_max_range= alt_part_elem->range_value;
5810 
5811                 if (*fast_alter_table)
5812                   alt_part_elem->part_state= PART_TO_BE_ADDED;
5813                 if (alt_part_count == 0)
5814                   tab_it.replace(alt_part_elem);
5815                 else
5816                   tab_it.after(alt_part_elem);
5817               } while (++alt_part_count < num_parts_new);
5818             }
5819             else if (found_last)
5820             {
5821               my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
5822               goto err;
5823             }
5824             else
5825               tab_it.remove();
5826           }
5827           else
5828           {
5829             if (found_first)
5830               found_last= TRUE;
5831           }
5832         } while (++part_count < tab_part_info->num_parts);
5833         if (drop_count != num_parts_reorged)
5834         {
5835           my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
5836           goto err;
5837         }
5838         tab_part_info->num_parts= check_total_partitions;
5839       }
5840     }
5841     else
5842     {
5843       DBUG_ASSERT(FALSE);
5844     }
5845     *partition_changed= TRUE;
5846     thd->work_part_info= tab_part_info;
5847     if (alter_info->partition_flags & (ALTER_PARTITION_ADD |
5848                                        ALTER_PARTITION_REORGANIZE))
5849     {
5850       if (tab_part_info->use_default_subpartitions &&
5851           !alt_part_info->use_default_subpartitions)
5852       {
5853         tab_part_info->use_default_subpartitions= FALSE;
5854         tab_part_info->use_default_num_subpartitions= FALSE;
5855       }
5856 
5857       if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
5858                                               table->file, 0, alt_part_info))
5859       {
5860         goto err;
5861       }
5862       /*
5863         The check below needs to be performed after check_partition_info
5864         since this function "fixes" the item trees of the new partitions
5865         to reorganize into
5866       */
5867       if (alter_info->partition_flags == ALTER_PARTITION_REORGANIZE &&
5868           tab_part_info->part_type == RANGE_PARTITION &&
5869           ((is_last_partition_reorged &&
5870             (tab_part_info->column_list ?
5871              (partition_info_compare_column_values(
5872                               alt_max_elem_val->col_val_array,
5873                               tab_max_elem_val->col_val_array) < 0) :
5874              alt_max_range < tab_max_range)) ||
5875             (!is_last_partition_reorged &&
5876              (tab_part_info->column_list ?
5877               (partition_info_compare_column_values(
5878                               alt_max_elem_val->col_val_array,
5879                               tab_max_elem_val->col_val_array) != 0) :
5880               alt_max_range != tab_max_range))))
5881       {
5882         /*
5883           For range partitioning the total resulting range before and
5884           after the change must be the same except in one case. This is
5885           when the last partition is reorganised, in this case it is
5886           acceptable to increase the total range.
5887           The reason is that it is not allowed to have "holes" in the
5888           middle of the ranges and thus we should not allow to reorganise
5889           to create "holes".
5890         */
5891         my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
5892         goto err;
5893       }
5894     }
5895   } // ADD, DROP, COALESCE, REORGANIZE, TABLE_REORG, REBUILD
5896   else
5897   {
5898     /*
5899      When thd->lex->part_info has a reference to a partition_info the
5900      ALTER TABLE contained a definition of a partitioning.
5901 
5902      Case I:
5903        If there was a partition before and there is a new one defined.
5904        We use the new partitioning. The new partitioning is already
5905        defined in the correct variable so no work is needed to
5906        accomplish this.
5907        We do however need to update partition_changed to ensure that not
5908        only the frm file is changed in the ALTER TABLE command.
5909 
5910      Case IIa:
5911        There was a partitioning before and there is no new one defined.
5912        Also the user has not specified to remove partitioning explicitly.
5913 
5914        We use the old partitioning also for the new table. We do this
5915        by assigning the partition_info from the table loaded in
5916        open_table to the partition_info struct used by mysql_create_table
5917        later in this method.
5918 
5919      Case IIb:
5920        There was a partitioning before and there is no new one defined.
5921        The user has specified explicitly to remove partitioning
5922 
5923        Since the user has specified explicitly to remove partitioning
5924        we override the old partitioning info and create a new table using
5925        the specified engine.
5926        In this case the partition also is changed.
5927 
5928      Case III:
5929        There was no partitioning before altering the table, there is
5930        partitioning defined in the altered table. Use the new partitioning.
5931        No work needed since the partitioning info is already in the
5932        correct variable.
5933 
5934        In this case we discover one case where the new partitioning is using
5935        the same partition function as the default (PARTITION BY KEY or
5936        PARTITION BY LINEAR KEY with the list of fields equal to the primary
5937        key fields OR PARTITION BY [LINEAR] KEY() for tables without primary
5938        key)
5939        Also here partition has changed and thus a new table must be
5940        created.
5941 
5942      Case IV:
5943        There was no partitioning before and no partitioning defined.
5944        Obviously no work needed.
5945     */
5946     partition_info *tab_part_info= table->part_info;
5947 
5948     if (tab_part_info)
5949     {
5950       if (alter_info->partition_flags & ALTER_PARTITION_REMOVE)
5951       {
5952         DBUG_PRINT("info", ("Remove partitioning"));
5953         if (!(create_info->used_fields & HA_CREATE_USED_ENGINE))
5954         {
5955           DBUG_PRINT("info", ("No explicit engine used"));
5956           create_info->db_type= tab_part_info->default_engine_type;
5957         }
5958         DBUG_PRINT("info", ("New engine type: %s",
5959                    ha_resolve_storage_engine_name(create_info->db_type)));
5960         thd->work_part_info= NULL;
5961         *partition_changed= TRUE;
5962       }
5963       else if (!thd->work_part_info)
5964       {
5965         /*
5966           Retain partitioning but possibly with a new storage engine
5967           beneath.
5968 
5969           Create a copy of TABLE::part_info to be able to modify it freely.
5970         */
5971         if (!(tab_part_info= tab_part_info->get_clone(thd)))
5972           DBUG_RETURN(TRUE);
5973         thd->work_part_info= tab_part_info;
5974         if (create_info->used_fields & HA_CREATE_USED_ENGINE &&
5975             create_info->db_type != tab_part_info->default_engine_type)
5976         {
5977           /*
5978             Make sure change of engine happens to all partitions.
5979           */
5980           DBUG_PRINT("info", ("partition changed"));
5981           if (tab_part_info->is_auto_partitioned)
5982           {
5983             /*
5984               If the user originally didn't specify partitioning to be
5985               used we can remove it now.
5986             */
5987             thd->work_part_info= NULL;
5988           }
5989           else
5990           {
5991             /*
5992               Ensure that all partitions have the proper engine set-up
5993             */
5994             set_engine_all_partitions(thd->work_part_info,
5995                                       create_info->db_type);
5996           }
5997           *partition_changed= TRUE;
5998         }
5999       }
6000       /*
6001         Prohibit inplace when partitioned by primary key and the primary key is changed.
6002       */
6003       if (!*partition_changed &&
6004           tab_part_info->part_field_array &&
6005           !tab_part_info->part_field_list.elements &&
6006           table->s->primary_key != MAX_KEY)
6007       {
6008 
6009         if (alter_info->flags & (ALTER_DROP_SYSTEM_VERSIONING |
6010                                  ALTER_ADD_SYSTEM_VERSIONING))
6011         {
6012           *partition_changed= true;
6013         }
6014         else
6015         {
6016           KEY *primary_key= table->key_info + table->s->primary_key;
6017           List_iterator_fast<Alter_drop> drop_it(alter_info->drop_list);
6018           const char *primary_name= primary_key->name.str;
6019           const Alter_drop *drop;
6020           drop_it.rewind();
6021           while ((drop= drop_it++))
6022           {
6023             if (drop->type == Alter_drop::KEY &&
6024                 0 == my_strcasecmp(system_charset_info, primary_name, drop->name))
6025               break;
6026           }
6027           if (drop)
6028             *partition_changed= TRUE;
6029         }
6030       }
6031     }
6032     if (thd->work_part_info)
6033     {
6034       partition_info *part_info= thd->work_part_info;
6035       bool is_native_partitioned= FALSE;
6036       /*
6037         Need to cater for engine types that can handle partition without
6038         using the partition handler.
6039       */
6040       if (part_info != tab_part_info)
6041       {
6042         if (part_info->fix_parser_data(thd))
6043         {
6044           goto err;
6045         }
6046         /*
6047           Compare the old and new part_info. If only key_algorithm
6048           change is done, don't consider it as changed partitioning (to avoid
6049           rebuild). This is to handle KEY (numeric_cols) partitioned tables
6050           created in 5.1. For more info, see bug#14521864.
6051         */
6052         if (alter_info->partition_flags != ALTER_PARTITION_INFO ||
6053             !table->part_info ||
6054             alter_info->algorithm(thd) !=
6055               Alter_info::ALTER_TABLE_ALGORITHM_INPLACE ||
6056             !table->part_info->has_same_partitioning(part_info))
6057         {
6058           DBUG_PRINT("info", ("partition changed"));
6059           *partition_changed= true;
6060         }
6061       }
6062 
6063       /*
6064         Set up partition default_engine_type either from the create_info
6065         or from the previus table
6066       */
6067       if (create_info->used_fields & HA_CREATE_USED_ENGINE)
6068         part_info->default_engine_type= create_info->db_type;
6069       else
6070       {
6071         if (tab_part_info)
6072           part_info->default_engine_type= tab_part_info->default_engine_type;
6073         else
6074           part_info->default_engine_type= create_info->db_type;
6075       }
6076       DBUG_ASSERT(part_info->default_engine_type &&
6077                   part_info->default_engine_type != partition_hton);
6078       if (check_native_partitioned(create_info, &is_native_partitioned,
6079                                    part_info, thd))
6080       {
6081         goto err;
6082       }
6083       if (!is_native_partitioned)
6084       {
6085         DBUG_ASSERT(create_info->db_type);
6086         create_info->db_type= partition_hton;
6087       }
6088     }
6089   }
6090   DBUG_RETURN(FALSE);
6091 err:
6092   *fast_alter_table= false;
6093   if (saved_part_info)
6094     table->part_info= saved_part_info;
6095   DBUG_RETURN(TRUE);
6096 }
6097 
6098 
6099 /*
6100   Change partitions, used to implement ALTER TABLE ADD/REORGANIZE/COALESCE
6101   partitions. This method is used to implement both single-phase and multi-
6102   phase implementations of ADD/REORGANIZE/COALESCE partitions.
6103 
6104   SYNOPSIS
6105     mysql_change_partitions()
6106     lpt                        Struct containing parameters
6107 
6108   RETURN VALUES
6109     TRUE                          Failure
6110     FALSE                         Success
6111 
6112   DESCRIPTION
6113     Request handler to add partitions as set in states of the partition
6114 
6115     Elements of the lpt parameters used:
6116     create_info                Create information used to create partitions
6117     db                         Database name
6118     table_name                 Table name
6119     copied                     Output parameter where number of copied
6120                                records are added
6121     deleted                    Output parameter where number of deleted
6122                                records are added
6123 */
6124 
mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE * lpt)6125 static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
6126 {
6127   char path[FN_REFLEN+1];
6128   int error;
6129   handler *file= lpt->table->file;
6130   THD *thd= lpt->thd;
6131   DBUG_ENTER("mysql_change_partitions");
6132 
6133   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6134 
6135   if(mysql_trans_prepare_alter_copy_data(thd))
6136     DBUG_RETURN(TRUE);
6137 
6138   /* TODO: test if bulk_insert would increase the performance */
6139 
6140   if (unlikely((error= file->ha_change_partitions(lpt->create_info, path,
6141                                                   &lpt->copied,
6142                                                   &lpt->deleted,
6143                                                   lpt->pack_frm_data,
6144                                                   lpt->pack_frm_len))))
6145   {
6146     file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR));
6147   }
6148 
6149   if (mysql_trans_commit_alter_copy_data(thd))
6150     error= 1;                                /* The error has been reported */
6151 
6152   DBUG_RETURN(MY_TEST(error));
6153 }
6154 
6155 
6156 /*
6157   Rename partitions in an ALTER TABLE of partitions
6158 
6159   SYNOPSIS
6160     mysql_rename_partitions()
6161     lpt                        Struct containing parameters
6162 
6163   RETURN VALUES
6164     TRUE                          Failure
6165     FALSE                         Success
6166 
6167   DESCRIPTION
6168     Request handler to rename partitions as set in states of the partition
6169 
6170     Parameters used:
6171     db                         Database name
6172     table_name                 Table name
6173 */
6174 
mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE * lpt)6175 static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
6176 {
6177   char path[FN_REFLEN+1];
6178   int error;
6179   DBUG_ENTER("mysql_rename_partitions");
6180 
6181   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6182   if (unlikely((error= lpt->table->file->ha_rename_partitions(path))))
6183   {
6184     if (error != 1)
6185       lpt->table->file->print_error(error, MYF(0));
6186     DBUG_RETURN(TRUE);
6187   }
6188   DBUG_RETURN(FALSE);
6189 }
6190 
6191 
6192 /*
6193   Drop partitions in an ALTER TABLE of partitions
6194 
6195   SYNOPSIS
6196     mysql_drop_partitions()
6197     lpt                        Struct containing parameters
6198 
6199   RETURN VALUES
6200     TRUE                          Failure
6201     FALSE                         Success
6202   DESCRIPTION
6203     Drop the partitions marked with PART_TO_BE_DROPPED state and remove
6204     those partitions from the list.
6205 
6206     Parameters used:
6207     table                       Table object
6208     db                          Database name
6209     table_name                  Table name
6210 */
6211 
mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE * lpt)6212 static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
6213 {
6214   char path[FN_REFLEN+1];
6215   partition_info *part_info= lpt->table->part_info;
6216   List_iterator<partition_element> part_it(part_info->partitions);
6217   uint i= 0;
6218   uint remove_count= 0;
6219   int error;
6220   DBUG_ENTER("mysql_drop_partitions");
6221 
6222   DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
6223                                                 lpt->table->s->db.str,
6224                                                 lpt->table->s->table_name.str,
6225                                                 MDL_EXCLUSIVE));
6226 
6227   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6228   if ((error= lpt->table->file->ha_drop_partitions(path)))
6229   {
6230     lpt->table->file->print_error(error, MYF(0));
6231     DBUG_RETURN(TRUE);
6232   }
6233   do
6234   {
6235     partition_element *part_elem= part_it++;
6236     if (part_elem->part_state == PART_IS_DROPPED)
6237     {
6238       part_it.remove();
6239       remove_count++;
6240     }
6241   } while (++i < part_info->num_parts);
6242   part_info->num_parts-= remove_count;
6243   DBUG_RETURN(FALSE);
6244 }
6245 
6246 
6247 /*
6248   Insert log entry into list
6249   SYNOPSIS
6250     insert_part_info_log_entry_list()
6251     log_entry
6252   RETURN VALUES
6253     NONE
6254 */
6255 
insert_part_info_log_entry_list(partition_info * part_info,DDL_LOG_MEMORY_ENTRY * log_entry)6256 static void insert_part_info_log_entry_list(partition_info *part_info,
6257                                             DDL_LOG_MEMORY_ENTRY *log_entry)
6258 {
6259   log_entry->next_active_log_entry= part_info->first_log_entry;
6260   part_info->first_log_entry= log_entry;
6261 }
6262 
6263 
6264 /*
6265   Release all log entries for this partition info struct
6266   SYNOPSIS
6267     release_part_info_log_entries()
6268     first_log_entry                 First log entry in list to release
6269   RETURN VALUES
6270     NONE
6271 */
6272 
release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY * log_entry)6273 static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry)
6274 {
6275   DBUG_ENTER("release_part_info_log_entries");
6276 
6277   while (log_entry)
6278   {
6279     release_ddl_log_memory_entry(log_entry);
6280     log_entry= log_entry->next_active_log_entry;
6281   }
6282   DBUG_VOID_RETURN;
6283 }
6284 
6285 
6286 /*
6287   Log an delete/rename frm file
6288   SYNOPSIS
6289     write_log_replace_delete_frm()
6290     lpt                            Struct for parameters
6291     next_entry                     Next reference to use in log record
6292     from_path                      Name to rename from
6293     to_path                        Name to rename to
6294     replace_flag                   TRUE if replace, else delete
6295   RETURN VALUES
6296     TRUE                           Error
6297     FALSE                          Success
6298   DESCRIPTION
6299     Support routine that writes a replace or delete of an frm file into the
6300     ddl log. It also inserts an entry that keeps track of used space into
6301     the partition info object
6302 */
6303 
write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE * lpt,uint next_entry,const char * from_path,const char * to_path,bool replace_flag)6304 static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
6305                                          uint next_entry,
6306                                          const char *from_path,
6307                                          const char *to_path,
6308                                          bool replace_flag)
6309 {
6310   DDL_LOG_ENTRY ddl_log_entry;
6311   DDL_LOG_MEMORY_ENTRY *log_entry;
6312   DBUG_ENTER("write_log_replace_delete_frm");
6313 
6314   if (replace_flag)
6315     ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
6316   else
6317     ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
6318   ddl_log_entry.next_entry= next_entry;
6319   ddl_log_entry.handler_name= reg_ext;
6320   ddl_log_entry.name= to_path;
6321   if (replace_flag)
6322     ddl_log_entry.from_name= from_path;
6323   if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
6324   {
6325     DBUG_RETURN(TRUE);
6326   }
6327   insert_part_info_log_entry_list(lpt->part_info, log_entry);
6328   DBUG_RETURN(FALSE);
6329 }
6330 
6331 
6332 /*
6333   Log final partition changes in change partition
6334   SYNOPSIS
6335     write_log_changed_partitions()
6336     lpt                      Struct containing parameters
6337   RETURN VALUES
6338     TRUE                     Error
6339     FALSE                    Success
6340   DESCRIPTION
6341     This code is used to perform safe ADD PARTITION for HASH partitions
6342     and COALESCE for HASH partitions and REORGANIZE for any type of
6343     partitions.
6344     We prepare entries for all partitions except the reorganised partitions
6345     in REORGANIZE partition, those are handled by
6346     write_log_dropped_partitions. For those partitions that are replaced
6347     special care is needed to ensure that this is performed correctly and
6348     this requires a two-phased approach with this log as a helper for this.
6349 
6350     This code is closely intertwined with the code in rename_partitions in
6351     the partition handler.
6352 */
6353 
write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE * lpt,uint * next_entry,const char * path)6354 static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
6355                                          uint *next_entry, const char *path)
6356 {
6357   DDL_LOG_ENTRY ddl_log_entry;
6358   partition_info *part_info= lpt->part_info;
6359   DDL_LOG_MEMORY_ENTRY *log_entry;
6360   char tmp_path[FN_REFLEN + 1];
6361   char normal_path[FN_REFLEN + 1];
6362   List_iterator<partition_element> part_it(part_info->partitions);
6363   uint temp_partitions= part_info->temp_partitions.elements;
6364   uint num_elements= part_info->partitions.elements;
6365   uint i= 0;
6366   DBUG_ENTER("write_log_changed_partitions");
6367 
6368   do
6369   {
6370     partition_element *part_elem= part_it++;
6371     if (part_elem->part_state == PART_IS_CHANGED ||
6372         (part_elem->part_state == PART_IS_ADDED && temp_partitions))
6373     {
6374       if (part_info->is_sub_partitioned())
6375       {
6376         List_iterator<partition_element> sub_it(part_elem->subpartitions);
6377         uint num_subparts= part_info->num_subparts;
6378         uint j= 0;
6379         do
6380         {
6381           partition_element *sub_elem= sub_it++;
6382           ddl_log_entry.next_entry= *next_entry;
6383           ddl_log_entry.handler_name=
6384                ha_resolve_storage_engine_name(sub_elem->engine_type);
6385           if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
6386                                        part_elem->partition_name,
6387                                        sub_elem->partition_name,
6388                                        TEMP_PART_NAME) ||
6389               create_subpartition_name(normal_path, sizeof(normal_path), path,
6390                                        part_elem->partition_name,
6391                                        sub_elem->partition_name,
6392                                        NORMAL_PART_NAME))
6393             DBUG_RETURN(TRUE);
6394           ddl_log_entry.name= normal_path;
6395           ddl_log_entry.from_name= tmp_path;
6396           if (part_elem->part_state == PART_IS_CHANGED)
6397             ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
6398           else
6399             ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
6400           if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
6401           {
6402             DBUG_RETURN(TRUE);
6403           }
6404           *next_entry= log_entry->entry_pos;
6405           sub_elem->log_entry= log_entry;
6406           insert_part_info_log_entry_list(part_info, log_entry);
6407         } while (++j < num_subparts);
6408       }
6409       else
6410       {
6411         ddl_log_entry.next_entry= *next_entry;
6412         ddl_log_entry.handler_name=
6413                ha_resolve_storage_engine_name(part_elem->engine_type);
6414         if (create_partition_name(tmp_path, sizeof(tmp_path), path,
6415                                   part_elem->partition_name, TEMP_PART_NAME,
6416                                   TRUE) ||
6417             create_partition_name(normal_path, sizeof(normal_path), path,
6418                                   part_elem->partition_name, NORMAL_PART_NAME,
6419                                   TRUE))
6420           DBUG_RETURN(TRUE);
6421         ddl_log_entry.name= normal_path;
6422         ddl_log_entry.from_name= tmp_path;
6423         if (part_elem->part_state == PART_IS_CHANGED)
6424           ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
6425         else
6426           ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
6427         if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
6428         {
6429           DBUG_RETURN(TRUE);
6430         }
6431         *next_entry= log_entry->entry_pos;
6432         part_elem->log_entry= log_entry;
6433         insert_part_info_log_entry_list(part_info, log_entry);
6434       }
6435     }
6436   } while (++i < num_elements);
6437   DBUG_RETURN(FALSE);
6438 }
6439 
6440 
6441 /*
6442   Log dropped partitions
6443   SYNOPSIS
6444     write_log_dropped_partitions()
6445     lpt                      Struct containing parameters
6446   RETURN VALUES
6447     TRUE                     Error
6448     FALSE                    Success
6449 */
6450 
write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE * lpt,uint * next_entry,const char * path,bool temp_list)6451 static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
6452                                          uint *next_entry,
6453                                          const char *path,
6454                                          bool temp_list)
6455 {
6456   DDL_LOG_ENTRY ddl_log_entry;
6457   partition_info *part_info= lpt->part_info;
6458   DDL_LOG_MEMORY_ENTRY *log_entry;
6459   char tmp_path[FN_REFLEN + 1];
6460   List_iterator<partition_element> part_it(part_info->partitions);
6461   List_iterator<partition_element> temp_it(part_info->temp_partitions);
6462   uint num_temp_partitions= part_info->temp_partitions.elements;
6463   uint num_elements= part_info->partitions.elements;
6464   DBUG_ENTER("write_log_dropped_partitions");
6465 
6466   ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
6467   if (temp_list)
6468     num_elements= num_temp_partitions;
6469   while (num_elements--)
6470   {
6471     partition_element *part_elem;
6472     if (temp_list)
6473       part_elem= temp_it++;
6474     else
6475       part_elem= part_it++;
6476     if (part_elem->part_state == PART_TO_BE_DROPPED ||
6477         part_elem->part_state == PART_TO_BE_ADDED ||
6478         part_elem->part_state == PART_CHANGED)
6479     {
6480       uint name_variant;
6481       if (part_elem->part_state == PART_CHANGED ||
6482           (part_elem->part_state == PART_TO_BE_ADDED &&
6483            num_temp_partitions))
6484         name_variant= TEMP_PART_NAME;
6485       else
6486         name_variant= NORMAL_PART_NAME;
6487       if (part_info->is_sub_partitioned())
6488       {
6489         List_iterator<partition_element> sub_it(part_elem->subpartitions);
6490         uint num_subparts= part_info->num_subparts;
6491         uint j= 0;
6492         do
6493         {
6494           partition_element *sub_elem= sub_it++;
6495           ddl_log_entry.next_entry= *next_entry;
6496           ddl_log_entry.handler_name=
6497                ha_resolve_storage_engine_name(sub_elem->engine_type);
6498           if (create_subpartition_name(tmp_path, sizeof(tmp_path), path,
6499                                        part_elem->partition_name,
6500                                        sub_elem->partition_name, name_variant))
6501             DBUG_RETURN(TRUE);
6502           ddl_log_entry.name= tmp_path;
6503           if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
6504           {
6505             DBUG_RETURN(TRUE);
6506           }
6507           *next_entry= log_entry->entry_pos;
6508           sub_elem->log_entry= log_entry;
6509           insert_part_info_log_entry_list(part_info, log_entry);
6510         } while (++j < num_subparts);
6511       }
6512       else
6513       {
6514         ddl_log_entry.next_entry= *next_entry;
6515         ddl_log_entry.handler_name=
6516                ha_resolve_storage_engine_name(part_elem->engine_type);
6517         if (create_partition_name(tmp_path, sizeof(tmp_path), path,
6518                                   part_elem->partition_name, name_variant,
6519                                   TRUE))
6520           DBUG_RETURN(TRUE);
6521         ddl_log_entry.name= tmp_path;
6522         if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
6523         {
6524           DBUG_RETURN(TRUE);
6525         }
6526         *next_entry= log_entry->entry_pos;
6527         part_elem->log_entry= log_entry;
6528         insert_part_info_log_entry_list(part_info, log_entry);
6529       }
6530     }
6531   }
6532   DBUG_RETURN(FALSE);
6533 }
6534 
6535 
6536 /*
6537   Set execute log entry in ddl log for this partitioned table
6538   SYNOPSIS
6539     set_part_info_exec_log_entry()
6540     part_info                      Partition info object
6541     exec_log_entry                 Log entry
6542   RETURN VALUES
6543     NONE
6544 */
6545 
set_part_info_exec_log_entry(partition_info * part_info,DDL_LOG_MEMORY_ENTRY * exec_log_entry)6546 static void set_part_info_exec_log_entry(partition_info *part_info,
6547                                          DDL_LOG_MEMORY_ENTRY *exec_log_entry)
6548 {
6549   part_info->exec_log_entry= exec_log_entry;
6550   exec_log_entry->next_active_log_entry= NULL;
6551 }
6552 
6553 
6554 /*
6555   Write the log entry to ensure that the shadow frm file is removed at
6556   crash.
6557   SYNOPSIS
6558     write_log_drop_shadow_frm()
6559     lpt                      Struct containing parameters
6560     install_frm              Should we log action to install shadow frm or should
6561                              the action be to remove the shadow frm file.
6562   RETURN VALUES
6563     TRUE                     Error
6564     FALSE                    Success
6565   DESCRIPTION
6566     Prepare an entry to the ddl log indicating a drop/install of the shadow frm
6567     file and its corresponding handler file.
6568 */
6569 
write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE * lpt)6570 static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
6571 {
6572   partition_info *part_info= lpt->part_info;
6573   DDL_LOG_MEMORY_ENTRY *log_entry;
6574   DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
6575   char shadow_path[FN_REFLEN + 1];
6576   DBUG_ENTER("write_log_drop_shadow_frm");
6577 
6578   build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
6579   mysql_mutex_lock(&LOCK_gdl);
6580   if (write_log_replace_delete_frm(lpt, 0UL, NULL,
6581                                   (const char*)shadow_path, FALSE))
6582     goto error;
6583   log_entry= part_info->first_log_entry;
6584   if (write_execute_ddl_log_entry(log_entry->entry_pos,
6585                                     FALSE, &exec_log_entry))
6586     goto error;
6587   mysql_mutex_unlock(&LOCK_gdl);
6588   set_part_info_exec_log_entry(part_info, exec_log_entry);
6589   DBUG_RETURN(FALSE);
6590 
6591 error:
6592   release_part_info_log_entries(part_info->first_log_entry);
6593   mysql_mutex_unlock(&LOCK_gdl);
6594   part_info->first_log_entry= NULL;
6595   my_error(ER_DDL_LOG_ERROR, MYF(0));
6596   DBUG_RETURN(TRUE);
6597 }
6598 
6599 
6600 /*
6601   Log renaming of shadow frm to real frm name and dropping of old frm
6602   SYNOPSIS
6603     write_log_rename_frm()
6604     lpt                      Struct containing parameters
6605   RETURN VALUES
6606     TRUE                     Error
6607     FALSE                    Success
6608   DESCRIPTION
6609     Prepare an entry to ensure that we complete the renaming of the frm
6610     file if failure occurs in the middle of the rename process.
6611 */
6612 
write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE * lpt)6613 static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
6614 {
6615   partition_info *part_info= lpt->part_info;
6616   DDL_LOG_MEMORY_ENTRY *log_entry;
6617   DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
6618   char path[FN_REFLEN + 1];
6619   char shadow_path[FN_REFLEN + 1];
6620   DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
6621   DBUG_ENTER("write_log_rename_frm");
6622 
6623   part_info->first_log_entry= NULL;
6624   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6625   build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
6626   mysql_mutex_lock(&LOCK_gdl);
6627   if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
6628     goto error;
6629   log_entry= part_info->first_log_entry;
6630   part_info->frm_log_entry= log_entry;
6631   if (write_execute_ddl_log_entry(log_entry->entry_pos,
6632                                     FALSE, &exec_log_entry))
6633     goto error;
6634   release_part_info_log_entries(old_first_log_entry);
6635   mysql_mutex_unlock(&LOCK_gdl);
6636   DBUG_RETURN(FALSE);
6637 
6638 error:
6639   release_part_info_log_entries(part_info->first_log_entry);
6640   mysql_mutex_unlock(&LOCK_gdl);
6641   part_info->first_log_entry= old_first_log_entry;
6642   part_info->frm_log_entry= NULL;
6643   my_error(ER_DDL_LOG_ERROR, MYF(0));
6644   DBUG_RETURN(TRUE);
6645 }
6646 
6647 
6648 /*
6649   Write the log entries to ensure that the drop partition command is completed
6650   even in the presence of a crash.
6651 
6652   SYNOPSIS
6653     write_log_drop_partition()
6654     lpt                      Struct containing parameters
6655   RETURN VALUES
6656     TRUE                     Error
6657     FALSE                    Success
6658   DESCRIPTION
6659     Prepare entries to the ddl log indicating all partitions to drop and to
6660     install the shadow frm file and remove the old frm file.
6661 */
6662 
write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE * lpt)6663 static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
6664 {
6665   partition_info *part_info= lpt->part_info;
6666   DDL_LOG_MEMORY_ENTRY *log_entry;
6667   DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
6668   char tmp_path[FN_REFLEN + 1];
6669   char path[FN_REFLEN + 1];
6670   uint next_entry= 0;
6671   DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
6672   DBUG_ENTER("write_log_drop_partition");
6673 
6674   part_info->first_log_entry= NULL;
6675   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6676   build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
6677   mysql_mutex_lock(&LOCK_gdl);
6678   if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
6679                                    FALSE))
6680     goto error;
6681   if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path,
6682                                   (const char*)path, TRUE))
6683     goto error;
6684   log_entry= part_info->first_log_entry;
6685   part_info->frm_log_entry= log_entry;
6686   if (write_execute_ddl_log_entry(log_entry->entry_pos,
6687                                     FALSE, &exec_log_entry))
6688     goto error;
6689   release_part_info_log_entries(old_first_log_entry);
6690   mysql_mutex_unlock(&LOCK_gdl);
6691   DBUG_RETURN(FALSE);
6692 
6693 error:
6694   release_part_info_log_entries(part_info->first_log_entry);
6695   mysql_mutex_unlock(&LOCK_gdl);
6696   part_info->first_log_entry= old_first_log_entry;
6697   part_info->frm_log_entry= NULL;
6698   my_error(ER_DDL_LOG_ERROR, MYF(0));
6699   DBUG_RETURN(TRUE);
6700 }
6701 
6702 
6703 /*
6704   Write the log entries to ensure that the add partition command is not
6705   executed at all if a crash before it has completed
6706 
6707   SYNOPSIS
6708     write_log_add_change_partition()
6709     lpt                      Struct containing parameters
6710   RETURN VALUES
6711     TRUE                     Error
6712     FALSE                    Success
6713   DESCRIPTION
6714     Prepare entries to the ddl log indicating all partitions to drop and to
6715     remove the shadow frm file.
6716     We always inject entries backwards in the list in the ddl log since we
6717     don't know the entry position until we have written it.
6718 */
6719 
write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE * lpt)6720 static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
6721 {
6722   partition_info *part_info= lpt->part_info;
6723   DDL_LOG_MEMORY_ENTRY *log_entry;
6724   DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
6725   char tmp_path[FN_REFLEN + 1];
6726   char path[FN_REFLEN + 1];
6727   uint next_entry= 0;
6728   DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
6729   /* write_log_drop_shadow_frm(lpt) must have been run first */
6730   DBUG_ASSERT(old_first_log_entry);
6731   DBUG_ENTER("write_log_add_change_partition");
6732 
6733   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6734   build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
6735   mysql_mutex_lock(&LOCK_gdl);
6736 
6737   /* Relink the previous drop shadow frm entry */
6738   if (old_first_log_entry)
6739     next_entry= old_first_log_entry->entry_pos;
6740   if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
6741                                    FALSE))
6742     goto error;
6743   log_entry= part_info->first_log_entry;
6744 
6745   if (write_execute_ddl_log_entry(log_entry->entry_pos,
6746                                   FALSE,
6747                                   /* Reuse the old execute ddl_log_entry */
6748                                   &exec_log_entry))
6749     goto error;
6750   mysql_mutex_unlock(&LOCK_gdl);
6751   set_part_info_exec_log_entry(part_info, exec_log_entry);
6752   DBUG_RETURN(FALSE);
6753 
6754 error:
6755   release_part_info_log_entries(part_info->first_log_entry);
6756   mysql_mutex_unlock(&LOCK_gdl);
6757   part_info->first_log_entry= old_first_log_entry;
6758   my_error(ER_DDL_LOG_ERROR, MYF(0));
6759   DBUG_RETURN(TRUE);
6760 }
6761 
6762 
6763 /*
6764   Write description of how to complete the operation after first phase of
6765   change partitions.
6766 
6767   SYNOPSIS
6768     write_log_final_change_partition()
6769     lpt                      Struct containing parameters
6770   RETURN VALUES
6771     TRUE                     Error
6772     FALSE                    Success
6773   DESCRIPTION
6774     We will write log entries that specify to
6775     1) Install the shadow frm file.
6776     2) Remove all partitions reorganized. (To be able to reorganize a partition
6777        to the same name. Like in REORGANIZE p0 INTO (p0, p1),
6778        so that the later rename from the new p0-temporary name to p0 don't
6779        fail because the partition already exists.
6780     3) Rename others to reflect the new naming scheme.
6781 
6782     Note that it is written in the ddl log in reverse.
6783 */
6784 
write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE * lpt)6785 static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
6786 {
6787   partition_info *part_info= lpt->part_info;
6788   DDL_LOG_MEMORY_ENTRY *log_entry;
6789   DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
6790   char path[FN_REFLEN + 1];
6791   char shadow_path[FN_REFLEN + 1];
6792   DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
6793   uint next_entry= 0;
6794   DBUG_ENTER("write_log_final_change_partition");
6795 
6796   /*
6797     Do not link any previous log entry.
6798     Replace the revert operations with forced retry operations.
6799   */
6800   part_info->first_log_entry= NULL;
6801   build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
6802   build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
6803   mysql_mutex_lock(&LOCK_gdl);
6804   if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
6805     goto error;
6806   if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
6807                                    lpt->alter_info->partition_flags &
6808                                    ALTER_PARTITION_REORGANIZE))
6809     goto error;
6810   if (write_log_replace_delete_frm(lpt, next_entry, shadow_path, path, TRUE))
6811     goto error;
6812   log_entry= part_info->first_log_entry;
6813   part_info->frm_log_entry= log_entry;
6814   /* Overwrite the revert execute log entry with this retry execute entry */
6815   if (write_execute_ddl_log_entry(log_entry->entry_pos,
6816                                     FALSE, &exec_log_entry))
6817     goto error;
6818   release_part_info_log_entries(old_first_log_entry);
6819   mysql_mutex_unlock(&LOCK_gdl);
6820   DBUG_RETURN(FALSE);
6821 
6822 error:
6823   release_part_info_log_entries(part_info->first_log_entry);
6824   mysql_mutex_unlock(&LOCK_gdl);
6825   part_info->first_log_entry= old_first_log_entry;
6826   part_info->frm_log_entry= NULL;
6827   my_error(ER_DDL_LOG_ERROR, MYF(0));
6828   DBUG_RETURN(TRUE);
6829 }
6830 
6831 
6832 /*
6833   Remove entry from ddl log and release resources for others to use
6834 
6835   SYNOPSIS
6836     write_log_completed()
6837     lpt                      Struct containing parameters
6838   RETURN VALUES
6839     TRUE                     Error
6840     FALSE                    Success
6841 */
6842 
write_log_completed(ALTER_PARTITION_PARAM_TYPE * lpt,bool dont_crash)6843 static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
6844                                 bool dont_crash)
6845 {
6846   partition_info *part_info= lpt->part_info;
6847   DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry;
6848   DBUG_ENTER("write_log_completed");
6849 
6850   DBUG_ASSERT(log_entry);
6851   mysql_mutex_lock(&LOCK_gdl);
6852   if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry))
6853   {
6854     /*
6855       Failed to write, Bad...
6856       We have completed the operation but have log records to REMOVE
6857       stuff that shouldn't be removed. What clever things could one do
6858       here? An error output was written to the error output by the
6859       above method so we don't do anything here.
6860     */
6861     ;
6862   }
6863   release_part_info_log_entries(part_info->first_log_entry);
6864   release_part_info_log_entries(part_info->exec_log_entry);
6865   mysql_mutex_unlock(&LOCK_gdl);
6866   part_info->exec_log_entry= NULL;
6867   part_info->first_log_entry= NULL;
6868   DBUG_VOID_RETURN;
6869 }
6870 
6871 
6872 /*
6873    Release all log entries
6874    SYNOPSIS
6875      release_log_entries()
6876      part_info                  Partition info struct
6877    RETURN VALUES
6878      NONE
6879 */
6880 
release_log_entries(partition_info * part_info)6881 static void release_log_entries(partition_info *part_info)
6882 {
6883   mysql_mutex_lock(&LOCK_gdl);
6884   release_part_info_log_entries(part_info->first_log_entry);
6885   release_part_info_log_entries(part_info->exec_log_entry);
6886   mysql_mutex_unlock(&LOCK_gdl);
6887   part_info->first_log_entry= NULL;
6888   part_info->exec_log_entry= NULL;
6889 }
6890 
6891 
6892 /*
6893   Final part of partition changes to handle things when under
6894   LOCK TABLES.
6895   SYNPOSIS
6896     alter_partition_lock_handling()
6897     lpt                        Struct carrying parameters
6898   RETURN VALUES
6899     NONE
6900 */
alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE * lpt)6901 static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
6902 {
6903   THD *thd= lpt->thd;
6904 
6905   if (lpt->table)
6906   {
6907     /*
6908       Remove all instances of the table and its locks and other resources.
6909     */
6910     close_all_tables_for_name(thd, lpt->table->s, HA_EXTRA_NOT_USED, NULL);
6911   }
6912   lpt->table= 0;
6913   lpt->table_list->table= 0;
6914   if (thd->locked_tables_mode)
6915   {
6916     Diagnostics_area *stmt_da= NULL;
6917     Diagnostics_area tmp_stmt_da(true);
6918 
6919     if (unlikely(thd->is_error()))
6920     {
6921       /* reopen might fail if we have a previous error, use a temporary da. */
6922       stmt_da= thd->get_stmt_da();
6923       thd->set_stmt_da(&tmp_stmt_da);
6924     }
6925 
6926     if (unlikely(thd->locked_tables_list.reopen_tables(thd, false)))
6927       sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
6928 
6929     if (stmt_da)
6930       thd->set_stmt_da(stmt_da);
6931   }
6932 }
6933 
6934 
6935 /**
6936   Unlock and close table before renaming and dropping partitions.
6937 
6938   @param lpt  Struct carrying parameters
6939 
6940   @return Always 0.
6941 */
6942 
alter_close_table(ALTER_PARTITION_PARAM_TYPE * lpt)6943 static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt)
6944 {
6945   DBUG_ENTER("alter_close_table");
6946 
6947   if (lpt->table->db_stat)
6948   {
6949     mysql_lock_remove(lpt->thd, lpt->thd->lock, lpt->table);
6950     lpt->table->file->ha_close();
6951     lpt->table->db_stat= 0;                        // Mark file closed
6952   }
6953   DBUG_RETURN(0);
6954 }
6955 
6956 
6957 /**
6958   Handle errors for ALTER TABLE for partitioning.
6959 
6960   @param lpt                Struct carrying parameters
6961   @param action_completed   The action must be completed, NOT reverted
6962   @param drop_partition     Partitions has not been dropped yet
6963   @param frm_install        The shadow frm-file has not yet been installed
6964   @param close_table        Table is still open, close it before reverting
6965 */
6966 
handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE * lpt,bool action_completed,bool drop_partition,bool frm_install,bool close_table)6967 void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
6968                              bool action_completed,
6969                              bool drop_partition,
6970                              bool frm_install,
6971                              bool close_table)
6972 {
6973   partition_info *part_info= lpt->part_info;
6974   THD *thd= lpt->thd;
6975   TABLE *table= lpt->table;
6976   DBUG_ENTER("handle_alter_part_error");
6977   DBUG_ASSERT(table->needs_reopen());
6978 
6979   if (close_table)
6980   {
6981     /*
6982       All instances of this table needs to be closed.
6983       Better to do that here, than leave the cleaning up to others.
6984       Aquire EXCLUSIVE mdl lock if not already aquired.
6985     */
6986     if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str,
6987                                         lpt->table_name.str,
6988                                         MDL_EXCLUSIVE))
6989     {
6990       if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6991       {
6992         /* At least remove this instance on failure */
6993         goto err_exclusive_lock;
6994       }
6995     }
6996     /* Ensure the share is destroyed and reopened. */
6997     if (part_info)
6998       part_info= part_info->get_clone(thd);
6999     close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
7000   }
7001   else
7002   {
7003 err_exclusive_lock:
7004     /*
7005       Temporarily remove it from the locked table list, so that it will get
7006       reopened.
7007     */
7008     thd->locked_tables_list.unlink_from_list(thd,
7009                                              table->pos_in_locked_tables,
7010                                              false);
7011     /*
7012       Make sure that the table is unlocked, closed and removed from
7013       the table cache.
7014     */
7015     mysql_lock_remove(thd, thd->lock, table);
7016     if (part_info)
7017       part_info= part_info->get_clone(thd);
7018     close_thread_table(thd, &thd->open_tables);
7019     lpt->table_list->table= NULL;
7020   }
7021 
7022   if (part_info->first_log_entry &&
7023       execute_ddl_log_entry(thd, part_info->first_log_entry->entry_pos))
7024   {
7025     /*
7026       We couldn't recover from error, most likely manual interaction
7027       is required.
7028     */
7029     write_log_completed(lpt, FALSE);
7030     release_log_entries(part_info);
7031     if (!action_completed)
7032     {
7033       if (drop_partition)
7034       {
7035         /* Table is still ok, but we left a shadow frm file behind. */
7036         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,
7037                             "%s %s",
7038            "Operation was unsuccessful, table is still intact,",
7039            "but it is possible that a shadow frm file was left behind");
7040       }
7041       else
7042       {
7043         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,
7044                             "%s %s %s %s",
7045            "Operation was unsuccessful, table is still intact,",
7046            "but it is possible that a shadow frm file was left behind.",
7047            "It is also possible that temporary partitions are left behind,",
7048            "these could be empty or more or less filled with records");
7049       }
7050     }
7051     else
7052     {
7053       if (frm_install)
7054       {
7055         /*
7056            Failed during install of shadow frm file, table isn't intact
7057            and dropped partitions are still there
7058         */
7059         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,
7060                             "%s %s %s",
7061           "Failed during alter of partitions, table is no longer intact.",
7062           "The frm file is in an unknown state, and a backup",
7063           "is required.");
7064       }
7065       else if (drop_partition)
7066       {
7067         /*
7068           Table is ok, we have switched to new table but left dropped
7069           partitions still in their places. We remove the log records and
7070           ask the user to perform the action manually. We remove the log
7071           records and ask the user to perform the action manually.
7072         */
7073         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,
7074                             "%s %s",
7075               "Failed during drop of partitions, table is intact.",
7076               "Manual drop of remaining partitions is required");
7077       }
7078       else
7079       {
7080         /*
7081           We failed during renaming of partitions. The table is most
7082           certainly in a very bad state so we give user warning and disable
7083           the table by writing an ancient frm version into it.
7084         */
7085         push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,
7086                             "%s %s %s",
7087            "Failed during renaming of partitions. We are now in a position",
7088            "where table is not reusable",
7089            "Table is disabled by writing ancient frm file version into it");
7090       }
7091     }
7092   }
7093   else
7094   {
7095     release_log_entries(part_info);
7096     if (!action_completed)
7097     {
7098       /*
7099         We hit an error before things were completed but managed
7100         to recover from the error. An error occurred and we have
7101         restored things to original so no need for further action.
7102       */
7103       ;
7104     }
7105     else
7106     {
7107       /*
7108         We hit an error after we had completed most of the operation
7109         and were successful in a second attempt so the operation
7110         actually is successful now. We need to issue a warning that
7111         even though we reported an error the operation was successfully
7112         completed.
7113       */
7114       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,"%s %s",
7115          "Operation was successfully completed by failure handling,",
7116          "after failure of normal operation");
7117     }
7118   }
7119 
7120   if (thd->locked_tables_mode)
7121   {
7122     Diagnostics_area *stmt_da= NULL;
7123     Diagnostics_area tmp_stmt_da(true);
7124 
7125     if (unlikely(thd->is_error()))
7126     {
7127       /* reopen might fail if we have a previous error, use a temporary da. */
7128       stmt_da= thd->get_stmt_da();
7129       thd->set_stmt_da(&tmp_stmt_da);
7130     }
7131 
7132     if (unlikely(thd->locked_tables_list.reopen_tables(thd, false)))
7133       sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
7134 
7135     if (stmt_da)
7136       thd->set_stmt_da(stmt_da);
7137   }
7138 
7139   DBUG_VOID_RETURN;
7140 }
7141 
7142 
7143 /**
7144   Downgrade an exclusive MDL lock if under LOCK TABLE.
7145 
7146   If we don't downgrade the lock, it will not be downgraded or released
7147   until the table is unlocked, resulting in blocking other threads using
7148   the table.
7149 */
7150 
downgrade_mdl_if_lock_tables_mode(THD * thd,MDL_ticket * ticket,enum_mdl_type type)7151 static void downgrade_mdl_if_lock_tables_mode(THD *thd, MDL_ticket *ticket,
7152                                               enum_mdl_type type)
7153 {
7154   if (thd->locked_tables_mode)
7155     ticket->downgrade_lock(type);
7156 }
7157 
7158 
7159 /**
7160   Actually perform the change requested by ALTER TABLE of partitions
7161   previously prepared.
7162 
7163   @param thd                           Thread object
7164   @param table                         Original table object with new part_info
7165   @param alter_info                    ALTER TABLE info
7166   @param create_info                   Create info for CREATE TABLE
7167   @param table_list                    List of the table involved
7168   @param db                            Database name of new table
7169   @param table_name                    Table name of new table
7170 
7171   @return Operation status
7172     @retval TRUE                          Error
7173     @retval FALSE                         Success
7174 
7175   @note
7176     Perform all ALTER TABLE operations for partitioned tables that can be
7177     performed fast without a full copy of the original table.
7178 */
7179 
fast_alter_partition_table(THD * thd,TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,TABLE_LIST * table_list,const LEX_CSTRING * db,const LEX_CSTRING * table_name)7180 uint fast_alter_partition_table(THD *thd, TABLE *table,
7181                                 Alter_info *alter_info,
7182                                 HA_CREATE_INFO *create_info,
7183                                 TABLE_LIST *table_list,
7184                                 const LEX_CSTRING *db,
7185                                 const LEX_CSTRING *table_name)
7186 {
7187   /* Set-up struct used to write frm files */
7188   partition_info *part_info;
7189   ALTER_PARTITION_PARAM_TYPE lpt_obj;
7190   ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
7191   bool action_completed= FALSE;
7192   bool close_table_on_failure= FALSE;
7193   bool frm_install= FALSE;
7194   MDL_ticket *mdl_ticket= table->mdl_ticket;
7195   DBUG_ENTER("fast_alter_partition_table");
7196   DBUG_ASSERT(table->needs_reopen());
7197 
7198   part_info= table->part_info;
7199   lpt->thd= thd;
7200   lpt->table_list= table_list;
7201   lpt->part_info= part_info;
7202   lpt->alter_info= alter_info;
7203   lpt->create_info= create_info;
7204   lpt->db_options= create_info->table_options_with_row_type();
7205   lpt->table= table;
7206   lpt->key_info_buffer= 0;
7207   lpt->key_count= 0;
7208   lpt->db= *db;
7209   lpt->table_name= *table_name;
7210   lpt->copied= 0;
7211   lpt->deleted= 0;
7212   lpt->pack_frm_data= NULL;
7213   lpt->pack_frm_len= 0;
7214 
7215   if (table->file->alter_table_flags(alter_info->flags) &
7216         HA_PARTITION_ONE_PHASE)
7217   {
7218     /*
7219       In the case where the engine supports one phase online partition
7220       changes it is not necessary to have any exclusive locks. The
7221       correctness is upheld instead by transactions being aborted if they
7222       access the table after its partition definition has changed (if they
7223       are still using the old partition definition).
7224 
7225       The handler is in this case responsible to ensure that all users
7226       start using the new frm file after it has changed. To implement
7227       one phase it is necessary for the handler to have the master copy
7228       of the frm file and use discovery mechanisms to renew it. Thus
7229       write frm will write the frm, pack the new frm and finally
7230       the frm is deleted and the discovery mechanisms will either restore
7231       back to the old or installing the new after the change is activated.
7232 
7233       Thus all open tables will be discovered that they are old, if not
7234       earlier as soon as they try an operation using the old table. One
7235       should ensure that this is checked already when opening a table,
7236       even if it is found in the cache of open tables.
7237 
7238       change_partitions will perform all operations and it is the duty of
7239       the handler to ensure that the frm files in the system gets updated
7240       in synch with the changes made and if an error occurs that a proper
7241       error handling is done.
7242 
7243       If the MySQL Server crashes at this moment but the handler succeeds
7244       in performing the change then the binlog is not written for the
7245       change. There is no way to solve this as long as the binlog is not
7246       transactional and even then it is hard to solve it completely.
7247 
7248       The first approach here was to downgrade locks. Now a different approach
7249       is decided upon. The idea is that the handler will have access to the
7250       Alter_info when store_lock arrives with TL_WRITE_ALLOW_READ. So if the
7251       handler knows that this functionality can be handled with a lower lock
7252       level it will set the lock level to TL_WRITE_ALLOW_WRITE immediately.
7253       Thus the need to downgrade the lock disappears.
7254       1) Write the new frm, pack it and then delete it
7255       2) Perform the change within the handler
7256     */
7257     if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
7258         mysql_change_partitions(lpt))
7259     {
7260       goto err;
7261     }
7262   }
7263   else if (alter_info->partition_flags & ALTER_PARTITION_DROP)
7264   {
7265     /*
7266       Now after all checks and setting state on dropped partitions we can
7267       start the actual dropping of the partitions.
7268 
7269       Drop partition is actually two things happening. The first is that
7270       a lot of records are deleted. The second is that the behaviour of
7271       subsequent updates and writes and deletes will change. The delete
7272       part can be handled without any particular high lock level by
7273       transactional engines whereas non-transactional engines need to
7274       ensure that this change is done with an exclusive lock on the table.
7275       The second part, the change of partitioning does however require
7276       an exclusive lock to install the new partitioning as one atomic
7277       operation. If this is not the case, it is possible for two
7278       transactions to see the change in a different order than their
7279       serialisation order. Thus we need an exclusive lock for both
7280       transactional and non-transactional engines.
7281 
7282       For LIST partitions it could be possible to avoid the exclusive lock
7283       (and for RANGE partitions if they didn't rearrange range definitions
7284       after a DROP PARTITION) if one ensured that failed accesses to the
7285       dropped partitions was aborted for sure (thus only possible for
7286       transactional engines).
7287 
7288       0) Write an entry that removes the shadow frm file if crash occurs
7289       1) Write the new frm file as a shadow frm
7290       2) Get an exclusive metadata lock on the table (waits for all active
7291          transactions using this table). This ensures that we
7292          can release all other locks on the table and since no one can open
7293          the table, there can be no new threads accessing the table. They
7294          will be hanging on this exclusive lock.
7295       3) Write the ddl log to ensure that the operation is completed
7296          even in the presence of a MySQL Server crash (the log is executed
7297          before any other threads are started, so there are no locking issues).
7298       4) Close the table that have already been opened but didn't stumble on
7299          the abort locked previously. This is done as part of the
7300          alter_close_table call.
7301       5) Write the bin log
7302          Unfortunately the writing of the binlog is not synchronised with
7303          other logging activities. So no matter in which order the binlog
7304          is written compared to other activities there will always be cases
7305          where crashes make strange things occur. In this placement it can
7306          happen that the ALTER TABLE DROP PARTITION gets performed in the
7307          master but not in the slaves if we have a crash, after writing the
7308          ddl log but before writing the binlog. A solution to this would
7309          require writing the statement first in the ddl log and then
7310          when recovering from the crash read the binlog and insert it into
7311          the binlog if not written already.
7312       6) Install the previously written shadow frm file
7313       7) Prepare handlers for drop of partitions
7314       8) Drop the partitions
7315       9) Remove entries from ddl log
7316       10) Reopen table if under lock tables
7317       11) Complete query
7318 
7319       We insert Error injections at all places where it could be interesting
7320       to test if recovery is properly done.
7321     */
7322     if (write_log_drop_shadow_frm(lpt) ||
7323         ERROR_INJECT_CRASH("crash_drop_partition_1") ||
7324         ERROR_INJECT_ERROR("fail_drop_partition_1") ||
7325         mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
7326         ERROR_INJECT_CRASH("crash_drop_partition_2") ||
7327         ERROR_INJECT_ERROR("fail_drop_partition_2") ||
7328         wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
7329         ERROR_INJECT_CRASH("crash_drop_partition_3") ||
7330         ERROR_INJECT_ERROR("fail_drop_partition_3") ||
7331         (close_table_on_failure= TRUE, FALSE) ||
7332         write_log_drop_partition(lpt) ||
7333         (action_completed= TRUE, FALSE) ||
7334         ERROR_INJECT_CRASH("crash_drop_partition_4") ||
7335         ERROR_INJECT_ERROR("fail_drop_partition_4") ||
7336         alter_close_table(lpt) ||
7337         (close_table_on_failure= FALSE, FALSE) ||
7338         ERROR_INJECT_CRASH("crash_drop_partition_5") ||
7339         ERROR_INJECT_ERROR("fail_drop_partition_5") ||
7340         ((!thd->lex->no_write_to_binlog) &&
7341          (write_bin_log(thd, FALSE,
7342                         thd->query(), thd->query_length()), FALSE)) ||
7343         ERROR_INJECT_CRASH("crash_drop_partition_6") ||
7344         ERROR_INJECT_ERROR("fail_drop_partition_6") ||
7345         (frm_install= TRUE, FALSE) ||
7346         mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
7347         (frm_install= FALSE, FALSE) ||
7348         ERROR_INJECT_CRASH("crash_drop_partition_7") ||
7349         ERROR_INJECT_ERROR("fail_drop_partition_7") ||
7350         mysql_drop_partitions(lpt) ||
7351         ERROR_INJECT_CRASH("crash_drop_partition_8") ||
7352         ERROR_INJECT_ERROR("fail_drop_partition_8") ||
7353         (write_log_completed(lpt, FALSE), FALSE) ||
7354         ERROR_INJECT_CRASH("crash_drop_partition_9") ||
7355         ERROR_INJECT_ERROR("fail_drop_partition_9") ||
7356         (alter_partition_lock_handling(lpt), FALSE))
7357     {
7358       handle_alter_part_error(lpt, action_completed, TRUE, frm_install,
7359                               close_table_on_failure);
7360       goto err;
7361     }
7362   }
7363   else if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
7364            (part_info->part_type == RANGE_PARTITION ||
7365             part_info->part_type == LIST_PARTITION))
7366   {
7367     /*
7368       ADD RANGE/LIST PARTITIONS
7369       In this case there are no tuples removed and no tuples are added.
7370       Thus the operation is merely adding a new partition. Thus it is
7371       necessary to perform the change as an atomic operation. Otherwise
7372       someone reading without seeing the new partition could potentially
7373       miss updates made by a transaction serialised before it that are
7374       inserted into the new partition.
7375 
7376       0) Write an entry that removes the shadow frm file if crash occurs
7377       1) Write the new frm file as a shadow frm file
7378       2) Get an exclusive metadata lock on the table (waits for all active
7379          transactions using this table). This ensures that we
7380          can release all other locks on the table and since no one can open
7381          the table, there can be no new threads accessing the table. They
7382          will be hanging on this exclusive lock.
7383       3) Write an entry to remove the new parttions if crash occurs
7384       4) Add the new partitions.
7385       5) Close all instances of the table and remove them from the table cache.
7386       6) Write binlog
7387       7) Now the change is completed except for the installation of the
7388          new frm file. We thus write an action in the log to change to
7389          the shadow frm file
7390       8) Install the new frm file of the table where the partitions are
7391          added to the table.
7392       9) Remove entries from ddl log
7393       10)Reopen tables if under lock tables
7394       11)Complete query
7395     */
7396     if (write_log_drop_shadow_frm(lpt) ||
7397         ERROR_INJECT_CRASH("crash_add_partition_1") ||
7398         ERROR_INJECT_ERROR("fail_add_partition_1") ||
7399         mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
7400         ERROR_INJECT_CRASH("crash_add_partition_2") ||
7401         ERROR_INJECT_ERROR("fail_add_partition_2") ||
7402         wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
7403         ERROR_INJECT_CRASH("crash_add_partition_3") ||
7404         ERROR_INJECT_ERROR("fail_add_partition_3") ||
7405         (close_table_on_failure= TRUE, FALSE) ||
7406         write_log_add_change_partition(lpt) ||
7407         ERROR_INJECT_CRASH("crash_add_partition_4") ||
7408         ERROR_INJECT_ERROR("fail_add_partition_4") ||
7409         mysql_change_partitions(lpt) ||
7410         ERROR_INJECT_CRASH("crash_add_partition_5") ||
7411         ERROR_INJECT_ERROR("fail_add_partition_5") ||
7412         (close_table_on_failure= FALSE, FALSE) ||
7413         alter_close_table(lpt) ||
7414         ERROR_INJECT_CRASH("crash_add_partition_6") ||
7415         ERROR_INJECT_ERROR("fail_add_partition_6") ||
7416         ((!thd->lex->no_write_to_binlog) &&
7417          (write_bin_log(thd, FALSE,
7418                         thd->query(), thd->query_length()), FALSE)) ||
7419         ERROR_INJECT_CRASH("crash_add_partition_7") ||
7420         ERROR_INJECT_ERROR("fail_add_partition_7") ||
7421         write_log_rename_frm(lpt) ||
7422         (action_completed= TRUE, FALSE) ||
7423         ERROR_INJECT_CRASH("crash_add_partition_8") ||
7424         ERROR_INJECT_ERROR("fail_add_partition_8") ||
7425         (frm_install= TRUE, FALSE) ||
7426         mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
7427         (frm_install= FALSE, FALSE) ||
7428         ERROR_INJECT_CRASH("crash_add_partition_9") ||
7429         ERROR_INJECT_ERROR("fail_add_partition_9") ||
7430         (write_log_completed(lpt, FALSE), FALSE) ||
7431         ERROR_INJECT_CRASH("crash_add_partition_10") ||
7432         ERROR_INJECT_ERROR("fail_add_partition_10") ||
7433         (alter_partition_lock_handling(lpt), FALSE))
7434     {
7435       handle_alter_part_error(lpt, action_completed, FALSE, frm_install,
7436                               close_table_on_failure);
7437       goto err;
7438     }
7439   }
7440   else
7441   {
7442     /*
7443       ADD HASH PARTITION/
7444       COALESCE PARTITION/
7445       REBUILD PARTITION/
7446       REORGANIZE PARTITION
7447 
7448       In this case all records are still around after the change although
7449       possibly organised into new partitions, thus by ensuring that all
7450       updates go to both the old and the new partitioning scheme we can
7451       actually perform this operation lock-free. The only exception to
7452       this is when REORGANIZE PARTITION adds/drops ranges. In this case
7453       there needs to be an exclusive lock during the time when the range
7454       changes occur.
7455       This is only possible if the handler can ensure double-write for a
7456       period. The double write will ensure that it doesn't matter where the
7457       data is read from since both places are updated for writes. If such
7458       double writing is not performed then it is necessary to perform the
7459       change with the usual exclusive lock. With double writes it is even
7460       possible to perform writes in parallel with the reorganisation of
7461       partitions.
7462 
7463       Without double write procedure we get the following procedure.
7464       The only difference with using double write is that we can downgrade
7465       the lock to TL_WRITE_ALLOW_WRITE. Double write in this case only
7466       double writes from old to new. If we had double writing in both
7467       directions we could perform the change completely without exclusive
7468       lock for HASH partitions.
7469       Handlers that perform double writing during the copy phase can actually
7470       use a lower lock level. This can be handled inside store_lock in the
7471       respective handler.
7472 
7473       0) Write an entry that removes the shadow frm file if crash occurs.
7474       1) Write the shadow frm file of new partitioning.
7475       2) Log such that temporary partitions added in change phase are
7476          removed in a crash situation.
7477       3) Add the new partitions.
7478          Copy from the reorganised partitions to the new partitions.
7479       4) Get an exclusive metadata lock on the table (waits for all active
7480          transactions using this table). This ensures that we
7481          can release all other locks on the table and since no one can open
7482          the table, there can be no new threads accessing the table. They
7483          will be hanging on this exclusive lock.
7484       5) Close the table.
7485       6) Log that operation is completed and log all complete actions
7486          needed to complete operation from here.
7487       7) Write bin log.
7488       8) Prepare handlers for rename and delete of partitions.
7489       9) Rename and drop the reorged partitions such that they are no
7490          longer used and rename those added to their real new names.
7491       10) Install the shadow frm file.
7492       11) Reopen the table if under lock tables.
7493       12) Complete query.
7494     */
7495     if (write_log_drop_shadow_frm(lpt) ||
7496         ERROR_INJECT_CRASH("crash_change_partition_1") ||
7497         ERROR_INJECT_ERROR("fail_change_partition_1") ||
7498         mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
7499         ERROR_INJECT_CRASH("crash_change_partition_2") ||
7500         ERROR_INJECT_ERROR("fail_change_partition_2") ||
7501         write_log_add_change_partition(lpt) ||
7502         ERROR_INJECT_CRASH("crash_change_partition_3") ||
7503         ERROR_INJECT_ERROR("fail_change_partition_3") ||
7504         mysql_change_partitions(lpt) ||
7505         (close_table_on_failure= TRUE, FALSE) ||
7506         ERROR_INJECT_CRASH("crash_change_partition_4") ||
7507         ERROR_INJECT_ERROR("fail_change_partition_4") ||
7508         wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
7509         ERROR_INJECT_CRASH("crash_change_partition_5") ||
7510         ERROR_INJECT_ERROR("fail_change_partition_5") ||
7511         alter_close_table(lpt) ||
7512         (close_table_on_failure= FALSE, FALSE) ||
7513         ERROR_INJECT_CRASH("crash_change_partition_6") ||
7514         ERROR_INJECT_ERROR("fail_change_partition_6") ||
7515         write_log_final_change_partition(lpt) ||
7516         (action_completed= TRUE, FALSE) ||
7517         ERROR_INJECT_CRASH("crash_change_partition_7") ||
7518         ERROR_INJECT_ERROR("fail_change_partition_7") ||
7519         ((!thd->lex->no_write_to_binlog) &&
7520          (write_bin_log(thd, FALSE,
7521                         thd->query(), thd->query_length()), FALSE)) ||
7522         ERROR_INJECT_CRASH("crash_change_partition_8") ||
7523         ERROR_INJECT_ERROR("fail_change_partition_8") ||
7524         ((frm_install= TRUE), FALSE) ||
7525         mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
7526         (frm_install= FALSE, FALSE) ||
7527         ERROR_INJECT_CRASH("crash_change_partition_9") ||
7528         ERROR_INJECT_ERROR("fail_change_partition_9") ||
7529         mysql_drop_partitions(lpt) ||
7530         ERROR_INJECT_CRASH("crash_change_partition_10") ||
7531         ERROR_INJECT_ERROR("fail_change_partition_10") ||
7532         mysql_rename_partitions(lpt) ||
7533         ERROR_INJECT_CRASH("crash_change_partition_11") ||
7534         ERROR_INJECT_ERROR("fail_change_partition_11") ||
7535         (write_log_completed(lpt, FALSE), FALSE) ||
7536         ERROR_INJECT_CRASH("crash_change_partition_12") ||
7537         ERROR_INJECT_ERROR("fail_change_partition_12") ||
7538         (alter_partition_lock_handling(lpt), FALSE))
7539     {
7540       handle_alter_part_error(lpt, action_completed, FALSE, frm_install,
7541                               close_table_on_failure);
7542       goto err;
7543     }
7544   }
7545   downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
7546   /*
7547     A final step is to write the query to the binlog and send ok to the
7548     user
7549   */
7550   DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted, table_list));
7551 err:
7552   downgrade_mdl_if_lock_tables_mode(thd, mdl_ticket, MDL_SHARED_NO_READ_WRITE);
7553   DBUG_RETURN(TRUE);
7554 }
7555 #endif
7556 
7557 
7558 /*
7559   Prepare for calling val_int on partition function by setting fields to
7560   point to the record where the values of the PF-fields are stored.
7561 
7562   SYNOPSIS
7563     set_field_ptr()
7564     ptr                 Array of fields to change ptr
7565     new_buf             New record pointer
7566     old_buf             Old record pointer
7567 
7568   DESCRIPTION
7569     Set ptr in field objects of field array to refer to new_buf record
7570     instead of previously old_buf. Used before calling val_int and after
7571     it is used to restore pointers to table->record[0].
7572     This routine is placed outside of partition code since it can be useful
7573     also for other programs.
7574 */
7575 
set_field_ptr(Field ** ptr,const uchar * new_buf,const uchar * old_buf)7576 void set_field_ptr(Field **ptr, const uchar *new_buf,
7577                    const uchar *old_buf)
7578 {
7579   my_ptrdiff_t diff= (new_buf - old_buf);
7580   DBUG_ENTER("set_field_ptr");
7581 
7582   do
7583   {
7584     (*ptr)->move_field_offset(diff);
7585   } while (*(++ptr));
7586   DBUG_VOID_RETURN;
7587 }
7588 
7589 
7590 /*
7591   Prepare for calling val_int on partition function by setting fields to
7592   point to the record where the values of the PF-fields are stored.
7593   This variant works on a key_part reference.
7594   It is not required that all fields are NOT NULL fields.
7595 
7596   SYNOPSIS
7597     set_key_field_ptr()
7598     key_info            key info with a set of fields to change ptr
7599     new_buf             New record pointer
7600     old_buf             Old record pointer
7601 
7602   DESCRIPTION
7603     Set ptr in field objects of field array to refer to new_buf record
7604     instead of previously old_buf. Used before calling val_int and after
7605     it is used to restore pointers to table->record[0].
7606     This routine is placed outside of partition code since it can be useful
7607     also for other programs.
7608 */
7609 
set_key_field_ptr(KEY * key_info,const uchar * new_buf,const uchar * old_buf)7610 void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
7611                        const uchar *old_buf)
7612 {
7613   KEY_PART_INFO *key_part= key_info->key_part;
7614   uint key_parts= key_info->user_defined_key_parts;
7615   uint i= 0;
7616   my_ptrdiff_t diff= (new_buf - old_buf);
7617   DBUG_ENTER("set_key_field_ptr");
7618 
7619   do
7620   {
7621     key_part->field->move_field_offset(diff);
7622     key_part++;
7623   } while (++i < key_parts);
7624   DBUG_VOID_RETURN;
7625 }
7626 
7627 
7628 /**
7629   Append all fields in read_set to string
7630 
7631   @param[in,out] str   String to append to.
7632   @param[in]     row   Row to append.
7633   @param[in]     table Table containing read_set and fields for the row.
7634 */
append_row_to_str(String & str,const uchar * row,TABLE * table)7635 void append_row_to_str(String &str, const uchar *row, TABLE *table)
7636 {
7637   Field **fields, **field_ptr;
7638   const uchar *rec;
7639   uint num_fields= bitmap_bits_set(table->read_set);
7640   uint curr_field_index= 0;
7641   bool is_rec0= !row || row == table->record[0];
7642   if (!row)
7643     rec= table->record[0];
7644   else
7645     rec= row;
7646 
7647   /* Create a new array of all read fields. */
7648   fields= (Field**) my_malloc(sizeof(void*) * (num_fields + 1),
7649                               MYF(0));
7650   if (!fields)
7651     return;
7652   fields[num_fields]= NULL;
7653   for (field_ptr= table->field;
7654        *field_ptr;
7655        field_ptr++)
7656   {
7657     if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index))
7658       continue;
7659     fields[curr_field_index++]= *field_ptr;
7660   }
7661 
7662 
7663   if (!is_rec0)
7664     set_field_ptr(fields, rec, table->record[0]);
7665 
7666   for (field_ptr= fields;
7667        *field_ptr;
7668        field_ptr++)
7669   {
7670     Field *field= *field_ptr;
7671     str.append(" ");
7672     str.append(&field->field_name);
7673     str.append(":");
7674     field_unpack(&str, field, rec, 0, false);
7675   }
7676 
7677   if (!is_rec0)
7678     set_field_ptr(fields, table->record[0], rec);
7679   my_free(fields);
7680 }
7681 
7682 
7683 #ifdef WITH_PARTITION_STORAGE_ENGINE
7684 /**
7685   Return comma-separated list of used partitions in the provided given string.
7686 
7687     @param      mem_root   Where to allocate following list
7688     @param      part_info  Partitioning info
7689     @param[out] parts      The resulting list of string to fill
7690     @param[out] used_partitions_list result list to fill
7691 
7692     Generate a list of used partitions (from bits in part_info->read_partitions
7693     bitmap), and store it into the provided String object.
7694 
7695     @note
7696     The produced string must not be longer then MAX_PARTITIONS * (1 + FN_LEN).
7697     In case of UPDATE, only the partitions read is given, not the partitions
7698     that was written or locked.
7699 */
7700 
make_used_partitions_str(MEM_ROOT * alloc,partition_info * part_info,String * parts_str,String_list & used_partitions_list)7701 void make_used_partitions_str(MEM_ROOT *alloc,
7702                               partition_info *part_info,
7703                               String *parts_str,
7704                               String_list &used_partitions_list)
7705 {
7706   parts_str->length(0);
7707   partition_element *pe;
7708   uint partition_id= 0;
7709   List_iterator<partition_element> it(part_info->partitions);
7710 
7711   if (part_info->is_sub_partitioned())
7712   {
7713     partition_element *head_pe;
7714     while ((head_pe= it++))
7715     {
7716       List_iterator<partition_element> it2(head_pe->subpartitions);
7717       while ((pe= it2++))
7718       {
7719         if (bitmap_is_set(&part_info->read_partitions, partition_id))
7720         {
7721           if (parts_str->length())
7722             parts_str->append(',');
7723           uint index= parts_str->length();
7724           parts_str->append(head_pe->partition_name,
7725                            strlen(head_pe->partition_name),
7726                            system_charset_info);
7727           parts_str->append('_');
7728           parts_str->append(pe->partition_name,
7729                            strlen(pe->partition_name),
7730                            system_charset_info);
7731           used_partitions_list.append_str(alloc, parts_str->ptr() + index);
7732         }
7733         partition_id++;
7734       }
7735     }
7736   }
7737   else
7738   {
7739     while ((pe= it++))
7740     {
7741       if (bitmap_is_set(&part_info->read_partitions, partition_id))
7742       {
7743         if (parts_str->length())
7744           parts_str->append(',');
7745         used_partitions_list.append_str(alloc, pe->partition_name);
7746         parts_str->append(pe->partition_name, strlen(pe->partition_name),
7747                          system_charset_info);
7748       }
7749       partition_id++;
7750     }
7751   }
7752 }
7753 #endif
7754 
7755 /****************************************************************************
7756  * Partition interval analysis support
7757  ***************************************************************************/
7758 
7759 /*
7760   Setup partition_info::* members related to partitioning range analysis
7761 
7762   SYNOPSIS
7763     set_up_partition_func_pointers()
7764       part_info  Partitioning info structure
7765 
7766   DESCRIPTION
7767     Assuming that passed partition_info structure already has correct values
7768     for members that specify [sub]partitioning type, table fields, and
7769     functions, set up partition_info::* members that are related to
7770     Partitioning Interval Analysis (see get_partitions_in_range_iter for its
7771     definition)
7772 
7773   IMPLEMENTATION
7774     There are three available interval analyzer functions:
7775     (1) get_part_iter_for_interval_via_mapping
7776     (2) get_part_iter_for_interval_cols_via_map
7777     (3) get_part_iter_for_interval_via_walking
7778 
7779     They all have limited applicability:
7780     (1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
7781     func is a monotonic function.
7782 
7783     (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
7784 
7785     (3) is applicable for
7786       "[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
7787 
7788     If both (1) and (3) are applicable, (1) is preferred over (3).
7789 
7790     This function sets part_info::get_part_iter_for_interval according to
7791     this criteria, and also sets some auxilary fields that the function
7792     uses.
7793 */
7794 #ifdef WITH_PARTITION_STORAGE_ENGINE
set_up_range_analysis_info(partition_info * part_info)7795 static void set_up_range_analysis_info(partition_info *part_info)
7796 {
7797   /* Set the catch-all default */
7798   part_info->get_part_iter_for_interval= NULL;
7799   part_info->get_subpart_iter_for_interval= NULL;
7800 
7801   /*
7802     Check if get_part_iter_for_interval_via_mapping() can be used for
7803     partitioning
7804   */
7805   switch (part_info->part_type) {
7806   case VERSIONING_PARTITION:
7807     if (!part_info->vers_info->interval.is_set())
7808       break;
7809     /* Fall through */
7810   case RANGE_PARTITION:
7811   case LIST_PARTITION:
7812     if (!part_info->column_list)
7813     {
7814       if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
7815       {
7816         part_info->get_part_iter_for_interval=
7817           get_part_iter_for_interval_via_mapping;
7818         goto setup_subparts;
7819       }
7820     }
7821     else
7822     {
7823       part_info->get_part_iter_for_interval=
7824         get_part_iter_for_interval_cols_via_map;
7825       goto setup_subparts;
7826     }
7827   default:
7828     ;
7829   }
7830 
7831   /*
7832     Check if get_part_iter_for_interval_via_walking() can be used for
7833     partitioning
7834   */
7835   if (part_info->num_part_fields == 1)
7836   {
7837     Field *field= part_info->part_field_array[0];
7838     switch (field->type()) {
7839     case MYSQL_TYPE_TINY:
7840     case MYSQL_TYPE_SHORT:
7841     case MYSQL_TYPE_INT24:
7842     case MYSQL_TYPE_LONG:
7843     case MYSQL_TYPE_LONGLONG:
7844       part_info->get_part_iter_for_interval=
7845         get_part_iter_for_interval_via_walking;
7846       break;
7847     default:
7848       ;
7849     }
7850   }
7851 
7852 setup_subparts:
7853   /*
7854     Check if get_part_iter_for_interval_via_walking() can be used for
7855     subpartitioning
7856   */
7857   if (part_info->num_subpart_fields == 1)
7858   {
7859     Field *field= part_info->subpart_field_array[0];
7860     switch (field->type()) {
7861     case MYSQL_TYPE_TINY:
7862     case MYSQL_TYPE_SHORT:
7863     case MYSQL_TYPE_LONG:
7864     case MYSQL_TYPE_LONGLONG:
7865       part_info->get_subpart_iter_for_interval=
7866         get_part_iter_for_interval_via_walking;
7867       break;
7868     default:
7869       ;
7870     }
7871   }
7872 }
7873 
7874 
7875 /*
7876   This function takes a memory of packed fields in opt-range format
7877   and stores it in record format. To avoid having to worry about how
7878   the length of fields are calculated in opt-range format we send
7879   an array of lengths used for each field in store_length_array.
7880 
7881   SYNOPSIS
7882   store_tuple_to_record()
7883   pfield                         Field array
7884   store_length_array             Array of field lengths
7885   value                          Memory where fields are stored
7886   value_end                      End of memory
7887 
7888   RETURN VALUE
7889   nparts                         Number of fields assigned
7890 */
store_tuple_to_record(Field ** pfield,uint32 * store_length_array,uchar * value,uchar * value_end)7891 uint32 store_tuple_to_record(Field **pfield,
7892                              uint32 *store_length_array,
7893                              uchar *value,
7894                              uchar *value_end)
7895 {
7896   /* This function is inspired by store_key_image_rec. */
7897   uint32 nparts= 0;
7898   uchar *loc_value;
7899   while (value < value_end)
7900   {
7901     loc_value= value;
7902     if ((*pfield)->real_maybe_null())
7903     {
7904       if (*loc_value)
7905         (*pfield)->set_null();
7906       else
7907         (*pfield)->set_notnull();
7908       loc_value++;
7909     }
7910     uint len= (*pfield)->pack_length();
7911     (*pfield)->set_key_image(loc_value, len);
7912     value+= *store_length_array;
7913     store_length_array++;
7914     nparts++;
7915     pfield++;
7916   }
7917   return nparts;
7918 }
7919 
7920 /**
7921   RANGE(columns) partitioning: compare partition value bound and probe tuple.
7922 
7923   @param val           Partition column values.
7924   @param nvals_in_rec  Number of (prefix) fields to compare.
7925 
7926   @return Less than/Equal to/Greater than 0 if the record is L/E/G than val.
7927 
7928   @note The partition value bound is always a full tuple (but may include the
7929   MAXVALUE special value). The probe tuple may be a prefix of partitioning
7930   tuple.
7931 */
7932 
cmp_rec_and_tuple(part_column_list_val * val,uint32 nvals_in_rec)7933 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec)
7934 {
7935   partition_info *part_info= val->part_info;
7936   Field **field= part_info->part_field_array;
7937   Field **fields_end= field + nvals_in_rec;
7938   int res;
7939 
7940   for (; field != fields_end; field++, val++)
7941   {
7942     if (val->max_value)
7943       return -1;
7944     if ((*field)->is_null())
7945     {
7946       if (val->null_value)
7947         continue;
7948       return -1;
7949     }
7950     if (val->null_value)
7951       return +1;
7952     res= (*field)->cmp((const uchar*)val->column_value);
7953     if (res)
7954       return res;
7955   }
7956   return 0;
7957 }
7958 
7959 
7960 /**
7961   Compare record and columns partition tuple including endpoint handling.
7962 
7963   @param  val               Columns partition tuple
7964   @param  n_vals_in_rec     Number of columns to compare
7965   @param  is_left_endpoint  True if left endpoint (part_tuple < rec or
7966                             part_tuple <= rec)
7967   @param  include_endpoint  If endpoint is included (part_tuple <= rec or
7968                             rec <= part_tuple)
7969 
7970   @return Less than/Equal to/Greater than 0 if the record is L/E/G than
7971   the partition tuple.
7972 
7973   @see get_list_array_idx_for_endpoint() and
7974   get_partition_id_range_for_endpoint().
7975 */
7976 
cmp_rec_and_tuple_prune(part_column_list_val * val,uint32 n_vals_in_rec,bool is_left_endpoint,bool include_endpoint)7977 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
7978                                    uint32 n_vals_in_rec,
7979                                    bool is_left_endpoint,
7980                                    bool include_endpoint)
7981 {
7982   int cmp;
7983   Field **field;
7984   if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec)))
7985     return cmp;
7986   field= val->part_info->part_field_array + n_vals_in_rec;
7987   if (!(*field))
7988   {
7989     /* Full match. Only equal if including endpoint. */
7990     if (include_endpoint)
7991       return 0;
7992 
7993     if (is_left_endpoint)
7994       return +4;     /* Start of range, part_tuple < rec, return higher. */
7995     return -4;     /* End of range, rec < part_tupe, return lesser. */
7996   }
7997   /*
7998     The prefix is equal and there are more partition columns to compare.
7999 
8000     If including left endpoint or not including right endpoint
8001     then the record is considered lesser compared to the partition.
8002 
8003     i.e:
8004     part(10, x) <= rec(10, unknown) and rec(10, unknown) < part(10, x)
8005     part <= rec -> lesser (i.e. this or previous partitions)
8006     rec < part -> lesser (i.e. this or previous partitions)
8007   */
8008   if (is_left_endpoint == include_endpoint)
8009     return -2;
8010 
8011   /*
8012     If right endpoint and the first additional partition value
8013     is MAXVALUE, then the record is lesser.
8014   */
8015   if (!is_left_endpoint && (val + n_vals_in_rec)->max_value)
8016     return -3;
8017 
8018   /*
8019     Otherwise the record is considered greater.
8020 
8021     rec <= part -> greater (i.e. does not match this partition, seek higher).
8022     part < rec -> greater (i.e. does not match this partition, seek higher).
8023   */
8024   return 2;
8025 }
8026 
8027 
8028 typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
8029                                     bool include_endpoint);
8030 
8031 typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint,
8032                                         bool include_endpoint,
8033                                         uint32 num_parts);
8034 
8035 /**
8036   Get partition for RANGE COLUMNS endpoint.
8037 
8038   @param part_info         Partitioning metadata.
8039   @param is_left_endpoint     True if left endpoint (const <=/< cols)
8040   @param include_endpoint  True if range includes the endpoint (<=/>=)
8041   @param nparts            Total number of partitions
8042 
8043   @return Partition id of matching partition.
8044 
8045   @see get_partition_id_cols_list_for_endpoint and
8046   get_partition_id_range_for_endpoint.
8047 */
8048 
get_partition_id_cols_range_for_endpoint(partition_info * part_info,bool is_left_endpoint,bool include_endpoint,uint32 nparts)8049 uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info,
8050                                                 bool is_left_endpoint,
8051                                                 bool include_endpoint,
8052                                                 uint32 nparts)
8053 {
8054   uint min_part_id= 0, max_part_id= part_info->num_parts, loc_part_id;
8055   part_column_list_val *range_col_array= part_info->range_col_array;
8056   uint num_columns= part_info->part_field_list.elements;
8057   DBUG_ENTER("get_partition_id_cols_range_for_endpoint");
8058 
8059   /* Find the matching partition (including taking endpoint into account). */
8060   do
8061   {
8062     /* Midpoint, adjusted down, so it can never be > last partition. */
8063     loc_part_id= (max_part_id + min_part_id) >> 1;
8064     if (0 <= cmp_rec_and_tuple_prune(range_col_array +
8065                                        loc_part_id * num_columns,
8066                                      nparts,
8067                                      is_left_endpoint,
8068                                      include_endpoint))
8069       min_part_id= loc_part_id + 1;
8070     else
8071       max_part_id= loc_part_id;
8072   } while (max_part_id > min_part_id);
8073   loc_part_id= max_part_id;
8074 
8075   /* Given value must be LESS THAN the found partition. */
8076   DBUG_ASSERT(loc_part_id == part_info->num_parts ||
8077               (0 > cmp_rec_and_tuple_prune(range_col_array +
8078                                              loc_part_id * num_columns,
8079                                            nparts, is_left_endpoint,
8080                                            include_endpoint)));
8081   /* Given value must be GREATER THAN or EQUAL to the previous partition. */
8082   DBUG_ASSERT(loc_part_id == 0 ||
8083               (0 <= cmp_rec_and_tuple_prune(range_col_array +
8084                                               (loc_part_id - 1) * num_columns,
8085                                             nparts, is_left_endpoint,
8086                                             include_endpoint)));
8087 
8088   if (!is_left_endpoint)
8089   {
8090     /* Set the end after this partition if not already after the last. */
8091     if (loc_part_id < part_info->num_parts)
8092       loc_part_id++;
8093   }
8094   DBUG_RETURN(loc_part_id);
8095 }
8096 
8097 
get_part_iter_for_interval_cols_via_map(partition_info * part_info,bool is_subpart,uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)8098 static int get_part_iter_for_interval_cols_via_map(partition_info *part_info,
8099                            bool is_subpart, uint32 *store_length_array,
8100                            uchar *min_value, uchar *max_value,
8101                            uint min_len, uint max_len,
8102                            uint flags, PARTITION_ITERATOR *part_iter)
8103 {
8104   bool can_match_multiple_values;
8105   uint32 nparts;
8106   get_col_endpoint_func  UNINIT_VAR(get_col_endpoint);
8107   uint full_length= 0;
8108   DBUG_ENTER("get_part_iter_for_interval_cols_via_map");
8109 
8110   if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
8111   {
8112     get_col_endpoint= get_partition_id_cols_range_for_endpoint;
8113     part_iter->get_next= get_next_partition_id_range;
8114   }
8115   else if (part_info->part_type == LIST_PARTITION)
8116   {
8117     if (part_info->has_default_partititon() &&
8118         part_info->num_parts == 1)
8119       DBUG_RETURN(-1); //only DEFAULT partition
8120     get_col_endpoint= get_partition_id_cols_list_for_endpoint;
8121     part_iter->get_next= get_next_partition_id_list;
8122     part_iter->part_info= part_info;
8123     DBUG_ASSERT(part_info->num_list_values);
8124   }
8125   else
8126     assert(0);
8127 
8128   for (uint32 i= 0; i < part_info->num_columns; i++)
8129     full_length+= store_length_array[i];
8130 
8131   can_match_multiple_values= ((flags &
8132                                (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN |
8133                                 NEAR_MAX)) ||
8134                               (min_len != max_len) ||
8135                               (min_len != full_length) ||
8136                               memcmp(min_value, max_value, min_len));
8137   DBUG_ASSERT(can_match_multiple_values || (flags & EQ_RANGE) || flags == 0);
8138   if (can_match_multiple_values && part_info->has_default_partititon())
8139     part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
8140 
8141   if (flags & NO_MIN_RANGE)
8142     part_iter->part_nums.start= part_iter->part_nums.cur= 0;
8143   else
8144   {
8145     // Copy from min_value to record
8146     nparts= store_tuple_to_record(part_info->part_field_array,
8147                                   store_length_array,
8148                                   min_value,
8149                                   min_value + min_len);
8150     part_iter->part_nums.start= part_iter->part_nums.cur=
8151       get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN),
8152                        nparts);
8153   }
8154   if (flags & NO_MAX_RANGE)
8155   {
8156     if (part_info->part_type == RANGE_PARTITION || part_info->part_type == VERSIONING_PARTITION)
8157       part_iter->part_nums.end= part_info->num_parts;
8158     else /* LIST_PARTITION */
8159     {
8160       DBUG_ASSERT(part_info->part_type == LIST_PARTITION);
8161       part_iter->part_nums.end= part_info->num_list_values;
8162     }
8163   }
8164   else
8165   {
8166     // Copy from max_value to record
8167     nparts= store_tuple_to_record(part_info->part_field_array,
8168                                   store_length_array,
8169                                   max_value,
8170                                   max_value + max_len);
8171     part_iter->part_nums.end= get_col_endpoint(part_info, FALSE,
8172                                                !(flags & NEAR_MAX),
8173                                                nparts);
8174   }
8175   if (part_iter->part_nums.start == part_iter->part_nums.end)
8176   {
8177     // No matching partition found.
8178     if (part_info->has_default_partititon())
8179     {
8180       part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
8181       DBUG_RETURN(1);
8182     }
8183     DBUG_RETURN(0);
8184   }
8185   DBUG_RETURN(1);
8186 }
8187 
8188 
8189 /**
8190   Partitioning Interval Analysis: Initialize the iterator for "mapping" case
8191 
8192   @param part_info   Partition info
8193   @param is_subpart  TRUE  - act for subpartitioning
8194                      FALSE - act for partitioning
8195   @param store_length_array  Ignored.
8196   @param min_value   minimum field value, in opt_range key format.
8197   @param max_value   minimum field value, in opt_range key format.
8198   @param min_len     Ignored.
8199   @param max_len     Ignored.
8200   @param flags       Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
8201                      NO_MAX_RANGE.
8202   @param part_iter   Iterator structure to be initialized
8203 
8204   @details Initialize partition set iterator to walk over the interval in
8205   ordered-array-of-partitions (for RANGE partitioning) or
8206   ordered-array-of-list-constants (for LIST partitioning) space.
8207 
8208   This function is used when partitioning is done by
8209   <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
8210   t.field space into a sub-array of partition_info::range_int_array or
8211   partition_info::list_array (see get_partition_id_range_for_endpoint,
8212   get_list_array_idx_for_endpoint for details).
8213 
8214   The function performs this interval mapping, and sets the iterator to
8215   traverse the sub-array and return appropriate partitions.
8216 
8217   @return Status of iterator
8218     @retval 0   No matching partitions (iterator not initialized)
8219     @retval 1   Ok, iterator intialized for traversal of matching partitions.
8220     @retval -1  All partitions would match (iterator not initialized)
8221 */
8222 
get_part_iter_for_interval_via_mapping(partition_info * part_info,bool is_subpart,uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)8223 static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
8224                         bool is_subpart,
8225                         uint32 *store_length_array, /* ignored */
8226                         uchar *min_value, uchar *max_value,
8227                         uint min_len, uint max_len, /* ignored */
8228                         uint flags, PARTITION_ITERATOR *part_iter)
8229 {
8230   Field *field= part_info->part_field_array[0];
8231   uint32             UNINIT_VAR(max_endpoint_val);
8232   get_endpoint_func  UNINIT_VAR(get_endpoint);
8233   bool               can_match_multiple_values;  /* is not '=' */
8234   uint field_len= field->pack_length_in_rec();
8235   MYSQL_TIME start_date;
8236   bool check_zero_dates= false;
8237   bool zero_in_start_date= true;
8238   DBUG_ENTER("get_part_iter_for_interval_via_mapping");
8239   DBUG_ASSERT(!is_subpart);
8240   (void) store_length_array;
8241   (void)min_len;
8242   (void)max_len;
8243   part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
8244   part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;
8245 
8246   if (part_info->part_type == RANGE_PARTITION ||
8247       part_info->part_type == VERSIONING_PARTITION)
8248   {
8249     if (part_info->part_charset_field_array)
8250       get_endpoint=        get_partition_id_range_for_endpoint_charset;
8251     else
8252       get_endpoint=        get_partition_id_range_for_endpoint;
8253     max_endpoint_val=    part_info->num_parts;
8254     part_iter->get_next= get_next_partition_id_range;
8255   }
8256   else if (part_info->part_type == LIST_PARTITION)
8257   {
8258 
8259     if (part_info->part_charset_field_array)
8260       get_endpoint=        get_list_array_idx_for_endpoint_charset;
8261     else
8262       get_endpoint=        get_list_array_idx_for_endpoint;
8263     max_endpoint_val=    part_info->num_list_values;
8264     part_iter->get_next= get_next_partition_id_list;
8265     part_iter->part_info= part_info;
8266     if (max_endpoint_val == 0)
8267     {
8268       /*
8269         We handle this special case without optimisations since it is
8270         of little practical value but causes a great number of complex
8271         checks later in the code.
8272       */
8273       part_iter->part_nums.start= part_iter->part_nums.end= 0;
8274       part_iter->part_nums.cur= 0;
8275       part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
8276       DBUG_RETURN(-1);
8277     }
8278   }
8279   else
8280     MY_ASSERT_UNREACHABLE();
8281 
8282   can_match_multiple_values= ((flags &
8283                                (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN |
8284                                 NEAR_MAX)) ||
8285                               memcmp(min_value, max_value, field_len));
8286   DBUG_ASSERT(can_match_multiple_values || (flags & EQ_RANGE) || flags == 0);
8287   if (can_match_multiple_values && part_info->has_default_partititon())
8288     part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
8289   if (can_match_multiple_values &&
8290       (part_info->part_type == RANGE_PARTITION ||
8291        part_info->has_null_value))
8292   {
8293     /* Range scan on RANGE or LIST partitioned table */
8294     enum_monotonicity_info monotonic;
8295     monotonic= part_info->part_expr->get_monotonicity_info();
8296     if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
8297         monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL)
8298     {
8299       /* col is NOT NULL, but F(col) can return NULL, add NULL partition */
8300       part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
8301       check_zero_dates= true;
8302     }
8303   }
8304 
8305   /*
8306     Find minimum: Do special handling if the interval has left bound in form
8307      " NULL <= X ":
8308   */
8309   if (field->real_maybe_null() && part_info->has_null_value &&
8310       !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value)
8311   {
8312     part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
8313     part_iter->part_nums.start= part_iter->part_nums.cur= 0;
8314     if (!(flags & NO_MAX_RANGE) && *max_value)
8315     {
8316       /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
8317       part_iter->part_nums.end= 0;
8318       /*
8319         It is something like select * from tbl where col IS NULL
8320         and we have partition with NULL to catch it, so we do not need
8321         DEFAULT partition
8322       */
8323       part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;
8324       DBUG_RETURN(1);
8325     }
8326   }
8327   else
8328   {
8329     if (flags & NO_MIN_RANGE)
8330       part_iter->part_nums.start= part_iter->part_nums.cur= 0;
8331     else
8332     {
8333       /*
8334         Store the interval edge in the record buffer, and call the
8335         function that maps the edge in table-field space to an edge
8336         in ordered-set-of-partitions (for RANGE partitioning) or
8337         index-in-ordered-array-of-list-constants (for LIST) space.
8338       */
8339       store_key_image_to_rec(field, min_value, field_len);
8340       bool include_endp= !MY_TEST(flags & NEAR_MIN);
8341       part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp);
8342       if (!can_match_multiple_values && part_info->part_expr->null_value)
8343       {
8344         /* col = x and F(x) = NULL -> only search NULL partition */
8345         part_iter->part_nums.cur= part_iter->part_nums.start= 0;
8346         part_iter->part_nums.end= 0;
8347         /*
8348           if NULL partition exists:
8349             for RANGE it is the first partition (always exists);
8350             for LIST should be indicator that it is present
8351         */
8352         if (part_info->part_type == RANGE_PARTITION ||
8353             part_info->has_null_value)
8354         {
8355           part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
8356           DBUG_RETURN(1);
8357         }
8358         // If no NULL partition look up in DEFAULT or there is no such value
8359         goto not_found;
8360       }
8361       part_iter->part_nums.cur= part_iter->part_nums.start;
8362       if (check_zero_dates && !part_info->part_expr->null_value)
8363       {
8364         if (!(flags & NO_MAX_RANGE) &&
8365             (field->type() == MYSQL_TYPE_DATE ||
8366              field->type() == MYSQL_TYPE_DATETIME))
8367         {
8368           /* Monotonic, but return NULL for dates with zeros in month/day. */
8369           zero_in_start_date= field->get_date(&start_date, 0);
8370           DBUG_PRINT("info", ("zero start %u %04d-%02d-%02d",
8371                               zero_in_start_date, start_date.year,
8372                               start_date.month, start_date.day));
8373         }
8374       }
8375       if (part_iter->part_nums.start == max_endpoint_val)
8376         goto not_found;
8377     }
8378   }
8379 
8380   /* Find maximum, do the same as above but for right interval bound */
8381   if (flags & NO_MAX_RANGE)
8382     part_iter->part_nums.end= max_endpoint_val;
8383   else
8384   {
8385     store_key_image_to_rec(field, max_value, field_len);
8386     bool include_endp= !MY_TEST(flags & NEAR_MAX);
8387     part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
8388     if (check_zero_dates &&
8389         !zero_in_start_date &&
8390         !part_info->part_expr->null_value)
8391     {
8392       MYSQL_TIME end_date;
8393       bool zero_in_end_date= field->get_date(&end_date, 0);
8394       /*
8395         This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
8396         the NULL partition for ranges that cannot include a date with 0 as
8397         month/day.
8398       */
8399       DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d",
8400                           zero_in_end_date,
8401                           end_date.year, end_date.month, end_date.day));
8402       DBUG_ASSERT(!memcmp(((Item_func*) part_info->part_expr)->func_name(),
8403                           "to_days", 7) ||
8404                   !memcmp(((Item_func*) part_info->part_expr)->func_name(),
8405                           "to_seconds", 10));
8406       if (!zero_in_end_date &&
8407           start_date.month == end_date.month &&
8408           start_date.year == end_date.year)
8409         part_iter->ret_null_part= part_iter->ret_null_part_orig= false;
8410     }
8411     if (part_iter->part_nums.start >= part_iter->part_nums.end &&
8412         !part_iter->ret_null_part)
8413       goto not_found;
8414   }
8415   DBUG_RETURN(1); /* Ok, iterator initialized */
8416 
8417 not_found:
8418   if (part_info->has_default_partititon())
8419   {
8420     part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
8421     DBUG_RETURN(1);
8422   }
8423   DBUG_RETURN(0); /* No partitions */
8424 }
8425 
8426 
8427 /* See get_part_iter_for_interval_via_walking for definition of what this is */
8428 #define MAX_RANGE_TO_WALK 32
8429 
8430 
8431 /*
8432   Partitioning Interval Analysis: Initialize iterator to walk field interval
8433 
8434   SYNOPSIS
8435     get_part_iter_for_interval_via_walking()
8436       part_info   Partition info
8437       is_subpart  TRUE  - act for subpartitioning
8438                   FALSE - act for partitioning
8439       min_value   minimum field value, in opt_range key format.
8440       max_value   minimum field value, in opt_range key format.
8441       flags       Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
8442                   NO_MAX_RANGE.
8443       part_iter   Iterator structure to be initialized
8444 
8445   DESCRIPTION
8446     Initialize partition set iterator to walk over interval in integer field
8447     space. That is, for "const1 <=? t.field <=? const2" interval, initialize
8448     the iterator to return a set of [sub]partitions obtained with the
8449     following procedure:
8450       get partition id for t.field = const1,   return it
8451       get partition id for t.field = const1+1, return it
8452        ...                 t.field = const1+2, ...
8453        ...                           ...       ...
8454        ...                 t.field = const2    ...
8455 
8456   IMPLEMENTATION
8457     See get_partitions_in_range_iter for general description of interval
8458     analysis. We support walking over the following intervals:
8459       "t.field IS NULL"
8460       "c1 <=? t.field <=? c2", where c1 and c2 are finite.
8461     Intervals with +inf/-inf, and [NULL, c1] interval can be processed but
8462     that is more tricky and I don't have time to do it right now.
8463 
8464   RETURN
8465     0 - No matching partitions, iterator not initialized
8466     1 - Some partitions would match, iterator intialized for traversing them
8467    -1 - All partitions would match, iterator not initialized
8468 */
8469 
get_part_iter_for_interval_via_walking(partition_info * part_info,bool is_subpart,uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)8470 static int get_part_iter_for_interval_via_walking(partition_info *part_info,
8471                          bool is_subpart,
8472                          uint32 *store_length_array, /* ignored */
8473                          uchar *min_value, uchar *max_value,
8474                          uint min_len, uint max_len, /* ignored */
8475                          uint flags, PARTITION_ITERATOR *part_iter)
8476 {
8477   Field *field;
8478   uint total_parts;
8479   partition_iter_func get_next_func;
8480   DBUG_ENTER("get_part_iter_for_interval_via_walking");
8481   (void)store_length_array;
8482   (void)min_len;
8483   (void)max_len;
8484 
8485   part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
8486   part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;
8487 
8488   if (is_subpart)
8489   {
8490     field= part_info->subpart_field_array[0];
8491     total_parts= part_info->num_subparts;
8492     get_next_func=  get_next_subpartition_via_walking;
8493   }
8494   else
8495   {
8496     field= part_info->part_field_array[0];
8497     total_parts= part_info->num_parts;
8498     get_next_func=  get_next_partition_via_walking;
8499   }
8500 
8501   /* Handle the "t.field IS NULL" interval, it is a special case */
8502   if (field->real_maybe_null() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
8503       *min_value && *max_value)
8504   {
8505     /*
8506       We don't have a part_iter->get_next() function that would find which
8507       partition "t.field IS NULL" belongs to, so find partition that contains
8508       NULL right here, and return an iterator over singleton set.
8509     */
8510     uint32 part_id;
8511     field->set_null();
8512     if (is_subpart)
8513     {
8514       if (!part_info->get_subpartition_id(part_info, &part_id))
8515       {
8516         init_single_partition_iterator(part_id, part_iter);
8517         DBUG_RETURN(1); /* Ok, iterator initialized */
8518       }
8519     }
8520     else
8521     {
8522       longlong dummy;
8523       int res= part_info->is_sub_partitioned() ?
8524                   part_info->get_part_partition_id(part_info, &part_id,
8525                                                    &dummy):
8526                   part_info->get_partition_id(part_info, &part_id, &dummy);
8527       if (!res)
8528       {
8529         init_single_partition_iterator(part_id, part_iter);
8530         DBUG_RETURN(1); /* Ok, iterator initialized */
8531       }
8532     }
8533     DBUG_RETURN(0); /* No partitions match */
8534   }
8535 
8536   if ((field->real_maybe_null() &&
8537        ((!(flags & NO_MIN_RANGE) && *min_value) ||  // NULL <? X
8538         (!(flags & NO_MAX_RANGE) && *max_value))) ||  // X <? NULL
8539       (flags & (NO_MIN_RANGE | NO_MAX_RANGE)))    // -inf at any bound
8540   {
8541     DBUG_RETURN(-1); /* Can't handle this interval, have to use all partitions */
8542   }
8543 
8544   /* Get integers for left and right interval bound */
8545   longlong a, b;
8546   uint len= field->pack_length_in_rec();
8547   store_key_image_to_rec(field, min_value, len);
8548   a= field->val_int();
8549 
8550   store_key_image_to_rec(field, max_value, len);
8551   b= field->val_int();
8552 
8553   /*
8554     Handle a special case where the distance between interval bounds is
8555     exactly 4G-1. This interval is too big for range walking, and if it is an
8556     (x,y]-type interval then the following "b +=..." code will convert it to
8557     an empty interval by "wrapping around" a + 4G-1 + 1 = a.
8558   */
8559   if ((ulonglong)b - (ulonglong)a == ~0ULL)
8560     DBUG_RETURN(-1);
8561 
8562   a+= MY_TEST(flags & NEAR_MIN);
8563   b+= MY_TEST(!(flags & NEAR_MAX));
8564   ulonglong n_values= b - a;
8565 
8566   /*
8567     Will it pay off to enumerate all values in the [a..b] range and evaluate
8568     the partitioning function for every value? It depends on
8569      1. whether we'll be able to infer that some partitions are not used
8570      2. if time savings from not scanning these partitions will be greater
8571         than time spent in enumeration.
8572     We will assume that the cost of accessing one extra partition is greater
8573     than the cost of evaluating the partitioning function O(#partitions).
8574     This means we should jump at any chance to eliminate a partition, which
8575     gives us this logic:
8576 
8577     Do the enumeration if
8578      - the number of values to enumerate is comparable to the number of
8579        partitions, or
8580      - there are not many values to enumerate.
8581   */
8582   if ((n_values > 2*total_parts) && n_values > MAX_RANGE_TO_WALK)
8583     DBUG_RETURN(-1);
8584 
8585   part_iter->field_vals.start= part_iter->field_vals.cur= a;
8586   part_iter->field_vals.end=   b;
8587   part_iter->part_info= part_info;
8588   part_iter->get_next=  get_next_func;
8589   DBUG_RETURN(1);
8590 }
8591 
8592 
8593 /*
8594   PARTITION_ITERATOR::get_next implementation: enumerate partitions in range
8595 
8596   SYNOPSIS
8597     get_next_partition_id_range()
8598       part_iter  Partition set iterator structure
8599 
8600   DESCRIPTION
8601     This is implementation of PARTITION_ITERATOR::get_next() that returns
8602     [sub]partition ids in [min_partition_id, max_partition_id] range.
8603     The function conforms to partition_iter_func type.
8604 
8605   RETURN
8606     partition id
8607     NOT_A_PARTITION_ID if there are no more partitions
8608 */
8609 
get_next_partition_id_range(PARTITION_ITERATOR * part_iter)8610 uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
8611 {
8612   if (part_iter->part_nums.cur >= part_iter->part_nums.end)
8613   {
8614     if (part_iter->ret_null_part)
8615     {
8616       part_iter->ret_null_part= FALSE;
8617       return 0;                    /* NULL always in first range partition */
8618     }
8619     // we do not have default partition in RANGE partitioning
8620     DBUG_ASSERT(!part_iter->ret_default_part);
8621 
8622     part_iter->part_nums.cur= part_iter->part_nums.start;
8623     part_iter->ret_null_part= part_iter->ret_null_part_orig;
8624     return NOT_A_PARTITION_ID;
8625   }
8626   else
8627     return part_iter->part_nums.cur++;
8628 }
8629 
8630 
8631 /*
8632   PARTITION_ITERATOR::get_next implementation for LIST partitioning
8633 
8634   SYNOPSIS
8635     get_next_partition_id_list()
8636       part_iter  Partition set iterator structure
8637 
8638   DESCRIPTION
8639     This implementation of PARTITION_ITERATOR::get_next() is special for
8640     LIST partitioning: it enumerates partition ids in
8641     part_info->list_array[i] (list_col_array[i*cols] for COLUMNS LIST
8642     partitioning) where i runs over [min_idx, max_idx] interval.
8643     The function conforms to partition_iter_func type.
8644 
8645   RETURN
8646     partition id
8647     NOT_A_PARTITION_ID if there are no more partitions
8648 */
8649 
get_next_partition_id_list(PARTITION_ITERATOR * part_iter)8650 uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
8651 {
8652   if (part_iter->part_nums.cur >= part_iter->part_nums.end)
8653   {
8654     if (part_iter->ret_null_part)
8655     {
8656       part_iter->ret_null_part= FALSE;
8657       return part_iter->part_info->has_null_part_id;
8658     }
8659     if (part_iter->ret_default_part)
8660     {
8661       part_iter->ret_default_part= FALSE;
8662       return part_iter->part_info->default_partition_id;
8663     }
8664     /* Reset partition for next read */
8665     part_iter->part_nums.cur= part_iter->part_nums.start;
8666     part_iter->ret_null_part= part_iter->ret_null_part_orig;
8667     part_iter->ret_default_part= part_iter->ret_default_part_orig;
8668     return NOT_A_PARTITION_ID;
8669   }
8670   else
8671   {
8672     partition_info *part_info= part_iter->part_info;
8673     uint32 num_part= part_iter->part_nums.cur++;
8674     if (part_info->column_list)
8675     {
8676       uint num_columns= part_info->part_field_list.elements;
8677       return part_info->list_col_array[num_part*num_columns].partition_id;
8678     }
8679     return part_info->list_array[num_part].partition_id;
8680   }
8681 }
8682 
8683 
8684 /*
8685   PARTITION_ITERATOR::get_next implementation: walk over field-space interval
8686 
8687   SYNOPSIS
8688     get_next_partition_via_walking()
8689       part_iter  Partitioning iterator
8690 
8691   DESCRIPTION
8692     This implementation of PARTITION_ITERATOR::get_next() returns ids of
8693     partitions that contain records with partitioning field value within
8694     [start_val, end_val] interval.
8695     The function conforms to partition_iter_func type.
8696 
8697   RETURN
8698     partition id
8699     NOT_A_PARTITION_ID if there are no more partitioning.
8700 */
8701 
get_next_partition_via_walking(PARTITION_ITERATOR * part_iter)8702 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter)
8703 {
8704   uint32 part_id;
8705   Field *field= part_iter->part_info->part_field_array[0];
8706   while (part_iter->field_vals.cur != part_iter->field_vals.end)
8707   {
8708     longlong dummy;
8709     field->store(part_iter->field_vals.cur++, field->flags & UNSIGNED_FLAG);
8710     if ((part_iter->part_info->is_sub_partitioned() &&
8711          !part_iter->part_info->get_part_partition_id(part_iter->part_info,
8712                                                       &part_id, &dummy)) ||
8713         !part_iter->part_info->get_partition_id(part_iter->part_info,
8714                                                 &part_id, &dummy))
8715       return part_id;
8716   }
8717   part_iter->field_vals.cur= part_iter->field_vals.start;
8718   return NOT_A_PARTITION_ID;
8719 }
8720 
8721 
8722 /* Same as get_next_partition_via_walking, but for subpartitions */
8723 
get_next_subpartition_via_walking(PARTITION_ITERATOR * part_iter)8724 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter)
8725 {
8726   Field *field= part_iter->part_info->subpart_field_array[0];
8727   uint32 res;
8728   if (part_iter->field_vals.cur == part_iter->field_vals.end)
8729   {
8730     part_iter->field_vals.cur= part_iter->field_vals.start;
8731     return NOT_A_PARTITION_ID;
8732   }
8733   field->store(part_iter->field_vals.cur++, field->flags & UNSIGNED_FLAG);
8734   if (part_iter->part_info->get_subpartition_id(part_iter->part_info,
8735                                                 &res))
8736     return NOT_A_PARTITION_ID;
8737   return res;
8738 }
8739 
8740 /* used in error messages below */
longest_str(const char * s1,const char * s2,const char * s3=0)8741 static const char *longest_str(const char *s1, const char *s2,
8742                                const char *s3=0)
8743 {
8744   if (strlen(s2) > strlen(s1)) s1= s2;
8745   if (s3 && strlen(s3) > strlen(s1)) s1= s3;
8746   return s1;
8747 }
8748 
8749 
8750 /*
8751   Create partition names
8752 
8753   SYNOPSIS
8754     create_partition_name()
8755     out:out                   The buffer for the created partition name string
8756                               must be *at least* of FN_REFLEN+1 bytes
8757     in1                       First part
8758     in2                       Second part
8759     name_variant              Normal, temporary or renamed partition name
8760 
8761   RETURN VALUE
8762     0 if ok, error if name too long
8763 
8764   DESCRIPTION
8765     This method is used to calculate the partition name, service routine to
8766     the del_ren_cre_table method.
8767 */
8768 
create_partition_name(char * out,size_t outlen,const char * in1,const char * in2,uint name_variant,bool translate)8769 int create_partition_name(char *out, size_t outlen, const char *in1,
8770                           const char *in2, uint name_variant, bool translate)
8771 {
8772   char transl_part_name[FN_REFLEN];
8773   const char *transl_part, *end;
8774   DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere
8775 
8776   if (translate)
8777   {
8778     tablename_to_filename(in2, transl_part_name, FN_REFLEN);
8779     transl_part= transl_part_name;
8780   }
8781   else
8782     transl_part= in2;
8783 
8784   if (name_variant == NORMAL_PART_NAME)
8785     end= strxnmov(out, outlen-1, in1, "#P#", transl_part, NullS);
8786   else if (name_variant == TEMP_PART_NAME)
8787     end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#TMP#", NullS);
8788   else
8789   {
8790     DBUG_ASSERT(name_variant == RENAMED_PART_NAME);
8791     end= strxnmov(out, outlen-1, in1, "#P#", transl_part, "#REN#", NullS);
8792   }
8793   if (end - out == static_cast<ptrdiff_t>(outlen-1))
8794   {
8795     my_error(ER_PATH_LENGTH, MYF(0), longest_str(in1, transl_part));
8796     return HA_WRONG_CREATE_OPTION;
8797   }
8798   return 0;
8799 }
8800 
8801 /**
8802   Create subpartition name. This method is used to calculate the
8803   subpartition name, service routine to the del_ren_cre_table method.
8804   The output buffer size should be FN_REFLEN + 1(terminating '\0').
8805 
8806     @param [out] out          Created partition name string
8807     @param in1                First part
8808     @param in2                Second part
8809     @param in3                Third part
8810     @param name_variant       Normal, temporary or renamed partition name
8811 
8812     @retval true              Error.
8813     @retval false             Success.
8814 */
8815 
create_subpartition_name(char * out,size_t outlen,const char * in1,const char * in2,const char * in3,uint name_variant)8816 int create_subpartition_name(char *out, size_t outlen,
8817                              const char *in1, const char *in2,
8818                              const char *in3, uint name_variant)
8819 {
8820   char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN], *end;
8821   DBUG_ASSERT(outlen >= FN_REFLEN + 1); // consistency! same limit everywhere
8822 
8823   tablename_to_filename(in2, transl_part_name, FN_REFLEN);
8824   tablename_to_filename(in3, transl_subpart_name, FN_REFLEN);
8825 
8826   if (name_variant == NORMAL_PART_NAME)
8827     end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
8828                   "#SP#", transl_subpart_name, NullS);
8829   else if (name_variant == TEMP_PART_NAME)
8830     end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
8831                   "#SP#", transl_subpart_name, "#TMP#", NullS);
8832   else
8833   {
8834     DBUG_ASSERT(name_variant == RENAMED_PART_NAME);
8835     end= strxnmov(out, outlen-1, in1, "#P#", transl_part_name,
8836                   "#SP#", transl_subpart_name, "#REN#", NullS);
8837   }
8838   if (end - out == static_cast<ptrdiff_t>(outlen-1))
8839   {
8840     my_error(ER_PATH_LENGTH, MYF(0),
8841              longest_str(in1, transl_part_name, transl_subpart_name));
8842     return HA_WRONG_CREATE_OPTION;
8843   }
8844   return 0;
8845 }
8846 
get_partition_field_store_length(Field * field)8847 uint get_partition_field_store_length(Field *field)
8848 {
8849   uint store_length;
8850 
8851   store_length= field->key_length();
8852   if (field->real_maybe_null())
8853     store_length+= HA_KEY_NULL_LENGTH;
8854   if (field->real_type() == MYSQL_TYPE_VARCHAR)
8855     store_length+= HA_KEY_BLOB_LENGTH;
8856   return store_length;
8857 }
8858 
8859 #endif
8860