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