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