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