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