1 /* Copyright (c) 2005, 2020, 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. It contains functionality used by all handlers that
26   support partitioning, such as the partitioning handler itself and the NDB
27   handler. (Much of the code in this file has been split into partition_info.cc
28   and the header files partition_info.h + partition_element.h + sql_partition.h)
29 
30   The first version supports RANGE partitioning, LIST partitioning, HASH
31   partitioning and composite partitioning (hereafter called subpartitioning)
32   where each RANGE/LIST partitioning is HASH partitioned. The hash function
33   can either be supplied by the user or by only a list of fields (also
34   called KEY partitioning), where the MySQL server will use an internal
35   hash function.
36   There are quite a few defaults that can be used as well.
37 
38   The second version introduces a new variant of RANGE and LIST partitioning
39   which is often referred to as column lists in the code variables. This
40   enables a user to specify a set of columns and their concatenated value
41   as the partition value. By comparing the concatenation of these values
42   the proper partition can be choosen.
43 */
44 
45 #include "sql/sql_partition.h"
46 
47 #include <assert.h>
48 #include <limits.h>
49 #include <string.h>
50 #include <algorithm>
51 
52 #include "field_types.h"  // enum_field_types
53 #include "m_string.h"
54 #include "my_bitmap.h"
55 #include "my_byteorder.h"
56 #include "my_compiler.h"
57 #include "my_dbug.h"
58 #include "my_io.h"
59 #include "my_sqlcommand.h"
60 #include "my_sys.h"
61 #include "mysql/components/services/psi_statement_bits.h"
62 #include "mysql/plugin.h"
63 #include "mysql/psi/mysql_file.h"
64 #include "mysql/service_mysql_alloc.h"
65 #include "mysql/udf_registration_types.h"
66 #include "mysql_com.h"
67 #include "mysql_time.h"
68 #include "mysqld_error.h"
69 #include "sql/create_field.h"
70 #include "sql/current_thd.h"
71 #include "sql/debug_sync.h"  // DEBUG_SYNC
72 #include "sql/derror.h"      // ER_THD
73 #include "sql/enum_query_type.h"
74 #include "sql/field.h"
75 #include "sql/handler.h"
76 #include "sql/item.h"       // enum_monotoncity_info
77 #include "sql/item_func.h"  // Item_func
78 #include "sql/key.h"
79 #include "sql/mdl.h"
80 #include "sql/mysqld.h"     // mysql_tmpdir
81 #include "sql/opt_range.h"  // store_key_image_to_rec
82 #include "sql/parse_tree_node_base.h"
83 #include "sql/partition_info.h"                  // partition_info
84 #include "sql/partitioning/partition_handler.h"  // Partition_handler
85 #include "sql/psi_memory_key.h"
86 #include "sql/query_options.h"
87 #include "sql/sql_alter.h"
88 #include "sql/sql_base.h"   // wait_while_table_is_used
89 #include "sql/sql_class.h"  // THD
90 #include "sql/sql_const.h"
91 #include "sql/sql_digest_stream.h"
92 #include "sql/sql_error.h"
93 #include "sql/sql_lex.h"
94 #include "sql/sql_list.h"
95 #include "sql/sql_parse.h"  // parse_sql
96 #include "sql/sql_show.h"
97 #include "sql/sql_table.h"  // build_table_filename
98 #include "sql/system_variables.h"
99 #include "sql/table.h"
100 #include "sql/thd_raii.h"
101 #include "sql_string.h"
102 
103 struct MEM_ROOT;
104 
105 using std::max;
106 using std::min;
107 
108 /*
109   Partition related functions declarations and some static constants;
110 */
111 const LEX_CSTRING partition_keywords[] = {{STRING_WITH_LEN("HASH")},
112                                           {STRING_WITH_LEN("RANGE")},
113                                           {STRING_WITH_LEN("LIST")},
114                                           {STRING_WITH_LEN("KEY")},
115                                           {STRING_WITH_LEN("MAXVALUE")},
116                                           {STRING_WITH_LEN("LINEAR ")},
117                                           {STRING_WITH_LEN(" COLUMNS")},
118                                           {STRING_WITH_LEN("ALGORITHM")}
119 
120 };
121 static const char *part_str = "PARTITION";
122 static const char *sub_str = "SUB";
123 static const char *by_str = "BY";
124 static const char *space_str = " ";
125 static const char *equal_str = "=";
126 static const char *end_paren_str = ")";
127 static const char *begin_paren_str = "(";
128 static const char *comma_str = ",";
129 
130 static int get_partition_id_list_col(partition_info *part_info, uint32 *part_id,
131                                      longlong *func_value);
132 static int get_partition_id_list(partition_info *part_info, uint32 *part_id,
133                                  longlong *func_value);
134 static int get_partition_id_range_col(partition_info *part_info,
135                                       uint32 *part_id, longlong *func_value);
136 static int get_partition_id_range(partition_info *part_info, uint32 *part_id,
137                                   longlong *func_value);
138 static int get_part_id_charset_func_part(partition_info *part_info,
139                                          uint32 *part_id, longlong *func_value);
140 static int get_part_id_charset_func_subpart(partition_info *part_info,
141                                             uint32 *part_id);
142 static int get_partition_id_hash_nosub(partition_info *part_info,
143                                        uint32 *part_id, longlong *func_value);
144 static int get_partition_id_key_nosub(partition_info *part_info,
145                                       uint32 *part_id, longlong *func_value);
146 static int get_partition_id_linear_hash_nosub(partition_info *part_info,
147                                               uint32 *part_id,
148                                               longlong *func_value);
149 static int get_partition_id_linear_key_nosub(partition_info *part_info,
150                                              uint32 *part_id,
151                                              longlong *func_value);
152 static int get_partition_id_with_sub(partition_info *part_info, uint32 *part_id,
153                                      longlong *func_value);
154 static int get_partition_id_hash_sub(partition_info *part_info,
155                                      uint32 *part_id);
156 static int get_partition_id_key_sub(partition_info *part_info, uint32 *part_id);
157 static int get_partition_id_linear_hash_sub(partition_info *part_info,
158                                             uint32 *part_id);
159 static int get_partition_id_linear_key_sub(partition_info *part_info,
160                                            uint32 *part_id);
161 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *);
162 static void set_up_range_analysis_info(partition_info *part_info);
163 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *);
164 
165 static uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
166                                                   bool left_endpoint,
167                                                   bool include_endpoint);
168 static uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter);
169 static int get_part_iter_for_interval_via_mapping(
170     partition_info *part_info, bool is_subpart, uint32 *store_length_array,
171     uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
172     PARTITION_ITERATOR *part_iter);
173 static int get_part_iter_for_interval_cols_via_map(
174     partition_info *part_info, bool is_subpart, uint32 *store_length_array,
175     uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
176     PARTITION_ITERATOR *part_iter);
177 static int get_part_iter_for_interval_via_walking(
178     partition_info *part_info, bool is_subpart, uint32 *store_length_array,
179     uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
180     PARTITION_ITERATOR *part_iter);
181 
182 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
183 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
184                                    uint32 n_vals_in_rec, bool is_left_endpoint,
185                                    bool include_endpoint);
186 
187 static void set_field_ptr(Field **ptr, const uchar *new_buf,
188                           const uchar *old_buf);
189 
190 static uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
191                                               bool left_endpoint,
192                                               bool include_endpoint);
193 
194 /*
195   Convert constants in VALUES definition to the character set the
196   corresponding field uses.
197 
198   SYNOPSIS
199     convert_charset_partition_constant()
200     item                                Item to convert
201     cs                                  Character set to convert to
202 
203   RETURN VALUE
204     NULL                                Error
205     item                                New converted item
206 */
207 
convert_charset_partition_constant(Item * item,const CHARSET_INFO * cs)208 Item *convert_charset_partition_constant(Item *item, const CHARSET_INFO *cs) {
209   THD *thd = current_thd;
210   Name_resolution_context *context = &thd->lex->current_select()->context;
211   TABLE_LIST *save_list = context->table_list;
212   const char *save_where = thd->where;
213 
214   item = item->safe_charset_converter(thd, cs);
215   context->table_list = nullptr;
216   thd->where = "convert character set partition constant";
217   if (!item || item->fix_fields(thd, (Item **)nullptr)) item = nullptr;
218   thd->where = save_where;
219   context->table_list = save_list;
220   return item;
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(const char * name,List<String> list_names)234 static bool is_name_in_list(const char *name, List<String> list_names) {
235   List_iterator<String> names_it(list_names);
236   uint num_names = list_names.elements;
237   uint i = 0;
238 
239   do {
240     String *list_name = names_it++;
241     if (!(my_strcasecmp(system_charset_info, name, list_name->c_ptr())))
242       return true;
243   } while (++i < num_names);
244   return false;
245 }
246 
247 /*
248   Set-up defaults for partitions.
249 
250   SYNOPSIS
251     partition_default_handling()
252     table                         Table object
253     part_info                     Partition info to set up
254     is_create_table_ind           Is this part of a table creation
255     normalized_path               Normalized path name of table and database
256 
257   RETURN VALUES
258     true                          Error
259     false                         Success
260 */
261 
partition_default_handling(TABLE * table,partition_info * part_info,bool is_create_table_ind,const char * normalized_path)262 static bool partition_default_handling(TABLE *table, partition_info *part_info,
263                                        bool is_create_table_ind,
264                                        const char *normalized_path) {
265   Partition_handler *part_handler = table->file->get_partition_handler();
266   DBUG_TRACE;
267 
268   if (!part_handler) {
269     DBUG_ASSERT(0);
270     my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
271     return true;
272   }
273 
274   if (!is_create_table_ind) {
275     if (part_info->use_default_num_partitions) {
276       if (part_handler->get_num_parts(normalized_path, &part_info->num_parts)) {
277         return true;
278       }
279     } else if (part_info->is_sub_partitioned() &&
280                part_info->use_default_num_subpartitions) {
281       uint num_parts;
282       if (part_handler->get_num_parts(normalized_path, &num_parts)) {
283         return true;
284       }
285       DBUG_ASSERT(part_info->num_parts > 0);
286       DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
287       part_info->num_subparts = num_parts / part_info->num_parts;
288     }
289   }
290   part_info->set_up_defaults_for_partitioning(part_handler, nullptr, 0U);
291   return false;
292 }
293 
294 /*
295   A useful routine used by update_row for partition handlers to calculate
296   the partition ids of the old and the new record.
297 
298   SYNOPSIS
299     get_parts_for_update()
300     old_data                Buffer of old record
301     new_data                Buffer of new record
302     rec0                    Reference to table->record[0]
303     part_info               Reference to partition information
304     out:old_part_id         The returned partition id of old record
305     out:new_part_id         The returned partition id of new record
306 
307   RETURN VALUE
308     0                       Success
309     > 0                     Error code
310 */
311 
get_parts_for_update(const uchar * old_data,const uchar * new_data MY_ATTRIBUTE ((unused)),const uchar * rec0,partition_info * part_info,uint32 * old_part_id,uint32 * new_part_id,longlong * new_func_value)312 int get_parts_for_update(const uchar *old_data,
313                          const uchar *new_data MY_ATTRIBUTE((unused)),
314                          const uchar *rec0, partition_info *part_info,
315                          uint32 *old_part_id, uint32 *new_part_id,
316                          longlong *new_func_value) {
317   Field **part_field_array = part_info->full_part_field_array;
318   int error;
319   longlong old_func_value;
320   DBUG_TRACE;
321 
322   DBUG_ASSERT(new_data == rec0);  // table->record[0]
323   set_field_ptr(part_field_array, old_data, rec0);
324   error = part_info->get_partition_id(part_info, old_part_id, &old_func_value);
325   set_field_ptr(part_field_array, rec0, old_data);
326   if (unlikely(error)) {
327     part_info->err_value = old_func_value;
328     return error;
329   }
330   if (unlikely((error = part_info->get_partition_id(part_info, new_part_id,
331                                                     new_func_value)))) {
332     part_info->err_value = *new_func_value;
333     return error;
334   }
335   return 0;
336 }
337 
338 /*
339   A useful routine used by delete_row for partition handlers to calculate
340   the partition id.
341 
342   SYNOPSIS
343     get_part_for_delete()
344     buf                     Buffer of old record
345     rec0                    Reference to table->record[0]
346     part_info               Reference to partition information
347     out:part_id             The returned partition id to delete from
348 
349   RETURN VALUE
350     0                       Success
351     > 0                     Error code
352 
353   DESCRIPTION
354     Dependent on whether buf is not record[0] we need to prepare the
355     fields. Then we call the function pointer get_partition_id to
356     calculate the partition id.
357 */
358 
get_part_for_delete(const uchar * buf,const uchar * rec0,partition_info * part_info,uint32 * part_id)359 int get_part_for_delete(const uchar *buf, const uchar *rec0,
360                         partition_info *part_info, uint32 *part_id) {
361   int error;
362   longlong func_value;
363   DBUG_TRACE;
364 
365   if (likely(buf == rec0)) {
366     if (unlikely((error = part_info->get_partition_id(part_info, part_id,
367                                                       &func_value)))) {
368       part_info->err_value = func_value;
369       return error;
370     }
371     DBUG_PRINT("info", ("Delete from partition %d", *part_id));
372   } else {
373     Field **part_field_array = part_info->full_part_field_array;
374     set_field_ptr(part_field_array, buf, rec0);
375     error = part_info->get_partition_id(part_info, part_id, &func_value);
376     set_field_ptr(part_field_array, rec0, buf);
377     if (unlikely(error)) {
378       part_info->err_value = func_value;
379       return error;
380     }
381     DBUG_PRINT("info", ("Delete from partition %d (path2)", *part_id));
382   }
383   return 0;
384 }
385 
386 /*
387   This method is used to set-up both partition and subpartitioning
388   field array and used for all types of partitioning.
389   It is part of the logic around fix_partition_func.
390 
391   SYNOPSIS
392     set_up_field_array()
393     table                TABLE object for which partition fields are set-up
394     sub_part             Is the table subpartitioned as well
395 
396   RETURN VALUE
397     true                 Error, some field didn't meet requirements
398     false                Ok, partition field array set-up
399 
400   DESCRIPTION
401 
402     A great number of functions below here is part of the fix_partition_func
403     method. It is used to set up the partition structures for execution from
404     openfrm. It is called at the end of the openfrm when the table struct has
405     been set-up apart from the partition information.
406     It involves:
407     1) Setting arrays of fields for the partition functions.
408     2) Setting up binary search array for LIST partitioning
409     3) Setting up array for binary search for RANGE partitioning
410     4) Setting up key_map's to assist in quick evaluation whether one
411        can deduce anything from a given index of what partition to use
412     5) Checking whether a set of partitions can be derived from a range on
413        a field in the partition function.
414     As part of doing this there is also a great number of error controls.
415     This is actually the place where most of the things are checked for
416     partition information when creating a table.
417     Things that are checked includes
418     1) All fields of partition function in Primary keys and unique indexes
419        (if not supported)
420 
421 
422     Create an array of partition fields (NULL terminated). Before this method
423     is called fix_fields or find_table_in_sef has been called to set
424     GET_FIXED_FIELDS_FLAG on all fields that are part of the partition
425     function.
426 */
427 
set_up_field_array(TABLE * table,bool is_sub_part)428 static bool set_up_field_array(TABLE *table, bool is_sub_part) {
429   Field **ptr, *field, **field_array;
430   uint num_fields = 0;
431   uint size_field_array;
432   uint i = 0;
433   uint inx;
434   partition_info *part_info = table->part_info;
435   int result = false;
436   DBUG_TRACE;
437 
438   ptr = table->field;
439   while ((field = *(ptr++))) {
440     if (field->is_flag_set(GET_FIXED_FIELDS_FLAG)) num_fields++;
441   }
442   if (num_fields > MAX_REF_PARTS) {
443     const char *err_str;
444     if (is_sub_part)
445       err_str = "subpartition function";
446     else
447       err_str = "partition function";
448     my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), err_str);
449     return true;
450   }
451   if (num_fields == 0) {
452     /*
453       We are using hidden key as partitioning field
454     */
455     DBUG_ASSERT(!is_sub_part);
456     return result;
457   }
458   size_field_array = (num_fields + 1) * sizeof(Field *);
459   field_array = (Field **)sql_calloc(size_field_array);
460   if (unlikely(!field_array)) {
461     mem_alloc_error(size_field_array);
462     result = true;
463   }
464   ptr = table->field;
465   while ((field = *(ptr++))) {
466     if (field->is_flag_set(GET_FIXED_FIELDS_FLAG)) {
467       field->clear_flag(GET_FIXED_FIELDS_FLAG);
468       field->set_flag(FIELD_IN_PART_FUNC_FLAG);
469       if (likely(!result)) {
470         if (!is_sub_part && part_info->column_list) {
471           List_iterator<char> it(part_info->part_field_list);
472           char *field_name;
473 
474           DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
475           inx = 0;
476           do {
477             field_name = it++;
478             if (!my_strcasecmp(system_charset_info, field_name,
479                                field->field_name))
480               break;
481           } while (++inx < num_fields);
482           if (inx == num_fields) {
483             /*
484               Should not occur since it should already been checked in either
485               add_column_list_values, handle_list_of_fields,
486               check_partition_info etc.
487             */
488             DBUG_ASSERT(0);
489             my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
490             result = true;
491             continue;
492           }
493         } else
494           inx = i;
495         field_array[inx] = field;
496         i++;
497 
498         /*
499           We check that the fields are proper. It is required for each
500           field in a partition function to:
501           1) Not be a BLOB of any type
502             A BLOB takes too long time to evaluate so we don't want it for
503             performance reasons.
504         */
505 
506         if (field->is_flag_set(BLOB_FLAG)) {
507           my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
508           result = true;
509         }
510       }
511     }
512   }
513   field_array[num_fields] = nullptr;
514   if (!is_sub_part) {
515     part_info->part_field_array = field_array;
516     part_info->num_part_fields = num_fields;
517   } else {
518     part_info->subpart_field_array = field_array;
519     part_info->num_subpart_fields = num_fields;
520   }
521   return result;
522 }
523 
524 /*
525   Create a field array including all fields of both the partitioning and the
526   subpartitioning functions.
527 
528   SYNOPSIS
529     create_full_part_field_array()
530     thd                  Thread handle
531     table                TABLE object for which partition fields are set-up
532     part_info            Reference to partitioning data structure
533 
534   RETURN VALUE
535     true                 Memory allocation of field array failed
536     false                Ok
537 
538   DESCRIPTION
539     If there is no subpartitioning then the same array is used as for the
540     partitioning. Otherwise a new array is built up using the flag
541     FIELD_IN_PART_FUNC in the field object.
542     This function is called from fix_partition_func
543 */
544 
create_full_part_field_array(THD * thd,TABLE * table,partition_info * part_info)545 static bool create_full_part_field_array(THD *thd, TABLE *table,
546                                          partition_info *part_info) {
547   bool result = false;
548   Field **ptr;
549   my_bitmap_map *bitmap_buf;
550   DBUG_TRACE;
551 
552   if (!part_info->is_sub_partitioned()) {
553     part_info->full_part_field_array = part_info->part_field_array;
554     part_info->num_full_part_fields = part_info->num_part_fields;
555   } else {
556     Field *field, **field_array;
557     uint num_part_fields = 0, size_field_array;
558     ptr = table->field;
559     while ((field = *(ptr++))) {
560       if (field->is_flag_set(FIELD_IN_PART_FUNC_FLAG)) num_part_fields++;
561     }
562     size_field_array = (num_part_fields + 1) * sizeof(Field *);
563     field_array = (Field **)sql_calloc(size_field_array);
564     if (unlikely(!field_array)) {
565       mem_alloc_error(size_field_array);
566       result = true;
567       goto end;
568     }
569     num_part_fields = 0;
570     ptr = table->field;
571     while ((field = *(ptr++))) {
572       if (field->is_flag_set(FIELD_IN_PART_FUNC_FLAG))
573         field_array[num_part_fields++] = field;
574     }
575     field_array[num_part_fields] = nullptr;
576     part_info->full_part_field_array = field_array;
577     part_info->num_full_part_fields = num_part_fields;
578   }
579 
580   /*
581     Initialize the set of all fields used in partition and subpartition
582     expression. Required for testing of partition fields in write_set
583     when updating. We need to set all bits in read_set because the row
584     may need to be inserted in a different [sub]partition.
585   */
586   if (!(bitmap_buf = (my_bitmap_map *)thd->alloc(
587             bitmap_buffer_size(table->s->fields)))) {
588     mem_alloc_error(bitmap_buffer_size(table->s->fields));
589     result = true;
590     goto end;
591   }
592   if (bitmap_init(&part_info->full_part_field_set, bitmap_buf,
593                   table->s->fields)) {
594     mem_alloc_error(table->s->fields);
595     result = true;
596     goto end;
597   }
598   /*
599     full_part_field_array may be NULL if storage engine supports native
600     partitioning.
601   */
602   if ((ptr = part_info->full_part_field_array))
603     for (; *ptr; ptr++)
604       bitmap_set_bit(&part_info->full_part_field_set, (*ptr)->field_index());
605 
606 end:
607   return result;
608 }
609 
610 /*
611 
612   Clear flag GET_FIXED_FIELDS_FLAG in all fields of a key previously set by
613   set_indicator_in_key_fields (always used in pairs).
614 
615   SYNOPSIS
616     clear_indicator_in_key_fields()
617     key_info                  Reference to find the key fields
618 
619   RETURN VALUE
620     NONE
621 
622   DESCRIPTION
623     These support routines is used to set/reset an indicator of all fields
624     in a certain key. It is used in conjunction with another support routine
625     that traverse all fields in the PF to find if all or some fields in the
626     PF is part of the key. This is used to check primary keys and unique
627     keys involve all fields in PF (unless supported) and to derive the
628     key_map's used to quickly decide whether the index can be used to
629     derive which partitions are needed to scan.
630 */
631 
clear_indicator_in_key_fields(KEY * key_info)632 static void clear_indicator_in_key_fields(KEY *key_info) {
633   KEY_PART_INFO *key_part;
634   uint key_parts = key_info->user_defined_key_parts, i;
635   for (i = 0, key_part = key_info->key_part; i < key_parts; i++, key_part++)
636     key_part->field->clear_flag(GET_FIXED_FIELDS_FLAG);
637 }
638 
639 /*
640   Set flag GET_FIXED_FIELDS_FLAG in all fields of a key.
641 
642   SYNOPSIS
643     set_indicator_in_key_fields
644     key_info                  Reference to find the key fields
645 
646   RETURN VALUE
647     NONE
648 */
649 
set_indicator_in_key_fields(KEY * key_info)650 static void set_indicator_in_key_fields(KEY *key_info) {
651   KEY_PART_INFO *key_part;
652   uint key_parts = key_info->user_defined_key_parts, i;
653   for (i = 0, key_part = key_info->key_part; i < key_parts; i++, key_part++)
654     key_part->field->set_flag(GET_FIXED_FIELDS_FLAG);
655 }
656 
657 /*
658   Check if all or some fields in partition field array is part of a key
659   previously used to tag key fields.
660 
661   SYNOPSIS
662     check_fields_in_PF()
663     ptr                  Partition field array
664     out:all_fields       Is all fields of partition field array used in key
665     out:some_fields      Is some fields of partition field array used in key
666 
667   RETURN VALUE
668     all_fields, some_fields
669 */
670 
check_fields_in_PF(Field ** ptr,bool * all_fields,bool * some_fields)671 static void check_fields_in_PF(Field **ptr, bool *all_fields,
672                                bool *some_fields) {
673   DBUG_TRACE;
674 
675   *all_fields = true;
676   *some_fields = false;
677   if ((!ptr) || !(*ptr)) {
678     *all_fields = false;
679     return;
680   }
681   do {
682     /* Check if the field of the PF is part of the current key investigated */
683     if ((*ptr)->is_flag_set(GET_FIXED_FIELDS_FLAG))
684       *some_fields = true;
685     else
686       *all_fields = false;
687   } while (*(++ptr));
688 }
689 
690 /*
691   Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
692   This routine is used for error handling purposes.
693 
694   SYNOPSIS
695     clear_field_flag()
696     table                TABLE object for which partition fields are set-up
697 
698   RETURN VALUE
699     NONE
700 */
701 
clear_field_flag(TABLE * table)702 static void clear_field_flag(TABLE *table) {
703   Field **ptr;
704   DBUG_TRACE;
705 
706   for (ptr = table->field; *ptr; ptr++)
707     (*ptr)->clear_flag(GET_FIXED_FIELDS_FLAG);
708 }
709 
710 /*
711   find_field_in_table_sef finds the field given its name. All fields get
712   GET_FIXED_FIELDS_FLAG set.
713 
714   SYNOPSIS
715     handle_list_of_fields()
716     it                   A list of field names for the partition function
717     table                TABLE object for which partition fields are set-up
718     part_info            Reference to partitioning data structure
719     sub_part             Is the table subpartitioned as well
720 
721   RETURN VALUE
722     true                 Fields in list of fields not part of table
723     false                All fields ok and array created
724 
725   DESCRIPTION
726     This routine sets-up the partition field array for KEY partitioning, it
727     also verifies that all fields in the list of fields is actually a part of
728     the table.
729 
730 */
731 
handle_list_of_fields(List_iterator<char> it,TABLE * table,partition_info * part_info,bool is_sub_part)732 static bool handle_list_of_fields(List_iterator<char> it, TABLE *table,
733                                   partition_info *part_info, bool is_sub_part) {
734   bool result;
735   char *field_name;
736   bool is_list_empty = true;
737   DBUG_TRACE;
738 
739   while ((field_name = it++)) {
740     is_list_empty = false;
741     Field *field = find_field_in_table_sef(table, field_name);
742     if (likely(field != nullptr))
743       field->set_flag(GET_FIXED_FIELDS_FLAG);
744     else {
745       my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
746       clear_field_flag(table);
747       result = true;
748       goto end;
749     }
750   }
751   if (is_list_empty && part_info->part_type == partition_type::HASH) {
752     uint primary_key = table->s->primary_key;
753     if (primary_key != MAX_KEY) {
754       uint num_key_parts = table->key_info[primary_key].user_defined_key_parts,
755            i;
756       /*
757         In the case of an empty list we use primary key as partition key.
758       */
759       for (i = 0; i < num_key_parts; i++) {
760         Field *field = table->key_info[primary_key].key_part[i].field;
761         field->set_flag(GET_FIXED_FIELDS_FLAG);
762       }
763     } else {
764       if (table->s->db_type()->partition_flags &&
765           (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)) {
766         /*
767           This engine can handle automatic partitioning and there is no
768           primary key. In this case we rely on that the engine handles
769           partitioning based on a hidden key. Thus we allocate no
770           array for partitioning fields.
771         */
772         return false;
773       } else {
774         my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
775         return true;
776       }
777     }
778   }
779   result = set_up_field_array(table, is_sub_part);
780 end:
781   return result;
782 }
783 
784 /*
785   Support function to check if all VALUES * (expression) is of the
786   right sign (no signed constants when unsigned partition function)
787 
788   SYNOPSIS
789     check_signed_flag()
790     part_info                Partition info object
791 
792   RETURN VALUES
793     0                        No errors due to sign errors
794     >0                       Sign error
795 */
796 
check_signed_flag(partition_info * part_info)797 static int check_signed_flag(partition_info *part_info) {
798   int error = 0;
799   uint i = 0;
800   if (part_info->part_type != partition_type::HASH &&
801       part_info->part_expr->unsigned_flag) {
802     List_iterator<partition_element> part_it(part_info->partitions);
803     do {
804       partition_element *part_elem = part_it++;
805 
806       if (part_elem->signed_flag) {
807         my_error(ER_PARTITION_CONST_DOMAIN_ERROR, MYF(0));
808         error = ER_PARTITION_CONST_DOMAIN_ERROR;
809         break;
810       }
811     } while (++i < part_info->num_parts);
812   }
813   return error;
814 }
815 
816 /**
817   Initialize lex object for use in fix_fields and parsing.
818 
819   @param thd      The thread object
820   @param table    The table object
821   @param lex      The LEX object, must be initialized and contain select_lex.
822 
823   @returns  false if success, true if error
824 
825   @details
826     This function is used to set up a lex object on the
827     stack for resolving of fields from a single table.
828 */
829 
init_lex_with_single_table(THD * thd,TABLE * table,LEX * lex)830 static bool init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) {
831   SELECT_LEX *select_lex = lex->select_lex;
832   Name_resolution_context *context = &select_lex->context;
833   /*
834     We will call the parser to create a part_info struct based on the
835     partition string stored in the frm file.
836     We will use a local lex object for this purpose. However we also
837     need to set the Name_resolution_object for this lex object. We
838     do this by using add_table_to_list where we add the table that
839     we're working with to the Name_resolution_context.
840   */
841   thd->lex = lex;
842   auto table_ident = new (thd->mem_root) Table_ident(
843       thd->get_protocol(), table->s->db, table->s->table_name, true);
844   if (table_ident == nullptr) return true;
845 
846   TABLE_LIST *table_list =
847       select_lex->add_table_to_list(thd, table_ident, nullptr, 0);
848   if (table_list == nullptr) return true;
849 
850   context->resolve_in_table_list_only(table_list);
851   lex->use_only_table_context = true;
852   table->get_fields_in_item_tree = true;
853   table_list->table = table;
854   table_list->cacheable_table = false;
855   return false;
856 }
857 
858 /**
859   End use of local lex with single table
860 
861   SYNOPSIS
862     end_lex_with_single_table()
863     @param thd               The thread object
864     @param table             The table object
865     @param old_lex           The real lex object connected to THD
866 
867   DESCRIPTION
868     This function restores the real lex object after calling
869     init_lex_with_single_table and also restores some table
870     variables temporarily set.
871 */
872 
end_lex_with_single_table(THD * thd,TABLE * table,LEX * old_lex)873 static void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex) {
874   LEX *lex = thd->lex;
875   table->get_fields_in_item_tree = false;
876   lex_end(lex);
877   thd->lex = old_lex;
878 }
879 
880 /*
881   The function uses a new feature in fix_fields where the flag
882   GET_FIXED_FIELDS_FLAG is set for all fields in the item tree.
883   This field must always be reset before returning from the function
884   since it is used for other purposes as well.
885 
886   SYNOPSIS
887     fix_fields_part_func()
888     thd                  The thread object
889     func_expr            The item tree reference of the partition function
890     table                The table object
891     part_info            Reference to partitioning data structure
892     is_sub_part          Is the table subpartitioned as well
893     is_create_table_ind  Indicator of whether openfrm was called as part of
894                          CREATE or ALTER TABLE
895 
896   RETURN VALUE
897     true                 An error occurred, something was wrong with the
898                          partition function.
899     false                Ok, a partition field array was created
900 
901   DESCRIPTION
902     This function is used to build an array of partition fields for the
903     partitioning function and subpartitioning function. The partitioning
904     function is an item tree that must reference at least one field in the
905     table. This is checked first in the parser that the function doesn't
906     contain non-cacheable parts (like a random function) and by checking
907     here that the function isn't a constant function.
908 
909     Calculate the number of fields in the partition function.
910     Use it allocate memory for array of Field pointers.
911     Initialise array of field pointers. Use information set when
912     calling fix_fields and reset it immediately after.
913     The get_fields_in_item_tree activates setting of bit in flags
914     on the field object.
915 */
916 
fix_fields_part_func(THD * thd,Item * func_expr,TABLE * table,bool is_sub_part,bool is_create_table_ind)917 static bool fix_fields_part_func(THD *thd, Item *func_expr, TABLE *table,
918                                  bool is_sub_part, bool is_create_table_ind) {
919   partition_info *part_info = table->part_info;
920   bool result = true;
921   int error;
922   LEX *old_lex = thd->lex;
923   LEX lex;
924   SELECT_LEX_UNIT unit(CTX_NONE);
925   SELECT_LEX select(thd->mem_root, nullptr, nullptr);
926   lex.new_static_query(&unit, &select);
927 
928   DBUG_TRACE;
929 
930   if (init_lex_with_single_table(thd, table, &lex)) goto end;
931 
932   {
933     Item_ident::Change_context ctx(&lex.select_lex->context);
934     func_expr->walk(&Item::change_context_processor, enum_walk::POSTFIX,
935                     (uchar *)&ctx);
936   }
937   thd->where = "partition function";
938   /*
939     In execution we must avoid the use of thd->change_item_tree since
940     we might release memory before statement is completed. We do this
941     by temporarily setting the stmt_arena->mem_root to be the mem_root
942     of the table object, this also ensures that any memory allocated
943     during fix_fields will not be released at end of execution of this
944     statement. Thus the item tree will remain valid also in subsequent
945     executions of this table object. We do however not at the moment
946     support allocations during execution of val_int so any item class
947     that does this during val_int must be disallowed as partition
948     function.
949     SEE Bug #21658
950 
951     This is a tricky call to prepare for since it can have a large number
952     of interesting side effects, both desirable and undesirable.
953   */
954   {
955     const bool save_agg_func = thd->lex->current_select()->agg_func_used();
956 
957     error = func_expr->fix_fields(thd, &func_expr);
958 
959     /*
960       Restore agg_func.
961       fix_fields should not affect the optimizer later, see Bug#46923.
962     */
963     thd->lex->current_select()->set_agg_func_used(save_agg_func);
964   }
965   if (unlikely(error)) {
966     DBUG_PRINT("info", ("Field in partition function not part of table"));
967     clear_field_flag(table);
968     goto end;
969   }
970   if (unlikely(func_expr->const_item())) {
971     my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
972     clear_field_flag(table);
973     goto end;
974   }
975 
976   /*
977     We don't allow creating partitions with expressions with non matching
978     arguments as a (sub)partitioning function,
979     but we want to allow such expressions when opening existing tables for
980     easier maintenance. This exception should be deprecated at some point
981     in future so that we always throw an error.
982   */
983   if (func_expr->walk(&Item::check_valid_arguments_processor,
984                       enum_walk::POSTFIX, nullptr)) {
985     if (is_create_table_ind) {
986       my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
987       goto end;
988     } else
989       push_warning(thd, Sql_condition::SL_WARNING,
990                    ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
991                    ER_THD(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
992   }
993 
994   if ((!is_sub_part) && (error = check_signed_flag(part_info))) goto end;
995   result = set_up_field_array(table, is_sub_part);
996 end:
997   end_lex_with_single_table(thd, table, old_lex);
998 #if !defined(DBUG_OFF)
999   Item_ident::Change_context nul_ctx(nullptr);
1000   func_expr->walk(&Item::change_context_processor, enum_walk::POSTFIX,
1001                   (uchar *)&nul_ctx);
1002 #endif
1003   return result;
1004 }
1005 
1006 /*
1007   Check that the primary key contains all partition fields if defined
1008 
1009   SYNOPSIS
1010     check_primary_key()
1011     table                TABLE object for which partition fields are set-up
1012 
1013   RETURN VALUES
1014     true                 Not all fields in partitioning function was part
1015                          of primary key
1016     false                Ok, all fields of partitioning function were part
1017                          of primary key
1018 
1019   DESCRIPTION
1020     This function verifies that if there is a primary key that it contains
1021     all the fields of the partition function.
1022     This is a temporary limitation that will hopefully be removed after a
1023     while.
1024 */
1025 
check_primary_key(TABLE * table)1026 static bool check_primary_key(TABLE *table) {
1027   uint primary_key = table->s->primary_key;
1028   bool all_fields, some_fields;
1029   bool result = false;
1030   DBUG_TRACE;
1031 
1032   if (primary_key < MAX_KEY) {
1033     set_indicator_in_key_fields(table->key_info + primary_key);
1034     check_fields_in_PF(table->part_info->full_part_field_array, &all_fields,
1035                        &some_fields);
1036     clear_indicator_in_key_fields(table->key_info + primary_key);
1037     if (unlikely(!all_fields)) {
1038       my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, MYF(0), "PRIMARY KEY");
1039       result = true;
1040     }
1041   }
1042   return result;
1043 }
1044 
1045 /*
1046   Check that unique keys contains all partition fields
1047 
1048   SYNOPSIS
1049     check_unique_keys()
1050     table                TABLE object for which partition fields are set-up
1051 
1052   RETURN VALUES
1053     true                 Not all fields in partitioning function was part
1054                          of all unique keys
1055     false                Ok, all fields of partitioning function were part
1056                          of unique keys
1057 
1058   DESCRIPTION
1059     This function verifies that if there is a unique index that it contains
1060     all the fields of the partition function.
1061     This is a temporary limitation that will hopefully be removed after a
1062     while.
1063 */
1064 
check_unique_keys(TABLE * table)1065 static bool check_unique_keys(TABLE *table) {
1066   bool all_fields, some_fields;
1067   bool result = false;
1068   uint keys = table->s->keys;
1069   uint i;
1070   DBUG_TRACE;
1071 
1072   for (i = 0; i < keys; i++) {
1073     if (table->key_info[i].flags & HA_NOSAME)  // Unique index
1074     {
1075       set_indicator_in_key_fields(table->key_info + i);
1076       check_fields_in_PF(table->part_info->full_part_field_array, &all_fields,
1077                          &some_fields);
1078       clear_indicator_in_key_fields(table->key_info + i);
1079       if (unlikely(!all_fields)) {
1080         my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, MYF(0), "UNIQUE INDEX");
1081         result = true;
1082         break;
1083       }
1084     }
1085   }
1086   return result;
1087 }
1088 
1089 /*
1090   An important optimisation is whether a range on a field can select a subset
1091   of the partitions.
1092   A prerequisite for this to happen is that the PF is a growing function OR
1093   a shrinking function.
1094   This can never happen for a multi-dimensional PF. Thus this can only happen
1095   with PF with at most one field involved in the PF.
1096   The idea is that if the function is a growing function and you know that
1097   the field of the PF is 4 <= A <= 6 then we can convert this to a range
1098   in the PF instead by setting the range to PF(4) <= PF(A) <= PF(6). In the
1099   case of RANGE PARTITIONING and LIST PARTITIONING this can be used to
1100   calculate a set of partitions rather than scanning all of them.
1101   Thus the following prerequisites are there to check if sets of partitions
1102   can be found.
1103   1) Only possible for RANGE and LIST partitioning (not for subpartitioning)
1104   2) Only possible if PF only contains 1 field
1105   3) Possible if PF is a growing function of the field
1106   4) Possible if PF is a shrinking function of the field
1107   OBSERVATION:
1108   1) IF f1(A) is a growing function AND f2(A) is a growing function THEN
1109      f1(A) + f2(A) is a growing function
1110      f1(A) * f2(A) is a growing function if f1(A) >= 0 and f2(A) >= 0
1111   2) IF f1(A) is a growing function and f2(A) is a shrinking function THEN
1112      f1(A) / f2(A) is a growing function if f1(A) >= 0 and f2(A) > 0
1113   3) IF A is a growing function then a function f(A) that removes the
1114      least significant portion of A is a growing function
1115      E.g. DATE(datetime) is a growing function
1116      MONTH(datetime) is not a growing/shrinking function
1117   4) IF f1(A) is a growing function and f2(A) is a growing function THEN
1118      f1(f2(A)) and f2(f1(A)) are also growing functions
1119   5) IF f1(A) is a shrinking function and f2(A) is a growing function THEN
1120      f1(f2(A)) is a shrinking function and f2(f1(A)) is a shrinking function
1121   6) f1(A) = A is a growing function
1122   7) f1(A) = A*a + b (where a and b are constants) is a growing function
1123 
1124   By analysing the item tree of the PF we can use these deducements and
1125   derive whether the PF is a growing function or a shrinking function or
1126   neither of it.
1127 
1128   If the PF is range capable then a flag is set on the table object
1129   indicating this to notify that we can use also ranges on the field
1130   of the PF to deduce a set of partitions if the fields of the PF were
1131   not all fully bound.
1132 
1133   SYNOPSIS
1134     check_range_capable_PF()
1135 
1136   DESCRIPTION
1137     Support for this is not implemented yet.
1138 */
1139 
check_range_capable_PF(TABLE *)1140 static void check_range_capable_PF(TABLE *) { DBUG_TRACE; }
1141 
1142 /**
1143   Set up partition bitmaps
1144 
1145     @param part_info     Reference to partitioning data structure
1146 
1147   @return Operation status
1148     @retval true         Memory allocation failure
1149     @retval false        Success
1150 
1151     Allocate memory for bitmaps of the partitioned table
1152     and initialise it.
1153 */
1154 
set_up_partition_bitmaps(partition_info * part_info)1155 static bool set_up_partition_bitmaps(partition_info *part_info) {
1156   DBUG_TRACE;
1157 
1158   DBUG_ASSERT(!part_info->bitmaps_are_initialized);
1159 
1160   if (part_info->init_partition_bitmap(&part_info->read_partitions,
1161                                        &part_info->table->mem_root))
1162     return true;
1163   if (part_info->init_partition_bitmap(&part_info->lock_partitions,
1164                                        &part_info->table->mem_root))
1165     return true;
1166 
1167   part_info->bitmaps_are_initialized = true;
1168   part_info->set_partition_bitmaps(nullptr);
1169   return false;
1170 }
1171 
1172 /*
1173   Set up partition key maps
1174 
1175   SYNOPSIS
1176     set_up_partition_key_maps()
1177     table                TABLE object for which partition fields are set-up
1178     part_info            Reference to partitioning data structure
1179 
1180   RETURN VALUES
1181     None
1182 
1183   DESCRIPTION
1184     This function sets up a couple of key maps to be able to quickly check
1185     if an index ever can be used to deduce the partition fields or even
1186     a part of the fields of the  partition function.
1187     We set up the following key_map's.
1188     PF = Partition Function
1189     1) All fields of the PF is set even by equal on the first fields in the
1190        key
1191     2) All fields of the PF is set if all fields of the key is set
1192     3) At least one field in the PF is set if all fields is set
1193     4) At least one field in the PF is part of the key
1194 */
1195 
set_up_partition_key_maps(TABLE * table,partition_info * part_info)1196 static void set_up_partition_key_maps(TABLE *table, partition_info *part_info) {
1197   uint keys = table->s->keys;
1198   uint i;
1199   bool all_fields, some_fields;
1200   DBUG_TRACE;
1201 
1202   part_info->all_fields_in_PF.clear_all();
1203   part_info->all_fields_in_PPF.clear_all();
1204   part_info->all_fields_in_SPF.clear_all();
1205   part_info->some_fields_in_PF.clear_all();
1206   for (i = 0; i < keys; i++) {
1207     set_indicator_in_key_fields(table->key_info + i);
1208     check_fields_in_PF(part_info->full_part_field_array, &all_fields,
1209                        &some_fields);
1210     if (all_fields) part_info->all_fields_in_PF.set_bit(i);
1211     if (some_fields) part_info->some_fields_in_PF.set_bit(i);
1212     if (part_info->is_sub_partitioned()) {
1213       check_fields_in_PF(part_info->part_field_array, &all_fields,
1214                          &some_fields);
1215       if (all_fields) part_info->all_fields_in_PPF.set_bit(i);
1216       check_fields_in_PF(part_info->subpart_field_array, &all_fields,
1217                          &some_fields);
1218       if (all_fields) part_info->all_fields_in_SPF.set_bit(i);
1219     }
1220     clear_indicator_in_key_fields(table->key_info + i);
1221   }
1222 }
1223 
1224 /*
1225   Set up function pointers for partition function
1226 
1227   SYNOPSIS
1228     set_up_partition_func_pointers()
1229     part_info            Reference to partitioning data structure
1230 
1231   RETURN VALUE
1232     NONE
1233 
1234   DESCRIPTION
1235     Set-up all function pointers for calculation of partition id,
1236     subpartition id and the upper part in subpartitioning. This is to speed up
1237     execution of get_partition_id which is executed once every record to be
1238     written and deleted and twice for updates.
1239 */
1240 
set_up_partition_func_pointers(partition_info * part_info)1241 static void set_up_partition_func_pointers(partition_info *part_info) {
1242   DBUG_TRACE;
1243 
1244   if (part_info->is_sub_partitioned()) {
1245     part_info->get_partition_id = get_partition_id_with_sub;
1246     if (part_info->part_type == partition_type::RANGE) {
1247       if (part_info->column_list)
1248         part_info->get_part_partition_id = get_partition_id_range_col;
1249       else
1250         part_info->get_part_partition_id = get_partition_id_range;
1251       if (part_info->list_of_subpart_fields) {
1252         if (part_info->linear_hash_ind)
1253           part_info->get_subpartition_id = get_partition_id_linear_key_sub;
1254         else
1255           part_info->get_subpartition_id = get_partition_id_key_sub;
1256       } else {
1257         if (part_info->linear_hash_ind)
1258           part_info->get_subpartition_id = get_partition_id_linear_hash_sub;
1259         else
1260           part_info->get_subpartition_id = get_partition_id_hash_sub;
1261       }
1262     } else /* LIST Partitioning */
1263     {
1264       if (part_info->column_list)
1265         part_info->get_part_partition_id = get_partition_id_list_col;
1266       else
1267         part_info->get_part_partition_id = get_partition_id_list;
1268       if (part_info->list_of_subpart_fields) {
1269         if (part_info->linear_hash_ind)
1270           part_info->get_subpartition_id = get_partition_id_linear_key_sub;
1271         else
1272           part_info->get_subpartition_id = get_partition_id_key_sub;
1273       } else {
1274         if (part_info->linear_hash_ind)
1275           part_info->get_subpartition_id = get_partition_id_linear_hash_sub;
1276         else
1277           part_info->get_subpartition_id = get_partition_id_hash_sub;
1278       }
1279     }
1280   } else /* No subpartitioning */
1281   {
1282     part_info->get_part_partition_id = nullptr;
1283     part_info->get_subpartition_id = nullptr;
1284     if (part_info->part_type == partition_type::RANGE) {
1285       if (part_info->column_list)
1286         part_info->get_partition_id = get_partition_id_range_col;
1287       else
1288         part_info->get_partition_id = get_partition_id_range;
1289     } else if (part_info->part_type == partition_type::LIST) {
1290       if (part_info->column_list)
1291         part_info->get_partition_id = get_partition_id_list_col;
1292       else
1293         part_info->get_partition_id = get_partition_id_list;
1294     } else /* HASH partitioning */
1295     {
1296       if (part_info->list_of_part_fields) {
1297         if (part_info->linear_hash_ind)
1298           part_info->get_partition_id = get_partition_id_linear_key_nosub;
1299         else
1300           part_info->get_partition_id = get_partition_id_key_nosub;
1301       } else {
1302         if (part_info->linear_hash_ind)
1303           part_info->get_partition_id = get_partition_id_linear_hash_nosub;
1304         else
1305           part_info->get_partition_id = get_partition_id_hash_nosub;
1306       }
1307     }
1308   }
1309   /*
1310     We need special functions to handle character sets since they require copy
1311     of field pointers and restore afterwards. For subpartitioned tables we do
1312     the copy and restore individually on the part and subpart parts. For non-
1313     subpartitioned tables we use the same functions as used for the parts part
1314     of subpartioning.
1315     Thus for subpartitioned tables the get_partition_id is always
1316     get_partition_id_with_sub, even when character sets exists.
1317   */
1318   if (part_info->part_charset_field_array) {
1319     if (part_info->is_sub_partitioned()) {
1320       DBUG_ASSERT(part_info->get_part_partition_id);
1321       if (!part_info->column_list) {
1322         part_info->get_part_partition_id_charset =
1323             part_info->get_part_partition_id;
1324         part_info->get_part_partition_id = get_part_id_charset_func_part;
1325       }
1326     } else {
1327       DBUG_ASSERT(part_info->get_partition_id);
1328       if (!part_info->column_list) {
1329         part_info->get_part_partition_id_charset = part_info->get_partition_id;
1330         part_info->get_part_partition_id = get_part_id_charset_func_part;
1331       }
1332     }
1333   }
1334   if (part_info->subpart_charset_field_array) {
1335     DBUG_ASSERT(part_info->get_subpartition_id);
1336     part_info->get_subpartition_id_charset = part_info->get_subpartition_id;
1337     part_info->get_subpartition_id = get_part_id_charset_func_subpart;
1338   }
1339 }
1340 
1341 /*
1342   For linear hashing we need a mask which is on the form 2**n - 1 where
1343   2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
1344 
1345   SYNOPSIS
1346     set_linear_hash_mask()
1347     part_info            Reference to partitioning data structure
1348     num_parts            Number of parts in linear hash partitioning
1349 
1350   RETURN VALUE
1351     NONE
1352 */
1353 
set_linear_hash_mask(partition_info * part_info,uint num_parts)1354 void set_linear_hash_mask(partition_info *part_info, uint num_parts) {
1355   uint mask;
1356 
1357   for (mask = 1; mask < num_parts; mask <<= 1)
1358     ;
1359   part_info->linear_hash_mask = mask - 1;
1360 }
1361 
1362 /*
1363   This function calculates the partition id provided the result of the hash
1364   function using linear hashing parameters, mask and number of partitions.
1365 
1366   SYNOPSIS
1367     get_part_id_from_linear_hash()
1368     hash_value          Hash value calculated by HASH function or KEY function
1369     mask                Mask calculated previously by set_linear_hash_mask
1370     num_parts           Number of partitions in HASH partitioned part
1371 
1372   RETURN VALUE
1373     part_id             The calculated partition identity (starting at 0)
1374 
1375   DESCRIPTION
1376     The partition is calculated according to the theory of linear hashing.
1377     See e.g. Linear hashing: a new tool for file and table addressing,
1378     Reprinted from VLDB-80 in Readings Database Systems, 2nd ed, M. Stonebraker
1379     (ed.), Morgan Kaufmann 1994.
1380 */
1381 
get_part_id_from_linear_hash(longlong hash_value,uint mask,uint num_parts)1382 static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
1383                                            uint num_parts) {
1384   uint32 part_id = (uint32)(hash_value & mask);
1385 
1386   if (part_id >= num_parts) {
1387     uint new_mask = ((mask + 1) >> 1) - 1;
1388     part_id = (uint32)(hash_value & new_mask);
1389   }
1390   return part_id;
1391 }
1392 
1393 /*
1394   Check if a particular field is in need of character set
1395   handling for partition functions.
1396 
1397   SYNOPSIS
1398     field_is_partition_charset()
1399     field                         The field to check
1400 
1401   RETURN VALUES
1402     false                        Not in need of character set handling
1403     true                         In need of character set handling
1404 */
1405 
field_is_partition_charset(Field * field)1406 bool field_is_partition_charset(Field *field) {
1407   if (!(field->type() == MYSQL_TYPE_STRING) &&
1408       !(field->type() == MYSQL_TYPE_VARCHAR))
1409     return false;
1410   {
1411     const CHARSET_INFO *cs = field->charset();
1412     if (!(field->type() == MYSQL_TYPE_STRING) || !(cs->state & MY_CS_BINSORT))
1413       return true;
1414     return false;
1415   }
1416 }
1417 
1418 /*
1419   Check that partition function doesn't contain any forbidden
1420   character sets and collations.
1421 
1422   SYNOPSIS
1423     check_part_func_fields()
1424     ptr                                 Array of Field pointers
1425     ok_with_charsets                    Will we report allowed charset
1426                                         fields as ok
1427   RETURN VALUES
1428     false                               Success
1429     true                                Error
1430 
1431   DESCRIPTION
1432     We will check in this routine that the fields of the partition functions
1433     do not contain unallowed parts. It can also be used to check if there
1434     are fields that require special care by calling my_strnxfrm before
1435     calling the functions to calculate partition id.
1436 */
1437 
check_part_func_fields(Field ** ptr,bool ok_with_charsets)1438 bool check_part_func_fields(Field **ptr, bool ok_with_charsets) {
1439   Field *field;
1440   DBUG_TRACE;
1441 
1442   while ((field = *(ptr++))) {
1443     /*
1444       For CHAR/VARCHAR fields we need to take special precautions.
1445       Binary collation with CHAR is automatically supported. Other
1446       types need some kind of standardisation function handling
1447     */
1448     if (field_is_partition_charset(field)) {
1449       const CHARSET_INFO *cs = field->charset();
1450       if (!ok_with_charsets || cs->mbmaxlen > 1 || cs->strxfrm_multiply > 1) {
1451         return true;
1452       }
1453     }
1454   }
1455   return false;
1456 }
1457 
1458 /*
1459   fix partition functions
1460 
1461   SYNOPSIS
1462     fix_partition_func()
1463     thd                  The thread object
1464     table                TABLE object for which partition fields are set-up
1465     is_create_table_ind  Indicator of whether openfrm was called as part of
1466                          CREATE or ALTER TABLE
1467 
1468   RETURN VALUE
1469     true                 Error
1470     false                Success
1471 
1472   DESCRIPTION
1473     The name parameter contains the full table name and is used to get the
1474     database name of the table which is used to set-up a correct
1475     TABLE_LIST object for use in fix_fields.
1476 
1477 NOTES
1478     This function is called as part of opening the table by opening the .frm
1479     file. It is a part of CREATE TABLE to do this so it is quite permissible
1480     that errors due to erroneus syntax isn't found until we come here.
1481     If the user has used a non-existing field in the table is one such example
1482     of an error that is not discovered until here.
1483 */
1484 
fix_partition_func(THD * thd,TABLE * table,bool is_create_table_ind)1485 bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) {
1486   bool result = true;
1487   partition_info *part_info = table->part_info;
1488   enum_mark_columns save_mark_used_columns = thd->mark_used_columns;
1489   Partition_handler *part_handler;
1490   const ulong save_want_privilege = thd->want_privilege;
1491   DBUG_TRACE;
1492 
1493   if (part_info->fixed) {
1494     return false;
1495   }
1496   thd->mark_used_columns = MARK_COLUMNS_NONE;
1497   thd->want_privilege = 0;
1498 
1499   if (!is_create_table_ind || thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
1500     if (partition_default_handling(table, part_info, is_create_table_ind,
1501                                    table->s->normalized_path.str)) {
1502       return true;
1503     }
1504   }
1505   if (part_info->is_sub_partitioned()) {
1506     DBUG_ASSERT(part_info->subpart_type == partition_type::HASH);
1507     /*
1508       Subpartition is defined. We need to verify that subpartitioning
1509       function is correct.
1510     */
1511     if (part_info->linear_hash_ind)
1512       set_linear_hash_mask(part_info, part_info->num_subparts);
1513     if (part_info->list_of_subpart_fields) {
1514       List_iterator<char> it(part_info->subpart_field_list);
1515       if (unlikely(handle_list_of_fields(it, table, part_info, true))) goto end;
1516     } else {
1517       if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr, table,
1518                                         true, is_create_table_ind)))
1519         goto end;
1520       if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) {
1521         part_info->report_part_expr_error(true);
1522         goto end;
1523       }
1524     }
1525   }
1526   DBUG_ASSERT(part_info->part_type != partition_type::NONE);
1527   /*
1528     Partition is defined. We need to verify that partitioning
1529     function is correct.
1530   */
1531   if (part_info->part_type == partition_type::HASH) {
1532     if (part_info->linear_hash_ind)
1533       set_linear_hash_mask(part_info, part_info->num_parts);
1534     if (part_info->list_of_part_fields) {
1535       List_iterator<char> it(part_info->part_field_list);
1536       if (unlikely(handle_list_of_fields(it, table, part_info, false)))
1537         goto end;
1538     } else {
1539       if (unlikely(fix_fields_part_func(thd, part_info->part_expr, table, false,
1540                                         is_create_table_ind)))
1541         goto end;
1542       if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) {
1543         part_info->report_part_expr_error(false);
1544         goto end;
1545       }
1546     }
1547     part_info->fixed = true;
1548   } else {
1549     const char *error_str;
1550     if (part_info->column_list) {
1551       List_iterator<char> it(part_info->part_field_list);
1552       if (unlikely(handle_list_of_fields(it, table, part_info, false)))
1553         goto end;
1554     } else {
1555       if (unlikely(fix_fields_part_func(thd, part_info->part_expr, table, false,
1556                                         is_create_table_ind)))
1557         goto end;
1558     }
1559     part_info->fixed = true;
1560     if (part_info->part_type == partition_type::RANGE) {
1561       error_str = partition_keywords[PKW_RANGE].str;
1562       if (unlikely(part_info->check_range_constants(thd))) goto end;
1563     } else if (part_info->part_type == partition_type::LIST) {
1564       error_str = partition_keywords[PKW_LIST].str;
1565       if (unlikely(part_info->check_list_constants(thd))) goto end;
1566     } else {
1567       DBUG_ASSERT(0);
1568       my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
1569       goto end;
1570     }
1571     if (unlikely(part_info->num_parts < 1)) {
1572       my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
1573       goto end;
1574     }
1575     if (unlikely(!part_info->column_list &&
1576                  part_info->part_expr->result_type() != INT_RESULT)) {
1577       part_info->report_part_expr_error(false);
1578       goto end;
1579     }
1580   }
1581   if (((part_info->part_type != partition_type::HASH ||
1582         part_info->list_of_part_fields == false) &&
1583        !part_info->column_list &&
1584        check_part_func_fields(part_info->part_field_array, true)) ||
1585       (part_info->list_of_subpart_fields == false &&
1586        part_info->is_sub_partitioned() &&
1587        check_part_func_fields(part_info->subpart_field_array, true))) {
1588     /*
1589       Range/List/HASH (but not KEY) and not COLUMNS or HASH subpartitioning
1590       with columns in the partitioning expression using unallowed charset.
1591     */
1592     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1593     goto end;
1594   }
1595   if (unlikely(create_full_part_field_array(thd, table, part_info))) goto end;
1596   if (unlikely(check_primary_key(table))) goto end;
1597   if (unlikely((!(table->s->db_type()->partition_flags &&
1598                   (table->s->db_type()->partition_flags() &
1599                    HA_CAN_PARTITION_UNIQUE))) &&
1600                check_unique_keys(table)))
1601     goto end;
1602   if (unlikely(set_up_partition_bitmaps(part_info))) goto end;
1603   if (unlikely(part_info->set_up_charset_field_preps())) {
1604     my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1605     goto end;
1606   }
1607   if (unlikely(part_info->check_partition_field_length())) {
1608     my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
1609     goto end;
1610   }
1611   check_range_capable_PF(table);
1612   set_up_partition_key_maps(table, part_info);
1613   set_up_partition_func_pointers(part_info);
1614   set_up_range_analysis_info(part_info);
1615   part_handler = table->file->get_partition_handler();
1616   if (part_handler) {
1617     part_handler->set_part_info(part_info, false);
1618     result = false;
1619   } else {
1620     DBUG_ASSERT(0);
1621     my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
1622   }
1623 end:
1624   thd->mark_used_columns = save_mark_used_columns;
1625   thd->want_privilege = save_want_privilege;
1626   DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
1627   return result;
1628 }
1629 
1630 // TODO: Change this to use streams instead, to make it possible to skip
1631 //       temporary files etc. and write directly to a string if wanted.
1632 /*
1633   The code below is support routines for the reverse parsing of the
1634   partitioning syntax. This feature is very useful to generate syntax for
1635   all default values to avoid all default checking when opening the frm
1636   file. It is also used when altering the partitioning by use of various
1637   ALTER TABLE commands. Finally it is used for SHOW CREATE TABLES.
1638 */
1639 
add_write(File fptr,const char * buf,size_t len)1640 static int add_write(File fptr, const char *buf, size_t len) {
1641   size_t ret_code =
1642       mysql_file_write(fptr, (const uchar *)buf, len, MYF(MY_FNABP));
1643 
1644   if (likely(ret_code == 0))
1645     return 0;
1646   else
1647     return 1;
1648 }
1649 
add_string_object(File fptr,String * string)1650 static int add_string_object(File fptr, String *string) {
1651   return add_write(fptr, string->ptr(), string->length());
1652 }
1653 
add_string(File fptr,const char * string)1654 static int add_string(File fptr, const char *string) {
1655   return add_write(fptr, string, strlen(string));
1656 }
1657 
add_string_len(File fptr,const char * string,size_t len)1658 static int add_string_len(File fptr, const char *string, size_t len) {
1659   return add_write(fptr, string, len);
1660 }
1661 
add_space(File fptr)1662 static int add_space(File fptr) { return add_string(fptr, space_str); }
1663 
add_comma(File fptr)1664 static int add_comma(File fptr) { return add_string(fptr, comma_str); }
1665 
add_equal(File fptr)1666 static int add_equal(File fptr) { return add_string(fptr, equal_str); }
1667 
add_end_parenthesis(File fptr)1668 static int add_end_parenthesis(File fptr) {
1669   return add_string(fptr, end_paren_str);
1670 }
1671 
add_begin_parenthesis(File fptr)1672 static int add_begin_parenthesis(File fptr) {
1673   return add_string(fptr, begin_paren_str);
1674 }
1675 
add_part_key_word(File fptr,const char * key_string)1676 static int add_part_key_word(File fptr, const char *key_string) {
1677   int err = add_string(fptr, key_string);
1678   err += add_space(fptr);
1679   return err;
1680 }
1681 
add_partition(File fptr)1682 static int add_partition(File fptr) {
1683   char buff[22];
1684   strxmov(buff, part_str, space_str, NullS);
1685   return add_string(fptr, buff);
1686 }
1687 
add_subpartition(File fptr)1688 static int add_subpartition(File fptr) {
1689   int err = add_string(fptr, sub_str);
1690 
1691   return err + add_partition(fptr);
1692 }
1693 
add_partition_by(File fptr)1694 static int add_partition_by(File fptr) {
1695   char buff[22];
1696   strxmov(buff, part_str, space_str, by_str, space_str, NullS);
1697   return add_string(fptr, buff);
1698 }
1699 
add_subpartition_by(File fptr)1700 static int add_subpartition_by(File fptr) {
1701   int err = add_string(fptr, sub_str);
1702 
1703   return err + add_partition_by(fptr);
1704 }
1705 
1706 /**
1707   Append field list to string.
1708 
1709   Used by KEY and COLUMNS partitioning.
1710 
1711   @param[in]     thd        Thread handle.
1712   @param[in,out] str        String to append.
1713   @param[in]     field_list List of field names to append.
1714 
1715   @return false if success, else true.
1716 */
1717 
append_field_list(THD * thd,String * str,List<char> field_list)1718 static bool append_field_list(THD *thd, String *str, List<char> field_list) {
1719   uint i, num_fields;
1720 
1721   List_iterator<char> part_it(field_list);
1722   num_fields = field_list.elements;
1723   i = 0;
1724   ulonglong save_options = thd->variables.option_bits;
1725   thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
1726   while (i < num_fields) {
1727     const char *field_str = part_it++;
1728     append_identifier(thd, str, field_str, strlen(field_str));
1729     if (i != (num_fields - 1)) {
1730       if (str->append(',')) {
1731         thd->variables.option_bits = save_options;
1732         return true;
1733       }
1734     }
1735     i++;
1736   }
1737   thd->variables.option_bits = save_options;
1738   return false;
1739 }
1740 
add_part_field_list(File fptr,List<char> field_list)1741 static int add_part_field_list(File fptr, List<char> field_list) {
1742   int err = 0;
1743   THD *thd = current_thd;
1744   String str("", 0, system_charset_info);
1745 
1746   err += add_begin_parenthesis(fptr);
1747   if (append_field_list(thd, &str, field_list)) {
1748     err++;
1749   }
1750   err += add_string_object(fptr, &str);
1751   err += add_end_parenthesis(fptr);
1752   return err;
1753 }
1754 
add_ident_string(File fptr,const char * name)1755 static int add_ident_string(File fptr, const char *name) {
1756   String name_string("", 0, system_charset_info);
1757   append_identifier(current_thd, &name_string, name, strlen(name));
1758   return add_string_object(fptr, &name_string);
1759 }
1760 
add_name_string(File fptr,const char * name)1761 static int add_name_string(File fptr, const char *name) {
1762   int err;
1763   THD *thd = current_thd;
1764   ulonglong save_options = thd->variables.option_bits;
1765   thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
1766   err = add_ident_string(fptr, name);
1767   thd->variables.option_bits = save_options;
1768   return err;
1769 }
1770 
add_int(File fptr,longlong number)1771 static int add_int(File fptr, longlong number) {
1772   char buff[32];
1773   llstr(number, buff);
1774   return add_string(fptr, buff);
1775 }
1776 
add_uint(File fptr,ulonglong number)1777 static int add_uint(File fptr, ulonglong number) {
1778   char buff[32];
1779   ullstr(number, buff);
1780   return add_string(fptr, buff);
1781 }
1782 
1783 /*
1784    Must escape strings in partitioned tables frm-files,
1785    parsing it later with mysql_unpack_partition will fail otherwise.
1786 */
add_quoted_string(File fptr,const char * quotestr)1787 static int add_quoted_string(File fptr, const char *quotestr) {
1788   String orgstr(quotestr, system_charset_info);
1789   String escapedstr;
1790   int err = add_string(fptr, "'");
1791   err += append_escaped(&escapedstr, &orgstr);
1792   err += add_string(fptr, escapedstr.c_ptr_safe());
1793   return err + add_string(fptr, "'");
1794 }
1795 
1796 /** Truncate the partition file name from a path if it exists.
1797 
1798 A partition file name will contain one or more '#' characters.
1799 One of the occurrences of '#' will be either "#P#" or "#p#" depending
1800 on whether the storage engine has converted the filename to lower case.
1801 If we need to truncate the name, we will allocate a new string and replace
1802 with, in case the original string was owned by something else.
1803 
1804   @param[in]      root   MEM_ROOT to allocate from. If NULL alter the string
1805                          directly.
1806   @param[in,out]  path   Pointer to string to check and truncate.
1807 */
truncate_partition_filename(MEM_ROOT * root,const char ** path)1808 void truncate_partition_filename(MEM_ROOT *root, const char **path) {
1809   if (*path) {
1810     const char *last_slash = strrchr(*path, FN_LIBCHAR);
1811 
1812 #ifdef _WIN32
1813     if (!last_slash) last_slash = strrchr(*path, FN_LIBCHAR2);
1814 #endif
1815 
1816     if (last_slash) {
1817       /* Look for a partition-type filename */
1818       for (const char *pound = strchr(last_slash, '#'); pound;
1819            pound = strchr(pound + 1, '#')) {
1820         if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#') {
1821           if (root == nullptr) {
1822             char *p = const_cast<char *>(last_slash);
1823             *p = '\0';
1824           } else {
1825             *path = strmake_root(root, *path, last_slash - *path);
1826           }
1827           break;
1828         }
1829       }
1830     }
1831   }
1832 }
1833 
1834 /**
1835   @brief  Output a filepath.  Similar to add_keyword_string except it
1836 also converts \ to / on Windows and skips the partition file name at
1837 the end if found.
1838 
1839   @note  When Mysql sends a DATA DIRECTORY from SQL for partitions it does
1840 not use a file name, but it does for DATA DIRECTORY on a non-partitioned
1841 table.  So when the storage engine is asked for the DATA DIRECTORY string
1842 after a restart through Handler::update_create_options(), the storage
1843 engine may include the filename.
1844 */
add_keyword_path(File fptr,const char * keyword,const char * path)1845 static int add_keyword_path(File fptr, const char *keyword, const char *path) {
1846   if (strlen(path) >= FN_REFLEN) {
1847     my_error(ER_PATH_LENGTH, MYF(0), keyword);
1848     return 1;
1849   }
1850 
1851   int err = add_string(fptr, keyword);
1852 
1853   err += add_space(fptr);
1854   err += add_equal(fptr);
1855   err += add_space(fptr);
1856 
1857   char temp_path[FN_REFLEN];
1858   const char *temp_path_p[1];
1859   temp_path_p[0] = temp_path;
1860   strncpy(temp_path, path, FN_REFLEN - 1);
1861   temp_path[FN_REFLEN - 1] = '\0';
1862 #ifdef _WIN32
1863   /* Convert \ to / to be able to create table on unix */
1864   char *pos, *end;
1865   size_t length = strlen(temp_path);
1866   for (pos = temp_path, end = pos + length; pos < end; pos++) {
1867     if (*pos == '\\') *pos = '/';
1868   }
1869 #endif
1870 
1871   /*
1872   If the partition file name with its "#P#" identifier
1873   is found after the last slash, truncate that filename.
1874   */
1875   truncate_partition_filename(nullptr, temp_path_p);
1876 
1877   err += add_quoted_string(fptr, temp_path);
1878 
1879   return err + add_space(fptr);
1880 }
1881 
add_keyword_string(File fptr,const char * keyword,bool should_use_quotes,const char * keystr)1882 static int add_keyword_string(File fptr, const char *keyword,
1883                               bool should_use_quotes, const char *keystr) {
1884   int err = add_string(fptr, keyword);
1885 
1886   err += add_space(fptr);
1887   err += add_equal(fptr);
1888   err += add_space(fptr);
1889   if (should_use_quotes)
1890     err += add_quoted_string(fptr, keystr);
1891   else
1892     err += add_string(fptr, keystr);
1893   return err + add_space(fptr);
1894 }
1895 
add_keyword_int(File fptr,const char * keyword,longlong num)1896 static int add_keyword_int(File fptr, const char *keyword, longlong num) {
1897   int err = add_string(fptr, keyword);
1898 
1899   err += add_space(fptr);
1900   err += add_equal(fptr);
1901   err += add_space(fptr);
1902   err += add_int(fptr, num);
1903   return err + add_space(fptr);
1904 }
1905 
add_engine(File fptr,handlerton * engine_type)1906 static int add_engine(File fptr, handlerton *engine_type) {
1907   const char *engine_str = ha_resolve_storage_engine_name(engine_type);
1908   DBUG_ASSERT(engine_type != nullptr);
1909   DBUG_PRINT("info", ("ENGINE: %s", engine_str));
1910   int err = add_string(fptr, "ENGINE = ");
1911   return err + add_string(fptr, engine_str);
1912 }
1913 
add_partition_options(File fptr,partition_element * p_elem)1914 static int add_partition_options(File fptr, partition_element *p_elem) {
1915   int err = 0;
1916 
1917   err += add_space(fptr);
1918   if (p_elem->tablespace_name) {
1919     err += add_string(fptr, "TABLESPACE = ");
1920     err += add_ident_string(fptr, p_elem->tablespace_name);
1921     err += add_space(fptr);
1922   }
1923   if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
1924     err += add_keyword_int(fptr, "NODEGROUP", (longlong)p_elem->nodegroup_id);
1925   if (p_elem->part_max_rows)
1926     err += add_keyword_int(fptr, "MAX_ROWS", (longlong)p_elem->part_max_rows);
1927   if (p_elem->part_min_rows)
1928     err += add_keyword_int(fptr, "MIN_ROWS", (longlong)p_elem->part_min_rows);
1929   if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) {
1930     if (p_elem->data_file_name)
1931       err += add_keyword_path(fptr, "DATA DIRECTORY", p_elem->data_file_name);
1932     if (p_elem->index_file_name)
1933       err += add_keyword_path(fptr, "INDEX DIRECTORY", p_elem->index_file_name);
1934   }
1935   if (p_elem->part_comment)
1936     err += add_keyword_string(fptr, "COMMENT", true, p_elem->part_comment);
1937   return err + add_engine(fptr, p_elem->engine_type);
1938 }
1939 
1940 /*
1941   Check partition fields for result type and if they need
1942   to check the character set.
1943 
1944   SYNOPSIS
1945     check_part_field()
1946     sql_type              Type provided by user
1947     field_name            Name of field, used for error handling
1948     result_type           Out value: Result type of field
1949     need_cs_check         Out value: Do we need character set check
1950 
1951   RETURN VALUES
1952     true                  Error
1953     false                 Ok
1954 */
1955 
check_part_field(enum_field_types sql_type,const char * field_name,Item_result * result_type,bool * need_cs_check)1956 static int check_part_field(enum_field_types sql_type, const char *field_name,
1957                             Item_result *result_type, bool *need_cs_check) {
1958   if (sql_type >= MYSQL_TYPE_TINY_BLOB && sql_type <= MYSQL_TYPE_BLOB) {
1959     my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
1960     return true;
1961   }
1962   switch (sql_type) {
1963     case MYSQL_TYPE_TINY:
1964     case MYSQL_TYPE_SHORT:
1965     case MYSQL_TYPE_LONG:
1966     case MYSQL_TYPE_LONGLONG:
1967     case MYSQL_TYPE_INT24:
1968       *result_type = INT_RESULT;
1969       *need_cs_check = false;
1970       return false;
1971     case MYSQL_TYPE_NEWDATE:
1972     case MYSQL_TYPE_DATE:
1973     case MYSQL_TYPE_TIME:
1974     case MYSQL_TYPE_DATETIME:
1975     case MYSQL_TYPE_TIME2:
1976     case MYSQL_TYPE_DATETIME2:
1977       *result_type = STRING_RESULT;
1978       *need_cs_check = true;
1979       return false;
1980     case MYSQL_TYPE_VARCHAR:
1981     case MYSQL_TYPE_STRING:
1982     case MYSQL_TYPE_VAR_STRING:
1983       *result_type = STRING_RESULT;
1984       *need_cs_check = true;
1985       return false;
1986     case MYSQL_TYPE_NEWDECIMAL:
1987     case MYSQL_TYPE_DECIMAL:
1988     case MYSQL_TYPE_TIMESTAMP:
1989     case MYSQL_TYPE_TIMESTAMP2:
1990     case MYSQL_TYPE_NULL:
1991     case MYSQL_TYPE_FLOAT:
1992     case MYSQL_TYPE_DOUBLE:
1993     case MYSQL_TYPE_BIT:
1994     case MYSQL_TYPE_ENUM:
1995     case MYSQL_TYPE_SET:
1996     case MYSQL_TYPE_GEOMETRY:
1997       goto error;
1998     default:
1999       goto error;
2000   }
2001 error:
2002   my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), field_name);
2003   return true;
2004 }
2005 
2006 /*
2007   Find the given field's Create_field object using name of field
2008 
2009   SYNOPSIS
2010     get_sql_field()
2011     field_name                   Field name
2012     create_fields                Info from ALTER TABLE/CREATE TABLE
2013 
2014   RETURN VALUE
2015     sql_field                    Object filled in by parser about field
2016     NULL                         No field found
2017 */
2018 
get_sql_field(const char * field_name,List<Create_field> * create_fields)2019 static Create_field *get_sql_field(const char *field_name,
2020                                    List<Create_field> *create_fields) {
2021   List_iterator<Create_field> it(*create_fields);
2022   Create_field *sql_field;
2023   DBUG_TRACE;
2024 
2025   while ((sql_field = it++)) {
2026     if (!(my_strcasecmp(system_charset_info, sql_field->field_name,
2027                         field_name))) {
2028       return sql_field;
2029     }
2030   }
2031   return nullptr;
2032 }
2033 
expr_to_string(String * val_conv,Item * item_expr,Field * field,const char * field_name,const HA_CREATE_INFO * create_info,List<Create_field> * create_fields)2034 int expr_to_string(String *val_conv, Item *item_expr, Field *field,
2035                    const char *field_name, const HA_CREATE_INFO *create_info,
2036                    List<Create_field> *create_fields) {
2037   char buffer[MAX_KEY_LENGTH];
2038   String str(buffer, sizeof(buffer), &my_charset_bin);
2039   String *res;
2040   const CHARSET_INFO *field_cs;
2041   bool need_cs_check = false;
2042   Item_result result_type = STRING_RESULT;
2043 
2044   /*
2045     This function is called at a very early stage, even before
2046     we have prepared the sql_field objects. Thus we have to
2047     find the proper sql_field object and get the character set
2048     from that object.
2049   */
2050   if (create_info) {
2051     Create_field *sql_field;
2052 
2053     if (!(sql_field = get_sql_field(field_name, create_fields))) {
2054       my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
2055       return 1;
2056     }
2057     if (check_part_field(sql_field->sql_type, sql_field->field_name,
2058                          &result_type, &need_cs_check))
2059       return 1;
2060     if (need_cs_check)
2061       field_cs = get_sql_field_charset(sql_field, create_info);
2062     else
2063       field_cs = nullptr;
2064   } else {
2065     result_type = field->result_type();
2066     if (check_part_field(field->real_type(), field->field_name, &result_type,
2067                          &need_cs_check))
2068       return 1;
2069     DBUG_ASSERT(result_type == field->result_type());
2070     if (need_cs_check)
2071       field_cs = field->charset();
2072     else
2073       field_cs = nullptr;
2074   }
2075   if (result_type != item_expr->result_type()) {
2076     my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
2077     return 1;
2078   }
2079   if (field_cs && field_cs != item_expr->collation.collation) {
2080     if (!(item_expr =
2081               convert_charset_partition_constant(item_expr, field_cs))) {
2082       my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2083       return 1;
2084     }
2085   }
2086   val_conv->set_charset(system_charset_info);
2087   res = item_expr->val_str(&str);
2088   if (get_cs_converted_part_value_from_string(current_thd, item_expr, res,
2089                                               val_conv, field_cs, false)) {
2090     return 1;
2091   }
2092   return 0;
2093 }
2094 
add_column_list_values(File fptr,partition_info * part_info,part_elem_value * list_value)2095 static int add_column_list_values(File fptr, partition_info *part_info,
2096                                   part_elem_value *list_value) {
2097   int err = 0;
2098   uint i;
2099   uint num_elements = part_info->part_field_list.elements;
2100   bool use_parenthesis = (part_info->part_type == partition_type::LIST &&
2101                           part_info->num_columns > 1U);
2102 
2103   if (use_parenthesis) err += add_begin_parenthesis(fptr);
2104   for (i = 0; i < num_elements; i++) {
2105     part_column_list_val *col_val = &list_value->col_val_array[i];
2106     if (col_val->max_value)
2107       err += add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
2108     else if (col_val->null_value)
2109       err += add_string(fptr, "NULL");
2110     else {
2111       char buffer[MAX_KEY_LENGTH];
2112       String str(buffer, sizeof(buffer), &my_charset_bin);
2113       Item *item_expr = col_val->item_expression;
2114       if (!item_expr) {
2115         /*
2116           The values are not from the parser, but from the
2117           dd::Partition_values table. See fill_partitioning_from_dd().
2118         */
2119         DBUG_ASSERT(col_val->column_value.value_str);
2120         err += add_string(fptr, col_val->column_value.value_str);
2121       } else if (item_expr->null_value) {
2122         err += add_string(fptr, "NULL");
2123       } else {
2124         String val_conv;
2125         err +=
2126             expr_to_string(&val_conv, item_expr, part_info->part_field_array[i],
2127                            nullptr, nullptr, nullptr);
2128         err += add_string_object(fptr, &val_conv);
2129       }
2130     }
2131     if (i != (num_elements - 1)) err += add_string(fptr, comma_str);
2132   }
2133   if (use_parenthesis) err += add_end_parenthesis(fptr);
2134   return err;
2135 }
2136 
add_partition_values(File fptr,partition_info * part_info,partition_element * p_elem)2137 static int add_partition_values(File fptr, partition_info *part_info,
2138                                 partition_element *p_elem) {
2139   int err = 0;
2140 
2141   if (part_info->part_type == partition_type::RANGE) {
2142     err += add_string(fptr, " VALUES LESS THAN ");
2143     if (part_info->column_list) {
2144       List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2145       part_elem_value *list_value = list_val_it++;
2146       err += add_begin_parenthesis(fptr);
2147       err += add_column_list_values(fptr, part_info, list_value);
2148       err += add_end_parenthesis(fptr);
2149     } else {
2150       if (!p_elem->max_value) {
2151         err += add_begin_parenthesis(fptr);
2152         if (p_elem->signed_flag)
2153           err += add_int(fptr, p_elem->range_value);
2154         else
2155           err += add_uint(fptr, p_elem->range_value);
2156         err += add_end_parenthesis(fptr);
2157       } else
2158         err += add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
2159     }
2160   } else if (part_info->part_type == partition_type::LIST) {
2161     uint i;
2162     List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2163     err += add_string(fptr, " VALUES IN ");
2164     uint num_items = p_elem->list_val_list.elements;
2165 
2166     err += add_begin_parenthesis(fptr);
2167     if (p_elem->has_null_value) {
2168       err += add_string(fptr, "NULL");
2169       if (num_items == 0) {
2170         err += add_end_parenthesis(fptr);
2171         goto end;
2172       }
2173       err += add_comma(fptr);
2174     }
2175     i = 0;
2176     do {
2177       part_elem_value *list_value = list_val_it++;
2178 
2179       if (part_info->column_list)
2180         err += add_column_list_values(fptr, part_info, list_value);
2181       else {
2182         if (!list_value->unsigned_flag)
2183           err += add_int(fptr, list_value->value);
2184         else
2185           err += add_uint(fptr, list_value->value);
2186       }
2187       if (i != (num_items - 1)) err += add_comma(fptr);
2188     } while (++i < num_items);
2189     err += add_end_parenthesis(fptr);
2190   }
2191 end:
2192   return err;
2193 }
2194 
2195 /**
2196   Add 'KEY' word, with optional 'ALGORTIHM = N'.
2197 
2198   @param fptr                   File to write to.
2199   @param part_info              partition_info holding the used key_algorithm
2200   @param current_comment_start  NULL, or comment string encapsulating the
2201                                 PARTITION BY clause.
2202 
2203   @return Operation status.
2204     @retval 0    Success
2205     @retval != 0 Failure
2206 */
2207 
add_key_with_algorithm(File fptr,partition_info * part_info,const char * current_comment_start)2208 static int add_key_with_algorithm(File fptr, partition_info *part_info,
2209                                   const char *current_comment_start) {
2210   int err = 0;
2211   err += add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
2212 
2213   /*
2214     current_comment_start is given when called from SHOW CREATE TABLE,
2215     Then only add ALGORITHM = 1, not the default 2 or non-set 0!
2216     For .frm current_comment_start is NULL, then add ALGORITHM if != 0.
2217   */
2218   if (part_info->key_algorithm ==
2219           enum_key_algorithm::KEY_ALGORITHM_51 ||  // SHOW
2220       (!current_comment_start &&                   // .frm
2221        (part_info->key_algorithm != enum_key_algorithm::KEY_ALGORITHM_NONE))) {
2222     /* If we already are within a comment, end that comment first. */
2223     if (current_comment_start) err += add_string(fptr, "*/ ");
2224     err += add_string(fptr, "/*!50611 ");
2225     err += add_part_key_word(fptr, partition_keywords[PKW_ALGORITHM].str);
2226     err += add_equal(fptr);
2227     err += add_space(fptr);
2228     err += add_int(fptr, static_cast<longlong>(part_info->key_algorithm));
2229     err += add_space(fptr);
2230     err += add_string(fptr, "*/ ");
2231     if (current_comment_start) {
2232       /* Skip new line. */
2233       if (current_comment_start[0] == '\n') current_comment_start++;
2234       err += add_string(fptr, current_comment_start);
2235       err += add_space(fptr);
2236     }
2237   }
2238   return err;
2239 }
2240 
get_file_content(File fptr,uint * buf_length,bool use_sql_alloc)2241 static char *get_file_content(File fptr, uint *buf_length, bool use_sql_alloc) {
2242   my_off_t buffer_length;
2243   char *buf;
2244   buffer_length = mysql_file_seek(fptr, 0L, MY_SEEK_END, MYF(0));
2245   if (unlikely(buffer_length == MY_FILEPOS_ERROR)) return nullptr;
2246   if (unlikely(mysql_file_seek(fptr, 0L, MY_SEEK_SET, MYF(0)) ==
2247                MY_FILEPOS_ERROR))
2248     return nullptr;
2249   *buf_length = (uint)buffer_length;
2250   if (use_sql_alloc)
2251     buf = (char *)(*THR_MALLOC)->Alloc(*buf_length + 1);
2252   else
2253     buf = (char *)my_malloc(key_memory_partition_syntax_buffer, *buf_length + 1,
2254                             MYF(MY_WME));
2255   if (!buf) return nullptr;
2256 
2257   if (unlikely(
2258           mysql_file_read(fptr, (uchar *)buf, *buf_length, MYF(MY_FNABP)))) {
2259     if (!use_sql_alloc) my_free(buf);
2260     buf = nullptr;
2261   } else
2262     buf[*buf_length] = 0;
2263   return buf;
2264 }
2265 
2266 /**
2267   Generate the partition syntax from the partition data structure.
2268   Useful for support of generating defaults, SHOW CREATE TABLES
2269   and easy partition management.
2270 
2271   @param  part_info               The partitioning data structure
2272   @param  buf_length              A pointer to the returned buffer length
2273   @param  use_sql_alloc           Allocate buffer from sql_alloc if true
2274                                   otherwise use my_malloc
2275   @param  show_partition_options  Should we display partition options
2276   @param  print_expr              Indicates whether partitioning expressions
2277                                   should be re-printed to get quoting according
2278                                   to current sql_mode.
2279   @param  current_comment_start   NULL, or comment string encapsulating the
2280                                   PARTITION BY clause.
2281 
2282   @retval NULL - error
2283 
2284   @note
2285   Here we will generate the full syntax for the given command where all
2286   defaults have been expanded. By so doing the it is also possible to
2287   make lots of checks of correctness while at it.
2288   This could will also be reused for SHOW CREATE TABLES and also for all
2289   type ALTER TABLE commands focusing on changing the PARTITION structure
2290   in any fashion.
2291 
2292   The implementation writes the syntax to a temporary file (essentially
2293   an abstraction of a dynamic array) and if all writes goes well it
2294   allocates a buffer and writes the syntax into this one and returns it.
2295 
2296   As a security precaution the file is deleted before writing into it. This
2297   means that no other processes on the machine can open and read the file
2298   while this processing is ongoing.
2299 
2300   The code is optimised for minimal code size since it is not used in any
2301   common queries.
2302 */
2303 
generate_partition_syntax(partition_info * part_info,uint * buf_length,bool use_sql_alloc,bool show_partition_options,bool print_expr,const char * current_comment_start)2304 char *generate_partition_syntax(partition_info *part_info, uint *buf_length,
2305                                 bool use_sql_alloc, bool show_partition_options,
2306                                 bool print_expr,
2307                                 const char *current_comment_start) {
2308   uint i, j, tot_num_parts, num_subparts;
2309   partition_element *part_elem;
2310   int err = 0;
2311   List_iterator<partition_element> part_it(part_info->partitions);
2312   File fptr;
2313   char *buf = nullptr;  // Return buffer
2314   DBUG_TRACE;
2315 
2316   if (!(fptr = mysql_tmpfile("psy"))) {
2317     return nullptr;
2318   }
2319   err += add_space(fptr);
2320   err += add_partition_by(fptr);
2321   switch (part_info->part_type) {
2322     case partition_type::RANGE:
2323       err += add_part_key_word(fptr, partition_keywords[PKW_RANGE].str);
2324       break;
2325     case partition_type::LIST:
2326       err += add_part_key_word(fptr, partition_keywords[PKW_LIST].str);
2327       break;
2328     case partition_type::HASH:
2329       if (part_info->linear_hash_ind)
2330         err += add_string(fptr, partition_keywords[PKW_LINEAR].str);
2331       if (part_info->list_of_part_fields) {
2332         err += add_key_with_algorithm(fptr, part_info, current_comment_start);
2333         err += add_part_field_list(fptr, part_info->part_field_list);
2334       } else
2335         err += add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
2336       break;
2337     default:
2338       DBUG_ASSERT(0);
2339       /* We really shouldn't get here, no use in continuing from here */
2340       my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
2341       return nullptr;
2342   }
2343   if (part_info->part_func_len) {
2344     err += add_begin_parenthesis(fptr);
2345     if (print_expr) {
2346       // Default on-stack buffer which allows to avoid malloc() in most cases.
2347       char expr_buff[256];
2348       String tmp(expr_buff, sizeof(expr_buff), system_charset_info);
2349       tmp.length(0);
2350 
2351       // No point in including schema and table name for identifiers
2352       // since any columns must be in this table.
2353       part_info->part_expr->print(
2354           current_thd, &tmp,
2355           enum_query_type(QT_TO_SYSTEM_CHARSET | QT_NO_DB | QT_NO_TABLE));
2356       err += add_string_len(fptr, tmp.ptr(), tmp.length());
2357     } else {
2358       err += add_string_len(fptr, part_info->part_func_string,
2359                             part_info->part_func_len);
2360     }
2361     err += add_end_parenthesis(fptr);
2362   } else if (part_info->column_list) {
2363     err += add_string(fptr, partition_keywords[PKW_COLUMNS].str);
2364     err += add_part_field_list(fptr, part_info->part_field_list);
2365   }
2366   if ((!part_info->use_default_num_partitions) &&
2367       part_info->use_default_partitions) {
2368     err += add_string(fptr, "\n");
2369     err += add_string(fptr, "PARTITIONS ");
2370     err += add_int(fptr, part_info->num_parts);
2371   }
2372   if (part_info->is_sub_partitioned()) {
2373     err += add_string(fptr, "\n");
2374     err += add_subpartition_by(fptr);
2375     /* Must be hash partitioning for subpartitioning */
2376     if (part_info->linear_hash_ind)
2377       err += add_string(fptr, partition_keywords[PKW_LINEAR].str);
2378     if (part_info->list_of_subpart_fields) {
2379       err += add_key_with_algorithm(fptr, part_info, current_comment_start);
2380       err += add_part_field_list(fptr, part_info->subpart_field_list);
2381     } else
2382       err += add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
2383     if (part_info->subpart_func_len) {
2384       err += add_begin_parenthesis(fptr);
2385       if (print_expr) {
2386         // Default on-stack buffer which allows to avoid malloc() in most cases.
2387         char expr_buff[256];
2388         String tmp(expr_buff, sizeof(expr_buff), system_charset_info);
2389         tmp.length(0);
2390 
2391         // No point in including schema and table name for identifiers
2392         // since any columns must be in this table.
2393         part_info->subpart_expr->print(
2394             current_thd, &tmp,
2395             enum_query_type(QT_TO_SYSTEM_CHARSET | QT_NO_DB | QT_NO_TABLE));
2396         err += add_string_len(fptr, tmp.ptr(), tmp.length());
2397       } else {
2398         err += add_string_len(fptr, part_info->subpart_func_string,
2399                               part_info->subpart_func_len);
2400       }
2401       err += add_end_parenthesis(fptr);
2402     }
2403     if ((!part_info->use_default_num_subpartitions) &&
2404         part_info->use_default_subpartitions) {
2405       err += add_string(fptr, "\n");
2406       err += add_string(fptr, "SUBPARTITIONS ");
2407       err += add_int(fptr, part_info->num_subparts);
2408     }
2409   }
2410   tot_num_parts = part_info->partitions.elements;
2411   num_subparts = part_info->num_subparts;
2412 
2413   if (!part_info->use_default_partitions) {
2414     bool first = true;
2415     err += add_string(fptr, "\n");
2416     err += add_begin_parenthesis(fptr);
2417     i = 0;
2418     do {
2419       part_elem = part_it++;
2420       if (part_elem->part_state != PART_TO_BE_DROPPED &&
2421           part_elem->part_state != PART_REORGED_DROPPED) {
2422         if (!first) {
2423           err += add_comma(fptr);
2424           err += add_string(fptr, "\n");
2425           err += add_space(fptr);
2426         }
2427         first = false;
2428         err += add_partition(fptr);
2429         err += add_name_string(fptr, part_elem->partition_name);
2430         err += add_partition_values(fptr, part_info, part_elem);
2431         if (!part_info->is_sub_partitioned() ||
2432             part_info->use_default_subpartitions) {
2433           if (show_partition_options)
2434             err += add_partition_options(fptr, part_elem);
2435         } else {
2436           err += add_string(fptr, "\n");
2437           err += add_space(fptr);
2438           err += add_begin_parenthesis(fptr);
2439           List_iterator<partition_element> sub_it(part_elem->subpartitions);
2440           partition_element *sub_elem;
2441           j = 0;
2442           do {
2443             sub_elem = sub_it++;
2444             err += add_subpartition(fptr);
2445             err += add_name_string(fptr, sub_elem->partition_name);
2446             if (show_partition_options)
2447               err += add_partition_options(fptr, sub_elem);
2448             if (j != (num_subparts - 1)) {
2449               err += add_comma(fptr);
2450               err += add_string(fptr, "\n");
2451               err += add_space(fptr);
2452               err += add_space(fptr);
2453             } else
2454               err += add_end_parenthesis(fptr);
2455           } while (++j < num_subparts);
2456         }
2457       }
2458       if (i == (tot_num_parts - 1)) err += add_end_parenthesis(fptr);
2459     } while (++i < tot_num_parts);
2460   }
2461   if (err) goto close_file;
2462   buf = get_file_content(fptr, buf_length, use_sql_alloc);
2463 close_file:
2464   if (buf == nullptr) {
2465     my_error(ER_INTERNAL_ERROR, MYF(0), "Failed to generate partition syntax");
2466   }
2467   mysql_file_close(fptr, MYF(0));
2468   return buf;
2469 }
2470 
2471 /*
2472   Check if partition key fields are modified and if it can be handled by the
2473   underlying storage engine.
2474 
2475   SYNOPSIS
2476     partition_key_modified
2477     table                TABLE object for which partition fields are set-up
2478     fields               Bitmap representing fields to be modified
2479 
2480   RETURN VALUES
2481     true                 Need special handling of UPDATE
2482     false                Normal UPDATE handling is ok
2483 */
2484 
partition_key_modified(TABLE * table,const MY_BITMAP * fields)2485 bool partition_key_modified(TABLE *table, const MY_BITMAP *fields) {
2486   Field **fld;
2487   partition_info *part_info = table->part_info;
2488   DBUG_TRACE;
2489 
2490   if (!part_info) return false;
2491   if (table->s->db_type()->partition_flags &&
2492       (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
2493     return false;
2494   for (fld = part_info->full_part_field_array; *fld; fld++)
2495     if (bitmap_is_set(fields, (*fld)->field_index())) return true;
2496   return false;
2497 }
2498 
2499 /*
2500   A function to handle correct handling of NULL values in partition
2501   functions.
2502   SYNOPSIS
2503     part_val_int()
2504     item_expr                 The item expression to evaluate
2505     out:result                The value of the partition function,
2506                                 LLONG_MIN if any null value in function
2507   RETURN VALUES
2508     true      Error in val_int()
2509     false     ok
2510 */
2511 
part_val_int(Item * item_expr,longlong * result)2512 static inline int part_val_int(Item *item_expr, longlong *result) {
2513   *result = item_expr->val_int();
2514   if (item_expr->null_value) {
2515     if (current_thd->is_error())
2516       return true;
2517     else
2518       *result = LLONG_MIN;
2519   }
2520   return false;
2521 }
2522 
2523 /*
2524   The next set of functions are used to calculate the partition identity.
2525   A handler sets up a variable that corresponds to one of these functions
2526   to be able to quickly call it whenever the partition id needs to calculated
2527   based on the record in table->record[0] (or set up to fake that).
2528   There are 4 functions for hash partitioning and 2 for RANGE/LIST partitions.
2529   In addition there are 4 variants for RANGE subpartitioning and 4 variants
2530   for LIST subpartitioning thus in total there are 14 variants of this
2531   function.
2532 
2533   We have a set of support functions for these 14 variants. There are 4
2534   variants of hash functions and there is a function for each. The KEY
2535   partitioning uses the function calculate_key_hash_value to calculate the hash
2536   value based on an array of fields. The linear hash variants uses the
2537   method get_part_id_from_linear_hash to get the partition id using the
2538   hash value and some parameters calculated from the number of partitions.
2539 */
2540 
2541 /*
2542   A simple support function to calculate part_id given local part and
2543   sub part.
2544 
2545   SYNOPSIS
2546     get_part_id_for_sub()
2547     loc_part_id             Local partition id
2548     sub_part_id             Subpartition id
2549     num_subparts            Number of subparts
2550 */
2551 
get_part_id_for_sub(uint32 loc_part_id,uint32 sub_part_id,uint num_subparts)2552 inline static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
2553                                          uint num_subparts) {
2554   return (uint32)((loc_part_id * num_subparts) + sub_part_id);
2555 }
2556 
2557 /*
2558   Calculate part_id for (SUB)PARTITION BY HASH
2559 
2560   SYNOPSIS
2561     get_part_id_hash()
2562     num_parts                Number of hash partitions
2563     part_expr                Item tree of hash function
2564     out:part_id              The returned partition id
2565     out:func_value           Value of hash function
2566 
2567   RETURN VALUE
2568     != 0                          Error code
2569     false                         Success
2570 */
2571 
get_part_id_hash(uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2572 static int get_part_id_hash(uint num_parts, Item *part_expr, uint32 *part_id,
2573                             longlong *func_value) {
2574   longlong int_hash_id;
2575   DBUG_TRACE;
2576 
2577   if (part_val_int(part_expr, func_value)) return HA_ERR_NO_PARTITION_FOUND;
2578 
2579   int_hash_id = *func_value % num_parts;
2580 
2581   *part_id = int_hash_id < 0 ? (uint32)-int_hash_id : (uint32)int_hash_id;
2582   return false;
2583 }
2584 
2585 /*
2586   Calculate part_id for (SUB)PARTITION BY LINEAR HASH
2587 
2588   SYNOPSIS
2589     get_part_id_linear_hash()
2590     part_info           A reference to the partition_info struct where all the
2591                         desired information is given
2592     num_parts           Number of hash partitions
2593     part_expr           Item tree of hash function
2594     out:part_id         The returned partition id
2595     out:func_value      Value of hash function
2596 
2597   RETURN VALUE
2598     != 0     Error code
2599     0        OK
2600 */
2601 
get_part_id_linear_hash(partition_info * part_info,uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2602 static int get_part_id_linear_hash(partition_info *part_info, uint num_parts,
2603                                    Item *part_expr, uint32 *part_id,
2604                                    longlong *func_value) {
2605   DBUG_TRACE;
2606 
2607   if (part_val_int(part_expr, func_value)) return HA_ERR_NO_PARTITION_FOUND;
2608 
2609   *part_id = get_part_id_from_linear_hash(
2610       *func_value, part_info->linear_hash_mask, num_parts);
2611   return false;
2612 }
2613 
2614 /**
2615   Calculate part_id for (SUB)PARTITION BY KEY
2616 
2617   @param file                Handler to storage engine
2618   @param field_array         Array of fields for PARTTION KEY
2619   @param num_parts           Number of KEY partitions
2620   @param [out] func_value    Returns calculated hash value
2621 
2622   @return Calculated partition id
2623 */
2624 
get_part_id_key(handler * file,Field ** field_array,uint num_parts,longlong * func_value)2625 inline static uint32 get_part_id_key(handler *file, Field **field_array,
2626                                      uint num_parts, longlong *func_value) {
2627   DBUG_TRACE;
2628   *func_value = file->calculate_key_hash_value(field_array);
2629   return (uint32)(*func_value % num_parts);
2630 }
2631 
2632 /*
2633   Calculate part_id for (SUB)PARTITION BY LINEAR KEY
2634 
2635   SYNOPSIS
2636     get_part_id_linear_key()
2637     part_info           A reference to the partition_info struct where all the
2638                         desired information is given
2639     field_array         Array of fields for PARTTION KEY
2640     num_parts            Number of KEY partitions
2641 
2642   RETURN VALUE
2643     Calculated partition id
2644 */
2645 
get_part_id_linear_key(partition_info * part_info,Field ** field_array,uint num_parts,longlong * func_value)2646 inline static uint32 get_part_id_linear_key(partition_info *part_info,
2647                                             Field **field_array, uint num_parts,
2648                                             longlong *func_value) {
2649   DBUG_TRACE;
2650 
2651   *func_value = part_info->table->file->calculate_key_hash_value(field_array);
2652   return get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask,
2653                                       num_parts);
2654 }
2655 
2656 /*
2657   Copy to field buffers and set up field pointers
2658 
2659   SYNOPSIS
2660     copy_to_part_field_buffers()
2661     ptr                          Array of fields to copy
2662     field_bufs                   Array of field buffers to copy to
2663     restore_ptr                  Array of pointers to restore to
2664 
2665   RETURN VALUES
2666     NONE
2667   DESCRIPTION
2668     This routine is used to take the data from field pointer, convert
2669     it to a standard format and store this format in a field buffer
2670     allocated for this purpose. Next the field pointers are moved to
2671     point to the field buffers. There is a separate to restore the
2672     field pointers after this call.
2673 */
2674 
copy_to_part_field_buffers(Field ** ptr,uchar ** field_bufs,uchar ** restore_ptr)2675 static void copy_to_part_field_buffers(Field **ptr, uchar **field_bufs,
2676                                        uchar **restore_ptr) {
2677   Field *field;
2678   while ((field = *(ptr++))) {
2679     *restore_ptr = field->field_ptr();
2680     restore_ptr++;
2681     if (!field->is_null()) {
2682       const CHARSET_INFO *cs = field->charset();
2683       uint max_len = field->pack_length();
2684       uint data_len = field->data_length();
2685       uchar *field_buf = *field_bufs;
2686       /*
2687          We only use the field buffer for VARCHAR and CHAR strings
2688          which isn't of a binary collation. We also only use the
2689          field buffer for fields which are not currently NULL.
2690          The field buffer will store a normalised string. We use
2691          the strnxfrm method to normalise the string.
2692        */
2693       if (field->type() == MYSQL_TYPE_VARCHAR) {
2694         uint len_bytes = field->get_length_bytes();
2695         my_strnxfrm(cs, field_buf + len_bytes, max_len, field->data_ptr(),
2696                     data_len);
2697         if (len_bytes == 1)
2698           *field_buf = (uchar)data_len;
2699         else
2700           int2store(field_buf, data_len);
2701       } else {
2702         my_strnxfrm(cs, field_buf, max_len, field->field_ptr(), max_len);
2703       }
2704       field->set_field_ptr(field_buf);
2705     }
2706     field_bufs++;
2707   }
2708   return;
2709 }
2710 
2711 /*
2712   Restore field pointers
2713   SYNOPSIS
2714     restore_part_field_pointers()
2715     ptr                            Array of fields to restore
2716     restore_ptr                    Array of field pointers to restore to
2717 
2718   RETURN VALUES
2719 */
2720 
restore_part_field_pointers(Field ** ptr,uchar ** restore_ptr)2721 static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) {
2722   Field *field;
2723   while ((field = *(ptr++))) {
2724     field->set_field_ptr(*restore_ptr);
2725     restore_ptr++;
2726   }
2727   return;
2728 }
2729 
2730 /*
2731   This function is used to calculate the partition id where all partition
2732   fields have been prepared to point to a record where the partition field
2733   values are bound.
2734 
2735   SYNOPSIS
2736     get_partition_id()
2737     part_info           A reference to the partition_info struct where all the
2738                         desired information is given
2739     out:part_id         The partition id is returned through this pointer
2740     out:func_value      Value of partition function (longlong)
2741 
2742   RETURN VALUE
2743     part_id                     Partition id of partition that would contain
2744                                 row with given values of PF-fields
2745     HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
2746                                 fit into any partition and thus the values of
2747                                 the PF-fields are not allowed.
2748 
2749   DESCRIPTION
2750     A routine used from write_row, update_row and delete_row from any
2751     handler supporting partitioning. It is also a support routine for
2752     get_partition_set used to find the set of partitions needed to scan
2753     for a certain index scan or full table scan.
2754 
2755     It is actually 9 different variants of this function which are called
2756     through a function pointer.
2757 
2758     get_partition_id_list
2759     get_partition_id_list_col
2760     get_partition_id_range
2761     get_partition_id_range_col
2762     get_partition_id_hash_nosub
2763     get_partition_id_key_nosub
2764     get_partition_id_linear_hash_nosub
2765     get_partition_id_linear_key_nosub
2766     get_partition_id_with_sub
2767 */
2768 
2769 /*
2770   This function is used to calculate the main partition to use in the case of
2771   subpartitioning and we don't know enough to get the partition identity in
2772   total.
2773 
2774   SYNOPSIS
2775     get_part_partition_id()
2776     part_info           A reference to the partition_info struct where all the
2777                         desired information is given
2778     out:part_id         The partition id is returned through this pointer
2779     out:func_value      The value calculated by partition function
2780 
2781   RETURN VALUE
2782     HA_ERR_NO_PARTITION_FOUND   The fields of the partition function didn't
2783                                 fit into any partition and thus the values of
2784                                 the PF-fields are not allowed.
2785     0                           OK
2786 
2787   DESCRIPTION
2788 
2789     It is actually 8 different variants of this function which are called
2790     through a function pointer.
2791 
2792     get_partition_id_list
2793     get_partition_id_list_col
2794     get_partition_id_range
2795     get_partition_id_range_col
2796     get_partition_id_hash_nosub
2797     get_partition_id_key_nosub
2798     get_partition_id_linear_hash_nosub
2799     get_partition_id_linear_key_nosub
2800 */
2801 
get_part_id_charset_func_part(partition_info * part_info,uint32 * part_id,longlong * func_value)2802 static int get_part_id_charset_func_part(partition_info *part_info,
2803                                          uint32 *part_id,
2804                                          longlong *func_value) {
2805   int res;
2806   DBUG_TRACE;
2807 
2808   copy_to_part_field_buffers(part_info->part_charset_field_array,
2809                              part_info->part_field_buffers,
2810                              part_info->restore_part_field_ptrs);
2811   res =
2812       part_info->get_part_partition_id_charset(part_info, part_id, func_value);
2813   restore_part_field_pointers(part_info->part_charset_field_array,
2814                               part_info->restore_part_field_ptrs);
2815   return res;
2816 }
2817 
get_part_id_charset_func_subpart(partition_info * part_info,uint32 * part_id)2818 static int get_part_id_charset_func_subpart(partition_info *part_info,
2819                                             uint32 *part_id) {
2820   int res;
2821   DBUG_TRACE;
2822 
2823   copy_to_part_field_buffers(part_info->subpart_charset_field_array,
2824                              part_info->subpart_field_buffers,
2825                              part_info->restore_subpart_field_ptrs);
2826   res = part_info->get_subpartition_id_charset(part_info, part_id);
2827   restore_part_field_pointers(part_info->subpart_charset_field_array,
2828                               part_info->restore_subpart_field_ptrs);
2829   return res;
2830 }
2831 
get_partition_id_list_col(partition_info * part_info,uint32 * part_id,longlong *)2832 static int get_partition_id_list_col(partition_info *part_info, uint32 *part_id,
2833                                      longlong *) {
2834   part_column_list_val *list_col_array = part_info->list_col_array;
2835   uint num_columns = part_info->part_field_list.elements;
2836   int list_index, cmp;
2837   int min_list_index = 0;
2838   int max_list_index = part_info->num_list_values - 1;
2839   DBUG_TRACE;
2840 
2841   while (max_list_index >= min_list_index) {
2842     list_index = (max_list_index + min_list_index) >> 1;
2843     cmp = cmp_rec_and_tuple(list_col_array + list_index * num_columns,
2844                             num_columns);
2845     if (cmp > 0)
2846       min_list_index = list_index + 1;
2847     else if (cmp < 0) {
2848       if (!list_index) goto notfound;
2849       max_list_index = list_index - 1;
2850     } else {
2851       *part_id = (uint32)list_col_array[list_index * num_columns].partition_id;
2852       return 0;
2853     }
2854   }
2855 notfound:
2856   *part_id = 0;
2857   return HA_ERR_NO_PARTITION_FOUND;
2858 }
2859 
get_partition_id_list(partition_info * part_info,uint32 * part_id,longlong * func_value)2860 static int get_partition_id_list(partition_info *part_info, uint32 *part_id,
2861                                  longlong *func_value) {
2862   LIST_PART_ENTRY *list_array = part_info->list_array;
2863   int list_index;
2864   int min_list_index = 0;
2865   int max_list_index = part_info->num_list_values - 1;
2866   longlong part_func_value;
2867   int error = part_val_int(part_info->part_expr, &part_func_value);
2868   longlong list_value;
2869   bool unsigned_flag = part_info->part_expr->unsigned_flag;
2870   DBUG_TRACE;
2871 
2872   if (error) goto notfound;
2873 
2874   if (part_info->part_expr->null_value) {
2875     if (part_info->has_null_value) {
2876       *part_id = part_info->has_null_part_id;
2877       return 0;
2878     }
2879     goto notfound;
2880   }
2881   *func_value = part_func_value;
2882   if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
2883   while (max_list_index >= min_list_index) {
2884     list_index = (max_list_index + min_list_index) >> 1;
2885     list_value = list_array[list_index].list_value;
2886     if (list_value < part_func_value)
2887       min_list_index = list_index + 1;
2888     else if (list_value > part_func_value) {
2889       if (!list_index) goto notfound;
2890       max_list_index = list_index - 1;
2891     } else {
2892       *part_id = (uint32)list_array[list_index].partition_id;
2893       return 0;
2894     }
2895   }
2896 notfound:
2897   *part_id = 0;
2898   return HA_ERR_NO_PARTITION_FOUND;
2899 }
2900 
get_partition_id_cols_list_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint,uint32 nparts)2901 static uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
2902                                                       bool left_endpoint,
2903                                                       bool include_endpoint,
2904                                                       uint32 nparts) {
2905   part_column_list_val *list_col_array = part_info->list_col_array;
2906   uint num_columns = part_info->part_field_list.elements;
2907   uint list_index;
2908   uint min_list_index = 0;
2909   int cmp;
2910   /* Notice that max_list_index = last_index + 1 here! */
2911   uint max_list_index = part_info->num_list_values;
2912   DBUG_TRACE;
2913 
2914   /* Find the matching partition (including taking endpoint into account). */
2915   do {
2916     /* Midpoint, adjusted down, so it can never be >= max_list_index. */
2917     list_index = (max_list_index + min_list_index) >> 1;
2918     cmp = cmp_rec_and_tuple_prune(list_col_array + list_index * num_columns,
2919                                   nparts, left_endpoint, include_endpoint);
2920     if (cmp > 0) {
2921       min_list_index = list_index + 1;
2922     } else {
2923       max_list_index = list_index;
2924       if (cmp == 0) break;
2925     }
2926   } while (max_list_index > min_list_index);
2927   list_index = max_list_index;
2928 
2929   /* Given value must be LESS THAN or EQUAL to the found partition. */
2930   DBUG_ASSERT(
2931       list_index == part_info->num_list_values ||
2932       (0 >= cmp_rec_and_tuple_prune(list_col_array + list_index * num_columns,
2933                                     nparts, left_endpoint, include_endpoint)));
2934   /* Given value must be GREATER THAN the previous partition. */
2935   DBUG_ASSERT(list_index == 0 ||
2936               (0 < cmp_rec_and_tuple_prune(
2937                        list_col_array + (list_index - 1) * num_columns, nparts,
2938                        left_endpoint, include_endpoint)));
2939 
2940   /* Include the right endpoint if not already passed end of array. */
2941   if (!left_endpoint && include_endpoint && cmp == 0 &&
2942       list_index < part_info->num_list_values)
2943     list_index++;
2944 
2945   return list_index;
2946 }
2947 
2948 /**
2949   Find the sub-array part_info->list_array that corresponds to given interval.
2950 
2951   @param part_info         Partitioning info (partitioning type must be LIST)
2952   @param left_endpoint     true  - the interval is [a; +inf) or (a; +inf)
2953                            false - the interval is (-inf; a] or (-inf; a)
2954   @param include_endpoint  true iff the interval includes the endpoint
2955 
2956   This function finds the sub-array of part_info->list_array where values of
2957   list_array[idx].list_value are contained within the specifed interval.
2958   list_array is ordered by list_value, so
2959   1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==true), the
2960      sought sub-array starts at some index idx and continues till array end.
2961      The function returns first number idx, such that
2962      list_array[idx].list_value is contained within the passed interval.
2963 
2964   2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==false), the
2965      sought sub-array starts at array start and continues till some last
2966      index idx.
2967      The function returns first number idx, such that
2968      list_array[idx].list_value is NOT contained within the passed interval.
2969      If all array elements are contained, part_info->num_list_values is
2970      returned.
2971 
2972   @note The caller will call this function and then will run along the
2973   sub-array of list_array to collect partition ids. If the number of list
2974   values is significantly higher then number of partitions, this could be slow
2975   and we could invent some other approach. The "run over list array" part is
2976   already wrapped in a get_next()-like function.
2977 
2978   @return The index of corresponding sub-array of part_info->list_array.
2979 */
2980 
get_list_array_idx_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)2981 static uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
2982                                                       bool left_endpoint,
2983                                                       bool include_endpoint) {
2984   uint32 res;
2985   copy_to_part_field_buffers(part_info->part_field_array,
2986                              part_info->part_field_buffers,
2987                              part_info->restore_part_field_ptrs);
2988   res = get_list_array_idx_for_endpoint(part_info, left_endpoint,
2989                                         include_endpoint);
2990   restore_part_field_pointers(part_info->part_field_array,
2991                               part_info->restore_part_field_ptrs);
2992   return res;
2993 }
2994 
get_list_array_idx_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)2995 static uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
2996                                               bool left_endpoint,
2997                                               bool include_endpoint) {
2998   LIST_PART_ENTRY *list_array = part_info->list_array;
2999   uint list_index;
3000   uint min_list_index = 0, max_list_index = part_info->num_list_values - 1;
3001   longlong list_value;
3002   /* Get the partitioning function value for the endpoint */
3003   longlong part_func_value =
3004       part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3005   bool unsigned_flag = part_info->part_expr->unsigned_flag;
3006   DBUG_TRACE;
3007 
3008   if (part_info->part_expr->null_value) {
3009     /*
3010       Special handling for MONOTONIC functions that can return NULL for
3011       values that are comparable. I.e.
3012       '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3013       returns NULL which cannot be compared used <, >, <=, >= etc.
3014 
3015       Otherwise, just return the the first index (lowest value).
3016     */
3017     enum_monotonicity_info monotonic;
3018     monotonic = part_info->part_expr->get_monotonicity_info();
3019     if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3020         monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) {
3021       /* F(col) can not return NULL, return index with lowest value */
3022       return 0;
3023     }
3024   }
3025 
3026   if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3027   DBUG_ASSERT(part_info->num_list_values);
3028   do {
3029     list_index = (max_list_index + min_list_index) >> 1;
3030     list_value = list_array[list_index].list_value;
3031     if (list_value < part_func_value)
3032       min_list_index = list_index + 1;
3033     else if (list_value > part_func_value) {
3034       if (!list_index) goto notfound;
3035       max_list_index = list_index - 1;
3036     } else {
3037       return list_index + ((left_endpoint ^ include_endpoint) ? 1 : 0);
3038     }
3039   } while (max_list_index >= min_list_index);
3040 notfound:
3041   if (list_value < part_func_value) list_index++;
3042   return list_index;
3043 }
3044 
get_partition_id_range_col(partition_info * part_info,uint32 * part_id,longlong *)3045 static int get_partition_id_range_col(partition_info *part_info,
3046                                       uint32 *part_id, longlong *) {
3047   part_column_list_val *range_col_array = part_info->range_col_array;
3048   uint num_columns = part_info->part_field_list.elements;
3049   uint max_partition = part_info->num_parts - 1;
3050   uint min_part_id = 0;
3051   uint max_part_id = max_partition;
3052   uint loc_part_id;
3053   DBUG_TRACE;
3054 
3055   while (max_part_id > min_part_id) {
3056     loc_part_id = (max_part_id + min_part_id + 1) >> 1;
3057     if (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3058                           num_columns) >= 0)
3059       min_part_id = loc_part_id + 1;
3060     else
3061       max_part_id = loc_part_id - 1;
3062   }
3063   loc_part_id = max_part_id;
3064   if (loc_part_id != max_partition)
3065     if (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3066                           num_columns) >= 0)
3067       loc_part_id++;
3068   *part_id = (uint32)loc_part_id;
3069   if (loc_part_id == max_partition &&
3070       (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3071                          num_columns) >= 0))
3072     return HA_ERR_NO_PARTITION_FOUND;
3073 
3074   DBUG_PRINT("exit", ("partition: %d", *part_id));
3075   return 0;
3076 }
3077 
get_partition_id_range(partition_info * part_info,uint32 * part_id,longlong * func_value)3078 int get_partition_id_range(partition_info *part_info, uint32 *part_id,
3079                            longlong *func_value) {
3080   longlong *range_array = part_info->range_int_array;
3081   uint max_partition = part_info->num_parts - 1;
3082   uint min_part_id = 0;
3083   uint max_part_id = max_partition;
3084   uint loc_part_id;
3085   longlong part_func_value;
3086   int error = part_val_int(part_info->part_expr, &part_func_value);
3087   bool unsigned_flag = part_info->part_expr->unsigned_flag;
3088   DBUG_TRACE;
3089 
3090   if (error) return HA_ERR_NO_PARTITION_FOUND;
3091 
3092   if (part_info->part_expr->null_value) {
3093     *part_id = 0;
3094     return 0;
3095   }
3096   *func_value = part_func_value;
3097   if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3098   /* Search for the partition containing part_func_value */
3099   while (max_part_id > min_part_id) {
3100     loc_part_id = (max_part_id + min_part_id) / 2;
3101     if (range_array[loc_part_id] <= part_func_value)
3102       min_part_id = loc_part_id + 1;
3103     else
3104       max_part_id = loc_part_id;
3105   }
3106   loc_part_id = max_part_id;
3107   *part_id = (uint32)loc_part_id;
3108   if (loc_part_id == max_partition &&
3109       part_func_value >= range_array[loc_part_id] &&
3110       !part_info->defined_max_value)
3111     return HA_ERR_NO_PARTITION_FOUND;
3112 
3113   DBUG_PRINT("exit", ("partition: %d", *part_id));
3114   return 0;
3115 }
3116 
3117 /*
3118   Find the sub-array of part_info->range_int_array that covers given interval
3119 
3120   SYNOPSIS
3121     get_partition_id_range_for_endpoint()
3122       part_info         Partitioning info (partitioning type must be RANGE)
3123       left_endpoint     true  - the interval is [a; +inf) or (a; +inf)
3124                         false - the interval is (-inf; a] or (-inf; a).
3125       include_endpoint  true <=> the endpoint itself is included in the
3126                         interval
3127 
3128   DESCRIPTION
3129     This function finds the sub-array of part_info->range_int_array where the
3130     elements have non-empty intersections with the given interval.
3131 
3132     A range_int_array element at index idx represents the interval
3133 
3134       [range_int_array[idx-1], range_int_array[idx]),
3135 
3136     intervals are disjoint and ordered by their right bound, so
3137 
3138     1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==true), the
3139        sought sub-array starts at some index idx and continues till array end.
3140        The function returns first number idx, such that the interval
3141        represented by range_int_array[idx] has non empty intersection with
3142        the passed interval.
3143 
3144     2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==false), the
3145        sought sub-array starts at array start and continues till some last
3146        index idx.
3147        The function returns first number idx, such that the interval
3148        represented by range_int_array[idx] has EMPTY intersection with the
3149        passed interval.
3150        If the interval represented by the last array element has non-empty
3151        intersection with the passed interval, part_info->num_parts is
3152        returned.
3153 
3154   RETURN
3155     The edge of corresponding part_info->range_int_array sub-array.
3156 */
3157 
get_partition_id_range_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)3158 static uint32 get_partition_id_range_for_endpoint_charset(
3159     partition_info *part_info, bool left_endpoint, bool include_endpoint) {
3160   uint32 res;
3161   copy_to_part_field_buffers(part_info->part_field_array,
3162                              part_info->part_field_buffers,
3163                              part_info->restore_part_field_ptrs);
3164   res = get_partition_id_range_for_endpoint(part_info, left_endpoint,
3165                                             include_endpoint);
3166   restore_part_field_pointers(part_info->part_field_array,
3167                               part_info->restore_part_field_ptrs);
3168   return res;
3169 }
3170 
get_partition_id_range_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)3171 static uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
3172                                                   bool left_endpoint,
3173                                                   bool include_endpoint) {
3174   longlong *range_array = part_info->range_int_array;
3175   longlong part_end_val;
3176   uint max_partition = part_info->num_parts - 1;
3177   uint min_part_id = 0, max_part_id = max_partition, loc_part_id;
3178   /* Get the partitioning function value for the endpoint */
3179   longlong part_func_value =
3180       part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3181 
3182   bool unsigned_flag = part_info->part_expr->unsigned_flag;
3183   DBUG_TRACE;
3184 
3185   if (part_info->part_expr->null_value) {
3186     /*
3187       Special handling for MONOTONIC functions that can return NULL for
3188       values that are comparable. I.e.
3189       '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3190       returns NULL which cannot be compared used <, >, <=, >= etc.
3191 
3192       Otherwise, just return the first partition
3193       (may be included if not left endpoint)
3194     */
3195     enum_monotonicity_info monotonic;
3196     monotonic = part_info->part_expr->get_monotonicity_info();
3197     if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3198         monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) {
3199       /* F(col) can not return NULL, return partition with lowest value */
3200       if (!left_endpoint && include_endpoint) return 1;
3201       return 0;
3202     }
3203   }
3204 
3205   if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3206   if (left_endpoint && !include_endpoint) part_func_value++;
3207 
3208   /*
3209     Search for the partition containing part_func_value
3210     (including the right endpoint).
3211   */
3212   while (max_part_id > min_part_id) {
3213     loc_part_id = (max_part_id + min_part_id) / 2;
3214     if (range_array[loc_part_id] < part_func_value)
3215       min_part_id = loc_part_id + 1;
3216     else
3217       max_part_id = loc_part_id;
3218   }
3219   loc_part_id = max_part_id;
3220 
3221   /* Adjust for endpoints */
3222   part_end_val = range_array[loc_part_id];
3223   if (left_endpoint) {
3224     DBUG_ASSERT(
3225         part_func_value > part_end_val
3226             ? (loc_part_id == max_partition && !part_info->defined_max_value)
3227             : 1);
3228     /*
3229       In case of PARTITION p VALUES LESS THAN MAXVALUE
3230       the maximum value is in the current (last) partition.
3231       If value is equal or greater than the endpoint,
3232       the range starts from the next partition.
3233     */
3234     if (part_func_value >= part_end_val &&
3235         (loc_part_id < max_partition || !part_info->defined_max_value))
3236       loc_part_id++;
3237   } else {
3238     /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */
3239     if (include_endpoint && loc_part_id < max_partition &&
3240         part_func_value == part_end_val)
3241       loc_part_id++;
3242 
3243     /* Right endpoint, set end after correct partition */
3244     loc_part_id++;
3245   }
3246   return loc_part_id;
3247 }
3248 
get_partition_id_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3249 static int get_partition_id_hash_nosub(partition_info *part_info,
3250                                        uint32 *part_id, longlong *func_value) {
3251   return get_part_id_hash(part_info->num_parts, part_info->part_expr, part_id,
3252                           func_value);
3253 }
3254 
get_partition_id_linear_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3255 static int get_partition_id_linear_hash_nosub(partition_info *part_info,
3256                                               uint32 *part_id,
3257                                               longlong *func_value) {
3258   return get_part_id_linear_hash(part_info, part_info->num_parts,
3259                                  part_info->part_expr, part_id, func_value);
3260 }
3261 
get_partition_id_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3262 static int get_partition_id_key_nosub(partition_info *part_info,
3263                                       uint32 *part_id, longlong *func_value) {
3264   *part_id =
3265       get_part_id_key(part_info->table->file, part_info->part_field_array,
3266                       part_info->num_parts, func_value);
3267   return 0;
3268 }
3269 
get_partition_id_linear_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3270 static int get_partition_id_linear_key_nosub(partition_info *part_info,
3271                                              uint32 *part_id,
3272                                              longlong *func_value) {
3273   *part_id = get_part_id_linear_key(part_info, part_info->part_field_array,
3274                                     part_info->num_parts, func_value);
3275   return 0;
3276 }
3277 
get_partition_id_with_sub(partition_info * part_info,uint32 * part_id,longlong * func_value)3278 static int get_partition_id_with_sub(partition_info *part_info, uint32 *part_id,
3279                                      longlong *func_value) {
3280   uint32 loc_part_id, sub_part_id;
3281   uint num_subparts;
3282   int error;
3283   DBUG_TRACE;
3284 
3285   if (unlikely((error = part_info->get_part_partition_id(
3286                     part_info, &loc_part_id, func_value)))) {
3287     return error;
3288   }
3289   num_subparts = part_info->num_subparts;
3290   if (unlikely(
3291           (error = part_info->get_subpartition_id(part_info, &sub_part_id)))) {
3292     return error;
3293   }
3294   *part_id = get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
3295   return 0;
3296 }
3297 
3298 /*
3299   This function is used to calculate the subpartition id
3300 
3301   SYNOPSIS
3302     get_subpartition_id()
3303     part_info           A reference to the partition_info struct where all the
3304                         desired information is given
3305 
3306   RETURN VALUE
3307     part_id             The subpartition identity
3308 
3309   DESCRIPTION
3310     A routine used in some SELECT's when only partial knowledge of the
3311     partitions is known.
3312 
3313     It is actually 4 different variants of this function which are called
3314     through a function pointer.
3315 
3316     get_partition_id_hash_sub
3317     get_partition_id_key_sub
3318     get_partition_id_linear_hash_sub
3319     get_partition_id_linear_key_sub
3320 */
3321 
get_partition_id_hash_sub(partition_info * part_info,uint32 * part_id)3322 static int get_partition_id_hash_sub(partition_info *part_info,
3323                                      uint32 *part_id) {
3324   longlong func_value;
3325   return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
3326                           part_id, &func_value);
3327 }
3328 
get_partition_id_linear_hash_sub(partition_info * part_info,uint32 * part_id)3329 static int get_partition_id_linear_hash_sub(partition_info *part_info,
3330                                             uint32 *part_id) {
3331   longlong func_value;
3332   return get_part_id_linear_hash(part_info, part_info->num_subparts,
3333                                  part_info->subpart_expr, part_id, &func_value);
3334 }
3335 
get_partition_id_key_sub(partition_info * part_info,uint32 * part_id)3336 static int get_partition_id_key_sub(partition_info *part_info,
3337                                     uint32 *part_id) {
3338   longlong func_value;
3339   *part_id =
3340       get_part_id_key(part_info->table->file, part_info->subpart_field_array,
3341                       part_info->num_subparts, &func_value);
3342   return false;
3343 }
3344 
get_partition_id_linear_key_sub(partition_info * part_info,uint32 * part_id)3345 static int get_partition_id_linear_key_sub(partition_info *part_info,
3346                                            uint32 *part_id) {
3347   longlong func_value;
3348   *part_id = get_part_id_linear_key(part_info, part_info->subpart_field_array,
3349                                     part_info->num_subparts, &func_value);
3350   return false;
3351 }
3352 
3353 /*
3354   Set an indicator on all partition fields that are set by the key
3355 
3356   SYNOPSIS
3357     set_PF_fields_in_key()
3358     key_info                   Information about the index
3359     key_length                 Length of key
3360 
3361   RETURN VALUE
3362     true                       Found partition field set by key
3363     false                      No partition field set by key
3364 */
3365 
set_PF_fields_in_key(KEY * key_info,uint key_length)3366 static bool set_PF_fields_in_key(KEY *key_info, uint key_length) {
3367   KEY_PART_INFO *key_part;
3368   bool found_part_field = false;
3369   DBUG_TRACE;
3370 
3371   for (key_part = key_info->key_part; (int)key_length > 0; key_part++) {
3372     if (key_part->null_bit) key_length--;
3373     if (key_part->type == HA_KEYTYPE_BIT) {
3374       if (((Field_bit *)key_part->field)->bit_len) key_length--;
3375     }
3376     if (key_part->key_part_flag & (HA_BLOB_PART + HA_VAR_LENGTH_PART)) {
3377       key_length -= HA_KEY_BLOB_LENGTH;
3378     }
3379     if (key_length < key_part->length) break;
3380     key_length -= key_part->length;
3381     if (key_part->field->is_flag_set(FIELD_IN_PART_FUNC_FLAG)) {
3382       found_part_field = true;
3383       key_part->field->set_flag(GET_FIXED_FIELDS_FLAG);
3384     }
3385   }
3386   return found_part_field;
3387 }
3388 
3389 /*
3390   We have found that at least one partition field was set by a key, now
3391   check if a partition function has all its fields bound or not.
3392 
3393   SYNOPSIS
3394     check_part_func_bound()
3395     ptr                     Array of fields NULL terminated (partition fields)
3396 
3397   RETURN VALUE
3398     true                    All fields in partition function are set
3399     false                   Not all fields in partition function are set
3400 */
3401 
check_part_func_bound(Field ** ptr)3402 static bool check_part_func_bound(Field **ptr) {
3403   bool result = true;
3404   DBUG_TRACE;
3405 
3406   for (; *ptr; ptr++) {
3407     if (!(*ptr)->is_flag_set(GET_FIXED_FIELDS_FLAG)) {
3408       result = false;
3409       break;
3410     }
3411   }
3412   return result;
3413 }
3414 
3415 /*
3416   Get the id of the subpartitioning part by using the key buffer of the
3417   index scan.
3418 
3419   SYNOPSIS
3420     get_sub_part_id_from_key()
3421     table         The table object
3422     buf           A buffer that can be used to evaluate the partition function
3423     key_info      The index object
3424     key_spec      A key_range containing key and key length
3425     out:part_id   The returned partition id
3426 
3427   RETURN VALUES
3428     true                    All fields in partition function are set
3429     false                   Not all fields in partition function are set
3430 
3431   DESCRIPTION
3432     Use key buffer to set-up record in buf, move field pointers and
3433     get the partition identity and restore field pointers afterwards.
3434 */
3435 
get_sub_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)3436 static int get_sub_part_id_from_key(const TABLE *table, uchar *buf,
3437                                     KEY *key_info, const key_range *key_spec,
3438                                     uint32 *part_id) {
3439   uchar *rec0 = table->record[0];
3440   partition_info *part_info = table->part_info;
3441   int res;
3442   DBUG_TRACE;
3443 
3444   key_restore(buf, key_spec->key, key_info, key_spec->length);
3445   if (likely(rec0 == buf)) {
3446     res = part_info->get_subpartition_id(part_info, part_id);
3447   } else {
3448     Field **part_field_array = part_info->subpart_field_array;
3449     set_field_ptr(part_field_array, buf, rec0);
3450     res = part_info->get_subpartition_id(part_info, part_id);
3451     set_field_ptr(part_field_array, rec0, buf);
3452   }
3453   return res;
3454 }
3455 
3456 /*
3457   Get the id of the partitioning part by using the key buffer of the
3458   index scan.
3459 
3460   SYNOPSIS
3461     get_part_id_from_key()
3462     table         The table object
3463     buf           A buffer that can be used to evaluate the partition function
3464     key_info      The index object
3465     key_spec      A key_range containing key and key length
3466     out:part_id   Partition to use
3467 
3468   RETURN VALUES
3469     true          Partition to use not found
3470     false         Ok, part_id indicates partition to use
3471 
3472   DESCRIPTION
3473     Use key buffer to set-up record in buf, move field pointers and
3474     get the partition identity and restore field pointers afterwards.
3475 */
3476 
get_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)3477 static bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
3478                                  const key_range *key_spec, uint32 *part_id) {
3479   bool result;
3480   uchar *rec0 = table->record[0];
3481   partition_info *part_info = table->part_info;
3482   longlong func_value;
3483   DBUG_TRACE;
3484 
3485   key_restore(buf, key_spec->key, key_info, key_spec->length);
3486   if (likely(rec0 == buf)) {
3487     result = part_info->get_part_partition_id(part_info, part_id, &func_value);
3488   } else {
3489     Field **part_field_array = part_info->part_field_array;
3490     set_field_ptr(part_field_array, buf, rec0);
3491     result = part_info->get_part_partition_id(part_info, part_id, &func_value);
3492     set_field_ptr(part_field_array, rec0, buf);
3493   }
3494   return result;
3495 }
3496 
3497 /*
3498   Get the partitioning id of the full PF by using the key buffer of the
3499   index scan.
3500 
3501   SYNOPSIS
3502     get_full_part_id_from_key()
3503     table         The table object
3504     buf           A buffer that is used to evaluate the partition function
3505     key_info      The index object
3506     key_spec      A key_range containing key and key length
3507     out:part_spec A partition id containing start part and end part
3508 
3509   RETURN VALUES
3510     part_spec
3511     No partitions to scan is indicated by end_part > start_part when returning
3512 
3513   DESCRIPTION
3514     Use key buffer to set-up record in buf, move field pointers if needed and
3515     get the partition identity and restore field pointers afterwards.
3516 */
3517 
get_full_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,part_id_range * part_spec)3518 void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
3519                                const key_range *key_spec,
3520                                part_id_range *part_spec) {
3521   bool result;
3522   partition_info *part_info = table->part_info;
3523   uchar *rec0 = table->record[0];
3524   longlong func_value;
3525   DBUG_TRACE;
3526 
3527   key_restore(buf, key_spec->key, key_info, key_spec->length);
3528   if (likely(rec0 == buf)) {
3529     result = part_info->get_partition_id(part_info, &part_spec->start_part,
3530                                          &func_value);
3531   } else {
3532     Field **part_field_array = part_info->full_part_field_array;
3533     set_field_ptr(part_field_array, buf, rec0);
3534     result = part_info->get_partition_id(part_info, &part_spec->start_part,
3535                                          &func_value);
3536     set_field_ptr(part_field_array, rec0, buf);
3537   }
3538   part_spec->end_part = part_spec->start_part;
3539   if (unlikely(result)) part_spec->start_part++;
3540 }
3541 
3542 /**
3543   @brief Verify that all rows in a table is in the given partition
3544 
3545   @param table      Table which contains the data that will be checked if
3546                     it is matching the partition definition.
3547   @param part_table Partitioned table containing the partition to check.
3548   @param part_id    Which partition to match with.
3549 
3550   @return Operation status
3551     @retval true                Not all rows match the given partition
3552     @retval false               OK
3553 */
verify_data_with_partition(TABLE * table,TABLE * part_table,uint32 part_id)3554 bool verify_data_with_partition(TABLE *table, TABLE *part_table,
3555                                 uint32 part_id) {
3556   uint32 found_part_id;
3557   longlong func_value; /* Unused */
3558   handler *file;
3559   int error;
3560   uchar *old_rec;
3561   partition_info *part_info;
3562   DBUG_TRACE;
3563   DBUG_ASSERT(table && table->file && part_table && part_table->part_info &&
3564               part_table->file);
3565 
3566   /*
3567     Verify all table rows.
3568     First implementation uses full scan + evaluates partition functions for
3569     every row. TODO: add optimization to use index if possible, see WL#5397.
3570 
3571     1) Open both tables (already done) and set the row buffers to use
3572        the same buffer (to avoid copy).
3573     2) Init rnd on table.
3574     3) loop over all rows.
3575       3.1) verify that partition_id on the row is correct. Break if error.
3576   */
3577   file = table->file;
3578   part_info = part_table->part_info;
3579   bitmap_union(table->read_set, &part_info->full_part_field_set);
3580   old_rec = part_table->record[0];
3581   part_table->record[0] = table->record[0];
3582   set_field_ptr(part_info->full_part_field_array, table->record[0], old_rec);
3583   if ((error = file->ha_rnd_init(true))) {
3584     file->print_error(error, MYF(0));
3585     goto err;
3586   }
3587 
3588   do {
3589     if ((error = file->ha_rnd_next(table->record[0]))) {
3590       if (error == HA_ERR_RECORD_DELETED) continue;
3591       if (error == HA_ERR_END_OF_FILE)
3592         error = 0;
3593       else
3594         file->print_error(error, MYF(0));
3595       break;
3596     }
3597     if ((error = part_info->get_partition_id(part_info, &found_part_id,
3598                                              &func_value))) {
3599       part_info->err_value = func_value;
3600       part_table->file->print_error(error, MYF(0));
3601       break;
3602     }
3603     DEBUG_SYNC(current_thd, "swap_partition_first_row_read");
3604     if (found_part_id != part_id) {
3605       my_error(ER_ROW_DOES_NOT_MATCH_PARTITION, MYF(0));
3606       error = 1;
3607       break;
3608     }
3609   } while (true);
3610   (void)file->ha_rnd_end();
3611 err:
3612   set_field_ptr(part_info->full_part_field_array, old_rec, table->record[0]);
3613   part_table->record[0] = old_rec;
3614   if (error) return true;
3615   return false;
3616 }
3617 
3618 /*
3619   Prune the set of partitions to use in query
3620 
3621   SYNOPSIS
3622     prune_partition_set()
3623     table         The table object
3624     out:part_spec Contains start part, end part
3625 
3626   DESCRIPTION
3627     This function is called to prune the range of partitions to scan by
3628     checking the read_partitions bitmap.
3629     If start_part > end_part at return it means no partition needs to be
3630     scanned. If start_part == end_part it always means a single partition
3631     needs to be scanned.
3632 
3633   RETURN VALUE
3634     part_spec
3635 */
prune_partition_set(const TABLE * table,part_id_range * part_spec)3636 void prune_partition_set(const TABLE *table, part_id_range *part_spec) {
3637   int last_partition = -1;
3638   uint i = part_spec->start_part;
3639   partition_info *part_info = table->part_info;
3640   DBUG_TRACE;
3641 
3642   if (i)
3643     i = bitmap_get_next_set(&part_info->read_partitions, i - 1);
3644   else
3645     i = bitmap_get_first_set(&part_info->read_partitions);
3646 
3647   part_spec->start_part = i;
3648 
3649   /* TODO: Only check next bit, no need to prune end if >= 2 partitions. */
3650   for (; i <= part_spec->end_part;
3651        i = bitmap_get_next_set(&part_info->read_partitions, i)) {
3652     DBUG_PRINT("info", ("Partition %d is set", i));
3653     if (last_partition == -1)
3654       /* First partition found in set and pruned bitmap */
3655       part_spec->start_part = i;
3656     last_partition = i;
3657   }
3658   if (last_partition == -1) /* No partition found in pruned bitmap */
3659     part_spec->start_part = part_spec->end_part + 1;
3660   else  // if (last_partition != -1)
3661     part_spec->end_part = last_partition;
3662 }
3663 
3664 /*
3665   Get the set of partitions to use in query.
3666 
3667   SYNOPSIS
3668     get_partition_set()
3669     table         The table object
3670     buf           A buffer that can be used to evaluate the partition function
3671     index         The index of the key used, if MAX_KEY no index used
3672     key_spec      A key_range containing key and key length
3673     out:part_spec Contains start part, end part and indicator if bitmap is
3674                   used for which partitions to scan
3675 
3676   DESCRIPTION
3677     This function is called to discover which partitions to use in an index
3678     scan or a full table scan.
3679     It returns a range of partitions to scan. If there are holes in this
3680     range with partitions that are not needed to scan a bit array is used
3681     to signal which partitions to use and which not to use.
3682     If start_part > end_part at return it means no partition needs to be
3683     scanned. If start_part == end_part it always means a single partition
3684     needs to be scanned.
3685 
3686   RETURN VALUE
3687     part_spec
3688 */
get_partition_set(const TABLE * table,uchar * buf,const uint index,const key_range * key_spec,part_id_range * part_spec)3689 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
3690                        const key_range *key_spec, part_id_range *part_spec) {
3691   partition_info *part_info = table->part_info;
3692   uint num_parts = part_info->get_tot_partitions();
3693   uint i, part_id;
3694   uint sub_part = num_parts;
3695   uint32 part_part = num_parts;
3696   KEY *key_info = nullptr;
3697   bool found_part_field = false;
3698   DBUG_TRACE;
3699 
3700   part_spec->start_part = 0;
3701   part_spec->end_part = num_parts - 1;
3702   if ((index < MAX_KEY) && key_spec &&
3703       key_spec->flag == (uint)HA_READ_KEY_EXACT &&
3704       part_info->some_fields_in_PF.is_set(index)) {
3705     key_info = table->key_info + index;
3706     /*
3707       The index can potentially provide at least one PF-field (field in the
3708       partition function). Thus it is interesting to continue our probe.
3709     */
3710     if (key_spec->length == key_info->key_length) {
3711       /*
3712         The entire key is set so we can check whether we can immediately
3713         derive either the complete PF or if we can derive either
3714         the top PF or the subpartitioning PF. This can be established by
3715         checking precalculated bits on each index.
3716       */
3717       if (part_info->all_fields_in_PF.is_set(index)) {
3718         /*
3719           We can derive the exact partition to use, no more than this one
3720           is needed.
3721         */
3722         get_full_part_id_from_key(table, buf, key_info, key_spec, part_spec);
3723         /*
3724           Check if range can be adjusted by looking in read_partitions
3725         */
3726         prune_partition_set(table, part_spec);
3727         return;
3728       } else if (part_info->is_sub_partitioned()) {
3729         if (part_info->all_fields_in_SPF.is_set(index)) {
3730           if (get_sub_part_id_from_key(table, buf, key_info, key_spec,
3731                                        &sub_part)) {
3732             part_spec->start_part = num_parts;
3733             return;
3734           }
3735         } else if (part_info->all_fields_in_PPF.is_set(index)) {
3736           if (get_part_id_from_key(table, buf, key_info, key_spec,
3737                                    &part_part)) {
3738             /*
3739               The value of the RANGE or LIST partitioning was outside of
3740               allowed values. Thus it is certain that the result of this
3741               scan will be empty.
3742             */
3743             part_spec->start_part = num_parts;
3744             return;
3745           }
3746         }
3747       }
3748     } else {
3749       /*
3750         Set an indicator on all partition fields that are bound.
3751         If at least one PF-field was bound it pays off to check whether
3752         the PF or PPF or SPF has been bound.
3753         (PF = Partition Function, SPF = Subpartition Function and
3754          PPF = Partition Function part of subpartitioning)
3755       */
3756       if ((found_part_field =
3757                set_PF_fields_in_key(key_info, key_spec->length))) {
3758         if (check_part_func_bound(part_info->full_part_field_array)) {
3759           /*
3760             We were able to bind all fields in the partition function even
3761             by using only a part of the key. Calculate the partition to use.
3762           */
3763           get_full_part_id_from_key(table, buf, key_info, key_spec, part_spec);
3764           clear_indicator_in_key_fields(key_info);
3765           /*
3766             Check if range can be adjusted by looking in read_partitions
3767           */
3768           prune_partition_set(table, part_spec);
3769           return;
3770         } else if (part_info->is_sub_partitioned()) {
3771           if (check_part_func_bound(part_info->subpart_field_array)) {
3772             if (get_sub_part_id_from_key(table, buf, key_info, key_spec,
3773                                          &sub_part)) {
3774               part_spec->start_part = num_parts;
3775               clear_indicator_in_key_fields(key_info);
3776               return;
3777             }
3778           } else if (check_part_func_bound(part_info->part_field_array)) {
3779             if (get_part_id_from_key(table, buf, key_info, key_spec,
3780                                      &part_part)) {
3781               part_spec->start_part = num_parts;
3782               clear_indicator_in_key_fields(key_info);
3783               return;
3784             }
3785           }
3786         }
3787       }
3788     }
3789   }
3790   {
3791     /*
3792       The next step is to analyse the table condition to see whether any
3793       information about which partitions to scan can be derived from there.
3794       Currently not implemented.
3795     */
3796   }
3797   /*
3798     If we come here we have found a range of sorts we have either discovered
3799     nothing or we have discovered a range of partitions with possible holes
3800     in it. We need a bitvector to further the work here.
3801   */
3802   if (!(part_part == num_parts && sub_part == num_parts)) {
3803     /*
3804       We can only arrive here if we are using subpartitioning.
3805     */
3806     if (part_part != num_parts) {
3807       /*
3808         We know the top partition and need to scan all underlying
3809         subpartitions. This is a range without holes.
3810       */
3811       DBUG_ASSERT(sub_part == num_parts);
3812       part_spec->start_part = part_part * part_info->num_subparts;
3813       part_spec->end_part = part_spec->start_part + part_info->num_subparts - 1;
3814     } else {
3815       DBUG_ASSERT(sub_part != num_parts);
3816       part_spec->start_part = sub_part;
3817       part_spec->end_part =
3818           sub_part + (part_info->num_subparts * (part_info->num_parts - 1));
3819       for (i = 0, part_id = sub_part; i < part_info->num_parts;
3820            i++, part_id += part_info->num_subparts)
3821         ;  // Set bit part_id in bit array
3822     }
3823   }
3824   if (found_part_field) clear_indicator_in_key_fields(key_info);
3825   /*
3826     Check if range can be adjusted by looking in read_partitions
3827   */
3828   prune_partition_set(table, part_spec);
3829 }
3830 
3831 /*
3832    If the table is partitioned we will read the partition info into the
3833    .frm file here.
3834    -------------------------------
3835    |  Fileinfo     64 bytes      |
3836    -------------------------------
3837    | Formnames     7 bytes       |
3838    -------------------------------
3839    | Not used    4021 bytes      |
3840    -------------------------------
3841    | Keyinfo + record            |
3842    -------------------------------
3843    | Padded to next multiple     |
3844    | of IO_SIZE                  |
3845    -------------------------------
3846    | Forminfo     288 bytes      |
3847    -------------------------------
3848    | Screen buffer, to make      |
3849    |field names readable        |
3850    -------------------------------
3851    | Packed field info           |
3852    |17 + 1 + strlen(field_name) |
3853    | + 1 end of file character   |
3854    -------------------------------
3855    | Partition info              |
3856    -------------------------------
3857    We provide the length of partition length in Fileinfo[55-58].
3858 
3859    Read the partition syntax from the frm file and parse it to get the
3860    data structures of the partitioning.
3861 
3862    SYNOPSIS
3863      mysql_unpack_partition()
3864      thd                           Thread object
3865      part_buf                      Partition info from frm file
3866      part_info_len                 Length of partition syntax
3867      table                         Table object of partitioned table
3868      create_table_ind              Is it called from CREATE TABLE
3869      default_db_type               What is the default engine of the table
3870      work_part_info_used           Flag is raised if we don't create new
3871                                    part_info, but used thd->work_part_info
3872 
3873    RETURN VALUE
3874      true                          Error
3875      false                         Sucess
3876 
3877    DESCRIPTION
3878      Read the partition syntax from the current position in the frm file.
3879      Initiate a LEX object, save the list of item tree objects to free after
3880      the query is done. Set-up partition info object such that parser knows
3881      it is called from internally. Call parser to create data structures
3882      (best possible recreation of item trees and so forth since there is no
3883      serialisation of these objects other than in parseable text format).
3884      We need to save the text of the partition functions since it is not
3885      possible to retrace this given an item tree.
3886 */
3887 
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)3888 bool mysql_unpack_partition(THD *thd, char *part_buf, uint part_info_len,
3889                             TABLE *table, bool is_create_table_ind,
3890                             handlerton *default_db_type,
3891                             bool *work_part_info_used) {
3892   bool result = true;
3893   partition_info *part_info;
3894   const CHARSET_INFO *old_character_set_client =
3895       thd->variables.character_set_client;
3896   LEX *old_lex = thd->lex;
3897   LEX lex;
3898   SELECT_LEX_UNIT unit(CTX_NONE);
3899   SELECT_LEX select(thd->mem_root, nullptr, nullptr);
3900   lex.new_static_query(&unit, &select);
3901 
3902   sql_digest_state *parent_digest = thd->m_digest;
3903   PSI_statement_locker *parent_locker = thd->m_statement_psi;
3904   Partition_handler *part_handler;
3905   DBUG_TRACE;
3906 
3907   thd->variables.character_set_client = system_charset_info;
3908   // This isn't strictly needed, but here for consistency.
3909   Sql_mode_parse_guard parse_guard(thd);
3910 
3911   Partition_expr_parser_state parser_state;
3912   if (parser_state.init(thd, part_buf, part_info_len)) goto end;
3913 
3914   if (init_lex_with_single_table(thd, table, &lex)) goto end;
3915 
3916   /*
3917     All Items created is put into a free list on the THD object. This list
3918     is used to free all Item objects after completing a query. We don't
3919     want that to happen with the Item tree created as part of the partition
3920     info. This should be attached to the table object and remain so until
3921     the table object is released.
3922     Thus we move away the current list temporarily and start a new list that
3923     we then save in the partition info structure.
3924   */
3925   *work_part_info_used = false;
3926   DBUG_PRINT("info", ("Parse: %s", part_buf));
3927 
3928   thd->m_digest = nullptr;
3929   thd->m_statement_psi = nullptr;
3930   if (parse_sql(thd, &parser_state, nullptr) ||
3931       parser_state.result->fix_parser_data(thd)) {
3932     thd->free_items();
3933     thd->m_digest = parent_digest;
3934     thd->m_statement_psi = parent_locker;
3935     goto end;
3936   }
3937   part_info = parser_state.result;
3938   thd->m_digest = parent_digest;
3939   thd->m_statement_psi = parent_locker;
3940   /*
3941     The parsed syntax residing in the frm file can still contain defaults.
3942     The reason is that the frm file is sometimes saved outside of this
3943     MySQL Server and used in backup and restore of clusters or partitioned
3944     tables. It is not certain that the restore will restore exactly the
3945     same default partitioning.
3946 
3947     The easiest manner of handling this is to simply continue using the
3948     part_info we already built up during mysql_create_table if we are
3949     in the process of creating a table. If the table already exists we
3950     need to discover the number of partitions for the default parts. Since
3951     the handler object hasn't been created here yet we need to postpone this
3952     to the fix_partition_func method.
3953   */
3954 
3955   DBUG_PRINT("info", ("Successful parse"));
3956   DBUG_PRINT("info",
3957              ("default engine = %s, default_db_type = %s",
3958               ha_resolve_storage_engine_name(part_info->default_engine_type),
3959               ha_resolve_storage_engine_name(default_db_type)));
3960   if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE) {
3961     /*
3962       When we come here we are doing a create table. In this case we
3963       have already done some preparatory work on the old part_info
3964       object. We don't really need this new partition_info object.
3965       Thus we go back to the old partition info object.
3966       We need to free any memory objects allocated on item_free_list
3967       by the parser since we are keeping the old info from the first
3968       parser call in CREATE TABLE.
3969 
3970       This table object can not be used any more. However, since
3971       this is CREATE TABLE, we know that it will be destroyed by the
3972       caller, and rely on that.
3973     */
3974     thd->free_items();
3975     part_info = thd->work_part_info;
3976     *work_part_info_used = true;
3977   }
3978   table->part_info = part_info;
3979   part_info->table = table;
3980   part_handler = table->file->get_partition_handler();
3981   DBUG_ASSERT(part_handler != nullptr);
3982   part_handler->set_part_info(part_info, true);
3983   if (!part_info->default_engine_type)
3984     part_info->default_engine_type = default_db_type;
3985   DBUG_ASSERT(part_info->default_engine_type == default_db_type);
3986   DBUG_ASSERT(part_info->default_engine_type->db_type != DB_TYPE_UNKNOWN);
3987 
3988   {
3989     /*
3990       This code part allocates memory for the serialised item information for
3991       the partition functions. In most cases this is not needed but if the
3992       table is used for SHOW CREATE TABLES or ALTER TABLE that modifies
3993       partition information it is needed and the info is lost if we don't
3994       save it here so unfortunately we have to do it here even if in most
3995       cases it is not needed. This is a consequence of that item trees are
3996       not serialisable.
3997     */
3998     size_t part_func_len = part_info->part_func_len;
3999     size_t subpart_func_len = part_info->subpart_func_len;
4000     char *part_func_string = nullptr;
4001     char *subpart_func_string = nullptr;
4002     /*
4003       TODO: Verify that it really should be allocated on the thd?
4004       Or simply remove it and use part_expr->print() instead?
4005     */
4006     if ((part_func_len &&
4007          !((part_func_string = (char *)thd->alloc(part_func_len)))) ||
4008         (subpart_func_len &&
4009          !((subpart_func_string = (char *)thd->alloc(subpart_func_len))))) {
4010       mem_alloc_error(part_func_len);
4011       thd->free_items();
4012       goto end;
4013     }
4014     if (part_func_len)
4015       memcpy(part_func_string, part_info->part_func_string, part_func_len);
4016     if (subpart_func_len)
4017       memcpy(subpart_func_string, part_info->subpart_func_string,
4018              subpart_func_len);
4019     part_info->part_func_string = part_func_string;
4020     part_info->subpart_func_string = subpart_func_string;
4021   }
4022 
4023   result = false;
4024 end:
4025   end_lex_with_single_table(thd, table, old_lex);
4026   thd->variables.character_set_client = old_character_set_client;
4027   return result;
4028 }
4029 
4030 /*
4031   Set engine type on all partition element objects
4032   SYNOPSIS
4033     set_engine_all_partitions()
4034     part_info                  Partition info
4035     engine_type                Handlerton reference of engine
4036   RETURN VALUES
4037     NONE
4038 */
4039 
set_engine_all_partitions(partition_info * part_info,handlerton * engine_type)4040 static void set_engine_all_partitions(partition_info *part_info,
4041                                       handlerton *engine_type) {
4042   uint i = 0;
4043   List_iterator<partition_element> part_it(part_info->partitions);
4044   do {
4045     partition_element *part_elem = part_it++;
4046 
4047     part_elem->engine_type = engine_type;
4048     if (part_info->is_sub_partitioned()) {
4049       List_iterator<partition_element> sub_it(part_elem->subpartitions);
4050       uint j = 0;
4051 
4052       do {
4053         partition_element *sub_elem = sub_it++;
4054 
4055         sub_elem->engine_type = engine_type;
4056       } while (++j < part_info->num_subparts);
4057     }
4058   } while (++i < part_info->num_parts);
4059 }
4060 
4061 /*
4062   We need to check if engine used by all partitions can handle
4063   partitioning natively.
4064 
4065   SYNOPSIS
4066     check_native_partitioned()
4067     create_info            Create info in CREATE TABLE
4068     out:ret_val            Return value
4069     part_info              Partition info
4070     thd                    Thread object
4071 
4072   RETURN VALUES
4073   Value returned in bool ret_value
4074     true                   Native partitioning supported by engine
4075     false                  Need to use partition handler
4076 
4077   Return value from function
4078     true                   Error
4079     false                  Success
4080 */
4081 
check_native_partitioned(HA_CREATE_INFO * create_info,bool * ret_val,partition_info * part_info,THD * thd)4082 static bool check_native_partitioned(HA_CREATE_INFO *create_info, bool *ret_val,
4083                                      partition_info *part_info, THD *thd) {
4084   bool table_engine_set;
4085   handlerton *engine_type = part_info->default_engine_type;
4086   handlerton *old_engine_type = engine_type;
4087   DBUG_TRACE;
4088 
4089   if (create_info->used_fields & HA_CREATE_USED_ENGINE) {
4090     table_engine_set = true;
4091     engine_type = create_info->db_type;
4092   } else {
4093     table_engine_set = false;
4094     if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
4095       table_engine_set = true;
4096     }
4097   }
4098   DBUG_PRINT("info",
4099              ("engine_type = %s, table_engine_set = %u",
4100               ha_resolve_storage_engine_name(engine_type), table_engine_set));
4101   if (part_info->check_engine_mix(engine_type, table_engine_set)) goto error;
4102 
4103   /*
4104     All engines are of the same type. Check if this engine supports
4105     native partitioning.
4106   */
4107 
4108   if (!engine_type) engine_type = old_engine_type;
4109   DBUG_PRINT("info",
4110              ("engine_type = %s", ha_resolve_storage_engine_name(engine_type)));
4111   if (engine_type->partition_flags) {
4112     create_info->db_type = engine_type;
4113     DBUG_PRINT("info", ("Changed to native partitioning"));
4114     *ret_val = true;
4115   }
4116   return false;
4117 error:
4118   /*
4119     Mixed engines not yet supported but when supported it will need
4120     the partition handler
4121   */
4122   my_error(ER_MIX_HANDLER_ERROR, MYF(0));
4123   *ret_val = false;
4124   return true;
4125 }
4126 
4127 /**
4128   Set part_state for all partitions to given state.
4129 
4130   @param tab_part_info  partition_info holding all partitions.
4131   @param part_state     Which state to set for the named partitions.
4132 */
4133 
set_all_part_state(partition_info * tab_part_info,enum partition_state part_state)4134 void set_all_part_state(partition_info *tab_part_info,
4135                         enum partition_state part_state) {
4136   uint part_count = 0;
4137   List_iterator<partition_element> part_it(tab_part_info->partitions);
4138 
4139   do {
4140     partition_element *part_elem = part_it++;
4141     part_elem->part_state = part_state;
4142     if (tab_part_info->is_sub_partitioned()) {
4143       List_iterator<partition_element> sub_it(part_elem->subpartitions);
4144       partition_element *sub_elem;
4145       while ((sub_elem = sub_it++)) {
4146         sub_elem->part_state = part_state;
4147       }
4148     }
4149   } while (++part_count < tab_part_info->num_parts);
4150 }
4151 
4152 /**
4153   Sets which partitions to be used in the command.
4154 
4155   @param alter_info     Alter_info pointer holding partition names and flags.
4156   @param tab_part_info  partition_info holding all partitions.
4157   @param part_state     Which state to set for the named partitions.
4158   @param include_subpartitions Also include subpartitions in the search.
4159 
4160   @return Operation status
4161     @retval false  Success
4162     @retval true   Failure
4163 */
4164 
set_part_state(Alter_info * alter_info,partition_info * tab_part_info,enum partition_state part_state,bool include_subpartitions)4165 bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
4166                     enum partition_state part_state,
4167                     bool include_subpartitions) {
4168   uint part_count = 0;
4169   uint num_parts_found = 0;
4170   List_iterator<partition_element> part_it(tab_part_info->partitions);
4171 
4172   do {
4173     partition_element *part_elem = part_it++;
4174     if ((alter_info->flags & Alter_info::ALTER_ALL_PARTITION) ||
4175         (is_name_in_list(part_elem->partition_name,
4176                          alter_info->partition_names))) {
4177       /*
4178         Mark the partition.
4179         I.e mark the partition as a partition to be "changed" by
4180         analyzing/optimizing/rebuilding/checking/repairing/...
4181       */
4182       num_parts_found++;
4183       part_elem->part_state = part_state;
4184       DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
4185                           part_state, part_elem->partition_name));
4186     } else if (include_subpartitions && tab_part_info->is_sub_partitioned()) {
4187       List_iterator<partition_element> sub_it(part_elem->subpartitions);
4188       partition_element *sub_elem;
4189       while ((sub_elem = sub_it++)) {
4190         if (is_name_in_list(sub_elem->partition_name,
4191                             alter_info->partition_names)) {
4192           num_parts_found++;
4193           sub_elem->part_state = part_state;
4194           DBUG_PRINT("info", ("Setting part_state to %u for subpartition %s",
4195                               part_state, sub_elem->partition_name));
4196         } else
4197           sub_elem->part_state = PART_NORMAL;
4198       }
4199       part_elem->part_state = PART_NORMAL;
4200     } else
4201       part_elem->part_state = PART_NORMAL;
4202   } while (++part_count < tab_part_info->num_parts);
4203 
4204   if (num_parts_found != alter_info->partition_names.elements &&
4205       !(alter_info->flags & Alter_info::ALTER_ALL_PARTITION)) {
4206     /* Not all given partitions found, revert and return failure */
4207     set_all_part_state(tab_part_info, PART_NORMAL);
4208     return true;
4209   }
4210   return false;
4211 }
4212 
4213 /**
4214   @brief Check if partition is exchangable with table by checking table options
4215 
4216   @param table_create_info Table options from table.
4217   @param part_elem         All the info of the partition.
4218 
4219   @retval false if they are equal, otherwise true.
4220 
4221   @note Any differens that would cause a change in the frm file is prohibited.
4222   Such options as data_file_name, index_file_name, min_rows, max_rows etc. are
4223   not allowed to differ. But comment is allowed to differ.
4224 */
compare_partition_options(HA_CREATE_INFO * table_create_info,partition_element * part_elem)4225 bool compare_partition_options(HA_CREATE_INFO *table_create_info,
4226                                partition_element *part_elem) {
4227 #define MAX_COMPARE_PARTITION_OPTION_ERRORS 5
4228   const char *option_diffs[MAX_COMPARE_PARTITION_OPTION_ERRORS + 1];
4229   int i, errors = 0;
4230   DBUG_TRACE;
4231   // TODO: Add test for EXCHANGE PARTITION with TABLESPACES!
4232   // Then if all works, simply remove the check for TABLESPACE (and eventually
4233   // DATA/INDEX DIRECTORY too).
4234 
4235   /*
4236     Note that there are not yet any engine supporting tablespace together
4237     with partitioning. TODO: when there are, add compare.
4238   */
4239   if (part_elem->tablespace_name || table_create_info->tablespace)
4240     option_diffs[errors++] = "TABLESPACE";
4241   if (part_elem->part_max_rows != table_create_info->max_rows)
4242     option_diffs[errors++] = "MAX_ROWS";
4243   if (part_elem->part_min_rows != table_create_info->min_rows)
4244     option_diffs[errors++] = "MIN_ROWS";
4245   if (part_elem->index_file_name || table_create_info->index_file_name)
4246     option_diffs[errors++] = "INDEX DIRECTORY";
4247 
4248   for (i = 0; i < errors; i++)
4249     my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0), option_diffs[i]);
4250   return errors != 0;
4251 }
4252 
4253 /*
4254   Prepare for ALTER TABLE of partition structure
4255 
4256   @param[in] thd                 Thread object
4257   @param[in] table               Table object
4258   @param[in,out] alter_info      Alter information
4259   @param[in,out] create_info     Create info for CREATE TABLE
4260   @param[in]  alter_ctx          ALTER TABLE runtime context
4261   @param[out] partition_changed  Boolean indicating whether partition changed
4262   @param[out] new_part_info      New partition_info object if in-place alter
4263                                  which requires mark-up in partition_info is
4264                                  possible.
4265 
4266   @return Operation status
4267     @retval true                 Error
4268     @retval false                Success
4269 
4270   @note
4271     This method handles all preparations for ALTER TABLE for partitioned
4272     tables.
4273     We need to handle both partition management command such as Add Partition
4274     and others here as well as an ALTER TABLE that completely changes the
4275     partitioning and yet others that don't change anything at all. We start
4276     by checking the partition management variants and then check the general
4277     change patterns.
4278 */
4279 
prep_alter_part_table(THD * thd,TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,Alter_table_ctx * alter_ctx MY_ATTRIBUTE ((unused)),bool * partition_changed,partition_info ** new_part_info)4280 uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
4281                            HA_CREATE_INFO *create_info,
4282                            Alter_table_ctx *alter_ctx MY_ATTRIBUTE((unused)),
4283                            bool *partition_changed,
4284                            partition_info **new_part_info) {
4285   DBUG_TRACE;
4286   DBUG_ASSERT(new_part_info);
4287 
4288   /* Remove partitioning on a not partitioned table is not possible */
4289   if (!table->part_info &&
4290       (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING)) {
4291     my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4292     return true;
4293   }
4294 
4295   if (thd->work_part_info &&
4296       !(thd->work_part_info = thd->lex->part_info->get_clone(thd, true)))
4297     return true;
4298 
4299   /* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
4300   DBUG_ASSERT(!(alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION));
4301 
4302   if (alter_info->flags &
4303       (Alter_info::ALTER_ADD_PARTITION | Alter_info::ALTER_DROP_PARTITION |
4304        Alter_info::ALTER_COALESCE_PARTITION |
4305        Alter_info::ALTER_REORGANIZE_PARTITION | Alter_info::ALTER_TABLE_REORG |
4306        Alter_info::ALTER_REBUILD_PARTITION)) {
4307     partition_info *tab_part_info;
4308     partition_info *alt_part_info = thd->work_part_info;
4309     uint flags = 0;
4310     bool is_last_partition_reorged = false;
4311     part_elem_value *tab_max_elem_val = nullptr;
4312     part_elem_value *alt_max_elem_val = nullptr;
4313     longlong tab_max_range = 0, alt_max_range = 0;
4314     Partition_handler *part_handler = table->file->get_partition_handler();
4315 
4316     if (!table->part_info) {
4317       my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4318       return true;
4319     }
4320     if (!part_handler) {
4321       DBUG_ASSERT(0);
4322       my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4323       return true;
4324     }
4325 
4326     /*
4327       Open our intermediate table, we will operate on a temporary instance
4328       of the original table, to be able to skip copying all partitions.
4329       Open it as a copy of the original table, and modify its partition_info
4330       object to allow in-place ALTER implementation to perform the changes.
4331     */
4332     DBUG_ASSERT(thd->mdl_context.owns_equal_or_stronger_lock(
4333         MDL_key::TABLE, alter_ctx->db, alter_ctx->table_name,
4334         MDL_INTENTION_EXCLUSIVE));
4335 
4336     /*
4337       We will operate on a cached instance of the original table,
4338       to be able to skip copying all non-changed partitions
4339       while allowing concurrent access.
4340 
4341       We create a new partition_info object which will carry
4342       the new state of the partitions. It will only be temporary
4343       attached to the handler when needed and then detached afterwards
4344       (through handler::set_part_info()). That way it will not get reused
4345       by next statement, even if the table object is reused due to LOCK TABLE.
4346     */
4347     tab_part_info = table->part_info->get_full_clone(thd);
4348     if (!tab_part_info) {
4349       mem_alloc_error(sizeof(partition_info));
4350       return true;
4351     }
4352 
4353     if (alter_info->flags & Alter_info::ALTER_TABLE_REORG) {
4354       uint new_part_no, curr_part_no;
4355       /*
4356         'ALTER TABLE t REORG PARTITION' only allowed with auto partition
4357          if default partitioning is used.
4358       */
4359 
4360       if (tab_part_info->part_type != partition_type::HASH ||
4361           ((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
4362            !tab_part_info->use_default_num_partitions) ||
4363           ((!(table->s->db_type()->partition_flags() &
4364               HA_USE_AUTO_PARTITION)) &&
4365            tab_part_info->use_default_num_partitions)) {
4366         my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
4367         goto err;
4368       }
4369       new_part_no = part_handler->get_default_num_partitions(create_info);
4370       curr_part_no = tab_part_info->num_parts;
4371       if (new_part_no == curr_part_no) {
4372         /*
4373           No change is needed, we will have the same number of partitions
4374           after the change as before. Thus we can reply ok immediately
4375           without any changes at all.
4376         */
4377         flags = part_handler->alter_flags(alter_info->flags);
4378         if (flags & HA_INPLACE_CHANGE_PARTITION) {
4379           *new_part_info = tab_part_info;
4380           /* Force table re-open for consistency with the main case. */
4381           table->m_needs_reopen = true;
4382         }
4383 
4384         thd->work_part_info = tab_part_info;
4385         return false;
4386       } else if (new_part_no > curr_part_no) {
4387         /*
4388           We will add more partitions, we use the ADD PARTITION without
4389           setting the flag for no default number of partitions
4390         */
4391         alter_info->flags |= Alter_info::ALTER_ADD_PARTITION;
4392         thd->work_part_info->num_parts = new_part_no - curr_part_no;
4393       } else {
4394         /*
4395           We will remove hash partitions, we use the COALESCE PARTITION
4396           without setting the flag for no default number of partitions
4397         */
4398         alter_info->flags |= Alter_info::ALTER_COALESCE_PARTITION;
4399         alter_info->num_parts = curr_part_no - new_part_no;
4400       }
4401     }
4402     if (!(flags = part_handler->alter_flags(alter_info->flags))) {
4403       my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
4404       goto err;
4405     }
4406     if (flags & HA_INPLACE_CHANGE_PARTITION) {
4407       /*
4408         "Inplace" change of partitioning is supported in this
4409         case. We will change TABLE::part_info (as this is how we pass
4410         information to storage engine in this case), so the table
4411         must be reopened.
4412       */
4413       *new_part_info = tab_part_info;
4414       table->m_needs_reopen = true;
4415     }
4416     DBUG_PRINT("info", ("*fast_alter_table flags: 0x%x", flags));
4417     if ((alter_info->flags & Alter_info::ALTER_ADD_PARTITION) ||
4418         (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION)) {
4419       if (thd->work_part_info->part_type != tab_part_info->part_type) {
4420         if (thd->work_part_info->part_type == partition_type::NONE) {
4421           if (tab_part_info->part_type == partition_type::RANGE) {
4422             my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
4423             goto err;
4424           } else if (tab_part_info->part_type == partition_type::LIST) {
4425             my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
4426             goto err;
4427           }
4428           /*
4429             Hash partitions can be altered without parser finds out about
4430             that it is HASH partitioned. So no error here.
4431           */
4432         } else {
4433           if (thd->work_part_info->part_type == partition_type::RANGE) {
4434             my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "RANGE",
4435                      "LESS THAN");
4436           } else if (thd->work_part_info->part_type == partition_type::LIST) {
4437             DBUG_ASSERT(thd->work_part_info->part_type == partition_type::LIST);
4438             my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN");
4439           } else if (tab_part_info->part_type == partition_type::RANGE) {
4440             my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE",
4441                      "LESS THAN");
4442           } else {
4443             DBUG_ASSERT(tab_part_info->part_type == partition_type::LIST);
4444             my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
4445           }
4446           goto err;
4447         }
4448       }
4449       if ((tab_part_info->column_list &&
4450            alt_part_info->num_columns != tab_part_info->num_columns) ||
4451           (!tab_part_info->column_list &&
4452            (tab_part_info->part_type == partition_type::RANGE ||
4453             tab_part_info->part_type == partition_type::LIST) &&
4454            alt_part_info->num_columns != 1U) ||
4455           (!tab_part_info->column_list &&
4456            tab_part_info->part_type == partition_type::HASH &&
4457            alt_part_info->num_columns != 0)) {
4458         my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
4459         goto err;
4460       }
4461       alt_part_info->column_list = tab_part_info->column_list;
4462       if (alt_part_info->fix_parser_data(thd)) {
4463         goto err;
4464       }
4465     }
4466     if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION) {
4467       /*
4468         We start by moving the new partitions to the list of temporary
4469         partitions. We will then check that the new partitions fit in the
4470         partitioning scheme as currently set-up.
4471         Partitions are always added at the end in ADD PARTITION.
4472       */
4473       uint num_new_partitions = alt_part_info->num_parts;
4474       uint num_orig_partitions = tab_part_info->num_parts;
4475       uint check_total_partitions = num_new_partitions + num_orig_partitions;
4476       uint new_total_partitions = check_total_partitions;
4477       /*
4478         We allow quite a lot of values to be supplied by defaults, however we
4479         must know the number of new partitions in this case.
4480       */
4481       if (thd->lex->no_write_to_binlog &&
4482           tab_part_info->part_type != partition_type::HASH) {
4483         my_error(ER_NO_BINLOG_ERROR, MYF(0));
4484         goto err;
4485       }
4486       if (tab_part_info->defined_max_value) {
4487         my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
4488         goto err;
4489       }
4490       if (num_new_partitions == 0) {
4491         my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
4492         goto err;
4493       }
4494       if (tab_part_info->is_sub_partitioned()) {
4495         if (alt_part_info->num_subparts == 0)
4496           alt_part_info->num_subparts = tab_part_info->num_subparts;
4497         else if (alt_part_info->num_subparts != tab_part_info->num_subparts) {
4498           my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
4499           goto err;
4500         }
4501         check_total_partitions =
4502             new_total_partitions * alt_part_info->num_subparts;
4503       }
4504       if (check_total_partitions > MAX_PARTITIONS) {
4505         my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4506         goto err;
4507       }
4508       alt_part_info->part_type = tab_part_info->part_type;
4509       alt_part_info->subpart_type = tab_part_info->subpart_type;
4510       if (alt_part_info->set_up_defaults_for_partitioning(
4511               part_handler, nullptr, tab_part_info->num_parts)) {
4512         goto err;
4513       }
4514       /*
4515       Handling of on-line cases:
4516 
4517       ADD PARTITION for RANGE/LIST PARTITIONING:
4518       ------------------------------------------
4519       For range and list partitions add partition is simply adding a
4520       new empty partition to the table. If the handler support this we
4521       will use the simple method of doing this. The figure below shows
4522       an example of this and the states involved in making this change.
4523 
4524       Existing partitions                                     New added
4525       partitions
4526       ------       ------        ------        ------      |  ------    ------
4527       |    |       |    |        |    |        |    |      |  |    |    |    |
4528       | p0 |       | p1 |        | p2 |        | p3 |      |  | p4 |    | p5 |
4529       ------       ------        ------        ------      |  ------    ------
4530       PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_TO_BE_ADDED*2
4531       PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_IS_ADDED*2
4532 
4533       The first line is the states before adding the new partitions and the
4534       second line is after the new partitions are added. All the partitions are
4535       in the partitions list, no partitions are placed in the temp_partitions
4536       list.
4537 
4538       ADD PARTITION for HASH PARTITIONING
4539       -----------------------------------
4540       This little figure tries to show the various partitions involved when
4541       adding two new partitions to a linear hash based partitioned table with
4542       four partitions to start with, which lists are used and the states they
4543       pass through. Adding partitions to a normal hash based is similar except
4544       that it is always all the existing partitions that are reorganised not
4545       only a subset of them.
4546 
4547       Existing partitions                                     New added
4548       partitions
4549       ------       ------        ------        ------      |  ------    ------
4550       |    |       |    |        |    |        |    |      |  |    |    |    |
4551       | p0 |       | p1 |        | p2 |        | p3 |      |  | p4 |    | p5 |
4552       ------       ------        ------        ------      |  ------    ------
4553       PART_CHANGED PART_CHANGED  PART_NORMAL   PART_NORMAL    PART_TO_BE_ADDED
4554       PART_IS_CHANGED*2          PART_NORMAL   PART_NORMAL    PART_IS_ADDED
4555       PART_NORMAL  PART_NORMAL   PART_NORMAL   PART_NORMAL    PART_IS_ADDED
4556 
4557       Reorganised existing partitions
4558       ------      ------
4559       |    |      |    |
4560       | p0'|      | p1'|
4561       ------      ------
4562 
4563       p0 - p5 will be in the partitions list of partitions.
4564       p0' and p1' will actually not exist as separate objects, there presence
4565       can be deduced from the state of the partition and also the names of those
4566       partitions can be deduced this way.
4567 
4568       After adding the partitions and copying the partition data to p0', p1',
4569       p4 and p5 from p0 and p1 the states change to adapt for the new situation
4570       where p0 and p1 is dropped and replaced by p0' and p1' and the new p4 and
4571       p5 are in the table again.
4572 
4573       The first line above shows the states of the partitions before we start
4574       adding and copying partitions, the second after completing the adding
4575       and copying and finally the third line after also dropping the partitions
4576       that are reorganised.
4577       */
4578       if (*new_part_info && tab_part_info->part_type == partition_type::HASH) {
4579         uint part_no = 0, start_part = 1, start_sec_part = 1;
4580         uint end_part = 0, end_sec_part = 0;
4581         uint upper_2n = tab_part_info->linear_hash_mask + 1;
4582         uint lower_2n = upper_2n >> 1;
4583         bool all_parts = true;
4584         if (tab_part_info->linear_hash_ind && num_new_partitions < upper_2n) {
4585           /*
4586             An analysis of which parts needs reorganisation shows that it is
4587             divided into two intervals. The first interval is those parts
4588             that are reorganised up until upper_2n - 1. From upper_2n and
4589             onwards it starts again from partition 0 and goes on until
4590             it reaches p(upper_2n - 1). If the last new partition reaches
4591             beyond upper_2n - 1 then the first interval will end with
4592             p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
4593             If lower_2n partitions are added then p0 to p(lower_2n - 1) will
4594             be reorganised which means that the two interval becomes one
4595             interval at this point. Thus only when adding less than
4596             lower_2n partitions and going beyond a total of upper_2n we
4597             actually get two intervals.
4598 
4599             To exemplify this assume we have 6 partitions to start with and
4600             add 1, 2, 3, 5, 6, 7, 8, 9 partitions.
4601             The first to add after p5 is p6 = 110 in bit numbers. Thus we
4602             can see that 10 = p2 will be partition to reorganise if only one
4603             partition.
4604             If 2 partitions are added we reorganise [p2, p3]. Those two
4605             cases are covered by the second if part below.
4606             If 3 partitions are added we reorganise [p2, p3] U [p0,p0]. This
4607             part is covered by the else part below.
4608             If 5 partitions are added we get [p2,p3] U [p0, p2] = [p0, p3].
4609             This is covered by the first if part where we need the max check
4610             to here use lower_2n - 1.
4611             If 7 partitions are added we get [p2,p3] U [p0, p4] = [p0, p4].
4612             This is covered by the first if part but here we use the first
4613             calculated end_part.
4614             Finally with 9 new partitions we would also reorganise p6 if we
4615             used the method below but we cannot reorganise more partitions
4616             than what we had from the start and thus we simply set all_parts
4617             to true. In this case we don't get into this if-part at all.
4618           */
4619           all_parts = false;
4620           if (num_new_partitions >= lower_2n) {
4621             /*
4622               In this case there is only one interval since the two intervals
4623               overlap and this starts from zero to last_part_no - upper_2n
4624             */
4625             start_part = 0;
4626             end_part = new_total_partitions - (upper_2n + 1);
4627             end_part = max(lower_2n - 1, end_part);
4628           } else if (new_total_partitions <= upper_2n) {
4629             /*
4630               Also in this case there is only one interval since we are not
4631               going over a 2**n boundary
4632             */
4633             start_part = num_orig_partitions - lower_2n;
4634             end_part = start_part + (num_new_partitions - 1);
4635           } else {
4636             /* We have two non-overlapping intervals since we are not
4637                passing a 2**n border and we have not at least lower_2n
4638                new parts that would ensure that the intervals become
4639                overlapping.
4640             */
4641             start_part = num_orig_partitions - lower_2n;
4642             end_part = upper_2n - 1;
4643             start_sec_part = 0;
4644             end_sec_part = new_total_partitions - (upper_2n + 1);
4645           }
4646         }
4647         List_iterator<partition_element> tab_it(tab_part_info->partitions);
4648         part_no = 0;
4649         do {
4650           partition_element *p_elem = tab_it++;
4651           if (all_parts || (part_no >= start_part && part_no <= end_part) ||
4652               (part_no >= start_sec_part && part_no <= end_sec_part)) {
4653             p_elem->part_state = PART_CHANGED;
4654           }
4655         } while (++part_no < num_orig_partitions);
4656       }
4657       /*
4658         Need to concatenate the lists here to make it possible to check the
4659         partition info for correctness using check_partition_info.
4660         For on-line add partition we set the state of this partition to
4661         PART_TO_BE_ADDED to ensure that it is known that it is not yet
4662         usable (becomes usable when partition is created and the switch of
4663         partition configuration is made.
4664       */
4665       {
4666         List_iterator<partition_element> alt_it(alt_part_info->partitions);
4667         uint part_count = 0;
4668         do {
4669           partition_element *part_elem = alt_it++;
4670           if (*new_part_info) part_elem->part_state = PART_TO_BE_ADDED;
4671           if (tab_part_info->partitions.push_back(part_elem)) {
4672             mem_alloc_error(1);
4673             goto err;
4674           }
4675         } while (++part_count < num_new_partitions);
4676         tab_part_info->num_parts += num_new_partitions;
4677       }
4678       /*
4679         If we specify partitions explicitly we don't use defaults anymore.
4680         Using ADD PARTITION also means that we don't have the default number
4681         of partitions anymore. We use this code also for Table reorganisations
4682         and here we don't set any default flags to false.
4683       */
4684       if (!(alter_info->flags & Alter_info::ALTER_TABLE_REORG)) {
4685         if (!alt_part_info->use_default_partitions) {
4686           DBUG_PRINT("info", ("part_info: %p", tab_part_info));
4687           tab_part_info->use_default_partitions = false;
4688         }
4689         tab_part_info->use_default_num_partitions = false;
4690         tab_part_info->is_auto_partitioned = false;
4691       }
4692     } else if (alter_info->flags & Alter_info::ALTER_DROP_PARTITION) {
4693       /*
4694         Drop a partition from a range partition and list partitioning is
4695         always safe and can be made more or less immediate. It is necessary
4696         however to ensure that the partition to be removed is safely removed
4697         and that REPAIR TABLE can remove the partition if for some reason the
4698         command to drop the partition failed in the middle.
4699       */
4700       uint part_count = 0;
4701       uint num_parts_dropped = alter_info->partition_names.elements;
4702       uint num_parts_found = 0;
4703       List_iterator<partition_element> part_it(tab_part_info->partitions);
4704 
4705       tab_part_info->is_auto_partitioned = false;
4706       if (!(tab_part_info->part_type == partition_type::RANGE ||
4707             tab_part_info->part_type == partition_type::LIST)) {
4708         my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
4709         goto err;
4710       }
4711       if (num_parts_dropped >= tab_part_info->num_parts) {
4712         my_error(ER_DROP_LAST_PARTITION, MYF(0));
4713         goto err;
4714       }
4715       do {
4716         partition_element *part_elem = part_it++;
4717         if (is_name_in_list(part_elem->partition_name,
4718                             alter_info->partition_names)) {
4719           /*
4720             Set state to indicate that the partition is to be dropped.
4721           */
4722           num_parts_found++;
4723           part_elem->part_state = PART_TO_BE_DROPPED;
4724         }
4725       } while (++part_count < tab_part_info->num_parts);
4726       if (num_parts_found != num_parts_dropped) {
4727         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
4728         goto err;
4729       }
4730       tab_part_info->num_parts -= num_parts_dropped;
4731     } else if (alter_info->flags & Alter_info::ALTER_REBUILD_PARTITION) {
4732       set_engine_all_partitions(tab_part_info,
4733                                 tab_part_info->default_engine_type);
4734       if (set_part_state(alter_info, tab_part_info, PART_CHANGED, false)) {
4735         my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
4736         goto err;
4737       }
4738       if (!(*new_part_info)) {
4739         table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
4740         goto err;
4741       }
4742     } else if (alter_info->flags & Alter_info::ALTER_COALESCE_PARTITION) {
4743       uint num_parts_coalesced = alter_info->num_parts;
4744       uint num_parts_remain = tab_part_info->num_parts - num_parts_coalesced;
4745       List_iterator<partition_element> part_it(tab_part_info->partitions);
4746       if (tab_part_info->part_type != partition_type::HASH) {
4747         my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
4748         goto err;
4749       }
4750       if (num_parts_coalesced == 0) {
4751         my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
4752         goto err;
4753       }
4754       if (num_parts_coalesced >= tab_part_info->num_parts) {
4755         my_error(ER_DROP_LAST_PARTITION, MYF(0));
4756         goto err;
4757       }
4758       /*
4759       Online handling:
4760       COALESCE PARTITION:
4761       -------------------
4762       The figure below shows the manner in which partitions are handled when
4763       performing an on-line coalesce partition and which states they go through
4764       at start, after adding and copying partitions and finally after dropping
4765       the partitions to drop. The figure shows an example using four partitions
4766       to start with, using linear hash and coalescing one partition (always the
4767       last partition).
4768 
4769       Using linear hash then all remaining partitions will have a new
4770       reorganised part.
4771 
4772       Existing partitions                     Coalesced partition
4773       ------       ------              ------   |      ------
4774       |    |       |    |              |    |   |      |    |
4775       | p0 |       | p1 |              | p2 |   |      | p3 |
4776       ------       ------              ------   |      ------
4777       PART_NORMAL  PART_CHANGED        PART_NORMAL     PART_REORGED_DROPPED
4778       PART_NORMAL  PART_IS_CHANGED     PART_NORMAL     PART_TO_BE_DROPPED
4779       PART_NORMAL  PART_NORMAL         PART_NORMAL     PART_IS_DROPPED
4780 
4781       Reorganised existing partitions
4782                   ------
4783                   |    |
4784                   | p1'|
4785                   ------
4786 
4787       p0 - p3 is in the partitions list.
4788       The p1' partition will actually not be in any list it is deduced from the
4789       state of p1.
4790       */
4791       {
4792         uint part_count = 0, start_part = 1, start_sec_part = 1;
4793         uint end_part = 0, end_sec_part = 0;
4794         bool all_parts = true;
4795         if (*new_part_info && tab_part_info->linear_hash_ind) {
4796           uint upper_2n = tab_part_info->linear_hash_mask + 1;
4797           uint lower_2n = upper_2n >> 1;
4798           all_parts = false;
4799           if (num_parts_coalesced >= lower_2n) {
4800             all_parts = true;
4801           } else if (num_parts_remain >= lower_2n) {
4802             end_part = tab_part_info->num_parts - (lower_2n + 1);
4803             start_part = num_parts_remain - lower_2n;
4804           } else {
4805             start_part = 0;
4806             end_part = tab_part_info->num_parts - (lower_2n + 1);
4807             end_sec_part = (lower_2n >> 1) - 1;
4808             start_sec_part = end_sec_part - (lower_2n - (num_parts_remain + 1));
4809           }
4810         }
4811         do {
4812           partition_element *p_elem = part_it++;
4813           if (*new_part_info &&
4814               (all_parts ||
4815                (part_count >= start_part && part_count <= end_part) ||
4816                (part_count >= start_sec_part && part_count <= end_sec_part)))
4817             p_elem->part_state = PART_CHANGED;
4818           if (++part_count > num_parts_remain) {
4819             if (*new_part_info)
4820               p_elem->part_state = PART_REORGED_DROPPED;
4821             else
4822               part_it.remove();
4823           }
4824         } while (part_count < tab_part_info->num_parts);
4825         tab_part_info->num_parts = num_parts_remain;
4826       }
4827       if (!(alter_info->flags & Alter_info::ALTER_TABLE_REORG)) {
4828         tab_part_info->use_default_num_partitions = false;
4829         tab_part_info->is_auto_partitioned = false;
4830       }
4831     } else if (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION) {
4832       /*
4833         Reorganise partitions takes a number of partitions that are next
4834         to each other (at least for RANGE PARTITIONS) and then uses those
4835         to create a set of new partitions. So data is copied from those
4836         partitions into the new set of partitions. Those new partitions
4837         can have more values in the LIST value specifications or less both
4838         are allowed. The ranges can be different but since they are
4839         changing a set of consecutive partitions they must cover the same
4840         range as those changed from.
4841         This command can be used on RANGE and LIST partitions.
4842       */
4843       uint num_parts_reorged = alter_info->partition_names.elements;
4844       uint num_parts_new = thd->work_part_info->partitions.elements;
4845       uint check_total_partitions;
4846 
4847       tab_part_info->is_auto_partitioned = false;
4848       if (num_parts_reorged > tab_part_info->num_parts) {
4849         my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
4850         goto err;
4851       }
4852       if (!(tab_part_info->part_type == partition_type::RANGE ||
4853             tab_part_info->part_type == partition_type::LIST) &&
4854           (num_parts_new != num_parts_reorged)) {
4855         my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
4856         goto err;
4857       }
4858       if (tab_part_info->is_sub_partitioned() && alt_part_info->num_subparts &&
4859           alt_part_info->num_subparts != tab_part_info->num_subparts) {
4860         my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
4861         goto err;
4862       }
4863       check_total_partitions = tab_part_info->num_parts + num_parts_new;
4864       check_total_partitions -= num_parts_reorged;
4865       if (check_total_partitions > MAX_PARTITIONS) {
4866         my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4867         goto err;
4868       }
4869       alt_part_info->part_type = tab_part_info->part_type;
4870       alt_part_info->subpart_type = tab_part_info->subpart_type;
4871       alt_part_info->num_subparts = tab_part_info->num_subparts;
4872       DBUG_ASSERT(!alt_part_info->use_default_partitions);
4873       /* We specified partitions explicitly so don't use defaults anymore. */
4874       tab_part_info->use_default_partitions = false;
4875       if (alt_part_info->set_up_defaults_for_partitioning(part_handler, nullptr,
4876                                                           0)) {
4877         goto err;
4878       }
4879       /*
4880       Online handling:
4881       REORGANIZE PARTITION:
4882       ---------------------
4883       The figure exemplifies the handling of partitions, their state changes and
4884       how they are organised. It exemplifies four partitions where two of the
4885       partitions are reorganised (p1 and p2) into two new partitions (p4 and
4886       p5). The reason of this change could be to change range limits, change
4887       list values or for hash partitions simply reorganise the partition which
4888       could also involve moving them to new disks or new node groups (MySQL
4889       Cluster).
4890 
4891       Existing partitions
4892       ------       ------        ------        ------
4893       |    |       |    |        |    |        |    |
4894       | p0 |       | p1 |        | p2 |        | p3 |
4895       ------       ------        ------        ------
4896       PART_NORMAL  PART_TO_BE_REORGED          PART_NORMAL
4897       PART_NORMAL  PART_TO_BE_DROPPED          PART_NORMAL
4898       PART_NORMAL  PART_IS_DROPPED             PART_NORMAL
4899 
4900       Reorganised new partitions (replacing p1 and p2)
4901       ------      ------
4902       |    |      |    |
4903       | p4 |      | p5 |
4904       ------      ------
4905       PART_TO_BE_ADDED
4906       PART_IS_ADDED
4907       PART_IS_ADDED
4908 
4909       All unchanged partitions and the new partitions are in the partitions list
4910       in the order they will have when the change is completed. The reorganised
4911       partitions are placed in the temp_partitions list. PART_IS_ADDED is only a
4912       temporary state not written in the frm file. It is used to ensure we write
4913       the generated partition syntax in a correct manner.
4914       */
4915       {
4916         List_iterator<partition_element> tab_it(tab_part_info->partitions);
4917         uint part_count = 0;
4918         bool found_first = false;
4919         bool found_last = false;
4920         uint drop_count = 0;
4921         do {
4922           partition_element *part_elem = tab_it++;
4923           is_last_partition_reorged = false;
4924           if (is_name_in_list(part_elem->partition_name,
4925                               alter_info->partition_names)) {
4926             is_last_partition_reorged = true;
4927             drop_count++;
4928             if (tab_part_info->column_list) {
4929               List_iterator<part_elem_value> p(part_elem->list_val_list);
4930               tab_max_elem_val = p++;
4931             } else
4932               tab_max_range = part_elem->range_value;
4933             if (*new_part_info &&
4934                 tab_part_info->temp_partitions.push_back(part_elem)) {
4935               mem_alloc_error(1);
4936               goto err;
4937             }
4938             if (*new_part_info) part_elem->part_state = PART_TO_BE_REORGED;
4939             if (!found_first) {
4940               uint alt_part_count = 0;
4941               partition_element *alt_part_elem;
4942               List_iterator<partition_element> alt_it(
4943                   alt_part_info->partitions);
4944               found_first = true;
4945               do {
4946                 alt_part_elem = alt_it++;
4947                 if (tab_part_info->column_list) {
4948                   List_iterator<part_elem_value> p(
4949                       alt_part_elem->list_val_list);
4950                   alt_max_elem_val = p++;
4951                 } else
4952                   alt_max_range = alt_part_elem->range_value;
4953 
4954                 if (*new_part_info)
4955                   alt_part_elem->part_state = PART_TO_BE_ADDED;
4956                 if (alt_part_count == 0)
4957                   tab_it.replace(alt_part_elem);
4958                 else
4959                   tab_it.after(alt_part_elem);
4960               } while (++alt_part_count < num_parts_new);
4961             } else if (found_last) {
4962               my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
4963               goto err;
4964             } else
4965               tab_it.remove();
4966           } else {
4967             if (found_first) found_last = true;
4968           }
4969         } while (++part_count < tab_part_info->num_parts);
4970         if (drop_count != num_parts_reorged) {
4971           my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
4972           goto err;
4973         }
4974         tab_part_info->num_parts = check_total_partitions;
4975       }
4976     } else {
4977       DBUG_ASSERT(false);
4978     }
4979     *partition_changed = true;
4980     thd->work_part_info = tab_part_info;
4981     if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION ||
4982         alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION) {
4983       if (tab_part_info->use_default_subpartitions &&
4984           !alt_part_info->use_default_subpartitions) {
4985         tab_part_info->use_default_subpartitions = false;
4986         tab_part_info->use_default_num_subpartitions = false;
4987       }
4988       if (tab_part_info->check_partition_info(thd, (handlerton **)nullptr,
4989                                               table->file, nullptr, true)) {
4990         goto err;
4991       }
4992       /*
4993         The check below needs to be performed after check_partition_info
4994         since this function "fixes" the item trees of the new partitions
4995         to reorganize into
4996       */
4997       if (alter_info->flags == Alter_info::ALTER_REORGANIZE_PARTITION &&
4998           tab_part_info->part_type == partition_type::RANGE) {
4999         bool is_error;
5000         if (is_last_partition_reorged) {
5001           if (tab_part_info->column_list) {
5002             is_error = tab_part_info->compare_column_values(
5003                 alt_max_elem_val->col_val_array,
5004                 tab_max_elem_val->col_val_array);  // a < b.
5005           } else {
5006             is_error = alt_max_range < tab_max_range;
5007           }
5008         } else {
5009           if (tab_part_info->column_list) {
5010             is_error = tab_part_info->compare_column_values(
5011                            alt_max_elem_val->col_val_array,
5012                            tab_max_elem_val->col_val_array) ||
5013                        tab_part_info->compare_column_values(
5014                            tab_max_elem_val->col_val_array,
5015                            alt_max_elem_val->col_val_array);  // a != b.
5016           } else {
5017             is_error = alt_max_range != tab_max_range;
5018           }
5019         }
5020         if (is_error) {
5021           /*
5022             For range partitioning the total resulting range before and
5023             after the change must be the same except in one case. This is
5024             when the last partition is reorganised, in this case it is
5025             acceptable to increase the total range.
5026             The reason is that it is not allowed to have "holes" in the
5027             middle of the ranges and thus we should not allow to reorganise
5028             to create "holes".
5029           */
5030           my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
5031           goto err;
5032         }
5033       }
5034     }
5035   } else {
5036     /*
5037      When thd->lex->part_info has a reference to a partition_info the
5038      ALTER TABLE contained a definition of a partitioning.
5039 
5040      Case I:
5041        If there was a partition before and there is a new one defined.
5042        We use the new partitioning. The new partitioning is already
5043        defined in the correct variable so no work is needed to
5044        accomplish this.
5045        We do however need to update partition_changed to ensure that not
5046        only the frm file is changed in the ALTER TABLE command.
5047 
5048      Case IIa:
5049        There was a partitioning before and there is no new one defined.
5050        Also the user has not specified to remove partitioning explicitly.
5051 
5052        We use the old partitioning also for the new table. We do this
5053        by assigning the partition_info from the table loaded in
5054        open_table to the partition_info struct used by mysql_create_table
5055        later in this method.
5056 
5057      Case IIb:
5058        There was a partitioning before and there is no new one defined.
5059        The user has specified explicitly to remove partitioning
5060 
5061        Since the user has specified explicitly to remove partitioning
5062        we override the old partitioning info and create a new table using
5063        the specified engine.
5064        In this case the partition also is changed.
5065 
5066      Case III:
5067        There was no partitioning before altering the table, there is
5068        partitioning defined in the altered table. Use the new partitioning.
5069        No work needed since the partitioning info is already in the
5070        correct variable.
5071 
5072        In this case we discover one case where the new partitioning is using
5073        the same partition function as the default (PARTITION BY KEY or
5074        PARTITION BY LINEAR KEY with the list of fields equal to the primary
5075        key fields OR PARTITION BY [LINEAR] KEY() for tables without primary
5076        key)
5077        Also here partition has changed and thus a new table must be
5078        created.
5079 
5080      Case IV:
5081        There was no partitioning before and no partitioning defined.
5082        Obviously no work needed.
5083     */
5084     partition_info *tab_part_info = table->part_info;
5085 
5086     if (tab_part_info) {
5087       /*
5088         The table must be reopened, this is necessary to avoid situations
5089         where a failing ALTER leaves behind a TABLE object which has its
5090         partitioning information updated by the SE, as InnoDB is doing in
5091         update_create_info().
5092       */
5093       table->m_needs_reopen = true;
5094       if (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING) {
5095         DBUG_PRINT("info", ("Remove partitioning"));
5096         if (!(create_info->used_fields & HA_CREATE_USED_ENGINE)) {
5097           DBUG_PRINT("info", ("No explicit engine used"));
5098           create_info->db_type = tab_part_info->default_engine_type;
5099         }
5100         DBUG_PRINT("info",
5101                    ("New engine type: %s",
5102                     ha_resolve_storage_engine_name(create_info->db_type)));
5103         thd->work_part_info = nullptr;
5104         *partition_changed = true;
5105       } else if (!thd->work_part_info) {
5106         /*
5107           Retain partitioning but possibly with a new storage engine
5108           beneath.
5109 
5110           Create a copy of TABLE::part_info to be able to modify it freely.
5111         */
5112         if (!(tab_part_info = tab_part_info->get_clone(thd))) return true;
5113         thd->work_part_info = tab_part_info;
5114         if (create_info->used_fields & HA_CREATE_USED_ENGINE &&
5115             create_info->db_type != tab_part_info->default_engine_type) {
5116           /*
5117             Make sure change of engine happens to all partitions.
5118           */
5119           DBUG_PRINT("info", ("partition changed"));
5120           if (tab_part_info->is_auto_partitioned) {
5121             /*
5122               If the user originally didn't specify partitioning to be
5123               used we can remove it now.
5124             */
5125             thd->work_part_info = nullptr;
5126           } else {
5127             /*
5128               Ensure that all partitions have the proper engine set-up
5129             */
5130             set_engine_all_partitions(thd->work_part_info,
5131                                       create_info->db_type);
5132           }
5133           *partition_changed = true;
5134         }
5135       }
5136     }
5137     if (thd->work_part_info) {
5138       partition_info *part_info = thd->work_part_info;
5139       bool is_native_partitioned = false;
5140       /*
5141         Need to cater for engine types that can handle partition without
5142         using the partition handler.
5143       */
5144       if (part_info != tab_part_info) {
5145         if (part_info->fix_parser_data(thd)) {
5146           goto err;
5147         }
5148         /*
5149           Compare the old and new part_info. If only key_algorithm
5150           change is done, don't consider it as changed partitioning (to avoid
5151           rebuild). This is to handle KEY (numeric_cols) partitioned tables
5152           created in 5.1. For more info, see bug#14521864.
5153         */
5154         if (alter_info->flags != Alter_info::ALTER_PARTITION ||
5155             !table->part_info ||
5156             alter_info->requested_algorithm !=
5157                 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE ||
5158             !table->part_info->has_same_partitioning(part_info)) {
5159           DBUG_PRINT("info", ("partition changed"));
5160           *partition_changed = true;
5161         }
5162       }
5163       /*
5164         Set up partition default_engine_type either from the create_info
5165         or from the previus table
5166       */
5167       if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5168         part_info->default_engine_type = create_info->db_type;
5169       else {
5170         if (tab_part_info)
5171           part_info->default_engine_type = tab_part_info->default_engine_type;
5172         else
5173           part_info->default_engine_type = create_info->db_type;
5174       }
5175       if (check_native_partitioned(create_info, &is_native_partitioned,
5176                                    part_info, thd)) {
5177         goto err;
5178       }
5179       if (!is_native_partitioned) {
5180         my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "native partitioning");
5181         goto err;
5182       }
5183     }
5184   }
5185   return false;
5186 err:
5187   *new_part_info = nullptr;
5188   return true;
5189 }
5190 
5191 /*
5192   Prepare for calling val_int on partition function by setting fields to
5193   point to the record where the values of the PF-fields are stored.
5194 
5195   SYNOPSIS
5196     set_field_ptr()
5197     ptr                 Array of fields to change ptr
5198     new_buf             New record pointer
5199     old_buf             Old record pointer
5200 
5201   DESCRIPTION
5202     Set ptr in field objects of field array to refer to new_buf record
5203     instead of previously old_buf. Used before calling val_int and after
5204     it is used to restore pointers to table->record[0].
5205     This routine is placed outside of partition code since it can be useful
5206     also for other programs.
5207 */
5208 
set_field_ptr(Field ** ptr,const uchar * new_buf,const uchar * old_buf)5209 static void set_field_ptr(Field **ptr, const uchar *new_buf,
5210                           const uchar *old_buf) {
5211   ptrdiff_t diff = (new_buf - old_buf);
5212   DBUG_TRACE;
5213 
5214   do {
5215     (*ptr)->move_field_offset(diff);
5216   } while (*(++ptr));
5217 }
5218 
5219 /**
5220   Append all fields in read_set to string
5221 
5222   @param[in,out] str   String to append to.
5223   @param[in]     row   Row to append.
5224   @param[in]     table Table containing read_set and fields for the row.
5225 */
append_row_to_str(String & str,const uchar * row,TABLE * table)5226 void append_row_to_str(String &str, const uchar *row, TABLE *table) {
5227   Field **fields, **field_ptr;
5228   const uchar *rec;
5229   uint num_fields = bitmap_bits_set(table->read_set);
5230   uint curr_field_index = 0;
5231   bool is_rec0 = !row || row == table->record[0];
5232   if (!row)
5233     rec = table->record[0];
5234   else
5235     rec = row;
5236 
5237   /* Create a new array of all read fields. */
5238   fields = (Field **)my_malloc(key_memory_handler_errmsgs,
5239                                sizeof(void *) * (num_fields + 1), MYF(0));
5240   if (!fields) return;
5241   fields[num_fields] = nullptr;
5242   for (field_ptr = table->field; *field_ptr; field_ptr++) {
5243     if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index())) continue;
5244     fields[curr_field_index++] = *field_ptr;
5245   }
5246 
5247   if (!is_rec0) set_field_ptr(fields, rec, table->record[0]);
5248 
5249   for (field_ptr = fields; *field_ptr; field_ptr++) {
5250     Field *field = *field_ptr;
5251     str.append(" ");
5252     str.append(field->field_name);
5253     str.append(":");
5254     field_unpack(&str, field, 0, false);
5255   }
5256 
5257   if (!is_rec0) set_field_ptr(fields, table->record[0], rec);
5258   my_free(fields);
5259 }
5260 
5261 /*
5262   SYNOPSIS
5263     mem_alloc_error()
5264     size                Size of memory attempted to allocate
5265     None
5266 
5267   RETURN VALUES
5268     None
5269 
5270   DESCRIPTION
5271     A routine to use for all the many places in the code where memory
5272     allocation error can happen, a tremendous amount of them, needs
5273     simple routine that signals this error.
5274 */
5275 
mem_alloc_error(size_t size)5276 void mem_alloc_error(size_t size) {
5277   my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), static_cast<int>(size));
5278 }
5279 
5280 /**
5281   Return comma-separated list of used partitions in the provided given string.
5282 
5283     @param      part_info  Partitioning info
5284     @param[out] parts      The resulting list of string to fill
5285 
5286     Generate a list of used partitions (from bits in part_info->read_partitions
5287     bitmap), and store it into the provided String object.
5288 
5289     @note
5290     The produced string must not be longer then MAX_PARTITIONS * (1 + FN_LEN).
5291     In case of UPDATE, only the partitions read is given, not the partitions
5292     that was written or locked.
5293 */
5294 
make_used_partitions_str(partition_info * part_info,List<const char> * parts)5295 bool make_used_partitions_str(partition_info *part_info,
5296                               List<const char> *parts) {
5297   parts->empty();
5298   partition_element *pe;
5299   uint partition_id = 0;
5300   List_iterator<partition_element> it(part_info->partitions);
5301   StringBuffer<FN_LEN> part_str(system_charset_info);
5302 
5303   if (part_info->is_sub_partitioned()) {
5304     partition_element *head_pe;
5305     while ((head_pe = it++)) {
5306       List_iterator<partition_element> it2(head_pe->subpartitions);
5307       while ((pe = it2++)) {
5308         if (bitmap_is_set(&part_info->read_partitions, partition_id)) {
5309           part_str.length(0);
5310           if ((part_str.append(head_pe->partition_name,
5311                                strlen(head_pe->partition_name),
5312                                system_charset_info)) ||
5313               part_str.append('_') ||
5314               part_str.append(pe->partition_name, strlen(pe->partition_name),
5315                               system_charset_info) ||
5316               parts->push_back(part_str.dup(current_thd->mem_root)))
5317             return true;
5318         }
5319         partition_id++;
5320       }
5321     }
5322   } else {
5323     while ((pe = it++)) {
5324       if (bitmap_is_set(&part_info->read_partitions, partition_id)) {
5325         part_str.length(0);
5326         if (part_str.append(pe->partition_name, strlen(pe->partition_name),
5327                             system_charset_info) ||
5328             parts->push_back(part_str.dup(current_thd->mem_root)))
5329           return true;
5330       }
5331       partition_id++;
5332     }
5333   }
5334   return false;
5335 }
5336 
5337 /****************************************************************************
5338  * Partition interval analysis support
5339  ***************************************************************************/
5340 
5341 /*
5342   Setup partition_info::* members related to partitioning range analysis
5343 
5344   SYNOPSIS
5345     set_up_partition_func_pointers()
5346       part_info  Partitioning info structure
5347 
5348   DESCRIPTION
5349     Assuming that passed partition_info structure already has correct values
5350     for members that specify [sub]partitioning type, table fields, and
5351     functions, set up partition_info::* members that are related to
5352     Partitioning Interval Analysis (see get_partitions_in_range_iter for its
5353     definition)
5354 
5355   IMPLEMENTATION
5356     There are three available interval analyzer functions:
5357     (1) get_part_iter_for_interval_via_mapping
5358     (2) get_part_iter_for_interval_cols_via_map
5359     (3) get_part_iter_for_interval_via_walking
5360 
5361     They all have limited applicability:
5362     (1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
5363     func is a monotonic function.
5364 
5365     (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
5366 
5367     (3) is applicable for
5368       "[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
5369 
5370     If both (1) and (3) are applicable, (1) is preferred over (3).
5371 
5372     This function sets part_info::get_part_iter_for_interval according to
5373     this criteria, and also sets some auxilary fields that the function
5374     uses.
5375 */
set_up_range_analysis_info(partition_info * part_info)5376 static void set_up_range_analysis_info(partition_info *part_info) {
5377   /* Set the catch-all default */
5378   part_info->get_part_iter_for_interval = nullptr;
5379   part_info->get_subpart_iter_for_interval = nullptr;
5380 
5381   /*
5382     Check if get_part_iter_for_interval_via_mapping() can be used for
5383     partitioning
5384   */
5385   switch (part_info->part_type) {
5386     case partition_type::RANGE:
5387     case partition_type::LIST:
5388       if (!part_info->column_list) {
5389         if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) {
5390           part_info->get_part_iter_for_interval =
5391               get_part_iter_for_interval_via_mapping;
5392           goto setup_subparts;
5393         }
5394       } else {
5395         part_info->get_part_iter_for_interval =
5396             get_part_iter_for_interval_cols_via_map;
5397         goto setup_subparts;
5398       }
5399     default:;
5400   }
5401 
5402   /*
5403     Check if get_part_iter_for_interval_via_walking() can be used for
5404     partitioning
5405   */
5406   if (part_info->num_part_fields == 1) {
5407     Field *field = part_info->part_field_array[0];
5408     switch (field->type()) {
5409       case MYSQL_TYPE_TINY:
5410       case MYSQL_TYPE_SHORT:
5411       case MYSQL_TYPE_INT24:
5412       case MYSQL_TYPE_LONG:
5413       case MYSQL_TYPE_LONGLONG:
5414         part_info->get_part_iter_for_interval =
5415             get_part_iter_for_interval_via_walking;
5416         break;
5417       default:;
5418     }
5419   }
5420 
5421 setup_subparts:
5422   /*
5423     Check if get_part_iter_for_interval_via_walking() can be used for
5424     subpartitioning
5425   */
5426   if (part_info->num_subpart_fields == 1) {
5427     Field *field = part_info->subpart_field_array[0];
5428     switch (field->type()) {
5429       case MYSQL_TYPE_TINY:
5430       case MYSQL_TYPE_SHORT:
5431       case MYSQL_TYPE_LONG:
5432       case MYSQL_TYPE_LONGLONG:
5433         part_info->get_subpart_iter_for_interval =
5434             get_part_iter_for_interval_via_walking;
5435         break;
5436       default:;
5437     }
5438   }
5439 }
5440 
5441 /*
5442   This function takes a memory of packed fields in opt-range format
5443   and stores it in record format. To avoid having to worry about how
5444   the length of fields are calculated in opt-range format we send
5445   an array of lengths used for each field in store_length_array.
5446 
5447   SYNOPSIS
5448   store_tuple_to_record()
5449   pfield                         Field array
5450   store_length_array             Array of field lengths
5451   value                          Memory where fields are stored
5452   value_end                      End of memory
5453 
5454   RETURN VALUE
5455   nparts                         Number of fields assigned
5456 */
store_tuple_to_record(Field ** pfield,uint32 * store_length_array,uchar * value,uchar * value_end)5457 static uint32 store_tuple_to_record(Field **pfield, uint32 *store_length_array,
5458                                     uchar *value, uchar *value_end) {
5459   /* This function is inspired by store_key_image_rec. */
5460   uint32 nparts = 0;
5461   uchar *loc_value;
5462   while (value < value_end) {
5463     loc_value = value;
5464     if ((*pfield)->is_nullable()) {
5465       if (*loc_value)
5466         (*pfield)->set_null();
5467       else
5468         (*pfield)->set_notnull();
5469       loc_value++;
5470     }
5471     uint len = (*pfield)->pack_length();
5472     (*pfield)->set_key_image(loc_value, len);
5473     value += *store_length_array;
5474     store_length_array++;
5475     nparts++;
5476     pfield++;
5477   }
5478   return nparts;
5479 }
5480 
5481 /**
5482   RANGE(columns) partitioning: compare partition value bound and probe tuple.
5483 
5484   @param val           Partition column values.
5485   @param nvals_in_rec  Number of (prefix) fields to compare.
5486 
5487   @return Less than/Equal to/Greater than 0 if the record is L/E/G than val.
5488 
5489   @note The partition value bound is always a full tuple (but may include the
5490   MAXVALUE special value). The probe tuple may be a prefix of partitioning
5491   tuple.
5492 */
5493 
cmp_rec_and_tuple(part_column_list_val * val,uint32 nvals_in_rec)5494 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec) {
5495   partition_info *part_info = val->part_info;
5496   Field **field = part_info->part_field_array;
5497   Field **fields_end = field + nvals_in_rec;
5498   int res;
5499 
5500   for (; field != fields_end; field++, val++) {
5501     if (val->max_value) return -1;
5502     if ((*field)->is_null()) {
5503       if (val->null_value) continue;
5504       return -1;
5505     }
5506     if (val->null_value) return +1;
5507     res = (*field)->cmp(val->column_value.field_image);
5508     if (res) return res;
5509   }
5510   return 0;
5511 }
5512 
5513 /**
5514   Compare record and columns partition tuple including endpoint handling.
5515 
5516   @param  val               Columns partition tuple
5517   @param  n_vals_in_rec     Number of columns to compare
5518   @param  is_left_endpoint  True if left endpoint (part_tuple < rec or
5519                             part_tuple <= rec)
5520   @param  include_endpoint  If endpoint is included (part_tuple <= rec or
5521                             rec <= part_tuple)
5522 
5523   @return Less than/Equal to/Greater than 0 if the record is L/E/G than
5524   the partition tuple.
5525 
5526   @see get_list_array_idx_for_endpoint() and
5527   get_partition_id_range_for_endpoint().
5528 */
5529 
cmp_rec_and_tuple_prune(part_column_list_val * val,uint32 n_vals_in_rec,bool is_left_endpoint,bool include_endpoint)5530 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
5531                                    uint32 n_vals_in_rec, bool is_left_endpoint,
5532                                    bool include_endpoint) {
5533   int cmp;
5534   Field **field;
5535   if ((cmp = cmp_rec_and_tuple(val, n_vals_in_rec))) return cmp;
5536   field = val->part_info->part_field_array + n_vals_in_rec;
5537   if (!(*field)) {
5538     /* Full match. Only equal if including endpoint. */
5539     if (include_endpoint) return 0;
5540 
5541     if (is_left_endpoint)
5542       return +4; /* Start of range, part_tuple < rec, return higher. */
5543     return -4;   /* End of range, rec < part_tupe, return lesser. */
5544   }
5545   /*
5546     The prefix is equal and there are more partition columns to compare.
5547 
5548     If including left endpoint or not including right endpoint
5549     then the record is considered lesser compared to the partition.
5550 
5551     i.e:
5552     part(10, x) <= rec(10, unknown) and rec(10, unknown) < part(10, x)
5553     part <= rec -> lesser (i.e. this or previous partitions)
5554     rec < part -> lesser (i.e. this or previous partitions)
5555   */
5556   if (is_left_endpoint == include_endpoint) return -2;
5557 
5558   /*
5559     If right endpoint and the first additional partition value
5560     is MAXVALUE, then the record is lesser.
5561   */
5562   if (!is_left_endpoint && (val + n_vals_in_rec)->max_value) return -3;
5563 
5564   /*
5565     Otherwise the record is considered greater.
5566 
5567     rec <= part -> greater (i.e. does not match this partition, seek higher).
5568     part < rec -> greater (i.e. does not match this partition, seek higher).
5569   */
5570   return 2;
5571 }
5572 
5573 typedef uint32 (*get_endpoint_func)(partition_info *, bool left_endpoint,
5574                                     bool include_endpoint);
5575 
5576 typedef uint32 (*get_col_endpoint_func)(partition_info *, bool left_endpoint,
5577                                         bool include_endpoint,
5578                                         uint32 num_parts);
5579 
5580 /**
5581   Get partition for RANGE COLUMNS endpoint.
5582 
5583   @param part_info         Partitioning metadata.
5584   @param is_left_endpoint     True if left endpoint (const <=/< cols)
5585   @param include_endpoint  True if range includes the endpoint (<=/>=)
5586   @param nparts            Total number of partitions
5587 
5588   @return Partition id of matching partition.
5589 
5590   @see get_partition_id_cols_list_for_endpoint and
5591   get_partition_id_range_for_endpoint.
5592 */
5593 
get_partition_id_cols_range_for_endpoint(partition_info * part_info,bool is_left_endpoint,bool include_endpoint,uint32 nparts)5594 static uint32 get_partition_id_cols_range_for_endpoint(
5595     partition_info *part_info, bool is_left_endpoint, bool include_endpoint,
5596     uint32 nparts) {
5597   uint min_part_id = 0, max_part_id = part_info->num_parts, loc_part_id;
5598   part_column_list_val *range_col_array = part_info->range_col_array;
5599   uint num_columns = part_info->part_field_list.elements;
5600   DBUG_TRACE;
5601 
5602   /* Find the matching partition (including taking endpoint into account). */
5603   do {
5604     /* Midpoint, adjusted down, so it can never be > last partition. */
5605     loc_part_id = (max_part_id + min_part_id) >> 1;
5606     if (0 <=
5607         cmp_rec_and_tuple_prune(range_col_array + loc_part_id * num_columns,
5608                                 nparts, is_left_endpoint, include_endpoint))
5609       min_part_id = loc_part_id + 1;
5610     else
5611       max_part_id = loc_part_id;
5612   } while (max_part_id > min_part_id);
5613   loc_part_id = max_part_id;
5614 
5615   /* Given value must be LESS THAN the found partition. */
5616   DBUG_ASSERT(loc_part_id == part_info->num_parts ||
5617               (0 > cmp_rec_and_tuple_prune(
5618                        range_col_array + loc_part_id * num_columns, nparts,
5619                        is_left_endpoint, include_endpoint)));
5620   /* Given value must be GREATER THAN or EQUAL to the previous partition. */
5621   DBUG_ASSERT(loc_part_id == 0 ||
5622               (0 <= cmp_rec_and_tuple_prune(
5623                         range_col_array + (loc_part_id - 1) * num_columns,
5624                         nparts, is_left_endpoint, include_endpoint)));
5625 
5626   if (!is_left_endpoint) {
5627     /* Set the end after this partition if not already after the last. */
5628     if (loc_part_id < part_info->num_parts) loc_part_id++;
5629   }
5630   return loc_part_id;
5631 }
5632 
get_part_iter_for_interval_cols_via_map(partition_info * part_info,bool,uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)5633 static int get_part_iter_for_interval_cols_via_map(
5634     partition_info *part_info, bool, uint32 *store_length_array,
5635     uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
5636     PARTITION_ITERATOR *part_iter) {
5637   uint32 nparts;
5638   get_col_endpoint_func get_col_endpoint;
5639   DBUG_TRACE;
5640 
5641   if (part_info->part_type == partition_type::RANGE) {
5642     get_col_endpoint = get_partition_id_cols_range_for_endpoint;
5643     part_iter->get_next = get_next_partition_id_range;
5644   } else if (part_info->part_type == partition_type::LIST) {
5645     get_col_endpoint = get_partition_id_cols_list_for_endpoint;
5646     part_iter->get_next = get_next_partition_id_list;
5647     part_iter->part_info = part_info;
5648     DBUG_ASSERT(part_info->num_list_values);
5649   } else {
5650     assert(0);
5651     get_col_endpoint = nullptr;
5652   }
5653 
5654   if (flags & NO_MIN_RANGE)
5655     part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5656   else {
5657     // Copy from min_value to record
5658     nparts =
5659         store_tuple_to_record(part_info->part_field_array, store_length_array,
5660                               min_value, min_value + min_len);
5661     part_iter->part_nums.start = part_iter->part_nums.cur =
5662         get_col_endpoint(part_info, true, !(flags & NEAR_MIN), nparts);
5663   }
5664   if (flags & NO_MAX_RANGE) {
5665     if (part_info->part_type == partition_type::RANGE)
5666       part_iter->part_nums.end = part_info->num_parts;
5667     else /* LIST_PARTITION */
5668     {
5669       DBUG_ASSERT(part_info->part_type == partition_type::LIST);
5670       part_iter->part_nums.end = part_info->num_list_values;
5671     }
5672   } else {
5673     // Copy from max_value to record
5674     nparts =
5675         store_tuple_to_record(part_info->part_field_array, store_length_array,
5676                               max_value, max_value + max_len);
5677     part_iter->part_nums.end =
5678         get_col_endpoint(part_info, false, !(flags & NEAR_MAX), nparts);
5679   }
5680   if (part_iter->part_nums.start == part_iter->part_nums.end) return 0;
5681   return 1;
5682 }
5683 
5684 /**
5685   Partitioning Interval Analysis: Initialize the iterator for "mapping" case
5686 
5687   @param part_info   Partition info
5688   @param is_subpart  true  - act for subpartitioning
5689                      false - act for partitioning
5690   @param store_length_array  Ignored.
5691   @param min_value   minimum field value, in opt_range key format.
5692   @param max_value   minimum field value, in opt_range key format.
5693   @param min_len     Ignored.
5694   @param max_len     Ignored.
5695   @param flags       Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
5696                      NO_MAX_RANGE.
5697   @param part_iter   Iterator structure to be initialized
5698 
5699   @details Initialize partition set iterator to walk over the interval in
5700   ordered-array-of-partitions (for RANGE partitioning) or
5701   ordered-array-of-list-constants (for LIST partitioning) space.
5702 
5703   This function is used when partitioning is done by
5704   <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
5705   t.field space into a sub-array of partition_info::range_int_array or
5706   partition_info::list_array (see get_partition_id_range_for_endpoint,
5707   get_list_array_idx_for_endpoint for details).
5708 
5709   The function performs this interval mapping, and sets the iterator to
5710   traverse the sub-array and return appropriate partitions.
5711 
5712   @return Status of iterator
5713     @retval 0   No matching partitions (iterator not initialized)
5714     @retval 1   Ok, iterator intialized for traversal of matching partitions.
5715     @retval -1  All partitions would match (iterator not initialized)
5716 */
5717 
get_part_iter_for_interval_via_mapping(partition_info * part_info,bool is_subpart MY_ATTRIBUTE ((unused)),uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)5718 static int get_part_iter_for_interval_via_mapping(
5719     partition_info *part_info, bool is_subpart MY_ATTRIBUTE((unused)),
5720     uint32 *store_length_array, /* ignored */
5721     uchar *min_value, uchar *max_value, uint min_len,
5722     uint max_len, /* ignored */
5723     uint flags, PARTITION_ITERATOR *part_iter) {
5724   Field *field = part_info->part_field_array[0];
5725   uint32 max_endpoint_val = 0;
5726   get_endpoint_func get_endpoint = nullptr;
5727   bool can_match_multiple_values; /* is not '=' */
5728   uint field_len = field->pack_length_in_rec();
5729   MYSQL_TIME start_date;
5730   bool check_zero_dates = false;
5731   bool zero_in_start_date = true;
5732   DBUG_TRACE;
5733   DBUG_ASSERT(!is_subpart);
5734   (void)store_length_array;
5735   (void)min_len;
5736   (void)max_len;
5737   part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5738 
5739   if (part_info->part_type == partition_type::RANGE) {
5740     if (part_info->part_charset_field_array)
5741       get_endpoint = get_partition_id_range_for_endpoint_charset;
5742     else
5743       get_endpoint = get_partition_id_range_for_endpoint;
5744     max_endpoint_val = part_info->num_parts;
5745     part_iter->get_next = get_next_partition_id_range;
5746   } else if (part_info->part_type == partition_type::LIST) {
5747     if (part_info->part_charset_field_array)
5748       get_endpoint = get_list_array_idx_for_endpoint_charset;
5749     else
5750       get_endpoint = get_list_array_idx_for_endpoint;
5751     max_endpoint_val = part_info->num_list_values;
5752     part_iter->get_next = get_next_partition_id_list;
5753     part_iter->part_info = part_info;
5754     if (max_endpoint_val == 0) {
5755       /*
5756         We handle this special case without optimisations since it is
5757         of little practical value but causes a great number of complex
5758         checks later in the code.
5759       */
5760       part_iter->part_nums.start = part_iter->part_nums.end = 0;
5761       part_iter->part_nums.cur = 0;
5762       part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5763       return -1;
5764     }
5765   } else
5766     MY_ASSERT_UNREACHABLE();
5767 
5768   can_match_multiple_values = (flags || !min_value || !max_value ||
5769                                memcmp(min_value, max_value, field_len));
5770   if (can_match_multiple_values &&
5771       (part_info->part_type == partition_type::RANGE ||
5772        part_info->has_null_value)) {
5773     /* Range scan on RANGE or LIST partitioned table */
5774     enum_monotonicity_info monotonic;
5775     monotonic = part_info->part_expr->get_monotonicity_info();
5776     if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
5777         monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL) {
5778       /* col is NOT NULL, but F(col) can return NULL, add NULL partition */
5779       part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5780       check_zero_dates = true;
5781     }
5782   }
5783 
5784   /*
5785     Find minimum: Do special handling if the interval has left bound in form
5786      " NULL <= X ":
5787   */
5788   if (field->is_nullable() && part_info->has_null_value &&
5789       !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value) {
5790     part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5791     part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5792     if (!(flags & NO_MAX_RANGE) && *max_value) {
5793       /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
5794       part_iter->part_nums.end = 0;
5795       return 1;
5796     }
5797   } else {
5798     if (flags & NO_MIN_RANGE)
5799       part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5800     else {
5801       /*
5802         Store the interval edge in the record buffer, and call the
5803         function that maps the edge in table-field space to an edge
5804         in ordered-set-of-partitions (for RANGE partitioning) or
5805         index-in-ordered-array-of-list-constants (for LIST) space.
5806       */
5807       store_key_image_to_rec(field, min_value, field_len);
5808       bool include_endp = !(flags & NEAR_MIN);
5809       part_iter->part_nums.start = get_endpoint(part_info, true, include_endp);
5810       if (!can_match_multiple_values && part_info->part_expr->null_value) {
5811         /* col = x and F(x) = NULL -> only search NULL partition */
5812         part_iter->part_nums.cur = part_iter->part_nums.start = 0;
5813         part_iter->part_nums.end = 0;
5814         part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5815         return 1;
5816       }
5817       part_iter->part_nums.cur = part_iter->part_nums.start;
5818       if (check_zero_dates && !part_info->part_expr->null_value) {
5819         if (!(flags & NO_MAX_RANGE) && (field->type() == MYSQL_TYPE_DATE ||
5820                                         field->type() == MYSQL_TYPE_DATETIME)) {
5821           /* Monotonic, but return NULL for dates with zeros in month/day. */
5822           zero_in_start_date = field->get_date(&start_date, 0);
5823           DBUG_PRINT("info",
5824                      ("zero start %u %04d-%02d-%02d", zero_in_start_date,
5825                       start_date.year, start_date.month, start_date.day));
5826         }
5827       }
5828       if (part_iter->part_nums.start == max_endpoint_val)
5829         return 0; /* No partitions */
5830     }
5831   }
5832 
5833   /* Find maximum, do the same as above but for right interval bound */
5834   if (flags & NO_MAX_RANGE)
5835     part_iter->part_nums.end = max_endpoint_val;
5836   else {
5837     store_key_image_to_rec(field, max_value, field_len);
5838     bool include_endp = !(flags & NEAR_MAX);
5839     part_iter->part_nums.end = get_endpoint(part_info, false, include_endp);
5840     if (check_zero_dates && !zero_in_start_date &&
5841         !part_info->part_expr->null_value) {
5842       MYSQL_TIME end_date;
5843       bool zero_in_end_date = field->get_date(&end_date, 0);
5844       /*
5845         This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
5846         the NULL partition for ranges that cannot include a date with 0 as
5847         month/day.
5848       */
5849       DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d", zero_in_end_date,
5850                           end_date.year, end_date.month, end_date.day));
5851       DBUG_ASSERT(!memcmp(((Item_func *)part_info->part_expr)->func_name(),
5852                           "to_days", 7) ||
5853                   !memcmp(((Item_func *)part_info->part_expr)->func_name(),
5854                           "to_seconds", 10));
5855       if (!zero_in_end_date && start_date.month == end_date.month &&
5856           start_date.year == end_date.year)
5857         part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5858     }
5859     if (part_iter->part_nums.start >= part_iter->part_nums.end &&
5860         !part_iter->ret_null_part)
5861       return 0; /* No partitions */
5862   }
5863   return 1; /* Ok, iterator initialized */
5864 }
5865 
5866 /* See get_part_iter_for_interval_via_walking for definition of what this is */
5867 #define MAX_RANGE_TO_WALK 32
5868 
5869 /*
5870   Partitioning Interval Analysis: Initialize iterator to walk field interval
5871 
5872   SYNOPSIS
5873     get_part_iter_for_interval_via_walking()
5874       part_info   Partition info
5875       is_subpart  true  - act for subpartitioning
5876                   false - act for partitioning
5877       min_value   minimum field value, in opt_range key format.
5878       max_value   minimum field value, in opt_range key format.
5879       flags       Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
5880                   NO_MAX_RANGE.
5881       part_iter   Iterator structure to be initialized
5882 
5883   DESCRIPTION
5884     Initialize partition set iterator to walk over interval in integer field
5885     space. That is, for "const1 <=? t.field <=? const2" interval, initialize
5886     the iterator to return a set of [sub]partitions obtained with the
5887     following procedure:
5888       get partition id for t.field = const1,   return it
5889       get partition id for t.field = const1+1, return it
5890        ...                 t.field = const1+2, ...
5891        ...                           ...       ...
5892        ...                 t.field = const2    ...
5893 
5894   IMPLEMENTATION
5895     See get_partitions_in_range_iter for general description of interval
5896     analysis. We support walking over the following intervals:
5897       "t.field IS NULL"
5898       "c1 <=? t.field <=? c2", where c1 and c2 are finite.
5899     Intervals with +inf/-inf, and [NULL, c1] interval can be processed but
5900     that is more tricky and I don't have time to do it right now.
5901 
5902   RETURN
5903     0 - No matching partitions, iterator not initialized
5904     1 - Some partitions would match, iterator intialized for traversing them
5905    -1 - All partitions would match, iterator not initialized
5906 */
5907 
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)5908 static int get_part_iter_for_interval_via_walking(
5909     partition_info *part_info, bool is_subpart,
5910     uint32 *store_length_array, /* ignored */
5911     uchar *min_value, uchar *max_value, uint min_len,
5912     uint max_len, /* ignored */
5913     uint flags, PARTITION_ITERATOR *part_iter) {
5914   Field *field;
5915   uint total_parts;
5916   partition_iter_func get_next_func;
5917   DBUG_TRACE;
5918   (void)store_length_array;
5919   (void)min_len;
5920   (void)max_len;
5921 
5922   part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5923   if (is_subpart) {
5924     field = part_info->subpart_field_array[0];
5925     total_parts = part_info->num_subparts;
5926     get_next_func = get_next_subpartition_via_walking;
5927   } else {
5928     field = part_info->part_field_array[0];
5929     total_parts = part_info->num_parts;
5930     get_next_func = get_next_partition_via_walking;
5931   }
5932 
5933   /* Handle the "t.field IS NULL" interval, it is a special case */
5934   if (field->is_nullable() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
5935       *min_value && *max_value) {
5936     /*
5937       We don't have a part_iter->get_next() function that would find which
5938       partition "t.field IS NULL" belongs to, so find partition that contains
5939       NULL right here, and return an iterator over singleton set.
5940     */
5941     uint32 part_id;
5942     field->set_null();
5943     if (is_subpart) {
5944       if (!part_info->get_subpartition_id(part_info, &part_id)) {
5945         init_single_partition_iterator(part_id, part_iter);
5946         return 1; /* Ok, iterator initialized */
5947       }
5948     } else {
5949       longlong dummy;
5950       int res =
5951           part_info->is_sub_partitioned()
5952               ? part_info->get_part_partition_id(part_info, &part_id, &dummy)
5953               : part_info->get_partition_id(part_info, &part_id, &dummy);
5954       if (!res) {
5955         init_single_partition_iterator(part_id, part_iter);
5956         return 1; /* Ok, iterator initialized */
5957       }
5958     }
5959     return 0; /* No partitions match */
5960   }
5961 
5962   if ((field->is_nullable() &&
5963        ((!(flags & NO_MIN_RANGE) && *min_value) ||    // NULL <? X
5964         (!(flags & NO_MAX_RANGE) && *max_value))) ||  // X <? NULL
5965       (flags & (NO_MIN_RANGE | NO_MAX_RANGE)))        // -inf at any bound
5966   {
5967     return -1; /* Can't handle this interval, have to use all partitions */
5968   }
5969 
5970   /* Get integers for left and right interval bound */
5971   ulonglong a, b;
5972   uint len = field->pack_length_in_rec();
5973   store_key_image_to_rec(field, min_value, len);
5974   a = field->val_int();
5975 
5976   store_key_image_to_rec(field, max_value, len);
5977   b = field->val_int();
5978 
5979   /*
5980     Handle a special case where the distance between interval bounds is
5981     exactly 4G-1. This interval is too big for range walking, and if it is an
5982     (x,y]-type interval then the following "b +=..." code will convert it to
5983     an empty interval by "wrapping around" a + 4G-1 + 1 = a.
5984   */
5985   if (b - a == ~0ULL) return -1;
5986 
5987   if (flags & NEAR_MIN) ++a;
5988   if (!(flags & NEAR_MAX)) ++b;
5989   ulonglong n_values = b - a;
5990 
5991   /*
5992     Will it pay off to enumerate all values in the [a..b] range and evaluate
5993     the partitioning function for every value? It depends on
5994      1. whether we'll be able to infer that some partitions are not used
5995      2. if time savings from not scanning these partitions will be greater
5996         than time spent in enumeration.
5997     We will assume that the cost of accessing one extra partition is greater
5998     than the cost of evaluating the partitioning function O(#partitions).
5999     This means we should jump at any chance to eliminate a partition, which
6000     gives us this logic:
6001 
6002     Do the enumeration if
6003      - the number of values to enumerate is comparable to the number of
6004        partitions, or
6005      - there are not many values to enumerate.
6006   */
6007   if ((n_values > 2 * total_parts) && n_values > MAX_RANGE_TO_WALK) return -1;
6008 
6009   part_iter->field_vals.start = part_iter->field_vals.cur = a;
6010   part_iter->field_vals.end = b;
6011   part_iter->part_info = part_info;
6012   part_iter->get_next = get_next_func;
6013   return 1;
6014 }
6015 
6016 /*
6017   PARTITION_ITERATOR::get_next implementation: enumerate partitions in range
6018 
6019   SYNOPSIS
6020     get_next_partition_id_range()
6021       part_iter  Partition set iterator structure
6022 
6023   DESCRIPTION
6024     This is implementation of PARTITION_ITERATOR::get_next() that returns
6025     [sub]partition ids in [min_partition_id, max_partition_id] range.
6026     The function conforms to partition_iter_func type.
6027 
6028   RETURN
6029     partition id
6030     NOT_A_PARTITION_ID if there are no more partitions
6031 */
6032 
get_next_partition_id_range(PARTITION_ITERATOR * part_iter)6033 uint32 get_next_partition_id_range(PARTITION_ITERATOR *part_iter) {
6034   if (part_iter->part_nums.cur >= part_iter->part_nums.end) {
6035     if (part_iter->ret_null_part) {
6036       part_iter->ret_null_part = false;
6037       return 0; /* NULL always in first range partition */
6038     }
6039     part_iter->part_nums.cur = part_iter->part_nums.start;
6040     part_iter->ret_null_part = part_iter->ret_null_part_orig;
6041     return NOT_A_PARTITION_ID;
6042   } else
6043     return part_iter->part_nums.cur++;
6044 }
6045 
6046 /*
6047   PARTITION_ITERATOR::get_next implementation for LIST partitioning
6048 
6049   SYNOPSIS
6050     get_next_partition_id_list()
6051       part_iter  Partition set iterator structure
6052 
6053   DESCRIPTION
6054     This implementation of PARTITION_ITERATOR::get_next() is special for
6055     LIST partitioning: it enumerates partition ids in
6056     part_info->list_array[i] (list_col_array[i*cols] for COLUMNS LIST
6057     partitioning) where i runs over [min_idx, max_idx] interval.
6058     The function conforms to partition_iter_func type.
6059 
6060   RETURN
6061     partition id
6062     NOT_A_PARTITION_ID if there are no more partitions
6063 */
6064 
get_next_partition_id_list(PARTITION_ITERATOR * part_iter)6065 static uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) {
6066   if (part_iter->part_nums.cur >= part_iter->part_nums.end) {
6067     if (part_iter->ret_null_part) {
6068       part_iter->ret_null_part = false;
6069       return part_iter->part_info->has_null_part_id;
6070     }
6071     part_iter->part_nums.cur = part_iter->part_nums.start;
6072     part_iter->ret_null_part = part_iter->ret_null_part_orig;
6073     return NOT_A_PARTITION_ID;
6074   } else {
6075     partition_info *part_info = part_iter->part_info;
6076     uint32 num_part = part_iter->part_nums.cur++;
6077     if (part_info->column_list) {
6078       uint num_columns = part_info->part_field_list.elements;
6079       return part_info->list_col_array[num_part * num_columns].partition_id;
6080     }
6081     return part_info->list_array[num_part].partition_id;
6082   }
6083 }
6084 
6085 /*
6086   PARTITION_ITERATOR::get_next implementation: walk over field-space interval
6087 
6088   SYNOPSIS
6089     get_next_partition_via_walking()
6090       part_iter  Partitioning iterator
6091 
6092   DESCRIPTION
6093     This implementation of PARTITION_ITERATOR::get_next() returns ids of
6094     partitions that contain records with partitioning field value within
6095     [start_val, end_val] interval.
6096     The function conforms to partition_iter_func type.
6097 
6098   RETURN
6099     partition id
6100     NOT_A_PARTITION_ID if there are no more partitioning.
6101 */
6102 
get_next_partition_via_walking(PARTITION_ITERATOR * part_iter)6103 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter) {
6104   uint32 part_id;
6105   Field *field = part_iter->part_info->part_field_array[0];
6106   while (part_iter->field_vals.cur != part_iter->field_vals.end) {
6107     longlong dummy;
6108     field->store(part_iter->field_vals.cur++,
6109                  field->is_flag_set(UNSIGNED_FLAG));
6110     if ((part_iter->part_info->is_sub_partitioned() &&
6111          !part_iter->part_info->get_part_partition_id(part_iter->part_info,
6112                                                       &part_id, &dummy)) ||
6113         !part_iter->part_info->get_partition_id(part_iter->part_info, &part_id,
6114                                                 &dummy))
6115       return part_id;
6116   }
6117   part_iter->field_vals.cur = part_iter->field_vals.start;
6118   return NOT_A_PARTITION_ID;
6119 }
6120 
6121 /* Same as get_next_partition_via_walking, but for subpartitions */
6122 
get_next_subpartition_via_walking(PARTITION_ITERATOR * part_iter)6123 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) {
6124   Field *field = part_iter->part_info->subpart_field_array[0];
6125   uint32 res;
6126   if (part_iter->field_vals.cur == part_iter->field_vals.end) {
6127     part_iter->field_vals.cur = part_iter->field_vals.start;
6128     return NOT_A_PARTITION_ID;
6129   }
6130   field->store(part_iter->field_vals.cur++, field->is_flag_set(UNSIGNED_FLAG));
6131   if (part_iter->part_info->get_subpartition_id(part_iter->part_info, &res))
6132     return NOT_A_PARTITION_ID;
6133   return res;
6134 }
6135 
get_partition_field_store_length(Field * field)6136 uint get_partition_field_store_length(Field *field) {
6137   uint store_length;
6138 
6139   store_length = field->key_length();
6140   if (field->is_nullable()) store_length += HA_KEY_NULL_LENGTH;
6141   if (field->real_type() == MYSQL_TYPE_VARCHAR)
6142     store_length += HA_KEY_BLOB_LENGTH;
6143   return store_length;
6144 }
6145