mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / sql_partition.cc
blobaa367abe22a1ed9b12d62ad49c555864bf24fc0b
1 /* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
17 This file is a container for general functionality related
18 to partitioning introduced in MySQL version 5.1. It contains functionality
19 used by all handlers that support partitioning, such as
20 the partitioning handler itself and the NDB handler.
22 The first version was written by Mikael Ronstrom.
24 This version supports RANGE partitioning, LIST partitioning, HASH
25 partitioning and composite partitioning (hereafter called subpartitioning)
26 where each RANGE/LIST partitioning is HASH partitioned. The hash function
27 can either be supplied by the user or by only a list of fields (also
28 called KEY partitioning), where the MySQL server will use an internal
29 hash function.
30 There are quite a few defaults that can be used as well.
33 /* Some general useful functions */
35 #define MYSQL_LEX 1
36 #include "mysql_priv.h"
37 #include <errno.h>
38 #include <m_ctype.h>
39 #include "my_md5.h"
41 #ifdef WITH_PARTITION_STORAGE_ENGINE
42 #include "ha_partition.h"
44 Partition related functions declarations and some static constants;
46 const LEX_STRING partition_keywords[]=
48 { C_STRING_WITH_LEN("HASH") },
49 { C_STRING_WITH_LEN("RANGE") },
50 { C_STRING_WITH_LEN("LIST") },
51 { C_STRING_WITH_LEN("KEY") },
52 { C_STRING_WITH_LEN("MAXVALUE") },
53 { C_STRING_WITH_LEN("LINEAR ") }
55 static const char *part_str= "PARTITION";
56 static const char *sub_str= "SUB";
57 static const char *by_str= "BY";
58 static const char *space_str= " ";
59 static const char *equal_str= "=";
60 static const char *end_paren_str= ")";
61 static const char *begin_paren_str= "(";
62 static const char *comma_str= ",";
64 static int get_part_id_charset_func_all(partition_info *part_info,
65 uint32 *part_id,
66 longlong *func_value);
67 static int get_part_id_charset_func_part(partition_info *part_info,
68 uint32 *part_id,
69 longlong *func_value);
70 static int get_part_id_charset_func_subpart(partition_info *part_info,
71 uint32 *part_id,
72 longlong *func_value);
73 static int get_part_part_id_charset_func(partition_info *part_info,
74 uint32 *part_id,
75 longlong *func_value);
76 static int get_subpart_id_charset_func(partition_info *part_info,
77 uint32 *part_id);
78 int get_partition_id_list(partition_info *part_info,
79 uint32 *part_id,
80 longlong *func_value);
81 int get_partition_id_range(partition_info *part_info,
82 uint32 *part_id,
83 longlong *func_value);
84 int get_partition_id_hash_nosub(partition_info *part_info,
85 uint32 *part_id,
86 longlong *func_value);
87 int get_partition_id_key_nosub(partition_info *part_info,
88 uint32 *part_id,
89 longlong *func_value);
90 int get_partition_id_linear_hash_nosub(partition_info *part_info,
91 uint32 *part_id,
92 longlong *func_value);
93 int get_partition_id_linear_key_nosub(partition_info *part_info,
94 uint32 *part_id,
95 longlong *func_value);
96 int get_partition_id_range_sub_hash(partition_info *part_info,
97 uint32 *part_id,
98 longlong *func_value);
99 int get_partition_id_range_sub_key(partition_info *part_info,
100 uint32 *part_id,
101 longlong *func_value);
102 int get_partition_id_range_sub_linear_hash(partition_info *part_info,
103 uint32 *part_id,
104 longlong *func_value);
105 int get_partition_id_range_sub_linear_key(partition_info *part_info,
106 uint32 *part_id,
107 longlong *func_value);
108 int get_partition_id_list_sub_hash(partition_info *part_info,
109 uint32 *part_id,
110 longlong *func_value);
111 int get_partition_id_list_sub_key(partition_info *part_info,
112 uint32 *part_id,
113 longlong *func_value);
114 int get_partition_id_list_sub_linear_hash(partition_info *part_info,
115 uint32 *part_id,
116 longlong *func_value);
117 int get_partition_id_list_sub_linear_key(partition_info *part_info,
118 uint32 *part_id,
119 longlong *func_value);
120 int get_partition_id_hash_sub(partition_info *part_info,
121 uint32 *part_id);
122 int get_partition_id_key_sub(partition_info *part_info,
123 uint32 *part_id);
124 int get_partition_id_linear_hash_sub(partition_info *part_info,
125 uint32 *part_id);
126 int get_partition_id_linear_key_sub(partition_info *part_info,
127 uint32 *part_id);
128 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR*);
129 static void set_up_range_analysis_info(partition_info *part_info);
130 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR*);
131 #endif
133 uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter);
134 uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter);
135 int get_part_iter_for_interval_via_mapping(partition_info *part_info,
136 bool is_subpart,
137 uchar *min_value, uchar *max_value,
138 uint flags,
139 PARTITION_ITERATOR *part_iter);
140 int get_part_iter_for_interval_via_walking(partition_info *part_info,
141 bool is_subpart,
142 uchar *min_value, uchar *max_value,
143 uint flags,
144 PARTITION_ITERATOR *part_iter);
146 #ifdef WITH_PARTITION_STORAGE_ENGINE
148 A support function to check if a name is in a list of strings
150 SYNOPSIS
151 is_name_in_list()
152 name String searched for
153 list_names A list of names searched in
155 RETURN VALUES
156 TRUE String found
157 FALSE String not found
160 bool is_name_in_list(char *name,
161 List<char> list_names)
163 List_iterator<char> names_it(list_names);
164 uint no_names= list_names.elements;
165 uint i= 0;
169 char *list_name= names_it++;
170 if (!(my_strcasecmp(system_charset_info, name, list_name)))
171 return TRUE;
172 } while (++i < no_names);
173 return FALSE;
179 Set-up defaults for partitions.
181 SYNOPSIS
182 partition_default_handling()
183 table Table object
184 part_info Partition info to set up
185 is_create_table_ind Is this part of a table creation
186 normalized_path Normalized path name of table and database
188 RETURN VALUES
189 TRUE Error
190 FALSE Success
193 bool partition_default_handling(TABLE *table, partition_info *part_info,
194 bool is_create_table_ind,
195 const char *normalized_path)
197 DBUG_ENTER("partition_default_handling");
199 if (!is_create_table_ind)
201 if (part_info->use_default_no_partitions)
203 if (table->file->get_no_parts(normalized_path, &part_info->no_parts))
205 DBUG_RETURN(TRUE);
208 else if (part_info->is_sub_partitioned() &&
209 part_info->use_default_no_subpartitions)
211 uint no_parts;
212 if (table->file->get_no_parts(normalized_path, &no_parts))
214 DBUG_RETURN(TRUE);
216 DBUG_ASSERT(part_info->no_parts > 0);
217 DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
218 part_info->no_subparts= no_parts / part_info->no_parts;
221 part_info->set_up_defaults_for_partitioning(table->file,
222 (ulonglong)0, (uint)0);
223 DBUG_RETURN(FALSE);
228 Check that the reorganized table will not have duplicate partitions.
230 SYNOPSIS
231 check_reorganise_list()
232 new_part_info New partition info
233 old_part_info Old partition info
234 list_part_names The list of partition names that will go away and
235 can be reused in the new table.
237 RETURN VALUES
238 TRUE Inacceptable name conflict detected.
239 FALSE New names are OK.
241 DESCRIPTION
242 Can handle that the 'new_part_info' and 'old_part_info' the same
243 in which case it checks that the list of names in the partitions
244 doesn't contain any duplicated names.
247 bool check_reorganise_list(partition_info *new_part_info,
248 partition_info *old_part_info,
249 List<char> list_part_names)
251 uint new_count, old_count;
252 uint no_new_parts= new_part_info->partitions.elements;
253 uint no_old_parts= old_part_info->partitions.elements;
254 List_iterator<partition_element> new_parts_it(new_part_info->partitions);
255 bool same_part_info= (new_part_info == old_part_info);
256 DBUG_ENTER("check_reorganise_list");
258 new_count= 0;
261 List_iterator<partition_element> old_parts_it(old_part_info->partitions);
262 char *new_name= (new_parts_it++)->partition_name;
263 new_count++;
264 old_count= 0;
267 char *old_name= (old_parts_it++)->partition_name;
268 old_count++;
269 if (same_part_info && old_count == new_count)
270 break;
271 if (!(my_strcasecmp(system_charset_info, old_name, new_name)))
273 if (!is_name_in_list(old_name, list_part_names))
274 DBUG_RETURN(TRUE);
276 } while (old_count < no_old_parts);
277 } while (new_count < no_new_parts);
278 DBUG_RETURN(FALSE);
283 A useful routine used by update_row for partition handlers to calculate
284 the partition ids of the old and the new record.
286 SYNOPSIS
287 get_part_for_update()
288 old_data Buffer of old record
289 new_data Buffer of new record
290 rec0 Reference to table->record[0]
291 part_info Reference to partition information
292 out:old_part_id The returned partition id of old record
293 out:new_part_id The returned partition id of new record
295 RETURN VALUE
296 0 Success
297 > 0 Error code
300 int get_parts_for_update(const uchar *old_data, uchar *new_data,
301 const uchar *rec0, partition_info *part_info,
302 uint32 *old_part_id, uint32 *new_part_id,
303 longlong *new_func_value)
305 Field **part_field_array= part_info->full_part_field_array;
306 int error;
307 longlong old_func_value;
308 DBUG_ENTER("get_parts_for_update");
310 DBUG_ASSERT(new_data == rec0);
311 set_field_ptr(part_field_array, old_data, rec0);
312 error= part_info->get_partition_id(part_info, old_part_id,
313 &old_func_value);
314 set_field_ptr(part_field_array, rec0, old_data);
315 if (unlikely(error)) // Should never happen
317 DBUG_ASSERT(0);
318 DBUG_RETURN(error);
320 #ifdef NOT_NEEDED
321 if (new_data == rec0)
322 #endif
324 if (unlikely(error= part_info->get_partition_id(part_info,
325 new_part_id,
326 new_func_value)))
328 DBUG_RETURN(error);
331 #ifdef NOT_NEEDED
332 else
335 This branch should never execute but it is written anyways for
336 future use. It will be tested by ensuring that the above
337 condition is false in one test situation before pushing the code.
339 set_field_ptr(part_field_array, new_data, rec0);
340 error= part_info->get_partition_id(part_info, new_part_id,
341 new_func_value);
342 set_field_ptr(part_field_array, rec0, new_data);
343 if (unlikely(error))
345 DBUG_RETURN(error);
348 #endif
349 DBUG_RETURN(0);
354 A useful routine used by delete_row for partition handlers to calculate
355 the partition id.
357 SYNOPSIS
358 get_part_for_delete()
359 buf Buffer of old record
360 rec0 Reference to table->record[0]
361 part_info Reference to partition information
362 out:part_id The returned partition id to delete from
364 RETURN VALUE
365 0 Success
366 > 0 Error code
368 DESCRIPTION
369 Dependent on whether buf is not record[0] we need to prepare the
370 fields. Then we call the function pointer get_partition_id to
371 calculate the partition id.
374 int get_part_for_delete(const uchar *buf, const uchar *rec0,
375 partition_info *part_info, uint32 *part_id)
377 int error;
378 longlong func_value;
379 DBUG_ENTER("get_part_for_delete");
381 if (likely(buf == rec0))
383 if (unlikely((error= part_info->get_partition_id(part_info, part_id,
384 &func_value))))
386 DBUG_RETURN(error);
388 DBUG_PRINT("info", ("Delete from partition %d", *part_id));
390 else
392 Field **part_field_array= part_info->full_part_field_array;
393 set_field_ptr(part_field_array, buf, rec0);
394 error= part_info->get_partition_id(part_info, part_id, &func_value);
395 set_field_ptr(part_field_array, rec0, buf);
396 if (unlikely(error))
398 DBUG_RETURN(error);
400 DBUG_PRINT("info", ("Delete from partition %d (path2)", *part_id));
402 DBUG_RETURN(0);
407 This method is used to set-up both partition and subpartitioning
408 field array and used for all types of partitioning.
409 It is part of the logic around fix_partition_func.
411 SYNOPSIS
412 set_up_field_array()
413 table TABLE object for which partition fields are set-up
414 sub_part Is the table subpartitioned as well
416 RETURN VALUE
417 TRUE Error, some field didn't meet requirements
418 FALSE Ok, partition field array set-up
420 DESCRIPTION
422 A great number of functions below here is part of the fix_partition_func
423 method. It is used to set up the partition structures for execution from
424 openfrm. It is called at the end of the openfrm when the table struct has
425 been set-up apart from the partition information.
426 It involves:
427 1) Setting arrays of fields for the partition functions.
428 2) Setting up binary search array for LIST partitioning
429 3) Setting up array for binary search for RANGE partitioning
430 4) Setting up key_map's to assist in quick evaluation whether one
431 can deduce anything from a given index of what partition to use
432 5) Checking whether a set of partitions can be derived from a range on
433 a field in the partition function.
434 As part of doing this there is also a great number of error controls.
435 This is actually the place where most of the things are checked for
436 partition information when creating a table.
437 Things that are checked includes
438 1) All fields of partition function in Primary keys and unique indexes
439 (if not supported)
442 Create an array of partition fields (NULL terminated). Before this method
443 is called fix_fields or find_table_in_sef has been called to set
444 GET_FIXED_FIELDS_FLAG on all fields that are part of the partition
445 function.
448 static bool set_up_field_array(TABLE *table,
449 bool is_sub_part)
451 Field **ptr, *field, **field_array;
452 uint no_fields= 0;
453 uint size_field_array;
454 uint i= 0;
455 partition_info *part_info= table->part_info;
456 int result= FALSE;
457 DBUG_ENTER("set_up_field_array");
459 ptr= table->field;
460 while ((field= *(ptr++)))
462 if (field->flags & GET_FIXED_FIELDS_FLAG)
463 no_fields++;
465 if (no_fields == 0)
468 We are using hidden key as partitioning field
470 DBUG_ASSERT(!is_sub_part);
471 DBUG_RETURN(result);
473 size_field_array= (no_fields+1)*sizeof(Field*);
474 field_array= (Field**)sql_alloc(size_field_array);
475 if (unlikely(!field_array))
477 mem_alloc_error(size_field_array);
478 result= TRUE;
480 ptr= table->field;
481 while ((field= *(ptr++)))
483 if (field->flags & GET_FIXED_FIELDS_FLAG)
485 field->flags&= ~GET_FIXED_FIELDS_FLAG;
486 field->flags|= FIELD_IN_PART_FUNC_FLAG;
487 if (likely(!result))
489 field_array[i++]= field;
492 We check that the fields are proper. It is required for each
493 field in a partition function to:
494 1) Not be a BLOB of any type
495 A BLOB takes too long time to evaluate so we don't want it for
496 performance reasons.
499 if (unlikely(field->flags & BLOB_FLAG))
501 my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
502 result= TRUE;
507 field_array[no_fields]= 0;
508 if (!is_sub_part)
510 part_info->part_field_array= field_array;
511 part_info->no_part_fields= no_fields;
513 else
515 part_info->subpart_field_array= field_array;
516 part_info->no_subpart_fields= no_fields;
518 DBUG_RETURN(result);
524 Create a field array including all fields of both the partitioning and the
525 subpartitioning functions.
527 SYNOPSIS
528 create_full_part_field_array()
529 thd Thread handle
530 table TABLE object for which partition fields are set-up
531 part_info Reference to partitioning data structure
533 RETURN VALUE
534 TRUE Memory allocation of field array failed
535 FALSE Ok
537 DESCRIPTION
538 If there is no subpartitioning then the same array is used as for the
539 partitioning. Otherwise a new array is built up using the flag
540 FIELD_IN_PART_FUNC in the field object.
541 This function is called from fix_partition_func
544 static bool create_full_part_field_array(THD *thd, TABLE *table,
545 partition_info *part_info)
547 bool result= FALSE;
548 Field **ptr;
549 my_bitmap_map *bitmap_buf;
550 DBUG_ENTER("create_full_part_field_array");
552 if (!part_info->is_sub_partitioned())
554 part_info->full_part_field_array= part_info->part_field_array;
555 part_info->no_full_part_fields= part_info->no_part_fields;
557 else
559 Field *field, **field_array;
560 uint no_part_fields=0, size_field_array;
561 ptr= table->field;
562 while ((field= *(ptr++)))
564 if (field->flags & FIELD_IN_PART_FUNC_FLAG)
565 no_part_fields++;
567 size_field_array= (no_part_fields+1)*sizeof(Field*);
568 field_array= (Field**)sql_alloc(size_field_array);
569 if (unlikely(!field_array))
571 mem_alloc_error(size_field_array);
572 result= TRUE;
573 goto end;
575 no_part_fields= 0;
576 ptr= table->field;
577 while ((field= *(ptr++)))
579 if (field->flags & FIELD_IN_PART_FUNC_FLAG)
580 field_array[no_part_fields++]= field;
582 field_array[no_part_fields]=0;
583 part_info->full_part_field_array= field_array;
584 part_info->no_full_part_fields= no_part_fields;
588 Initialize the set of all fields used in partition and subpartition
589 expression. Required for testing of partition fields in write_set
590 when updating. We need to set all bits in read_set because the row
591 may need to be inserted in a different [sub]partition.
593 if (!(bitmap_buf= (my_bitmap_map*)
594 thd->alloc(bitmap_buffer_size(table->s->fields))))
596 mem_alloc_error(bitmap_buffer_size(table->s->fields));
597 result= TRUE;
598 goto end;
600 if (bitmap_init(&part_info->full_part_field_set, bitmap_buf,
601 table->s->fields, FALSE))
603 mem_alloc_error(table->s->fields);
604 result= TRUE;
605 goto end;
608 full_part_field_array may be NULL if storage engine supports native
609 partitioning.
611 if ((ptr= part_info->full_part_field_array))
612 for (; *ptr; ptr++)
613 bitmap_set_bit(&part_info->full_part_field_set, (*ptr)->field_index);
615 end:
616 DBUG_RETURN(result);
622 Clear flag GET_FIXED_FIELDS_FLAG in all fields of a key previously set by
623 set_indicator_in_key_fields (always used in pairs).
625 SYNOPSIS
626 clear_indicator_in_key_fields()
627 key_info Reference to find the key fields
629 RETURN VALUE
630 NONE
632 DESCRIPTION
633 These support routines is used to set/reset an indicator of all fields
634 in a certain key. It is used in conjunction with another support routine
635 that traverse all fields in the PF to find if all or some fields in the
636 PF is part of the key. This is used to check primary keys and unique
637 keys involve all fields in PF (unless supported) and to derive the
638 key_map's used to quickly decide whether the index can be used to
639 derive which partitions are needed to scan.
642 static void clear_indicator_in_key_fields(KEY *key_info)
644 KEY_PART_INFO *key_part;
645 uint key_parts= key_info->key_parts, i;
646 for (i= 0, key_part=key_info->key_part; i < key_parts; i++, key_part++)
647 key_part->field->flags&= (~GET_FIXED_FIELDS_FLAG);
652 Set flag GET_FIXED_FIELDS_FLAG in all fields of a key.
654 SYNOPSIS
655 set_indicator_in_key_fields
656 key_info Reference to find the key fields
658 RETURN VALUE
659 NONE
662 static void set_indicator_in_key_fields(KEY *key_info)
664 KEY_PART_INFO *key_part;
665 uint key_parts= key_info->key_parts, i;
666 for (i= 0, key_part=key_info->key_part; i < key_parts; i++, key_part++)
667 key_part->field->flags|= GET_FIXED_FIELDS_FLAG;
672 Check if all or some fields in partition field array is part of a key
673 previously used to tag key fields.
675 SYNOPSIS
676 check_fields_in_PF()
677 ptr Partition field array
678 out:all_fields Is all fields of partition field array used in key
679 out:some_fields Is some fields of partition field array used in key
681 RETURN VALUE
682 all_fields, some_fields
685 static void check_fields_in_PF(Field **ptr, bool *all_fields,
686 bool *some_fields)
688 DBUG_ENTER("check_fields_in_PF");
690 *all_fields= TRUE;
691 *some_fields= FALSE;
692 if ((!ptr) || !(*ptr))
694 *all_fields= FALSE;
695 DBUG_VOID_RETURN;
699 /* Check if the field of the PF is part of the current key investigated */
700 if ((*ptr)->flags & GET_FIXED_FIELDS_FLAG)
701 *some_fields= TRUE;
702 else
703 *all_fields= FALSE;
704 } while (*(++ptr));
705 DBUG_VOID_RETURN;
710 Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
711 This routine is used for error handling purposes.
713 SYNOPSIS
714 clear_field_flag()
715 table TABLE object for which partition fields are set-up
717 RETURN VALUE
718 NONE
721 static void clear_field_flag(TABLE *table)
723 Field **ptr;
724 DBUG_ENTER("clear_field_flag");
726 for (ptr= table->field; *ptr; ptr++)
727 (*ptr)->flags&= (~GET_FIXED_FIELDS_FLAG);
728 DBUG_VOID_RETURN;
733 find_field_in_table_sef finds the field given its name. All fields get
734 GET_FIXED_FIELDS_FLAG set.
736 SYNOPSIS
737 handle_list_of_fields()
738 it A list of field names for the partition function
739 table TABLE object for which partition fields are set-up
740 part_info Reference to partitioning data structure
741 sub_part Is the table subpartitioned as well
743 RETURN VALUE
744 TRUE Fields in list of fields not part of table
745 FALSE All fields ok and array created
747 DESCRIPTION
748 This routine sets-up the partition field array for KEY partitioning, it
749 also verifies that all fields in the list of fields is actually a part of
750 the table.
755 static bool handle_list_of_fields(List_iterator<char> it,
756 TABLE *table,
757 partition_info *part_info,
758 bool is_sub_part)
760 Field *field;
761 bool result;
762 char *field_name;
763 bool is_list_empty= TRUE;
764 int fields_handled = 0;
765 char* field_name_array[MAX_KEY];
767 DBUG_ENTER("handle_list_of_fields");
769 while ((field_name= it++))
771 is_list_empty= FALSE;
772 field= find_field_in_table_sef(table, field_name);
773 if (likely(field != 0))
774 field->flags|= GET_FIXED_FIELDS_FLAG;
775 else
777 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
778 clear_field_flag(table);
779 result= TRUE;
780 goto end;
784 Check for duplicate fields in the list.
785 Assuming that there are not many fields in the partition key list.
786 If there were, it would be better to replace the for-loop
787 with a more efficient algorithm.
790 field_name_array[fields_handled] = field_name;
791 for (int i = 0; i < fields_handled; ++i)
793 if (my_strcasecmp(system_charset_info,
794 field_name_array[i], field_name) == 0)
796 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
797 DBUG_RETURN(TRUE);
800 fields_handled++;
802 if (is_list_empty)
804 uint primary_key= table->s->primary_key;
805 if (primary_key != MAX_KEY)
807 uint no_key_parts= table->key_info[primary_key].key_parts, i;
809 In the case of an empty list we use primary key as partition key.
811 for (i= 0; i < no_key_parts; i++)
813 Field *field= table->key_info[primary_key].key_part[i].field;
814 field->flags|= GET_FIXED_FIELDS_FLAG;
817 else
819 if (table->s->db_type()->partition_flags &&
820 (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
821 (table->s->db_type()->partition_flags() & HA_CAN_PARTITION))
824 This engine can handle automatic partitioning and there is no
825 primary key. In this case we rely on that the engine handles
826 partitioning based on a hidden key. Thus we allocate no
827 array for partitioning fields.
829 DBUG_RETURN(FALSE);
831 else
833 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
834 DBUG_RETURN(TRUE);
838 result= set_up_field_array(table, is_sub_part);
839 end:
840 DBUG_RETURN(result);
845 Support function to check if all VALUES * (expression) is of the
846 right sign (no signed constants when unsigned partition function)
848 SYNOPSIS
849 check_signed_flag()
850 part_info Partition info object
852 RETURN VALUES
853 0 No errors due to sign errors
854 >0 Sign error
857 int check_signed_flag(partition_info *part_info)
859 int error= 0;
860 uint i= 0;
861 if (part_info->part_type != HASH_PARTITION &&
862 part_info->part_expr->unsigned_flag)
864 List_iterator<partition_element> part_it(part_info->partitions);
867 partition_element *part_elem= part_it++;
869 if (part_elem->signed_flag)
871 my_error(ER_PARTITION_CONST_DOMAIN_ERROR, MYF(0));
872 error= ER_PARTITION_CONST_DOMAIN_ERROR;
873 break;
875 } while (++i < part_info->no_parts);
877 return error;
882 The function uses a new feature in fix_fields where the flag
883 GET_FIXED_FIELDS_FLAG is set for all fields in the item tree.
884 This field must always be reset before returning from the function
885 since it is used for other purposes as well.
887 SYNOPSIS
888 fix_fields_part_func()
889 thd The thread object
890 func_expr The item tree reference of the partition function
891 table The table object
892 part_info Reference to partitioning data structure
893 is_sub_part Is the table subpartitioned as well
894 is_field_to_be_setup Flag if we are to set-up field arrays
895 is_create_table_ind Indicator of whether openfrm was called as part of
896 CREATE or ALTER TABLE
898 RETURN VALUE
899 TRUE An error occurred, something was wrong with the
900 partition function.
901 FALSE Ok, a partition field array was created
903 DESCRIPTION
904 This function is used to build an array of partition fields for the
905 partitioning function and subpartitioning function. The partitioning
906 function is an item tree that must reference at least one field in the
907 table. This is checked first in the parser that the function doesn't
908 contain non-cacheable parts (like a random function) and by checking
909 here that the function isn't a constant function.
911 Calculate the number of fields in the partition function.
912 Use it allocate memory for array of Field pointers.
913 Initialise array of field pointers. Use information set when
914 calling fix_fields and reset it immediately after.
915 The get_fields_in_item_tree activates setting of bit in flags
916 on the field object.
919 static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
920 bool is_sub_part, bool is_field_to_be_setup,
921 bool is_create_table_ind)
923 partition_info *part_info= table->part_info;
924 uint dir_length, home_dir_length;
925 bool result= TRUE;
926 TABLE_LIST tables;
927 TABLE_LIST *save_table_list, *save_first_table, *save_last_table;
928 int error;
929 Name_resolution_context *context;
930 const char *save_where;
931 char* db_name;
932 char db_name_string[FN_REFLEN];
933 DBUG_ENTER("fix_fields_part_func");
935 if (part_info->fixed)
937 if (!(is_sub_part || (error= check_signed_flag(part_info))))
938 result= FALSE;
939 goto end;
943 Set-up the TABLE_LIST object to be a list with a single table
944 Set the object to zero to create NULL pointers and set alias
945 and real name to table name and get database name from file name.
946 TODO: Consider generalizing or refactoring Lex::add_table_to_list() so
947 it can be used in all places where we create TABLE_LIST objects.
948 Also consider creating appropriate constructors for TABLE_LIST.
951 bzero((void*)&tables, sizeof(TABLE_LIST));
952 tables.alias= tables.table_name= (char*) table->s->table_name.str;
953 tables.table= table;
954 tables.next_local= 0;
955 tables.next_name_resolution_table= 0;
957 Cache the table in Item_fields. All the tables can be cached except
958 the trigger pseudo table.
960 tables.cacheable_table= TRUE;
961 context= thd->lex->current_context();
962 tables.select_lex= context->select_lex;
963 strmov(db_name_string, table->s->normalized_path.str);
964 dir_length= dirname_length(db_name_string);
965 db_name_string[dir_length - 1]= 0;
966 home_dir_length= dirname_length(db_name_string);
967 db_name= &db_name_string[home_dir_length];
968 tables.db= db_name;
970 table->map= 1; //To ensure correct calculation of const item
971 table->get_fields_in_item_tree= TRUE;
972 save_table_list= context->table_list;
973 save_first_table= context->first_name_resolution_table;
974 save_last_table= context->last_name_resolution_table;
975 context->table_list= &tables;
976 context->first_name_resolution_table= &tables;
977 context->last_name_resolution_table= NULL;
978 func_expr->walk(&Item::change_context_processor, 0, (uchar*) context);
979 save_where= thd->where;
980 thd->where= "partition function";
982 In execution we must avoid the use of thd->change_item_tree since
983 we might release memory before statement is completed. We do this
984 by temporarily setting the stmt_arena->mem_root to be the mem_root
985 of the table object, this also ensures that any memory allocated
986 during fix_fields will not be released at end of execution of this
987 statement. Thus the item tree will remain valid also in subsequent
988 executions of this table object. We do however not at the moment
989 support allocations during execution of val_int so any item class
990 that does this during val_int must be disallowed as partition
991 function.
992 SEE Bug #21658
995 This is a tricky call to prepare for since it can have a large number
996 of interesting side effects, both desirable and undesirable.
1000 const bool save_use_only_table_context= thd->lex->use_only_table_context;
1001 thd->lex->use_only_table_context= TRUE;
1002 thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
1003 const bool save_agg_field= thd->lex->current_select->non_agg_field_used();
1004 const bool save_agg_func= thd->lex->current_select->agg_func_used();
1005 const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func;
1006 thd->lex->allow_sum_func= 0;
1008 error= func_expr->fix_fields(thd, (Item**)&func_expr);
1011 Restore agg_field/agg_func and allow_sum_func,
1012 fix_fields should not affect mysql_select later, see Bug#46923.
1014 thd->lex->current_select->set_non_agg_field_used(save_agg_field);
1015 thd->lex->current_select->set_agg_func_used(save_agg_func);
1016 thd->lex->allow_sum_func= saved_allow_sum_func;
1017 thd->lex->use_only_table_context= save_use_only_table_context;
1020 context->table_list= save_table_list;
1021 context->first_name_resolution_table= save_first_table;
1022 context->last_name_resolution_table= save_last_table;
1023 if (unlikely(error))
1025 DBUG_PRINT("info", ("Field in partition function not part of table"));
1026 if (is_field_to_be_setup)
1027 clear_field_flag(table);
1028 goto end;
1030 thd->where= save_where;
1031 if (unlikely(func_expr->const_item()))
1033 my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
1034 clear_field_flag(table);
1035 goto end;
1039 We don't allow creating partitions with expressions with non matching
1040 arguments as a (sub)partitioning function,
1041 but we want to allow such expressions when opening existing tables for
1042 easier maintenance. This exception should be deprecated at some point
1043 in future so that we always throw an error.
1045 if (func_expr->walk(&Item::check_valid_arguments_processor,
1046 0, NULL))
1048 if (is_create_table_ind)
1050 my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
1051 goto end;
1053 else
1054 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
1055 ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
1056 ER(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
1059 if ((!is_sub_part) && (error= check_signed_flag(part_info)))
1060 goto end;
1061 result= FALSE;
1062 if (is_field_to_be_setup)
1063 result= set_up_field_array(table, is_sub_part);
1064 if (!is_sub_part)
1065 part_info->fixed= TRUE;
1066 end:
1067 table->get_fields_in_item_tree= FALSE;
1068 table->map= 0; //Restore old value
1069 DBUG_RETURN(result);
1074 Check that the primary key contains all partition fields if defined
1076 SYNOPSIS
1077 check_primary_key()
1078 table TABLE object for which partition fields are set-up
1080 RETURN VALUES
1081 TRUE Not all fields in partitioning function was part
1082 of primary key
1083 FALSE Ok, all fields of partitioning function were part
1084 of primary key
1086 DESCRIPTION
1087 This function verifies that if there is a primary key that it contains
1088 all the fields of the partition function.
1089 This is a temporary limitation that will hopefully be removed after a
1090 while.
1093 static bool check_primary_key(TABLE *table)
1095 uint primary_key= table->s->primary_key;
1096 bool all_fields, some_fields;
1097 bool result= FALSE;
1098 DBUG_ENTER("check_primary_key");
1100 if (primary_key < MAX_KEY)
1102 set_indicator_in_key_fields(table->key_info+primary_key);
1103 check_fields_in_PF(table->part_info->full_part_field_array,
1104 &all_fields, &some_fields);
1105 clear_indicator_in_key_fields(table->key_info+primary_key);
1106 if (unlikely(!all_fields))
1108 my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF,MYF(0),"PRIMARY KEY");
1109 result= TRUE;
1112 DBUG_RETURN(result);
1117 Check that unique keys contains all partition fields
1119 SYNOPSIS
1120 check_unique_keys()
1121 table TABLE object for which partition fields are set-up
1123 RETURN VALUES
1124 TRUE Not all fields in partitioning function was part
1125 of all unique keys
1126 FALSE Ok, all fields of partitioning function were part
1127 of unique keys
1129 DESCRIPTION
1130 This function verifies that if there is a unique index that it contains
1131 all the fields of the partition function.
1132 This is a temporary limitation that will hopefully be removed after a
1133 while.
1136 static bool check_unique_keys(TABLE *table)
1138 bool all_fields, some_fields;
1139 bool result= FALSE;
1140 uint keys= table->s->keys;
1141 uint i;
1142 DBUG_ENTER("check_unique_keys");
1144 for (i= 0; i < keys; i++)
1146 if (table->key_info[i].flags & HA_NOSAME) //Unique index
1148 set_indicator_in_key_fields(table->key_info+i);
1149 check_fields_in_PF(table->part_info->full_part_field_array,
1150 &all_fields, &some_fields);
1151 clear_indicator_in_key_fields(table->key_info+i);
1152 if (unlikely(!all_fields))
1154 my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF,MYF(0),"UNIQUE INDEX");
1155 result= TRUE;
1156 break;
1160 DBUG_RETURN(result);
1165 An important optimisation is whether a range on a field can select a subset
1166 of the partitions.
1167 A prerequisite for this to happen is that the PF is a growing function OR
1168 a shrinking function.
1169 This can never happen for a multi-dimensional PF. Thus this can only happen
1170 with PF with at most one field involved in the PF.
1171 The idea is that if the function is a growing function and you know that
1172 the field of the PF is 4 <= A <= 6 then we can convert this to a range
1173 in the PF instead by setting the range to PF(4) <= PF(A) <= PF(6). In the
1174 case of RANGE PARTITIONING and LIST PARTITIONING this can be used to
1175 calculate a set of partitions rather than scanning all of them.
1176 Thus the following prerequisites are there to check if sets of partitions
1177 can be found.
1178 1) Only possible for RANGE and LIST partitioning (not for subpartitioning)
1179 2) Only possible if PF only contains 1 field
1180 3) Possible if PF is a growing function of the field
1181 4) Possible if PF is a shrinking function of the field
1182 OBSERVATION:
1183 1) IF f1(A) is a growing function AND f2(A) is a growing function THEN
1184 f1(A) + f2(A) is a growing function
1185 f1(A) * f2(A) is a growing function if f1(A) >= 0 and f2(A) >= 0
1186 2) IF f1(A) is a growing function and f2(A) is a shrinking function THEN
1187 f1(A) / f2(A) is a growing function if f1(A) >= 0 and f2(A) > 0
1188 3) IF A is a growing function then a function f(A) that removes the
1189 least significant portion of A is a growing function
1190 E.g. DATE(datetime) is a growing function
1191 MONTH(datetime) is not a growing/shrinking function
1192 4) IF f1(A) is a growing function and f2(A) is a growing function THEN
1193 f1(f2(A)) and f2(f1(A)) are also growing functions
1194 5) IF f1(A) is a shrinking function and f2(A) is a growing function THEN
1195 f1(f2(A)) is a shrinking function and f2(f1(A)) is a shrinking function
1196 6) f1(A) = A is a growing function
1197 7) f1(A) = A*a + b (where a and b are constants) is a growing function
1199 By analysing the item tree of the PF we can use these deducements and
1200 derive whether the PF is a growing function or a shrinking function or
1201 neither of it.
1203 If the PF is range capable then a flag is set on the table object
1204 indicating this to notify that we can use also ranges on the field
1205 of the PF to deduce a set of partitions if the fields of the PF were
1206 not all fully bound.
1208 SYNOPSIS
1209 check_range_capable_PF()
1210 table TABLE object for which partition fields are set-up
1212 DESCRIPTION
1213 Support for this is not implemented yet.
1216 void check_range_capable_PF(TABLE *table)
1218 DBUG_ENTER("check_range_capable_PF");
1220 DBUG_VOID_RETURN;
1225 Set up partition bitmap
1227 SYNOPSIS
1228 set_up_partition_bitmap()
1229 thd Thread object
1230 part_info Reference to partitioning data structure
1232 RETURN VALUE
1233 TRUE Memory allocation failure
1234 FALSE Success
1236 DESCRIPTION
1237 Allocate memory for bitmap of the partitioned table
1238 and initialise it.
1241 static bool set_up_partition_bitmap(THD *thd, partition_info *part_info)
1243 uint32 *bitmap_buf;
1244 uint bitmap_bits= part_info->no_subparts?
1245 (part_info->no_subparts* part_info->no_parts):
1246 part_info->no_parts;
1247 uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
1248 DBUG_ENTER("set_up_partition_bitmap");
1250 if (!(bitmap_buf= (uint32*)thd->alloc(bitmap_bytes)))
1252 mem_alloc_error(bitmap_bytes);
1253 DBUG_RETURN(TRUE);
1255 bitmap_init(&part_info->used_partitions, bitmap_buf, bitmap_bytes*8, FALSE);
1256 bitmap_set_all(&part_info->used_partitions);
1257 DBUG_RETURN(FALSE);
1262 Set up partition key maps
1264 SYNOPSIS
1265 set_up_partition_key_maps()
1266 table TABLE object for which partition fields are set-up
1267 part_info Reference to partitioning data structure
1269 RETURN VALUES
1270 None
1272 DESCRIPTION
1273 This function sets up a couple of key maps to be able to quickly check
1274 if an index ever can be used to deduce the partition fields or even
1275 a part of the fields of the partition function.
1276 We set up the following key_map's.
1277 PF = Partition Function
1278 1) All fields of the PF is set even by equal on the first fields in the
1280 2) All fields of the PF is set if all fields of the key is set
1281 3) At least one field in the PF is set if all fields is set
1282 4) At least one field in the PF is part of the key
1285 static void set_up_partition_key_maps(TABLE *table,
1286 partition_info *part_info)
1288 uint keys= table->s->keys;
1289 uint i;
1290 bool all_fields, some_fields;
1291 DBUG_ENTER("set_up_partition_key_maps");
1293 part_info->all_fields_in_PF.clear_all();
1294 part_info->all_fields_in_PPF.clear_all();
1295 part_info->all_fields_in_SPF.clear_all();
1296 part_info->some_fields_in_PF.clear_all();
1297 for (i= 0; i < keys; i++)
1299 set_indicator_in_key_fields(table->key_info+i);
1300 check_fields_in_PF(part_info->full_part_field_array,
1301 &all_fields, &some_fields);
1302 if (all_fields)
1303 part_info->all_fields_in_PF.set_bit(i);
1304 if (some_fields)
1305 part_info->some_fields_in_PF.set_bit(i);
1306 if (part_info->is_sub_partitioned())
1308 check_fields_in_PF(part_info->part_field_array,
1309 &all_fields, &some_fields);
1310 if (all_fields)
1311 part_info->all_fields_in_PPF.set_bit(i);
1312 check_fields_in_PF(part_info->subpart_field_array,
1313 &all_fields, &some_fields);
1314 if (all_fields)
1315 part_info->all_fields_in_SPF.set_bit(i);
1317 clear_indicator_in_key_fields(table->key_info+i);
1319 DBUG_VOID_RETURN;
1324 Set up function pointers for partition function
1326 SYNOPSIS
1327 set_up_partition_func_pointers()
1328 part_info Reference to partitioning data structure
1330 RETURN VALUE
1331 NONE
1333 DESCRIPTION
1334 Set-up all function pointers for calculation of partition id,
1335 subpartition id and the upper part in subpartitioning. This is to speed up
1336 execution of get_partition_id which is executed once every record to be
1337 written and deleted and twice for updates.
1340 static void set_up_partition_func_pointers(partition_info *part_info)
1342 DBUG_ENTER("set_up_partition_func_pointers");
1344 if (part_info->is_sub_partitioned())
1346 if (part_info->part_type == RANGE_PARTITION)
1348 part_info->get_part_partition_id= get_partition_id_range;
1349 if (part_info->list_of_subpart_fields)
1351 if (part_info->linear_hash_ind)
1353 part_info->get_partition_id= get_partition_id_range_sub_linear_key;
1354 part_info->get_subpartition_id= get_partition_id_linear_key_sub;
1356 else
1358 part_info->get_partition_id= get_partition_id_range_sub_key;
1359 part_info->get_subpartition_id= get_partition_id_key_sub;
1362 else
1364 if (part_info->linear_hash_ind)
1366 part_info->get_partition_id= get_partition_id_range_sub_linear_hash;
1367 part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
1369 else
1371 part_info->get_partition_id= get_partition_id_range_sub_hash;
1372 part_info->get_subpartition_id= get_partition_id_hash_sub;
1376 else /* LIST Partitioning */
1378 part_info->get_part_partition_id= get_partition_id_list;
1379 if (part_info->list_of_subpart_fields)
1381 if (part_info->linear_hash_ind)
1383 part_info->get_partition_id= get_partition_id_list_sub_linear_key;
1384 part_info->get_subpartition_id= get_partition_id_linear_key_sub;
1386 else
1388 part_info->get_partition_id= get_partition_id_list_sub_key;
1389 part_info->get_subpartition_id= get_partition_id_key_sub;
1392 else
1394 if (part_info->linear_hash_ind)
1396 part_info->get_partition_id= get_partition_id_list_sub_linear_hash;
1397 part_info->get_subpartition_id= get_partition_id_linear_hash_sub;
1399 else
1401 part_info->get_partition_id= get_partition_id_list_sub_hash;
1402 part_info->get_subpartition_id= get_partition_id_hash_sub;
1407 else /* No subpartitioning */
1409 part_info->get_part_partition_id= NULL;
1410 part_info->get_subpartition_id= NULL;
1411 if (part_info->part_type == RANGE_PARTITION)
1412 part_info->get_partition_id= get_partition_id_range;
1413 else if (part_info->part_type == LIST_PARTITION)
1414 part_info->get_partition_id= get_partition_id_list;
1415 else /* HASH partitioning */
1417 if (part_info->list_of_part_fields)
1419 if (part_info->linear_hash_ind)
1420 part_info->get_partition_id= get_partition_id_linear_key_nosub;
1421 else
1422 part_info->get_partition_id= get_partition_id_key_nosub;
1424 else
1426 if (part_info->linear_hash_ind)
1427 part_info->get_partition_id= get_partition_id_linear_hash_nosub;
1428 else
1429 part_info->get_partition_id= get_partition_id_hash_nosub;
1433 if (part_info->full_part_charset_field_array)
1435 DBUG_ASSERT(part_info->get_partition_id);
1436 part_info->get_partition_id_charset= part_info->get_partition_id;
1437 if (part_info->part_charset_field_array &&
1438 part_info->subpart_charset_field_array)
1439 part_info->get_partition_id= get_part_id_charset_func_all;
1440 else if (part_info->part_charset_field_array)
1441 part_info->get_partition_id= get_part_id_charset_func_part;
1442 else
1443 part_info->get_partition_id= get_part_id_charset_func_subpart;
1445 if (part_info->part_charset_field_array &&
1446 part_info->is_sub_partitioned())
1448 DBUG_ASSERT(part_info->get_part_partition_id);
1449 part_info->get_part_partition_id_charset=
1450 part_info->get_part_partition_id;
1451 part_info->get_part_partition_id= get_part_part_id_charset_func;
1453 if (part_info->subpart_charset_field_array)
1455 DBUG_ASSERT(part_info->get_subpartition_id);
1456 part_info->get_subpartition_id_charset=
1457 part_info->get_subpartition_id;
1458 part_info->get_subpartition_id= get_subpart_id_charset_func;
1460 DBUG_VOID_RETURN;
1465 For linear hashing we need a mask which is on the form 2**n - 1 where
1466 2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
1468 SYNOPSIS
1469 set_linear_hash_mask()
1470 part_info Reference to partitioning data structure
1471 no_parts Number of parts in linear hash partitioning
1473 RETURN VALUE
1474 NONE
1477 void set_linear_hash_mask(partition_info *part_info, uint no_parts)
1479 uint mask;
1481 for (mask= 1; mask < no_parts; mask<<=1)
1483 part_info->linear_hash_mask= mask - 1;
1488 This function calculates the partition id provided the result of the hash
1489 function using linear hashing parameters, mask and number of partitions.
1491 SYNOPSIS
1492 get_part_id_from_linear_hash()
1493 hash_value Hash value calculated by HASH function or KEY function
1494 mask Mask calculated previously by set_linear_hash_mask
1495 no_parts Number of partitions in HASH partitioned part
1497 RETURN VALUE
1498 part_id The calculated partition identity (starting at 0)
1500 DESCRIPTION
1501 The partition is calculated according to the theory of linear hashing.
1502 See e.g. Linear hashing: a new tool for file and table addressing,
1503 Reprinted from VLDB-80 in Readings Database Systems, 2nd ed, M. Stonebraker
1504 (ed.), Morgan Kaufmann 1994.
1507 static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
1508 uint no_parts)
1510 uint32 part_id= (uint32)(hash_value & mask);
1512 if (part_id >= no_parts)
1514 uint new_mask= ((mask + 1) >> 1) - 1;
1515 part_id= (uint32)(hash_value & new_mask);
1517 return part_id;
1522 Check if a particular field is in need of character set
1523 handling for partition functions.
1525 SYNOPSIS
1526 field_is_partition_charset()
1527 field The field to check
1529 RETURN VALUES
1530 FALSE Not in need of character set handling
1531 TRUE In need of character set handling
1534 bool field_is_partition_charset(Field *field)
1536 if (!(field->type() == MYSQL_TYPE_STRING) &&
1537 !(field->type() == MYSQL_TYPE_VARCHAR))
1538 return FALSE;
1540 CHARSET_INFO *cs= ((Field_str*)field)->charset();
1541 if (!(field->type() == MYSQL_TYPE_STRING) ||
1542 !(cs->state & MY_CS_BINSORT))
1543 return TRUE;
1544 return FALSE;
1550 Check that partition function doesn't contain any forbidden
1551 character sets and collations.
1553 SYNOPSIS
1554 check_part_func_fields()
1555 ptr Array of Field pointers
1556 ok_with_charsets Will we report allowed charset
1557 fields as ok
1558 RETURN VALUES
1559 FALSE Success
1560 TRUE Error
1562 DESCRIPTION
1563 We will check in this routine that the fields of the partition functions
1564 do not contain unallowed parts. It can also be used to check if there
1565 are fields that require special care by calling my_strnxfrm before
1566 calling the functions to calculate partition id.
1569 bool check_part_func_fields(Field **ptr, bool ok_with_charsets)
1571 Field *field;
1572 DBUG_ENTER("check_part_func_fields");
1574 while ((field= *(ptr++)))
1577 For CHAR/VARCHAR fields we need to take special precautions.
1578 Binary collation with CHAR is automatically supported. Other
1579 types need some kind of standardisation function handling
1581 if (field_is_partition_charset(field))
1583 CHARSET_INFO *cs= ((Field_str*)field)->charset();
1584 if (!ok_with_charsets ||
1585 cs->mbmaxlen > 1 ||
1586 cs->strxfrm_multiply > 1)
1588 DBUG_RETURN(TRUE);
1592 DBUG_RETURN(FALSE);
1597 fix partition functions
1599 SYNOPSIS
1600 fix_partition_func()
1601 thd The thread object
1602 table TABLE object for which partition fields are set-up
1603 is_create_table_ind Indicator of whether openfrm was called as part of
1604 CREATE or ALTER TABLE
1606 RETURN VALUE
1607 TRUE Error
1608 FALSE Success
1610 DESCRIPTION
1611 The name parameter contains the full table name and is used to get the
1612 database name of the table which is used to set-up a correct
1613 TABLE_LIST object for use in fix_fields.
1615 NOTES
1616 This function is called as part of opening the table by opening the .frm
1617 file. It is a part of CREATE TABLE to do this so it is quite permissible
1618 that errors due to erroneus syntax isn't found until we come here.
1619 If the user has used a non-existing field in the table is one such example
1620 of an error that is not discovered until here.
1623 bool fix_partition_func(THD *thd, TABLE *table,
1624 bool is_create_table_ind)
1626 bool result= TRUE;
1627 partition_info *part_info= table->part_info;
1628 enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
1629 DBUG_ENTER("fix_partition_func");
1631 if (part_info->fixed)
1633 DBUG_RETURN(FALSE);
1635 thd->mark_used_columns= MARK_COLUMNS_NONE;
1636 DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
1638 if (!is_create_table_ind ||
1639 thd->lex->sql_command != SQLCOM_CREATE_TABLE)
1641 if (partition_default_handling(table, part_info,
1642 is_create_table_ind,
1643 table->s->normalized_path.str))
1645 DBUG_RETURN(TRUE);
1648 if (part_info->is_sub_partitioned())
1650 DBUG_ASSERT(part_info->subpart_type == HASH_PARTITION);
1652 Subpartition is defined. We need to verify that subpartitioning
1653 function is correct.
1655 if (part_info->linear_hash_ind)
1656 set_linear_hash_mask(part_info, part_info->no_subparts);
1657 if (part_info->list_of_subpart_fields)
1659 List_iterator<char> it(part_info->subpart_field_list);
1660 if (unlikely(handle_list_of_fields(it, table, part_info, TRUE)))
1661 goto end;
1663 else
1665 if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr,
1666 table, TRUE, TRUE,
1667 is_create_table_ind)))
1668 goto end;
1669 if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT))
1671 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0),
1672 "SUBPARTITION");
1673 goto end;
1677 DBUG_ASSERT(part_info->part_type != NOT_A_PARTITION);
1679 Partition is defined. We need to verify that partitioning
1680 function is correct.
1682 if (part_info->part_type == HASH_PARTITION)
1684 if (part_info->linear_hash_ind)
1685 set_linear_hash_mask(part_info, part_info->no_parts);
1686 if (part_info->list_of_part_fields)
1688 List_iterator<char> it(part_info->part_field_list);
1689 if (unlikely(handle_list_of_fields(it, table, part_info, FALSE)))
1690 goto end;
1692 else
1694 if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
1695 table, FALSE, TRUE,
1696 is_create_table_ind)))
1697 goto end;
1698 if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
1700 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
1701 goto end;
1703 part_info->part_result_type= INT_RESULT;
1706 else
1708 const char *error_str;
1709 if (unlikely(fix_fields_part_func(thd, part_info->part_expr,
1710 table, FALSE, TRUE,
1711 is_create_table_ind)))
1712 goto end;
1713 if (part_info->part_type == RANGE_PARTITION)
1715 error_str= partition_keywords[PKW_RANGE].str;
1716 if (unlikely(part_info->check_range_constants()))
1717 goto end;
1719 else if (part_info->part_type == LIST_PARTITION)
1721 error_str= partition_keywords[PKW_LIST].str;
1722 if (unlikely(part_info->check_list_constants()))
1723 goto end;
1725 else
1727 DBUG_ASSERT(0);
1728 my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
1729 goto end;
1731 if (unlikely(part_info->no_parts < 1))
1733 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
1734 goto end;
1736 if (unlikely(part_info->part_expr->result_type() != INT_RESULT))
1738 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str);
1739 goto end;
1742 if (((part_info->part_type != HASH_PARTITION ||
1743 part_info->list_of_part_fields == FALSE) &&
1744 check_part_func_fields(part_info->part_field_array, TRUE)) ||
1745 (part_info->list_of_subpart_fields == FALSE &&
1746 part_info->is_sub_partitioned() &&
1747 check_part_func_fields(part_info->subpart_field_array, TRUE)))
1749 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1750 goto end;
1752 if (unlikely(create_full_part_field_array(thd, table, part_info)))
1753 goto end;
1754 if (unlikely(check_primary_key(table)))
1755 goto end;
1756 if (unlikely((!(table->s->db_type()->partition_flags &&
1757 (table->s->db_type()->partition_flags() & HA_CAN_PARTITION_UNIQUE))) &&
1758 check_unique_keys(table)))
1759 goto end;
1760 if (unlikely(set_up_partition_bitmap(thd, part_info)))
1761 goto end;
1762 if (unlikely(part_info->set_up_charset_field_preps()))
1764 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1765 goto end;
1767 check_range_capable_PF(table);
1768 set_up_partition_key_maps(table, part_info);
1769 set_up_partition_func_pointers(part_info);
1770 set_up_range_analysis_info(part_info);
1771 result= FALSE;
1772 end:
1773 thd->mark_used_columns= save_mark_used_columns;
1774 DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
1775 DBUG_RETURN(result);
1780 The code below is support routines for the reverse parsing of the
1781 partitioning syntax. This feature is very useful to generate syntax for
1782 all default values to avoid all default checking when opening the frm
1783 file. It is also used when altering the partitioning by use of various
1784 ALTER TABLE commands. Finally it is used for SHOW CREATE TABLES.
1787 static int add_write(File fptr, const char *buf, uint len)
1789 uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0));
1791 if (likely(len == len_written))
1792 return 0;
1793 else
1794 return 1;
1797 static int add_string_object(File fptr, String *string)
1799 return add_write(fptr, string->ptr(), string->length());
1802 static int add_string(File fptr, const char *string)
1804 return add_write(fptr, string, strlen(string));
1807 static int add_string_len(File fptr, const char *string, uint len)
1809 return add_write(fptr, string, len);
1812 static int add_space(File fptr)
1814 return add_string(fptr, space_str);
1817 static int add_comma(File fptr)
1819 return add_string(fptr, comma_str);
1822 static int add_equal(File fptr)
1824 return add_string(fptr, equal_str);
1827 static int add_end_parenthesis(File fptr)
1829 return add_string(fptr, end_paren_str);
1832 static int add_begin_parenthesis(File fptr)
1834 return add_string(fptr, begin_paren_str);
1837 static int add_part_key_word(File fptr, const char *key_string)
1839 int err= add_string(fptr, key_string);
1841 err+= add_space(fptr);
1842 return err + add_begin_parenthesis(fptr);
1845 static int add_hash(File fptr)
1847 return add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
1850 static int add_partition(File fptr)
1852 char buff[22];
1853 strxmov(buff, part_str, space_str, NullS);
1854 return add_string(fptr, buff);
1857 static int add_subpartition(File fptr)
1859 int err= add_string(fptr, sub_str);
1861 return err + add_partition(fptr);
1864 static int add_partition_by(File fptr)
1866 char buff[22];
1867 strxmov(buff, part_str, space_str, by_str, space_str, NullS);
1868 return add_string(fptr, buff);
1871 static int add_subpartition_by(File fptr)
1873 int err= add_string(fptr, sub_str);
1875 return err + add_partition_by(fptr);
1878 static int add_key_partition(File fptr, List<char> field_list)
1880 uint i, no_fields;
1881 int err;
1883 List_iterator<char> part_it(field_list);
1884 err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
1885 no_fields= field_list.elements;
1886 i= 0;
1887 while (i < no_fields)
1889 const char *field_str= part_it++;
1890 String field_string("", 0, system_charset_info);
1891 THD *thd= current_thd;
1892 ulonglong save_options= thd->options;
1893 thd->options= 0;
1894 append_identifier(thd, &field_string, field_str,
1895 strlen(field_str));
1896 thd->options= save_options;
1897 err+= add_string_object(fptr, &field_string);
1898 if (i != (no_fields-1))
1899 err+= add_comma(fptr);
1900 i++;
1902 return err;
1905 static int add_name_string(File fptr, const char *name)
1907 int err;
1908 String name_string("", 0, system_charset_info);
1909 THD *thd= current_thd;
1910 ulonglong save_options= thd->options;
1912 thd->options= 0;
1913 append_identifier(thd, &name_string, name,
1914 strlen(name));
1915 thd->options= save_options;
1916 err= add_string_object(fptr, &name_string);
1917 return err;
1920 static int add_int(File fptr, longlong number)
1922 char buff[32];
1923 llstr(number, buff);
1924 return add_string(fptr, buff);
1927 static int add_uint(File fptr, ulonglong number)
1929 char buff[32];
1930 longlong2str(number, buff, 10);
1931 return add_string(fptr, buff);
1935 Must escape strings in partitioned tables frm-files,
1936 parsing it later with mysql_unpack_partition will fail otherwise.
1938 static int add_quoted_string(File fptr, const char *quotestr)
1940 String orgstr(quotestr, system_charset_info);
1941 String escapedstr;
1942 int err= add_string(fptr, "'");
1943 err+= append_escaped(&escapedstr, &orgstr);
1944 err+= add_string(fptr, escapedstr.c_ptr_safe());
1945 return err + add_string(fptr, "'");
1948 static int add_keyword_string(File fptr, const char *keyword,
1949 bool should_use_quotes,
1950 const char *keystr)
1952 int err= add_string(fptr, keyword);
1954 err+= add_space(fptr);
1955 err+= add_equal(fptr);
1956 err+= add_space(fptr);
1957 if (should_use_quotes)
1958 err+= add_quoted_string(fptr, keystr);
1959 else
1960 err+= add_string(fptr, keystr);
1961 return err + add_space(fptr);
1964 static int add_keyword_int(File fptr, const char *keyword, longlong num)
1966 int err= add_string(fptr, keyword);
1968 err+= add_space(fptr);
1969 err+= add_equal(fptr);
1970 err+= add_space(fptr);
1971 err+= add_int(fptr, num);
1972 return err + add_space(fptr);
1975 static int add_engine(File fptr, handlerton *engine_type)
1977 const char *engine_str= ha_resolve_storage_engine_name(engine_type);
1978 DBUG_PRINT("info", ("ENGINE: %s", engine_str));
1979 int err= add_string(fptr, "ENGINE = ");
1980 return err + add_string(fptr, engine_str);
1983 static int add_partition_options(File fptr, partition_element *p_elem)
1985 int err= 0;
1987 err+= add_space(fptr);
1988 if (p_elem->tablespace_name)
1989 err+= add_keyword_string(fptr,"TABLESPACE", FALSE,
1990 p_elem->tablespace_name);
1991 if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
1992 err+= add_keyword_int(fptr,"NODEGROUP",(longlong)p_elem->nodegroup_id);
1993 if (p_elem->part_max_rows)
1994 err+= add_keyword_int(fptr,"MAX_ROWS",(longlong)p_elem->part_max_rows);
1995 if (p_elem->part_min_rows)
1996 err+= add_keyword_int(fptr,"MIN_ROWS",(longlong)p_elem->part_min_rows);
1997 if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
1999 if (p_elem->data_file_name)
2000 err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE,
2001 p_elem->data_file_name);
2002 if (p_elem->index_file_name)
2003 err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE,
2004 p_elem->index_file_name);
2006 if (p_elem->part_comment)
2007 err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment);
2008 return err + add_engine(fptr,p_elem->engine_type);
2011 static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem)
2013 int err= 0;
2015 if (part_info->part_type == RANGE_PARTITION)
2017 err+= add_string(fptr, " VALUES LESS THAN ");
2018 if (!p_elem->max_value)
2020 err+= add_begin_parenthesis(fptr);
2021 if (p_elem->signed_flag)
2022 err+= add_int(fptr, p_elem->range_value);
2023 else
2024 err+= add_uint(fptr, p_elem->range_value);
2025 err+= add_end_parenthesis(fptr);
2027 else
2028 err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
2030 else if (part_info->part_type == LIST_PARTITION)
2032 uint i;
2033 List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2034 err+= add_string(fptr, " VALUES IN ");
2035 uint no_items= p_elem->list_val_list.elements;
2037 err+= add_begin_parenthesis(fptr);
2038 if (p_elem->has_null_value)
2040 err+= add_string(fptr, "NULL");
2041 if (no_items == 0)
2043 err+= add_end_parenthesis(fptr);
2044 goto end;
2046 err+= add_comma(fptr);
2048 i= 0;
2051 part_elem_value *list_value= list_val_it++;
2053 if (!list_value->unsigned_flag)
2054 err+= add_int(fptr, list_value->value);
2055 else
2056 err+= add_uint(fptr, list_value->value);
2057 if (i != (no_items-1))
2058 err+= add_comma(fptr);
2059 } while (++i < no_items);
2060 err+= add_end_parenthesis(fptr);
2062 end:
2063 return err;
2067 Generate the partition syntax from the partition data structure.
2068 Useful for support of generating defaults, SHOW CREATE TABLES
2069 and easy partition management.
2071 SYNOPSIS
2072 generate_partition_syntax()
2073 part_info The partitioning data structure
2074 buf_length A pointer to the returned buffer length
2075 use_sql_alloc Allocate buffer from sql_alloc if true
2076 otherwise use my_malloc
2077 show_partition_options Should we display partition options
2079 RETURN VALUES
2080 NULL error
2081 buf, buf_length Buffer and its length
2083 DESCRIPTION
2084 Here we will generate the full syntax for the given command where all
2085 defaults have been expanded. By so doing the it is also possible to
2086 make lots of checks of correctness while at it.
2087 This could will also be reused for SHOW CREATE TABLES and also for all
2088 type ALTER TABLE commands focusing on changing the PARTITION structure
2089 in any fashion.
2091 The implementation writes the syntax to a temporary file (essentially
2092 an abstraction of a dynamic array) and if all writes goes well it
2093 allocates a buffer and writes the syntax into this one and returns it.
2095 As a security precaution the file is deleted before writing into it. This
2096 means that no other processes on the machine can open and read the file
2097 while this processing is ongoing.
2099 The code is optimised for minimal code size since it is not used in any
2100 common queries.
2103 char *generate_partition_syntax(partition_info *part_info,
2104 uint *buf_length,
2105 bool use_sql_alloc,
2106 bool show_partition_options)
2108 uint i,j, tot_no_parts, no_subparts;
2109 partition_element *part_elem;
2110 ulonglong buffer_length;
2111 char path[FN_REFLEN];
2112 int err= 0;
2113 List_iterator<partition_element> part_it(part_info->partitions);
2114 File fptr;
2115 char *buf= NULL; //Return buffer
2116 DBUG_ENTER("generate_partition_syntax");
2118 if (unlikely(((fptr= create_temp_file(path,mysql_tmpdir,"psy",
2119 O_RDWR | O_BINARY | O_TRUNC |
2120 O_TEMPORARY, MYF(MY_WME)))) < 0))
2121 DBUG_RETURN(NULL);
2122 #ifndef __WIN__
2123 unlink(path);
2124 #endif
2125 err+= add_space(fptr);
2126 err+= add_partition_by(fptr);
2127 switch (part_info->part_type)
2129 case RANGE_PARTITION:
2130 err+= add_part_key_word(fptr, partition_keywords[PKW_RANGE].str);
2131 break;
2132 case LIST_PARTITION:
2133 err+= add_part_key_word(fptr, partition_keywords[PKW_LIST].str);
2134 break;
2135 case HASH_PARTITION:
2136 if (part_info->linear_hash_ind)
2137 err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
2138 if (part_info->list_of_part_fields)
2139 err+= add_key_partition(fptr, part_info->part_field_list);
2140 else
2141 err+= add_hash(fptr);
2142 break;
2143 default:
2144 DBUG_ASSERT(0);
2145 /* We really shouldn't get here, no use in continuing from here */
2146 my_error(ER_OUT_OF_RESOURCES, MYF(0));
2147 current_thd->fatal_error();
2148 DBUG_RETURN(NULL);
2150 if (part_info->part_expr)
2151 err+= add_string_len(fptr, part_info->part_func_string,
2152 part_info->part_func_len);
2153 err+= add_end_parenthesis(fptr);
2154 if ((!part_info->use_default_no_partitions) &&
2155 part_info->use_default_partitions)
2157 err+= add_string(fptr, "\n");
2158 err+= add_string(fptr, "PARTITIONS ");
2159 err+= add_int(fptr, part_info->no_parts);
2161 if (part_info->is_sub_partitioned())
2163 err+= add_string(fptr, "\n");
2164 err+= add_subpartition_by(fptr);
2165 /* Must be hash partitioning for subpartitioning */
2166 if (part_info->linear_hash_ind)
2167 err+= add_string(fptr, partition_keywords[PKW_LINEAR].str);
2168 if (part_info->list_of_subpart_fields)
2169 err+= add_key_partition(fptr, part_info->subpart_field_list);
2170 else
2171 err+= add_hash(fptr);
2172 if (part_info->subpart_expr)
2173 err+= add_string_len(fptr, part_info->subpart_func_string,
2174 part_info->subpart_func_len);
2175 err+= add_end_parenthesis(fptr);
2176 if ((!part_info->use_default_no_subpartitions) &&
2177 part_info->use_default_subpartitions)
2179 err+= add_string(fptr, "\n");
2180 err+= add_string(fptr, "SUBPARTITIONS ");
2181 err+= add_int(fptr, part_info->no_subparts);
2184 tot_no_parts= part_info->partitions.elements;
2185 no_subparts= part_info->no_subparts;
2187 if (!part_info->use_default_partitions)
2189 bool first= TRUE;
2190 err+= add_string(fptr, "\n");
2191 err+= add_begin_parenthesis(fptr);
2192 i= 0;
2195 part_elem= part_it++;
2196 if (part_elem->part_state != PART_TO_BE_DROPPED &&
2197 part_elem->part_state != PART_REORGED_DROPPED)
2199 if (!first)
2201 err+= add_comma(fptr);
2202 err+= add_string(fptr, "\n");
2203 err+= add_space(fptr);
2205 first= FALSE;
2206 err+= add_partition(fptr);
2207 err+= add_name_string(fptr, part_elem->partition_name);
2208 err+= add_partition_values(fptr, part_info, part_elem);
2209 if (!part_info->is_sub_partitioned() ||
2210 part_info->use_default_subpartitions)
2212 if (show_partition_options)
2213 err+= add_partition_options(fptr, part_elem);
2215 else
2217 err+= add_string(fptr, "\n");
2218 err+= add_space(fptr);
2219 err+= add_begin_parenthesis(fptr);
2220 List_iterator<partition_element> sub_it(part_elem->subpartitions);
2221 j= 0;
2224 part_elem= sub_it++;
2225 err+= add_subpartition(fptr);
2226 err+= add_name_string(fptr, part_elem->partition_name);
2227 if (show_partition_options)
2228 err+= add_partition_options(fptr, part_elem);
2229 if (j != (no_subparts-1))
2231 err+= add_comma(fptr);
2232 err+= add_string(fptr, "\n");
2233 err+= add_space(fptr);
2234 err+= add_space(fptr);
2236 else
2237 err+= add_end_parenthesis(fptr);
2238 } while (++j < no_subparts);
2241 if (i == (tot_no_parts-1))
2242 err+= add_end_parenthesis(fptr);
2243 } while (++i < tot_no_parts);
2245 if (err)
2246 goto close_file;
2247 buffer_length= my_seek(fptr, 0L,MY_SEEK_END,MYF(0));
2248 if (unlikely(buffer_length == MY_FILEPOS_ERROR))
2249 goto close_file;
2250 if (unlikely(my_seek(fptr, 0L, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR))
2251 goto close_file;
2252 *buf_length= (uint)buffer_length;
2253 if (use_sql_alloc)
2254 buf= (char*) sql_alloc(*buf_length+1);
2255 else
2256 buf= (char*) my_malloc(*buf_length+1, MYF(MY_WME));
2257 if (!buf)
2258 goto close_file;
2260 if (unlikely(my_read(fptr, (uchar*)buf, *buf_length, MYF(MY_FNABP))))
2262 if (!use_sql_alloc)
2263 my_free(buf, MYF(0));
2264 else
2265 buf= NULL;
2267 else
2268 buf[*buf_length]= 0;
2270 close_file:
2271 my_close(fptr, MYF(0));
2272 DBUG_RETURN(buf);
2277 Check if partition key fields are modified and if it can be handled by the
2278 underlying storage engine.
2280 SYNOPSIS
2281 partition_key_modified
2282 table TABLE object for which partition fields are set-up
2283 fields Bitmap representing fields to be modified
2285 RETURN VALUES
2286 TRUE Need special handling of UPDATE
2287 FALSE Normal UPDATE handling is ok
2290 bool partition_key_modified(TABLE *table, const MY_BITMAP *fields)
2292 Field **fld;
2293 partition_info *part_info= table->part_info;
2294 DBUG_ENTER("partition_key_modified");
2296 if (!part_info)
2297 DBUG_RETURN(FALSE);
2298 if (table->s->db_type()->partition_flags &&
2299 (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
2300 DBUG_RETURN(FALSE);
2301 for (fld= part_info->full_part_field_array; *fld; fld++)
2302 if (bitmap_is_set(fields, (*fld)->field_index))
2303 DBUG_RETURN(TRUE);
2304 DBUG_RETURN(FALSE);
2309 A function to handle correct handling of NULL values in partition
2310 functions.
2311 SYNOPSIS
2312 part_val_int()
2313 item_expr The item expression to evaluate
2314 out:result The value of the partition function,
2315 LONGLONG_MIN if any null value in function
2316 RETURN VALUES
2317 TRUE Error in val_int()
2318 FALSE ok
2321 static inline int part_val_int(Item *item_expr, longlong *result)
2323 *result= item_expr->val_int();
2324 if (item_expr->null_value)
2326 if (current_thd->is_error())
2327 return TRUE;
2328 else
2329 *result= LONGLONG_MIN;
2331 return FALSE;
2336 The next set of functions are used to calculate the partition identity.
2337 A handler sets up a variable that corresponds to one of these functions
2338 to be able to quickly call it whenever the partition id needs to calculated
2339 based on the record in table->record[0] (or set up to fake that).
2340 There are 4 functions for hash partitioning and 2 for RANGE/LIST partitions.
2341 In addition there are 4 variants for RANGE subpartitioning and 4 variants
2342 for LIST subpartitioning thus in total there are 14 variants of this
2343 function.
2345 We have a set of support functions for these 14 variants. There are 4
2346 variants of hash functions and there is a function for each. The KEY
2347 partitioning uses the function calculate_key_value to calculate the hash
2348 value based on an array of fields. The linear hash variants uses the
2349 method get_part_id_from_linear_hash to get the partition id using the
2350 hash value and some parameters calculated from the number of partitions.
2354 Calculate hash value for KEY partitioning using an array of fields.
2356 SYNOPSIS
2357 calculate_key_value()
2358 field_array An array of the fields in KEY partitioning
2360 RETURN VALUE
2361 hash_value calculated
2363 DESCRIPTION
2364 Uses the hash function on the character set of the field. Integer and
2365 floating point fields use the binary character set by default.
2368 static uint32 calculate_key_value(Field **field_array)
2370 ulong nr1= 1;
2371 ulong nr2= 4;
2375 Field *field= *field_array;
2376 field->hash(&nr1, &nr2);
2377 } while (*(++field_array));
2378 return (uint32) nr1;
2383 A simple support function to calculate part_id given local part and
2384 sub part.
2386 SYNOPSIS
2387 get_part_id_for_sub()
2388 loc_part_id Local partition id
2389 sub_part_id Subpartition id
2390 no_subparts Number of subparts
2393 inline
2394 static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
2395 uint no_subparts)
2397 return (uint32)((loc_part_id * no_subparts) + sub_part_id);
2402 Calculate part_id for (SUB)PARTITION BY HASH
2404 SYNOPSIS
2405 get_part_id_hash()
2406 no_parts Number of hash partitions
2407 part_expr Item tree of hash function
2408 out:part_id The returned partition id
2409 out:func_value Value of hash function
2411 RETURN VALUE
2412 != 0 Error code
2413 FALSE Success
2416 static int get_part_id_hash(uint no_parts,
2417 Item *part_expr,
2418 uint32 *part_id,
2419 longlong *func_value)
2421 longlong int_hash_id;
2422 DBUG_ENTER("get_part_id_hash");
2424 if (part_val_int(part_expr, func_value))
2425 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2427 int_hash_id= *func_value % no_parts;
2429 *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id;
2430 DBUG_RETURN(FALSE);
2435 Calculate part_id for (SUB)PARTITION BY LINEAR HASH
2437 SYNOPSIS
2438 get_part_id_linear_hash()
2439 part_info A reference to the partition_info struct where all the
2440 desired information is given
2441 no_parts Number of hash partitions
2442 part_expr Item tree of hash function
2443 out:part_id The returned partition id
2444 out:func_value Value of hash function
2446 RETURN VALUE
2447 != 0 Error code
2448 0 OK
2451 static int get_part_id_linear_hash(partition_info *part_info,
2452 uint no_parts,
2453 Item *part_expr,
2454 uint32 *part_id,
2455 longlong *func_value)
2457 DBUG_ENTER("get_part_id_linear_hash");
2459 if (part_val_int(part_expr, func_value))
2460 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2462 *part_id= get_part_id_from_linear_hash(*func_value,
2463 part_info->linear_hash_mask,
2464 no_parts);
2465 DBUG_RETURN(FALSE);
2470 Calculate part_id for (SUB)PARTITION BY KEY
2472 SYNOPSIS
2473 get_part_id_key()
2474 field_array Array of fields for PARTTION KEY
2475 no_parts Number of KEY partitions
2477 RETURN VALUE
2478 Calculated partition id
2481 inline
2482 static uint32 get_part_id_key(Field **field_array,
2483 uint no_parts,
2484 longlong *func_value)
2486 DBUG_ENTER("get_part_id_key");
2487 *func_value= calculate_key_value(field_array);
2488 DBUG_RETURN((uint32) (*func_value % no_parts));
2493 Calculate part_id for (SUB)PARTITION BY LINEAR KEY
2495 SYNOPSIS
2496 get_part_id_linear_key()
2497 part_info A reference to the partition_info struct where all the
2498 desired information is given
2499 field_array Array of fields for PARTTION KEY
2500 no_parts Number of KEY partitions
2502 RETURN VALUE
2503 Calculated partition id
2506 inline
2507 static uint32 get_part_id_linear_key(partition_info *part_info,
2508 Field **field_array,
2509 uint no_parts,
2510 longlong *func_value)
2512 DBUG_ENTER("get_partition_id_linear_key");
2514 *func_value= calculate_key_value(field_array);
2515 DBUG_RETURN(get_part_id_from_linear_hash(*func_value,
2516 part_info->linear_hash_mask,
2517 no_parts));
2521 Copy to field buffers and set up field pointers
2523 SYNOPSIS
2524 copy_to_part_field_buffers()
2525 ptr Array of fields to copy
2526 field_bufs Array of field buffers to copy to
2527 restore_ptr Array of pointers to restore to
2529 RETURN VALUES
2530 NONE
2531 DESCRIPTION
2532 This routine is used to take the data from field pointer, convert
2533 it to a standard format and store this format in a field buffer
2534 allocated for this purpose. Next the field pointers are moved to
2535 point to the field buffers. There is a separate to restore the
2536 field pointers after this call.
2539 static void copy_to_part_field_buffers(Field **ptr,
2540 uchar **field_bufs,
2541 uchar **restore_ptr)
2543 Field *field;
2544 while ((field= *(ptr++)))
2546 *restore_ptr= field->ptr;
2547 restore_ptr++;
2548 if (!field->maybe_null() || !field->is_null())
2550 CHARSET_INFO *cs= ((Field_str*)field)->charset();
2551 uint len= field->pack_length();
2552 uchar *field_buf= *field_bufs;
2554 We only use the field buffer for VARCHAR and CHAR strings
2555 which isn't of a binary collation. We also only use the
2556 field buffer for fields which are not currently NULL.
2557 The field buffer will store a normalised string. We use
2558 the strnxfrm method to normalise the string.
2560 if (field->type() == MYSQL_TYPE_VARCHAR)
2562 uint len_bytes= ((Field_varstring*)field)->length_bytes;
2563 my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes),
2564 field->ptr + len_bytes, field->field_length);
2565 if (len_bytes == 1)
2566 *field_buf= (uchar) field->field_length;
2567 else
2568 int2store(field_buf, field->field_length);
2570 else
2572 my_strnxfrm(cs, field_buf, len,
2573 field->ptr, field->field_length);
2575 field->ptr= field_buf;
2577 field_bufs++;
2579 return;
2583 Restore field pointers
2584 SYNOPSIS
2585 restore_part_field_pointers()
2586 ptr Array of fields to restore
2587 restore_ptr Array of field pointers to restore to
2589 RETURN VALUES
2592 static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr)
2594 Field *field;
2595 while ((field= *(ptr++)))
2597 field->ptr= *restore_ptr;
2598 restore_ptr++;
2600 return;
2605 This function is used to calculate the main partition to use in the case of
2606 subpartitioning and we don't know enough to get the partition identity in
2607 total.
2609 SYNOPSIS
2610 get_part_partition_id()
2611 part_info A reference to the partition_info struct where all the
2612 desired information is given
2613 out:part_id The partition id is returned through this pointer
2614 out:func_value The value calculated by partition function
2616 RETURN VALUE
2617 HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
2618 fit into any partition and thus the values of
2619 the PF-fields are not allowed.
2620 0 OK
2622 DESCRIPTION
2624 It is actually 6 different variants of this function which are called
2625 through a function pointer.
2627 get_partition_id_list
2628 get_partition_id_range
2629 get_partition_id_hash_nosub
2630 get_partition_id_key_nosub
2631 get_partition_id_linear_hash_nosub
2632 get_partition_id_linear_key_nosub
2635 static int get_part_id_charset_func_subpart(partition_info *part_info,
2636 uint32 *part_id,
2637 longlong *func_value)
2639 int res;
2640 copy_to_part_field_buffers(part_info->subpart_charset_field_array,
2641 part_info->subpart_field_buffers,
2642 part_info->restore_subpart_field_ptrs);
2643 res= part_info->get_partition_id_charset(part_info, part_id, func_value);
2644 restore_part_field_pointers(part_info->subpart_charset_field_array,
2645 part_info->restore_subpart_field_ptrs);
2646 return res;
2650 static int get_part_id_charset_func_part(partition_info *part_info,
2651 uint32 *part_id,
2652 longlong *func_value)
2654 int res;
2655 copy_to_part_field_buffers(part_info->part_charset_field_array,
2656 part_info->part_field_buffers,
2657 part_info->restore_part_field_ptrs);
2658 res= part_info->get_partition_id_charset(part_info, part_id, func_value);
2659 restore_part_field_pointers(part_info->part_charset_field_array,
2660 part_info->restore_part_field_ptrs);
2661 return res;
2665 static int get_part_id_charset_func_all(partition_info *part_info,
2666 uint32 *part_id,
2667 longlong *func_value)
2669 int res;
2670 copy_to_part_field_buffers(part_info->full_part_field_array,
2671 part_info->full_part_field_buffers,
2672 part_info->restore_full_part_field_ptrs);
2673 res= part_info->get_partition_id_charset(part_info, part_id, func_value);
2674 restore_part_field_pointers(part_info->full_part_field_array,
2675 part_info->restore_full_part_field_ptrs);
2676 return res;
2680 static int get_part_part_id_charset_func(partition_info *part_info,
2681 uint32 *part_id,
2682 longlong *func_value)
2684 int res;
2685 copy_to_part_field_buffers(part_info->part_charset_field_array,
2686 part_info->part_field_buffers,
2687 part_info->restore_part_field_ptrs);
2688 res= part_info->get_part_partition_id_charset(part_info,
2689 part_id, func_value);
2690 restore_part_field_pointers(part_info->part_charset_field_array,
2691 part_info->restore_part_field_ptrs);
2692 return res;
2696 static int get_subpart_id_charset_func(partition_info *part_info,
2697 uint32 *part_id)
2699 int res;
2700 copy_to_part_field_buffers(part_info->subpart_charset_field_array,
2701 part_info->subpart_field_buffers,
2702 part_info->restore_subpart_field_ptrs);
2703 res= part_info->get_subpartition_id_charset(part_info, part_id);
2704 restore_part_field_pointers(part_info->subpart_charset_field_array,
2705 part_info->restore_subpart_field_ptrs);
2706 return res;
2710 int get_partition_id_list(partition_info *part_info,
2711 uint32 *part_id,
2712 longlong *func_value)
2714 LIST_PART_ENTRY *list_array= part_info->list_array;
2715 int list_index;
2716 int min_list_index= 0;
2717 int max_list_index= part_info->no_list_values - 1;
2718 longlong part_func_value;
2719 int error= part_val_int(part_info->part_expr, &part_func_value);
2720 longlong list_value;
2721 bool unsigned_flag= part_info->part_expr->unsigned_flag;
2722 DBUG_ENTER("get_partition_id_list");
2724 if (error)
2725 goto notfound;
2727 if (part_info->part_expr->null_value)
2729 if (part_info->has_null_value)
2731 *part_id= part_info->has_null_part_id;
2732 DBUG_RETURN(0);
2734 goto notfound;
2736 *func_value= part_func_value;
2737 if (unsigned_flag)
2738 part_func_value-= 0x8000000000000000ULL;
2739 while (max_list_index >= min_list_index)
2741 list_index= (max_list_index + min_list_index) >> 1;
2742 list_value= list_array[list_index].list_value;
2743 if (list_value < part_func_value)
2744 min_list_index= list_index + 1;
2745 else if (list_value > part_func_value)
2747 if (!list_index)
2748 goto notfound;
2749 max_list_index= list_index - 1;
2751 else
2753 *part_id= (uint32)list_array[list_index].partition_id;
2754 DBUG_RETURN(0);
2757 notfound:
2758 *part_id= 0;
2759 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2764 Find the sub-array part_info->list_array that corresponds to given interval
2766 SYNOPSIS
2767 get_list_array_idx_for_endpoint()
2768 part_info Partitioning info (partitioning type must be LIST)
2769 left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
2770 FALSE - the interval is (-inf; a] or (-inf; a)
2771 include_endpoint TRUE iff the interval includes the endpoint
2773 DESCRIPTION
2774 This function finds the sub-array of part_info->list_array where values of
2775 list_array[idx].list_value are contained within the specifed interval.
2776 list_array is ordered by list_value, so
2777 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
2778 sought sub-array starts at some index idx and continues till array end.
2779 The function returns first number idx, such that
2780 list_array[idx].list_value is contained within the passed interval.
2782 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
2783 sought sub-array starts at array start and continues till some last
2784 index idx.
2785 The function returns first number idx, such that
2786 list_array[idx].list_value is NOT contained within the passed interval.
2787 If all array elements are contained, part_info->no_list_values is
2788 returned.
2790 NOTE
2791 The caller will call this function and then will run along the sub-array of
2792 list_array to collect partition ids. If the number of list values is
2793 significantly higher then number of partitions, this could be slow and
2794 we could invent some other approach. The "run over list array" part is
2795 already wrapped in a get_next()-like function.
2797 RETURN
2798 The edge of corresponding sub-array of part_info->list_array
2801 uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
2802 bool left_endpoint,
2803 bool include_endpoint)
2805 uint32 res;
2806 copy_to_part_field_buffers(part_info->part_field_array,
2807 part_info->part_field_buffers,
2808 part_info->restore_part_field_ptrs);
2809 res= get_list_array_idx_for_endpoint(part_info, left_endpoint,
2810 include_endpoint);
2811 restore_part_field_pointers(part_info->part_field_array,
2812 part_info->restore_part_field_ptrs);
2813 return res;
2816 uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
2817 bool left_endpoint,
2818 bool include_endpoint)
2820 LIST_PART_ENTRY *list_array= part_info->list_array;
2821 uint list_index;
2822 uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
2823 longlong list_value;
2824 /* Get the partitioning function value for the endpoint */
2825 longlong part_func_value=
2826 part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
2827 bool unsigned_flag= part_info->part_expr->unsigned_flag;
2828 DBUG_ENTER("get_list_array_idx_for_endpoint");
2830 if (part_info->part_expr->null_value)
2833 Special handling for MONOTONIC functions that can return NULL for
2834 values that are comparable. I.e.
2835 '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
2836 returns NULL which cannot be compared used <, >, <=, >= etc.
2838 Otherwise, just return the the first index (lowest value).
2840 enum_monotonicity_info monotonic;
2841 monotonic= part_info->part_expr->get_monotonicity_info();
2842 if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
2843 monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL)
2845 /* F(col) can not return NULL, return index with lowest value */
2846 DBUG_RETURN(0);
2850 if (unsigned_flag)
2851 part_func_value-= 0x8000000000000000ULL;
2852 DBUG_ASSERT(part_info->no_list_values);
2855 list_index= (max_list_index + min_list_index) >> 1;
2856 list_value= list_array[list_index].list_value;
2857 if (list_value < part_func_value)
2858 min_list_index= list_index + 1;
2859 else if (list_value > part_func_value)
2861 if (!list_index)
2862 goto notfound;
2863 max_list_index= list_index - 1;
2865 else
2867 DBUG_RETURN(list_index + test(left_endpoint ^ include_endpoint));
2869 } while (max_list_index >= min_list_index);
2870 notfound:
2871 if (list_value < part_func_value)
2872 list_index++;
2873 DBUG_RETURN(list_index);
2877 int get_partition_id_range(partition_info *part_info,
2878 uint32 *part_id,
2879 longlong *func_value)
2881 longlong *range_array= part_info->range_int_array;
2882 uint max_partition= part_info->no_parts - 1;
2883 uint min_part_id= 0;
2884 uint max_part_id= max_partition;
2885 uint loc_part_id;
2886 longlong part_func_value;
2887 int error= part_val_int(part_info->part_expr, &part_func_value);
2888 bool unsigned_flag= part_info->part_expr->unsigned_flag;
2889 DBUG_ENTER("get_partition_id_range");
2891 if (error)
2892 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2894 if (part_info->part_expr->null_value)
2896 *part_id= 0;
2897 DBUG_RETURN(0);
2899 *func_value= part_func_value;
2900 if (unsigned_flag)
2901 part_func_value-= 0x8000000000000000ULL;
2902 /* Search for the partition containing part_func_value */
2903 while (max_part_id > min_part_id)
2905 loc_part_id= (max_part_id + min_part_id) / 2;
2906 if (range_array[loc_part_id] <= part_func_value)
2907 min_part_id= loc_part_id + 1;
2908 else
2909 max_part_id= loc_part_id;
2911 loc_part_id= max_part_id;
2912 *part_id= (uint32)loc_part_id;
2913 if (loc_part_id == max_partition &&
2914 part_func_value >= range_array[loc_part_id] &&
2915 !part_info->defined_max_value)
2916 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
2918 DBUG_PRINT("exit",("partition: %d", *part_id));
2919 DBUG_RETURN(0);
2924 Find the sub-array of part_info->range_int_array that covers given interval
2926 SYNOPSIS
2927 get_partition_id_range_for_endpoint()
2928 part_info Partitioning info (partitioning type must be RANGE)
2929 left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
2930 FALSE - the interval is (-inf; a] or (-inf; a).
2931 include_endpoint TRUE <=> the endpoint itself is included in the
2932 interval
2934 DESCRIPTION
2935 This function finds the sub-array of part_info->range_int_array where the
2936 elements have non-empty intersections with the given interval.
2938 A range_int_array element at index idx represents the interval
2940 [range_int_array[idx-1], range_int_array[idx]),
2942 intervals are disjoint and ordered by their right bound, so
2944 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
2945 sought sub-array starts at some index idx and continues till array end.
2946 The function returns first number idx, such that the interval
2947 represented by range_int_array[idx] has non empty intersection with
2948 the passed interval.
2950 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
2951 sought sub-array starts at array start and continues till some last
2952 index idx.
2953 The function returns first number idx, such that the interval
2954 represented by range_int_array[idx] has EMPTY intersection with the
2955 passed interval.
2956 If the interval represented by the last array element has non-empty
2957 intersection with the passed interval, part_info->no_parts is
2958 returned.
2960 RETURN
2961 The edge of corresponding part_info->range_int_array sub-array.
2964 static uint32
2965 get_partition_id_range_for_endpoint_charset(partition_info *part_info,
2966 bool left_endpoint,
2967 bool include_endpoint)
2969 uint32 res;
2970 copy_to_part_field_buffers(part_info->part_field_array,
2971 part_info->part_field_buffers,
2972 part_info->restore_part_field_ptrs);
2973 res= get_partition_id_range_for_endpoint(part_info, left_endpoint,
2974 include_endpoint);
2975 restore_part_field_pointers(part_info->part_field_array,
2976 part_info->restore_part_field_ptrs);
2977 return res;
2980 uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
2981 bool left_endpoint,
2982 bool include_endpoint)
2984 longlong *range_array= part_info->range_int_array;
2985 longlong part_end_val;
2986 uint max_partition= part_info->no_parts - 1;
2987 uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
2988 /* Get the partitioning function value for the endpoint */
2989 longlong part_func_value=
2990 part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
2992 bool unsigned_flag= part_info->part_expr->unsigned_flag;
2993 DBUG_ENTER("get_partition_id_range_for_endpoint");
2995 if (part_info->part_expr->null_value)
2998 Special handling for MONOTONIC functions that can return NULL for
2999 values that are comparable. I.e.
3000 '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3001 returns NULL which cannot be compared used <, >, <=, >= etc.
3003 Otherwise, just return the first partition
3004 (may be included if not left endpoint)
3006 enum_monotonicity_info monotonic;
3007 monotonic= part_info->part_expr->get_monotonicity_info();
3008 if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3009 monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL)
3011 /* F(col) can not return NULL, return partition with lowest value */
3012 if (!left_endpoint && include_endpoint)
3013 DBUG_RETURN(1);
3014 DBUG_RETURN(0);
3019 if (unsigned_flag)
3020 part_func_value-= 0x8000000000000000ULL;
3021 if (left_endpoint && !include_endpoint)
3022 part_func_value++;
3025 Search for the partition containing part_func_value
3026 (including the right endpoint).
3028 while (max_part_id > min_part_id)
3030 loc_part_id= (max_part_id + min_part_id) / 2;
3031 if (range_array[loc_part_id] < part_func_value)
3032 min_part_id= loc_part_id + 1;
3033 else
3034 max_part_id= loc_part_id;
3036 loc_part_id= max_part_id;
3038 /* Adjust for endpoints */
3039 part_end_val= range_array[loc_part_id];
3040 if (left_endpoint)
3042 DBUG_ASSERT(part_func_value > part_end_val ?
3043 (loc_part_id == max_partition &&
3044 !part_info->defined_max_value) :
3047 In case of PARTITION p VALUES LESS THAN MAXVALUE
3048 the maximum value is in the current (last) partition.
3049 If value is equal or greater than the endpoint,
3050 the range starts from the next partition.
3052 if (part_func_value >= part_end_val &&
3053 (loc_part_id < max_partition || !part_info->defined_max_value))
3054 loc_part_id++;
3056 else
3058 /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */
3059 if (include_endpoint && loc_part_id < max_partition &&
3060 part_func_value == part_end_val)
3061 loc_part_id++;
3063 /* Right endpoint, set end after correct partition */
3064 loc_part_id++;
3066 DBUG_RETURN(loc_part_id);
3070 int get_partition_id_hash_nosub(partition_info *part_info,
3071 uint32 *part_id,
3072 longlong *func_value)
3074 return get_part_id_hash(part_info->no_parts, part_info->part_expr,
3075 part_id, func_value);
3079 int get_partition_id_linear_hash_nosub(partition_info *part_info,
3080 uint32 *part_id,
3081 longlong *func_value)
3083 return get_part_id_linear_hash(part_info, part_info->no_parts,
3084 part_info->part_expr, part_id, func_value);
3088 int get_partition_id_key_nosub(partition_info *part_info,
3089 uint32 *part_id,
3090 longlong *func_value)
3092 *part_id= get_part_id_key(part_info->part_field_array,
3093 part_info->no_parts, func_value);
3094 return 0;
3098 int get_partition_id_linear_key_nosub(partition_info *part_info,
3099 uint32 *part_id,
3100 longlong *func_value)
3102 *part_id= get_part_id_linear_key(part_info,
3103 part_info->part_field_array,
3104 part_info->no_parts, func_value);
3105 return 0;
3109 int get_partition_id_range_sub_hash(partition_info *part_info,
3110 uint32 *part_id,
3111 longlong *func_value)
3113 uint32 loc_part_id, sub_part_id;
3114 uint no_subparts;
3115 longlong local_func_value;
3116 int error;
3117 DBUG_ENTER("get_partition_id_range_sub_hash");
3118 LINT_INIT(loc_part_id);
3119 LINT_INIT(sub_part_id);
3121 if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
3122 func_value))))
3124 DBUG_RETURN(error);
3126 no_subparts= part_info->no_subparts;
3127 if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
3128 &sub_part_id, &local_func_value))))
3130 DBUG_RETURN(error);
3133 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3134 DBUG_RETURN(0);
3138 int get_partition_id_range_sub_linear_hash(partition_info *part_info,
3139 uint32 *part_id,
3140 longlong *func_value)
3142 uint32 loc_part_id, sub_part_id;
3143 uint no_subparts;
3144 longlong local_func_value;
3145 int error;
3146 DBUG_ENTER("get_partition_id_range_sub_linear_hash");
3147 LINT_INIT(loc_part_id);
3148 LINT_INIT(sub_part_id);
3150 if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
3151 func_value))))
3153 DBUG_RETURN(error);
3155 no_subparts= part_info->no_subparts;
3156 if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
3157 part_info->subpart_expr,
3158 &sub_part_id,
3159 &local_func_value))))
3161 DBUG_RETURN(error);
3164 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3165 DBUG_RETURN(0);
3169 int get_partition_id_range_sub_key(partition_info *part_info,
3170 uint32 *part_id,
3171 longlong *func_value)
3173 uint32 loc_part_id, sub_part_id;
3174 uint no_subparts;
3175 longlong local_func_value;
3176 int error;
3177 DBUG_ENTER("get_partition_id_range_sub_key");
3178 LINT_INIT(loc_part_id);
3180 if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
3181 func_value))))
3183 DBUG_RETURN(error);
3185 no_subparts= part_info->no_subparts;
3186 sub_part_id= get_part_id_key(part_info->subpart_field_array,
3187 no_subparts, &local_func_value);
3188 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3189 DBUG_RETURN(0);
3193 int get_partition_id_range_sub_linear_key(partition_info *part_info,
3194 uint32 *part_id,
3195 longlong *func_value)
3197 uint32 loc_part_id, sub_part_id;
3198 uint no_subparts;
3199 longlong local_func_value;
3200 int error;
3201 DBUG_ENTER("get_partition_id_range_sub_linear_key");
3202 LINT_INIT(loc_part_id);
3204 if (unlikely((error= get_partition_id_range(part_info, &loc_part_id,
3205 func_value))))
3207 DBUG_RETURN(error);
3209 no_subparts= part_info->no_subparts;
3210 sub_part_id= get_part_id_linear_key(part_info,
3211 part_info->subpart_field_array,
3212 no_subparts, &local_func_value);
3213 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3214 DBUG_RETURN(0);
3218 int get_partition_id_list_sub_hash(partition_info *part_info,
3219 uint32 *part_id,
3220 longlong *func_value)
3222 uint32 loc_part_id, sub_part_id;
3223 uint no_subparts;
3224 longlong local_func_value;
3225 int error;
3226 DBUG_ENTER("get_partition_id_list_sub_hash");
3227 LINT_INIT(sub_part_id);
3229 if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
3230 func_value))))
3232 DBUG_RETURN(error);
3234 no_subparts= part_info->no_subparts;
3235 if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr,
3236 &sub_part_id, &local_func_value))))
3238 DBUG_RETURN(error);
3241 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3242 DBUG_RETURN(0);
3246 int get_partition_id_list_sub_linear_hash(partition_info *part_info,
3247 uint32 *part_id,
3248 longlong *func_value)
3250 uint32 loc_part_id, sub_part_id;
3251 uint no_subparts;
3252 longlong local_func_value;
3253 int error;
3254 DBUG_ENTER("get_partition_id_list_sub_linear_hash");
3255 LINT_INIT(sub_part_id);
3257 if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
3258 func_value))))
3260 DBUG_RETURN(error);
3262 no_subparts= part_info->no_subparts;
3263 if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts,
3264 part_info->subpart_expr,
3265 &sub_part_id,
3266 &local_func_value))))
3268 DBUG_RETURN(error);
3271 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3272 DBUG_RETURN(0);
3276 int get_partition_id_list_sub_key(partition_info *part_info,
3277 uint32 *part_id,
3278 longlong *func_value)
3280 uint32 loc_part_id, sub_part_id;
3281 uint no_subparts;
3282 longlong local_func_value;
3283 int error;
3284 DBUG_ENTER("get_partition_id_range_sub_key");
3286 if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
3287 func_value))))
3289 DBUG_RETURN(error);
3291 no_subparts= part_info->no_subparts;
3292 sub_part_id= get_part_id_key(part_info->subpart_field_array,
3293 no_subparts, &local_func_value);
3294 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3295 DBUG_RETURN(0);
3299 int get_partition_id_list_sub_linear_key(partition_info *part_info,
3300 uint32 *part_id,
3301 longlong *func_value)
3303 uint32 loc_part_id, sub_part_id;
3304 uint no_subparts;
3305 longlong local_func_value;
3306 int error;
3307 DBUG_ENTER("get_partition_id_list_sub_linear_key");
3309 if (unlikely((error= get_partition_id_list(part_info, &loc_part_id,
3310 func_value))))
3312 DBUG_RETURN(error);
3314 no_subparts= part_info->no_subparts;
3315 sub_part_id= get_part_id_linear_key(part_info,
3316 part_info->subpart_field_array,
3317 no_subparts, &local_func_value);
3318 *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts);
3319 DBUG_RETURN(0);
3324 This function is used to calculate the subpartition id
3326 SYNOPSIS
3327 get_subpartition_id()
3328 part_info A reference to the partition_info struct where all the
3329 desired information is given
3331 RETURN VALUE
3332 part_id The subpartition identity
3334 DESCRIPTION
3335 A routine used in some SELECT's when only partial knowledge of the
3336 partitions is known.
3338 It is actually 4 different variants of this function which are called
3339 through a function pointer.
3341 get_partition_id_hash_sub
3342 get_partition_id_key_sub
3343 get_partition_id_linear_hash_sub
3344 get_partition_id_linear_key_sub
3347 int get_partition_id_hash_sub(partition_info *part_info,
3348 uint32 *part_id)
3350 longlong func_value;
3351 return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr,
3352 part_id, &func_value);
3356 int get_partition_id_linear_hash_sub(partition_info *part_info,
3357 uint32 *part_id)
3359 longlong func_value;
3360 return get_part_id_linear_hash(part_info, part_info->no_subparts,
3361 part_info->subpart_expr, part_id,
3362 &func_value);
3366 int get_partition_id_key_sub(partition_info *part_info,
3367 uint32 *part_id)
3369 longlong func_value;
3370 *part_id= get_part_id_key(part_info->subpart_field_array,
3371 part_info->no_subparts, &func_value);
3372 return FALSE;
3376 int get_partition_id_linear_key_sub(partition_info *part_info,
3377 uint32 *part_id)
3379 longlong func_value;
3380 *part_id= get_part_id_linear_key(part_info,
3381 part_info->subpart_field_array,
3382 part_info->no_subparts, &func_value);
3383 return FALSE;
3388 Set an indicator on all partition fields that are set by the key
3390 SYNOPSIS
3391 set_PF_fields_in_key()
3392 key_info Information about the index
3393 key_length Length of key
3395 RETURN VALUE
3396 TRUE Found partition field set by key
3397 FALSE No partition field set by key
3400 static bool set_PF_fields_in_key(KEY *key_info, uint key_length)
3402 KEY_PART_INFO *key_part;
3403 bool found_part_field= FALSE;
3404 DBUG_ENTER("set_PF_fields_in_key");
3406 for (key_part= key_info->key_part; (int)key_length > 0; key_part++)
3408 if (key_part->null_bit)
3409 key_length--;
3410 if (key_part->type == HA_KEYTYPE_BIT)
3412 if (((Field_bit*)key_part->field)->bit_len)
3413 key_length--;
3415 if (key_part->key_part_flag & (HA_BLOB_PART + HA_VAR_LENGTH_PART))
3417 key_length-= HA_KEY_BLOB_LENGTH;
3419 if (key_length < key_part->length)
3420 break;
3421 key_length-= key_part->length;
3422 if (key_part->field->flags & FIELD_IN_PART_FUNC_FLAG)
3424 found_part_field= TRUE;
3425 key_part->field->flags|= GET_FIXED_FIELDS_FLAG;
3428 DBUG_RETURN(found_part_field);
3433 We have found that at least one partition field was set by a key, now
3434 check if a partition function has all its fields bound or not.
3436 SYNOPSIS
3437 check_part_func_bound()
3438 ptr Array of fields NULL terminated (partition fields)
3440 RETURN VALUE
3441 TRUE All fields in partition function are set
3442 FALSE Not all fields in partition function are set
3445 static bool check_part_func_bound(Field **ptr)
3447 bool result= TRUE;
3448 DBUG_ENTER("check_part_func_bound");
3450 for (; *ptr; ptr++)
3452 if (!((*ptr)->flags & GET_FIXED_FIELDS_FLAG))
3454 result= FALSE;
3455 break;
3458 DBUG_RETURN(result);
3463 Get the id of the subpartitioning part by using the key buffer of the
3464 index scan.
3466 SYNOPSIS
3467 get_sub_part_id_from_key()
3468 table The table object
3469 buf A buffer that can be used to evaluate the partition function
3470 key_info The index object
3471 key_spec A key_range containing key and key length
3472 out:part_id The returned partition id
3474 RETURN VALUES
3475 TRUE All fields in partition function are set
3476 FALSE Not all fields in partition function are set
3478 DESCRIPTION
3479 Use key buffer to set-up record in buf, move field pointers and
3480 get the partition identity and restore field pointers afterwards.
3483 static int get_sub_part_id_from_key(const TABLE *table,uchar *buf,
3484 KEY *key_info,
3485 const key_range *key_spec,
3486 uint32 *part_id)
3488 uchar *rec0= table->record[0];
3489 partition_info *part_info= table->part_info;
3490 int res;
3491 DBUG_ENTER("get_sub_part_id_from_key");
3493 key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
3494 if (likely(rec0 == buf))
3496 res= part_info->get_subpartition_id(part_info, part_id);
3498 else
3500 Field **part_field_array= part_info->subpart_field_array;
3501 set_field_ptr(part_field_array, buf, rec0);
3502 res= part_info->get_subpartition_id(part_info, part_id);
3503 set_field_ptr(part_field_array, rec0, buf);
3505 DBUG_RETURN(res);
3509 Get the id of the partitioning part by using the key buffer of the
3510 index scan.
3512 SYNOPSIS
3513 get_part_id_from_key()
3514 table The table object
3515 buf A buffer that can be used to evaluate the partition function
3516 key_info The index object
3517 key_spec A key_range containing key and key length
3518 out:part_id Partition to use
3520 RETURN VALUES
3521 TRUE Partition to use not found
3522 FALSE Ok, part_id indicates partition to use
3524 DESCRIPTION
3525 Use key buffer to set-up record in buf, move field pointers and
3526 get the partition identity and restore field pointers afterwards.
3529 bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
3530 const key_range *key_spec, uint32 *part_id)
3532 bool result;
3533 uchar *rec0= table->record[0];
3534 partition_info *part_info= table->part_info;
3535 longlong func_value;
3536 DBUG_ENTER("get_part_id_from_key");
3538 key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
3539 if (likely(rec0 == buf))
3541 result= part_info->get_part_partition_id(part_info, part_id,
3542 &func_value);
3544 else
3546 Field **part_field_array= part_info->part_field_array;
3547 set_field_ptr(part_field_array, buf, rec0);
3548 result= part_info->get_part_partition_id(part_info, part_id,
3549 &func_value);
3550 set_field_ptr(part_field_array, rec0, buf);
3552 DBUG_RETURN(result);
3556 Get the partitioning id of the full PF by using the key buffer of the
3557 index scan.
3559 SYNOPSIS
3560 get_full_part_id_from_key()
3561 table The table object
3562 buf A buffer that is used to evaluate the partition function
3563 key_info The index object
3564 key_spec A key_range containing key and key length
3565 out:part_spec A partition id containing start part and end part
3567 RETURN VALUES
3568 part_spec
3569 No partitions to scan is indicated by end_part > start_part when returning
3571 DESCRIPTION
3572 Use key buffer to set-up record in buf, move field pointers if needed and
3573 get the partition identity and restore field pointers afterwards.
3576 void get_full_part_id_from_key(const TABLE *table, uchar *buf,
3577 KEY *key_info,
3578 const key_range *key_spec,
3579 part_id_range *part_spec)
3581 bool result;
3582 partition_info *part_info= table->part_info;
3583 uchar *rec0= table->record[0];
3584 longlong func_value;
3585 DBUG_ENTER("get_full_part_id_from_key");
3587 key_restore(buf, (uchar*)key_spec->key, key_info, key_spec->length);
3588 if (likely(rec0 == buf))
3590 result= part_info->get_partition_id(part_info, &part_spec->start_part,
3591 &func_value);
3593 else
3595 Field **part_field_array= part_info->full_part_field_array;
3596 set_field_ptr(part_field_array, buf, rec0);
3597 result= part_info->get_partition_id(part_info, &part_spec->start_part,
3598 &func_value);
3599 set_field_ptr(part_field_array, rec0, buf);
3601 part_spec->end_part= part_spec->start_part;
3602 if (unlikely(result))
3603 part_spec->start_part++;
3604 DBUG_VOID_RETURN;
3608 Prune the set of partitions to use in query
3610 SYNOPSIS
3611 prune_partition_set()
3612 table The table object
3613 out:part_spec Contains start part, end part
3615 DESCRIPTION
3616 This function is called to prune the range of partitions to scan by
3617 checking the used_partitions bitmap.
3618 If start_part > end_part at return it means no partition needs to be
3619 scanned. If start_part == end_part it always means a single partition
3620 needs to be scanned.
3622 RETURN VALUE
3623 part_spec
3625 void prune_partition_set(const TABLE *table, part_id_range *part_spec)
3627 int last_partition= -1;
3628 uint i;
3629 partition_info *part_info= table->part_info;
3631 DBUG_ENTER("prune_partition_set");
3632 for (i= part_spec->start_part; i <= part_spec->end_part; i++)
3634 if (bitmap_is_set(&(part_info->used_partitions), i))
3636 DBUG_PRINT("info", ("Partition %d is set", i));
3637 if (last_partition == -1)
3638 /* First partition found in set and pruned bitmap */
3639 part_spec->start_part= i;
3640 last_partition= i;
3643 if (last_partition == -1)
3644 /* No partition found in pruned bitmap */
3645 part_spec->start_part= part_spec->end_part + 1;
3646 else //if (last_partition != -1)
3647 part_spec->end_part= last_partition;
3649 DBUG_VOID_RETURN;
3653 Get the set of partitions to use in query.
3655 SYNOPSIS
3656 get_partition_set()
3657 table The table object
3658 buf A buffer that can be used to evaluate the partition function
3659 index The index of the key used, if MAX_KEY no index used
3660 key_spec A key_range containing key and key length
3661 out:part_spec Contains start part, end part and indicator if bitmap is
3662 used for which partitions to scan
3664 DESCRIPTION
3665 This function is called to discover which partitions to use in an index
3666 scan or a full table scan.
3667 It returns a range of partitions to scan. If there are holes in this
3668 range with partitions that are not needed to scan a bit array is used
3669 to signal which partitions to use and which not to use.
3670 If start_part > end_part at return it means no partition needs to be
3671 scanned. If start_part == end_part it always means a single partition
3672 needs to be scanned.
3674 RETURN VALUE
3675 part_spec
3677 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
3678 const key_range *key_spec, part_id_range *part_spec)
3680 partition_info *part_info= table->part_info;
3681 uint no_parts= part_info->get_tot_partitions();
3682 uint i, part_id;
3683 uint sub_part= no_parts;
3684 uint32 part_part= no_parts;
3685 KEY *key_info= NULL;
3686 bool found_part_field= FALSE;
3687 DBUG_ENTER("get_partition_set");
3689 part_spec->start_part= 0;
3690 part_spec->end_part= no_parts - 1;
3691 if ((index < MAX_KEY) &&
3692 key_spec->flag == (uint)HA_READ_KEY_EXACT &&
3693 part_info->some_fields_in_PF.is_set(index))
3695 key_info= table->key_info+index;
3697 The index can potentially provide at least one PF-field (field in the
3698 partition function). Thus it is interesting to continue our probe.
3700 if (key_spec->length == key_info->key_length)
3703 The entire key is set so we can check whether we can immediately
3704 derive either the complete PF or if we can derive either
3705 the top PF or the subpartitioning PF. This can be established by
3706 checking precalculated bits on each index.
3708 if (part_info->all_fields_in_PF.is_set(index))
3711 We can derive the exact partition to use, no more than this one
3712 is needed.
3714 get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
3716 Check if range can be adjusted by looking in used_partitions
3718 prune_partition_set(table, part_spec);
3719 DBUG_VOID_RETURN;
3721 else if (part_info->is_sub_partitioned())
3723 if (part_info->all_fields_in_SPF.is_set(index))
3725 if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
3727 part_spec->start_part= no_parts;
3728 DBUG_VOID_RETURN;
3731 else if (part_info->all_fields_in_PPF.is_set(index))
3733 if (get_part_id_from_key(table,buf,key_info,
3734 key_spec,(uint32*)&part_part))
3737 The value of the RANGE or LIST partitioning was outside of
3738 allowed values. Thus it is certain that the result of this
3739 scan will be empty.
3741 part_spec->start_part= no_parts;
3742 DBUG_VOID_RETURN;
3747 else
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)
3756 if ((found_part_field= set_PF_fields_in_key(key_info,
3757 key_spec->length)))
3759 if (check_part_func_bound(part_info->full_part_field_array))
3762 We were able to bind all fields in the partition function even
3763 by using only a part of the key. Calculate the partition to use.
3765 get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
3766 clear_indicator_in_key_fields(key_info);
3768 Check if range can be adjusted by looking in used_partitions
3770 prune_partition_set(table, part_spec);
3771 DBUG_VOID_RETURN;
3773 else if (part_info->is_sub_partitioned())
3775 if (check_part_func_bound(part_info->subpart_field_array))
3777 if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part))
3779 part_spec->start_part= no_parts;
3780 clear_indicator_in_key_fields(key_info);
3781 DBUG_VOID_RETURN;
3784 else if (check_part_func_bound(part_info->part_field_array))
3786 if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part))
3788 part_spec->start_part= no_parts;
3789 clear_indicator_in_key_fields(key_info);
3790 DBUG_VOID_RETURN;
3799 The next step is to analyse the table condition to see whether any
3800 information about which partitions to scan can be derived from there.
3801 Currently not implemented.
3805 If we come here we have found a range of sorts we have either discovered
3806 nothing or we have discovered a range of partitions with possible holes
3807 in it. We need a bitvector to further the work here.
3809 if (!(part_part == no_parts && sub_part == no_parts))
3812 We can only arrive here if we are using subpartitioning.
3814 if (part_part != no_parts)
3817 We know the top partition and need to scan all underlying
3818 subpartitions. This is a range without holes.
3820 DBUG_ASSERT(sub_part == no_parts);
3821 part_spec->start_part= part_part * part_info->no_subparts;
3822 part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1;
3824 else
3826 DBUG_ASSERT(sub_part != no_parts);
3827 part_spec->start_part= sub_part;
3828 part_spec->end_part=sub_part+
3829 (part_info->no_subparts*(part_info->no_parts-1));
3830 for (i= 0, part_id= sub_part; i < part_info->no_parts;
3831 i++, part_id+= part_info->no_subparts)
3832 ; //Set bit part_id in bit array
3835 if (found_part_field)
3836 clear_indicator_in_key_fields(key_info);
3838 Check if range can be adjusted by looking in used_partitions
3840 prune_partition_set(table, part_spec);
3841 DBUG_VOID_RETURN;
3845 If the table is partitioned we will read the partition info into the
3846 .frm file here.
3847 -------------------------------
3848 | Fileinfo 64 bytes |
3849 -------------------------------
3850 | Formnames 7 bytes |
3851 -------------------------------
3852 | Not used 4021 bytes |
3853 -------------------------------
3854 | Keyinfo + record |
3855 -------------------------------
3856 | Padded to next multiple |
3857 | of IO_SIZE |
3858 -------------------------------
3859 | Forminfo 288 bytes |
3860 -------------------------------
3861 | Screen buffer, to make |
3862 |field names readable |
3863 -------------------------------
3864 | Packed field info |
3865 |17 + 1 + strlen(field_name) |
3866 | + 1 end of file character |
3867 -------------------------------
3868 | Partition info |
3869 -------------------------------
3870 We provide the length of partition length in Fileinfo[55-58].
3872 Read the partition syntax from the frm file and parse it to get the
3873 data structures of the partitioning.
3875 SYNOPSIS
3876 mysql_unpack_partition()
3877 thd Thread object
3878 part_buf Partition info from frm file
3879 part_info_len Length of partition syntax
3880 table Table object of partitioned table
3881 create_table_ind Is it called from CREATE TABLE
3882 default_db_type What is the default engine of the table
3883 work_part_info_used Flag is raised if we don't create new
3884 part_info, but used thd->work_part_info
3886 RETURN VALUE
3887 TRUE Error
3888 FALSE Sucess
3890 DESCRIPTION
3891 Read the partition syntax from the current position in the frm file.
3892 Initiate a LEX object, save the list of item tree objects to free after
3893 the query is done. Set-up partition info object such that parser knows
3894 it is called from internally. Call parser to create data structures
3895 (best possible recreation of item trees and so forth since there is no
3896 serialisation of these objects other than in parseable text format).
3897 We need to save the text of the partition functions since it is not
3898 possible to retrace this given an item tree.
3901 bool mysql_unpack_partition(THD *thd,
3902 char *part_buf, uint part_info_len,
3903 const char *part_state, uint part_state_len,
3904 TABLE* table, bool is_create_table_ind,
3905 handlerton *default_db_type,
3906 bool *work_part_info_used)
3908 bool result= TRUE;
3909 partition_info *part_info;
3910 CHARSET_INFO *old_character_set_client= thd->variables.character_set_client;
3911 LEX *old_lex= thd->lex;
3912 LEX lex;
3913 DBUG_ENTER("mysql_unpack_partition");
3915 thd->lex= &lex;
3916 thd->variables.character_set_client= system_charset_info;
3918 Parser_state parser_state;
3919 if (parser_state.init(thd, part_buf, part_info_len))
3920 goto end;
3922 lex_start(thd);
3923 *work_part_info_used= false;
3925 We need to use the current SELECT_LEX since I need to keep the
3926 Name_resolution_context object which is referenced from the
3927 Item_field objects.
3928 This is not a nice solution since if the parser uses current_select
3929 for anything else it will corrupt the current LEX object.
3930 Also, we need to make sure there even is a select -- if the statement
3931 was a "USE ...", current_select will be NULL, but we may still end up
3932 here if we try to log to a partitioned table. This is currently
3933 unsupported, but should still fail rather than crash!
3935 if (!(thd->lex->current_select= old_lex->current_select))
3936 goto end;
3938 All Items created is put into a free list on the THD object. This list
3939 is used to free all Item objects after completing a query. We don't
3940 want that to happen with the Item tree created as part of the partition
3941 info. This should be attached to the table object and remain so until
3942 the table object is released.
3943 Thus we move away the current list temporarily and start a new list that
3944 we then save in the partition info structure.
3946 lex.part_info= new partition_info();/* Indicates MYSQLparse from this place */
3947 if (!lex.part_info)
3949 mem_alloc_error(sizeof(partition_info));
3950 goto end;
3952 lex.part_info->part_state= part_state;
3953 lex.part_info->part_state_len= part_state_len;
3954 DBUG_PRINT("info", ("Parse: %s", part_buf));
3955 if (parse_sql(thd, & parser_state, NULL))
3957 thd->free_items();
3958 goto end;
3961 The parsed syntax residing in the frm file can still contain defaults.
3962 The reason is that the frm file is sometimes saved outside of this
3963 MySQL Server and used in backup and restore of clusters or partitioned
3964 tables. It is not certain that the restore will restore exactly the
3965 same default partitioning.
3967 The easiest manner of handling this is to simply continue using the
3968 part_info we already built up during mysql_create_table if we are
3969 in the process of creating a table. If the table already exists we
3970 need to discover the number of partitions for the default parts. Since
3971 the handler object hasn't been created here yet we need to postpone this
3972 to the fix_partition_func method.
3975 DBUG_PRINT("info", ("Successful parse"));
3976 part_info= lex.part_info;
3977 DBUG_PRINT("info", ("default engine = %s, default_db_type = %s",
3978 ha_resolve_storage_engine_name(part_info->default_engine_type),
3979 ha_resolve_storage_engine_name(default_db_type)));
3980 if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
3982 if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
3985 This code is executed when we create table in CREATE TABLE t1 LIKE t2.
3986 old_lex->query_tables contains table list element for t2 and the table
3987 we are opening has name t1.
3989 if (partition_default_handling(table, part_info, FALSE,
3990 old_lex->query_tables->table->s->path.str))
3992 result= TRUE;
3993 goto end;
3996 else
3999 When we come here we are doing a create table. In this case we
4000 have already done some preparatory work on the old part_info
4001 object. We don't really need this new partition_info object.
4002 Thus we go back to the old partition info object.
4003 We need to free any memory objects allocated on item_free_list
4004 by the parser since we are keeping the old info from the first
4005 parser call in CREATE TABLE.
4006 We'll ensure that this object isn't put into table cache also
4007 just to ensure we don't get into strange situations with the
4008 item objects.
4010 thd->free_items();
4011 part_info= thd->work_part_info;
4012 table->s->version= 0UL;
4013 *work_part_info_used= true;
4016 table->part_info= part_info;
4017 table->file->set_part_info(part_info);
4018 if (!part_info->default_engine_type)
4019 part_info->default_engine_type= default_db_type;
4020 DBUG_ASSERT(part_info->default_engine_type == default_db_type);
4021 DBUG_ASSERT(part_info->default_engine_type->db_type != DB_TYPE_UNKNOWN);
4022 DBUG_ASSERT(part_info->default_engine_type != partition_hton);
4026 This code part allocates memory for the serialised item information for
4027 the partition functions. In most cases this is not needed but if the
4028 table is used for SHOW CREATE TABLES or ALTER TABLE that modifies
4029 partition information it is needed and the info is lost if we don't
4030 save it here so unfortunately we have to do it here even if in most
4031 cases it is not needed. This is a consequence of that item trees are
4032 not serialisable.
4034 uint part_func_len= part_info->part_func_len;
4035 uint subpart_func_len= part_info->subpart_func_len;
4036 char *part_func_string= NULL;
4037 char *subpart_func_string= NULL;
4038 if ((part_func_len &&
4039 !((part_func_string= (char*) thd->alloc(part_func_len)))) ||
4040 (subpart_func_len &&
4041 !((subpart_func_string= (char*) thd->alloc(subpart_func_len)))))
4043 mem_alloc_error(part_func_len);
4044 thd->free_items();
4045 goto end;
4047 if (part_func_len)
4048 memcpy(part_func_string, part_info->part_func_string, part_func_len);
4049 if (subpart_func_len)
4050 memcpy(subpart_func_string, part_info->subpart_func_string,
4051 subpart_func_len);
4052 part_info->part_func_string= part_func_string;
4053 part_info->subpart_func_string= subpart_func_string;
4056 result= FALSE;
4057 end:
4058 lex_end(thd->lex);
4059 thd->lex= old_lex;
4060 thd->variables.character_set_client= old_character_set_client;
4061 DBUG_RETURN(result);
4066 Set engine type on all partition element objects
4067 SYNOPSIS
4068 set_engine_all_partitions()
4069 part_info Partition info
4070 engine_type Handlerton reference of engine
4071 RETURN VALUES
4072 NONE
4075 static
4076 void
4077 set_engine_all_partitions(partition_info *part_info,
4078 handlerton *engine_type)
4080 uint i= 0;
4081 List_iterator<partition_element> part_it(part_info->partitions);
4084 partition_element *part_elem= part_it++;
4086 part_elem->engine_type= engine_type;
4087 if (part_info->is_sub_partitioned())
4089 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4090 uint j= 0;
4094 partition_element *sub_elem= sub_it++;
4096 sub_elem->engine_type= engine_type;
4097 } while (++j < part_info->no_subparts);
4099 } while (++i < part_info->no_parts);
4102 SYNOPSIS
4103 fast_end_partition()
4104 thd Thread object
4105 out:copied Number of records copied
4106 out:deleted Number of records deleted
4107 table_list Table list with the one table in it
4108 empty Has nothing been done
4109 lpt Struct to be used by error handler
4111 RETURN VALUES
4112 FALSE Success
4113 TRUE Failure
4115 DESCRIPTION
4116 Support routine to handle the successful cases for partition
4117 management.
4120 static int fast_end_partition(THD *thd, ulonglong copied,
4121 ulonglong deleted,
4122 TABLE *table,
4123 TABLE_LIST *table_list, bool is_empty,
4124 ALTER_PARTITION_PARAM_TYPE *lpt,
4125 bool written_bin_log)
4127 int error;
4128 char tmp_name[80];
4129 DBUG_ENTER("fast_end_partition");
4131 thd->proc_info="end";
4133 if (!is_empty)
4134 query_cache_invalidate3(thd, table_list, 0);
4136 error= ha_autocommit_or_rollback(thd, 0);
4137 if (end_active_trans(thd))
4138 error= 1;
4140 if (error)
4142 /* If error during commit, no need to rollback, it's done. */
4143 table->file->print_error(error, MYF(0));
4144 DBUG_RETURN(TRUE);
4147 if ((!is_empty) && (!written_bin_log) &&
4148 (!thd->lex->no_write_to_binlog) &&
4149 write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
4150 DBUG_RETURN(TRUE);
4152 my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
4153 (ulong) (copied + deleted),
4154 (ulong) deleted,
4155 (ulong) 0);
4156 my_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name);
4157 DBUG_RETURN(FALSE);
4162 We need to check if engine used by all partitions can handle
4163 partitioning natively.
4165 SYNOPSIS
4166 check_native_partitioned()
4167 create_info Create info in CREATE TABLE
4168 out:ret_val Return value
4169 part_info Partition info
4170 thd Thread object
4172 RETURN VALUES
4173 Value returned in bool ret_value
4174 TRUE Native partitioning supported by engine
4175 FALSE Need to use partition handler
4177 Return value from function
4178 TRUE Error
4179 FALSE Success
4182 static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val,
4183 partition_info *part_info, THD *thd)
4185 bool table_engine_set;
4186 handlerton *engine_type= part_info->default_engine_type;
4187 handlerton *old_engine_type= engine_type;
4188 DBUG_ENTER("check_native_partitioned");
4190 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
4192 table_engine_set= TRUE;
4193 engine_type= create_info->db_type;
4195 else
4197 table_engine_set= FALSE;
4198 if (thd->lex->sql_command != SQLCOM_CREATE_TABLE)
4200 table_engine_set= TRUE;
4201 DBUG_ASSERT(engine_type && engine_type != partition_hton);
4204 DBUG_PRINT("info", ("engine_type = %s, table_engine_set = %u",
4205 ha_resolve_storage_engine_name(engine_type),
4206 table_engine_set));
4207 if (part_info->check_engine_mix(engine_type, table_engine_set))
4208 goto error;
4211 All engines are of the same type. Check if this engine supports
4212 native partitioning.
4215 if (!engine_type)
4216 engine_type= old_engine_type;
4217 DBUG_PRINT("info", ("engine_type = %s",
4218 ha_resolve_storage_engine_name(engine_type)));
4219 if (engine_type->partition_flags &&
4220 (engine_type->partition_flags() & HA_CAN_PARTITION))
4222 create_info->db_type= engine_type;
4223 DBUG_PRINT("info", ("Changed to native partitioning"));
4224 *ret_val= TRUE;
4226 DBUG_RETURN(FALSE);
4227 error:
4229 Mixed engines not yet supported but when supported it will need
4230 the partition handler
4232 my_error(ER_MIX_HANDLER_ERROR, MYF(0));
4233 *ret_val= FALSE;
4234 DBUG_RETURN(TRUE);
4239 Sets which partitions to be used in the command
4241 uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
4242 enum partition_state part_state)
4244 uint part_count= 0;
4245 uint no_parts_found= 0;
4246 List_iterator<partition_element> part_it(tab_part_info->partitions);
4250 partition_element *part_elem= part_it++;
4251 if ((alter_info->flags & ALTER_ALL_PARTITION) ||
4252 (is_name_in_list(part_elem->partition_name,
4253 alter_info->partition_names)))
4256 Mark the partition.
4257 I.e mark the partition as a partition to be "changed" by
4258 analyzing/optimizing/rebuilding/checking/repairing
4260 no_parts_found++;
4261 part_elem->part_state= part_state;
4262 DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
4263 part_state, part_elem->partition_name));
4265 } while (++part_count < tab_part_info->no_parts);
4266 return no_parts_found;
4271 Prepare for ALTER TABLE of partition structure
4273 SYNOPSIS
4274 prep_alter_part_table()
4275 thd Thread object
4276 table Table object
4277 inout:alter_info Alter information
4278 inout:create_info Create info for CREATE TABLE
4279 old_db_type Old engine type
4280 out:partition_changed Boolean indicating whether partition changed
4281 out:fast_alter_partition Boolean indicating whether fast partition
4282 change is requested
4284 RETURN VALUES
4285 TRUE Error
4286 FALSE Success
4287 partition_changed
4288 fast_alter_partition
4290 DESCRIPTION
4291 This method handles all preparations for ALTER TABLE for partitioned
4292 tables
4293 We need to handle both partition management command such as Add Partition
4294 and others here as well as an ALTER TABLE that completely changes the
4295 partitioning and yet others that don't change anything at all. We start
4296 by checking the partition management variants and then check the general
4297 change patterns.
4300 uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
4301 HA_CREATE_INFO *create_info,
4302 handlerton *old_db_type,
4303 bool *partition_changed,
4304 uint *fast_alter_partition)
4306 DBUG_ENTER("prep_alter_part_table");
4308 /* Foreign keys on partitioned tables are not supported, waits for WL#148 */
4309 if (table->part_info && (alter_info->flags & ALTER_FOREIGN_KEY))
4311 my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
4312 DBUG_RETURN(TRUE);
4315 We are going to manipulate the partition info on the table object
4316 so we need to ensure that the data structure of the table object
4317 is freed by setting version to 0. table->s->version= 0 forces a
4318 flush of the table object in close_thread_tables().
4320 if (table->part_info)
4321 table->s->version= 0L;
4323 thd->work_part_info= thd->lex->part_info;
4324 if (thd->work_part_info &&
4325 !(thd->work_part_info= thd->lex->part_info->get_clone()))
4326 DBUG_RETURN(TRUE);
4328 /* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
4329 DBUG_ASSERT(!(alter_info->flags & ALTER_ADMIN_PARTITION));
4331 if (alter_info->flags &
4332 (ALTER_ADD_PARTITION | ALTER_DROP_PARTITION |
4333 ALTER_COALESCE_PARTITION | ALTER_REORGANIZE_PARTITION |
4334 ALTER_TABLE_REORG | ALTER_REBUILD_PARTITION))
4336 partition_info *tab_part_info= table->part_info;
4337 partition_info *alt_part_info= thd->work_part_info;
4338 uint flags= 0;
4339 if (!tab_part_info)
4341 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4342 DBUG_RETURN(TRUE);
4344 if (alter_info->flags & ALTER_TABLE_REORG)
4346 uint new_part_no, curr_part_no;
4347 if (tab_part_info->part_type != HASH_PARTITION ||
4348 tab_part_info->use_default_no_partitions)
4350 my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
4351 DBUG_RETURN(TRUE);
4353 new_part_no= table->file->get_default_no_partitions(create_info);
4354 curr_part_no= tab_part_info->no_parts;
4355 if (new_part_no == curr_part_no)
4358 No change is needed, we will have the same number of partitions
4359 after the change as before. Thus we can reply ok immediately
4360 without any changes at all.
4362 *fast_alter_partition= TRUE;
4363 DBUG_RETURN(FALSE);
4365 else if (new_part_no > curr_part_no)
4368 We will add more partitions, we use the ADD PARTITION without
4369 setting the flag for no default number of partitions
4371 alter_info->flags|= ALTER_ADD_PARTITION;
4372 thd->work_part_info->no_parts= new_part_no - curr_part_no;
4374 else
4377 We will remove hash partitions, we use the COALESCE PARTITION
4378 without setting the flag for no default number of partitions
4380 alter_info->flags|= ALTER_COALESCE_PARTITION;
4381 alter_info->no_parts= curr_part_no - new_part_no;
4384 if (!(flags= table->file->alter_table_flags(alter_info->flags)))
4386 my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
4387 DBUG_RETURN(1);
4389 *fast_alter_partition=
4390 ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0);
4391 DBUG_PRINT("info", ("*fast_alter_partition: %d flags: 0x%x",
4392 *fast_alter_partition, flags));
4393 if (((alter_info->flags & ALTER_ADD_PARTITION) ||
4394 (alter_info->flags & ALTER_REORGANIZE_PARTITION)) &&
4395 (thd->work_part_info->part_type != tab_part_info->part_type) &&
4396 (thd->work_part_info->part_type != NOT_A_PARTITION))
4398 if (thd->work_part_info->part_type == RANGE_PARTITION)
4400 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
4401 "RANGE", "LESS THAN");
4403 else if (thd->work_part_info->part_type == LIST_PARTITION)
4405 DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION);
4406 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0),
4407 "LIST", "IN");
4409 else if (tab_part_info->part_type == RANGE_PARTITION)
4411 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
4412 "RANGE", "LESS THAN");
4414 else
4416 DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION);
4417 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0),
4418 "LIST", "IN");
4420 DBUG_RETURN(TRUE);
4422 if (alter_info->flags & ALTER_ADD_PARTITION)
4425 We start by moving the new partitions to the list of temporary
4426 partitions. We will then check that the new partitions fit in the
4427 partitioning scheme as currently set-up.
4428 Partitions are always added at the end in ADD PARTITION.
4430 uint no_new_partitions= alt_part_info->no_parts;
4431 uint no_orig_partitions= tab_part_info->no_parts;
4432 uint check_total_partitions= no_new_partitions + no_orig_partitions;
4433 uint new_total_partitions= check_total_partitions;
4435 We allow quite a lot of values to be supplied by defaults, however we
4436 must know the number of new partitions in this case.
4438 if (thd->lex->no_write_to_binlog &&
4439 tab_part_info->part_type != HASH_PARTITION)
4441 my_error(ER_NO_BINLOG_ERROR, MYF(0));
4442 DBUG_RETURN(TRUE);
4444 if (tab_part_info->defined_max_value)
4446 my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
4447 DBUG_RETURN(TRUE);
4449 if (no_new_partitions == 0)
4451 my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
4452 DBUG_RETURN(TRUE);
4454 if (tab_part_info->is_sub_partitioned())
4456 if (alt_part_info->no_subparts == 0)
4457 alt_part_info->no_subparts= tab_part_info->no_subparts;
4458 else if (alt_part_info->no_subparts != tab_part_info->no_subparts)
4460 my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
4461 DBUG_RETURN(TRUE);
4463 check_total_partitions= new_total_partitions*
4464 alt_part_info->no_subparts;
4466 if (check_total_partitions > MAX_PARTITIONS)
4468 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4469 DBUG_RETURN(TRUE);
4471 alt_part_info->part_type= tab_part_info->part_type;
4472 alt_part_info->subpart_type= tab_part_info->subpart_type;
4473 if (alt_part_info->set_up_defaults_for_partitioning(table->file,
4474 ULL(0),
4475 tab_part_info->no_parts))
4477 DBUG_RETURN(TRUE);
4480 Handling of on-line cases:
4482 ADD PARTITION for RANGE/LIST PARTITIONING:
4483 ------------------------------------------
4484 For range and list partitions add partition is simply adding a
4485 new empty partition to the table. If the handler support this we
4486 will use the simple method of doing this. The figure below shows
4487 an example of this and the states involved in making this change.
4489 Existing partitions New added partitions
4490 ------ ------ ------ ------ | ------ ------
4491 | | | | | | | | | | | | |
4492 | p0 | | p1 | | p2 | | p3 | | | p4 | | p5 |
4493 ------ ------ ------ ------ | ------ ------
4494 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_TO_BE_ADDED*2
4495 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_ADDED*2
4497 The first line is the states before adding the new partitions and the
4498 second line is after the new partitions are added. All the partitions are
4499 in the partitions list, no partitions are placed in the temp_partitions
4500 list.
4502 ADD PARTITION for HASH PARTITIONING
4503 -----------------------------------
4504 This little figure tries to show the various partitions involved when
4505 adding two new partitions to a linear hash based partitioned table with
4506 four partitions to start with, which lists are used and the states they
4507 pass through. Adding partitions to a normal hash based is similar except
4508 that it is always all the existing partitions that are reorganised not
4509 only a subset of them.
4511 Existing partitions New added partitions
4512 ------ ------ ------ ------ | ------ ------
4513 | | | | | | | | | | | | |
4514 | p0 | | p1 | | p2 | | p3 | | | p4 | | p5 |
4515 ------ ------ ------ ------ | ------ ------
4516 PART_CHANGED PART_CHANGED PART_NORMAL PART_NORMAL PART_TO_BE_ADDED
4517 PART_IS_CHANGED*2 PART_NORMAL PART_NORMAL PART_IS_ADDED
4518 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_ADDED
4520 Reorganised existing partitions
4521 ------ ------
4522 | | | |
4523 | p0'| | p1'|
4524 ------ ------
4526 p0 - p5 will be in the partitions list of partitions.
4527 p0' and p1' will actually not exist as separate objects, there presence can
4528 be deduced from the state of the partition and also the names of those
4529 partitions can be deduced this way.
4531 After adding the partitions and copying the partition data to p0', p1',
4532 p4 and p5 from p0 and p1 the states change to adapt for the new situation
4533 where p0 and p1 is dropped and replaced by p0' and p1' and the new p4 and
4534 p5 are in the table again.
4536 The first line above shows the states of the partitions before we start
4537 adding and copying partitions, the second after completing the adding
4538 and copying and finally the third line after also dropping the partitions
4539 that are reorganised.
4541 if (*fast_alter_partition &&
4542 tab_part_info->part_type == HASH_PARTITION)
4544 uint part_no= 0, start_part= 1, start_sec_part= 1;
4545 uint end_part= 0, end_sec_part= 0;
4546 uint upper_2n= tab_part_info->linear_hash_mask + 1;
4547 uint lower_2n= upper_2n >> 1;
4548 bool all_parts= TRUE;
4549 if (tab_part_info->linear_hash_ind &&
4550 no_new_partitions < upper_2n)
4553 An analysis of which parts needs reorganisation shows that it is
4554 divided into two intervals. The first interval is those parts
4555 that are reorganised up until upper_2n - 1. From upper_2n and
4556 onwards it starts again from partition 0 and goes on until
4557 it reaches p(upper_2n - 1). If the last new partition reaches
4558 beyond upper_2n - 1 then the first interval will end with
4559 p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n).
4560 If lower_2n partitions are added then p0 to p(lower_2n - 1) will
4561 be reorganised which means that the two interval becomes one
4562 interval at this point. Thus only when adding less than
4563 lower_2n partitions and going beyond a total of upper_2n we
4564 actually get two intervals.
4566 To exemplify this assume we have 6 partitions to start with and
4567 add 1, 2, 3, 5, 6, 7, 8, 9 partitions.
4568 The first to add after p5 is p6 = 110 in bit numbers. Thus we
4569 can see that 10 = p2 will be partition to reorganise if only one
4570 partition.
4571 If 2 partitions are added we reorganise [p2, p3]. Those two
4572 cases are covered by the second if part below.
4573 If 3 partitions are added we reorganise [p2, p3] U [p0,p0]. This
4574 part is covered by the else part below.
4575 If 5 partitions are added we get [p2,p3] U [p0, p2] = [p0, p3].
4576 This is covered by the first if part where we need the max check
4577 to here use lower_2n - 1.
4578 If 7 partitions are added we get [p2,p3] U [p0, p4] = [p0, p4].
4579 This is covered by the first if part but here we use the first
4580 calculated end_part.
4581 Finally with 9 new partitions we would also reorganise p6 if we
4582 used the method below but we cannot reorganise more partitions
4583 than what we had from the start and thus we simply set all_parts
4584 to TRUE. In this case we don't get into this if-part at all.
4586 all_parts= FALSE;
4587 if (no_new_partitions >= lower_2n)
4590 In this case there is only one interval since the two intervals
4591 overlap and this starts from zero to last_part_no - upper_2n
4593 start_part= 0;
4594 end_part= new_total_partitions - (upper_2n + 1);
4595 end_part= max(lower_2n - 1, end_part);
4597 else if (new_total_partitions <= upper_2n)
4600 Also in this case there is only one interval since we are not
4601 going over a 2**n boundary
4603 start_part= no_orig_partitions - lower_2n;
4604 end_part= start_part + (no_new_partitions - 1);
4606 else
4608 /* We have two non-overlapping intervals since we are not
4609 passing a 2**n border and we have not at least lower_2n
4610 new parts that would ensure that the intervals become
4611 overlapping.
4613 start_part= no_orig_partitions - lower_2n;
4614 end_part= upper_2n - 1;
4615 start_sec_part= 0;
4616 end_sec_part= new_total_partitions - (upper_2n + 1);
4619 List_iterator<partition_element> tab_it(tab_part_info->partitions);
4620 part_no= 0;
4623 partition_element *p_elem= tab_it++;
4624 if (all_parts ||
4625 (part_no >= start_part && part_no <= end_part) ||
4626 (part_no >= start_sec_part && part_no <= end_sec_part))
4628 p_elem->part_state= PART_CHANGED;
4630 } while (++part_no < no_orig_partitions);
4633 Need to concatenate the lists here to make it possible to check the
4634 partition info for correctness using check_partition_info.
4635 For on-line add partition we set the state of this partition to
4636 PART_TO_BE_ADDED to ensure that it is known that it is not yet
4637 usable (becomes usable when partition is created and the switch of
4638 partition configuration is made.
4641 List_iterator<partition_element> alt_it(alt_part_info->partitions);
4642 uint part_count= 0;
4645 partition_element *part_elem= alt_it++;
4646 if (*fast_alter_partition)
4647 part_elem->part_state= PART_TO_BE_ADDED;
4648 if (tab_part_info->partitions.push_back(part_elem))
4650 mem_alloc_error(1);
4651 DBUG_RETURN(TRUE);
4653 } while (++part_count < no_new_partitions);
4654 tab_part_info->no_parts+= no_new_partitions;
4657 If we specify partitions explicitly we don't use defaults anymore.
4658 Using ADD PARTITION also means that we don't have the default number
4659 of partitions anymore. We use this code also for Table reorganisations
4660 and here we don't set any default flags to FALSE.
4662 if (!(alter_info->flags & ALTER_TABLE_REORG))
4664 if (!alt_part_info->use_default_partitions)
4666 DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info));
4667 tab_part_info->use_default_partitions= FALSE;
4669 tab_part_info->use_default_no_partitions= FALSE;
4670 tab_part_info->is_auto_partitioned= FALSE;
4673 else if (alter_info->flags & ALTER_DROP_PARTITION)
4676 Drop a partition from a range partition and list partitioning is
4677 always safe and can be made more or less immediate. It is necessary
4678 however to ensure that the partition to be removed is safely removed
4679 and that REPAIR TABLE can remove the partition if for some reason the
4680 command to drop the partition failed in the middle.
4682 uint part_count= 0;
4683 uint no_parts_dropped= alter_info->partition_names.elements;
4684 uint no_parts_found= 0;
4685 List_iterator<partition_element> part_it(tab_part_info->partitions);
4687 tab_part_info->is_auto_partitioned= FALSE;
4688 if (!(tab_part_info->part_type == RANGE_PARTITION ||
4689 tab_part_info->part_type == LIST_PARTITION))
4691 my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
4692 DBUG_RETURN(TRUE);
4694 if (no_parts_dropped >= tab_part_info->no_parts)
4696 my_error(ER_DROP_LAST_PARTITION, MYF(0));
4697 DBUG_RETURN(TRUE);
4701 partition_element *part_elem= part_it++;
4702 if (is_name_in_list(part_elem->partition_name,
4703 alter_info->partition_names))
4706 Set state to indicate that the partition is to be dropped.
4708 no_parts_found++;
4709 part_elem->part_state= PART_TO_BE_DROPPED;
4711 } while (++part_count < tab_part_info->no_parts);
4712 if (no_parts_found != no_parts_dropped)
4714 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
4715 DBUG_RETURN(TRUE);
4717 if (table->file->is_fk_defined_on_table_or_index(MAX_KEY))
4719 my_error(ER_ROW_IS_REFERENCED, MYF(0));
4720 DBUG_RETURN(TRUE);
4722 tab_part_info->no_parts-= no_parts_dropped;
4724 else if (alter_info->flags & ALTER_REBUILD_PARTITION)
4726 uint no_parts_found;
4727 uint no_parts_opt= alter_info->partition_names.elements;
4728 set_engine_all_partitions(tab_part_info,
4729 tab_part_info->default_engine_type);
4730 no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED);
4731 if (no_parts_found != no_parts_opt &&
4732 (!(alter_info->flags & ALTER_ALL_PARTITION)))
4734 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
4735 DBUG_RETURN(TRUE);
4737 if (!(*fast_alter_partition))
4739 table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
4740 DBUG_RETURN(TRUE);
4743 else if (alter_info->flags & ALTER_COALESCE_PARTITION)
4745 uint no_parts_coalesced= alter_info->no_parts;
4746 uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced;
4747 List_iterator<partition_element> part_it(tab_part_info->partitions);
4748 if (tab_part_info->part_type != HASH_PARTITION)
4750 my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
4751 DBUG_RETURN(TRUE);
4753 if (no_parts_coalesced == 0)
4755 my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
4756 DBUG_RETURN(TRUE);
4758 if (no_parts_coalesced >= tab_part_info->no_parts)
4760 my_error(ER_DROP_LAST_PARTITION, MYF(0));
4761 DBUG_RETURN(TRUE);
4764 Online handling:
4765 COALESCE PARTITION:
4766 -------------------
4767 The figure below shows the manner in which partitions are handled when
4768 performing an on-line coalesce partition and which states they go through
4769 at start, after adding and copying partitions and finally after dropping
4770 the partitions to drop. The figure shows an example using four partitions
4771 to start with, using linear hash and coalescing one partition (always the
4772 last partition).
4774 Using linear hash then all remaining partitions will have a new reorganised
4775 part.
4777 Existing partitions Coalesced partition
4778 ------ ------ ------ | ------
4779 | | | | | | | | |
4780 | p0 | | p1 | | p2 | | | p3 |
4781 ------ ------ ------ | ------
4782 PART_NORMAL PART_CHANGED PART_NORMAL PART_REORGED_DROPPED
4783 PART_NORMAL PART_IS_CHANGED PART_NORMAL PART_TO_BE_DROPPED
4784 PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_DROPPED
4786 Reorganised existing partitions
4787 ------
4789 | p1'|
4790 ------
4792 p0 - p3 is in the partitions list.
4793 The p1' partition will actually not be in any list it is deduced from the
4794 state of p1.
4797 uint part_count= 0, start_part= 1, start_sec_part= 1;
4798 uint end_part= 0, end_sec_part= 0;
4799 bool all_parts= TRUE;
4800 if (*fast_alter_partition &&
4801 tab_part_info->linear_hash_ind)
4803 uint upper_2n= tab_part_info->linear_hash_mask + 1;
4804 uint lower_2n= upper_2n >> 1;
4805 all_parts= FALSE;
4806 if (no_parts_coalesced >= lower_2n)
4808 all_parts= TRUE;
4810 else if (no_parts_remain >= lower_2n)
4812 end_part= tab_part_info->no_parts - (lower_2n + 1);
4813 start_part= no_parts_remain - lower_2n;
4815 else
4817 start_part= 0;
4818 end_part= tab_part_info->no_parts - (lower_2n + 1);
4819 end_sec_part= (lower_2n >> 1) - 1;
4820 start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1));
4825 partition_element *p_elem= part_it++;
4826 if (*fast_alter_partition &&
4827 (all_parts ||
4828 (part_count >= start_part && part_count <= end_part) ||
4829 (part_count >= start_sec_part && part_count <= end_sec_part)))
4830 p_elem->part_state= PART_CHANGED;
4831 if (++part_count > no_parts_remain)
4833 if (*fast_alter_partition)
4834 p_elem->part_state= PART_REORGED_DROPPED;
4835 else
4836 part_it.remove();
4838 } while (part_count < tab_part_info->no_parts);
4839 tab_part_info->no_parts= no_parts_remain;
4841 if (!(alter_info->flags & ALTER_TABLE_REORG))
4843 tab_part_info->use_default_no_partitions= FALSE;
4844 tab_part_info->is_auto_partitioned= FALSE;
4847 else if (alter_info->flags & ALTER_REORGANIZE_PARTITION)
4850 Reorganise partitions takes a number of partitions that are next
4851 to each other (at least for RANGE PARTITIONS) and then uses those
4852 to create a set of new partitions. So data is copied from those
4853 partitions into the new set of partitions. Those new partitions
4854 can have more values in the LIST value specifications or less both
4855 are allowed. The ranges can be different but since they are
4856 changing a set of consecutive partitions they must cover the same
4857 range as those changed from.
4858 This command can be used on RANGE and LIST partitions.
4860 uint no_parts_reorged= alter_info->partition_names.elements;
4861 uint no_parts_new= thd->work_part_info->partitions.elements;
4862 partition_info *alt_part_info= thd->work_part_info;
4863 uint check_total_partitions;
4865 tab_part_info->is_auto_partitioned= FALSE;
4866 if (no_parts_reorged > tab_part_info->no_parts)
4868 my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
4869 DBUG_RETURN(TRUE);
4871 if (!(tab_part_info->part_type == RANGE_PARTITION ||
4872 tab_part_info->part_type == LIST_PARTITION) &&
4873 (no_parts_new != no_parts_reorged))
4875 my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
4876 DBUG_RETURN(TRUE);
4878 if (tab_part_info->is_sub_partitioned() &&
4879 alt_part_info->no_subparts &&
4880 alt_part_info->no_subparts != tab_part_info->no_subparts)
4882 my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
4883 DBUG_RETURN(TRUE);
4885 check_total_partitions= tab_part_info->no_parts + no_parts_new;
4886 check_total_partitions-= no_parts_reorged;
4887 if (check_total_partitions > MAX_PARTITIONS)
4889 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4890 DBUG_RETURN(TRUE);
4892 alt_part_info->part_type= tab_part_info->part_type;
4893 alt_part_info->subpart_type= tab_part_info->subpart_type;
4894 alt_part_info->no_subparts= tab_part_info->no_subparts;
4895 DBUG_ASSERT(!alt_part_info->use_default_partitions);
4896 if (alt_part_info->set_up_defaults_for_partitioning(table->file,
4897 ULL(0),
4900 DBUG_RETURN(TRUE);
4903 Online handling:
4904 REORGANIZE PARTITION:
4905 ---------------------
4906 The figure exemplifies the handling of partitions, their state changes and
4907 how they are organised. It exemplifies four partitions where two of the
4908 partitions are reorganised (p1 and p2) into two new partitions (p4 and p5).
4909 The reason of this change could be to change range limits, change list
4910 values or for hash partitions simply reorganise the partition which could
4911 also involve moving them to new disks or new node groups (MySQL Cluster).
4913 Existing partitions
4914 ------ ------ ------ ------
4915 | | | | | | | |
4916 | p0 | | p1 | | p2 | | p3 |
4917 ------ ------ ------ ------
4918 PART_NORMAL PART_TO_BE_REORGED PART_NORMAL
4919 PART_NORMAL PART_TO_BE_DROPPED PART_NORMAL
4920 PART_NORMAL PART_IS_DROPPED PART_NORMAL
4922 Reorganised new partitions (replacing p1 and p2)
4923 ------ ------
4924 | | | |
4925 | p4 | | p5 |
4926 ------ ------
4927 PART_TO_BE_ADDED
4928 PART_IS_ADDED
4929 PART_IS_ADDED
4931 All unchanged partitions and the new partitions are in the partitions list
4932 in the order they will have when the change is completed. The reorganised
4933 partitions are placed in the temp_partitions list. PART_IS_ADDED is only a
4934 temporary state not written in the frm file. It is used to ensure we write
4935 the generated partition syntax in a correct manner.
4938 List_iterator<partition_element> tab_it(tab_part_info->partitions);
4939 uint part_count= 0;
4940 bool found_first= FALSE;
4941 bool found_last= FALSE;
4942 bool is_last_partition_reorged;
4943 uint drop_count= 0;
4944 longlong tab_max_range= 0, alt_max_range= 0;
4947 partition_element *part_elem= tab_it++;
4948 is_last_partition_reorged= FALSE;
4949 if (is_name_in_list(part_elem->partition_name,
4950 alter_info->partition_names))
4952 is_last_partition_reorged= TRUE;
4953 drop_count++;
4954 tab_max_range= part_elem->range_value;
4955 if (*fast_alter_partition &&
4956 tab_part_info->temp_partitions.push_back(part_elem))
4958 mem_alloc_error(1);
4959 DBUG_RETURN(TRUE);
4961 if (*fast_alter_partition)
4962 part_elem->part_state= PART_TO_BE_REORGED;
4963 if (!found_first)
4965 uint alt_part_count= 0;
4966 found_first= TRUE;
4967 List_iterator<partition_element>
4968 alt_it(alt_part_info->partitions);
4971 partition_element *alt_part_elem= alt_it++;
4972 alt_max_range= alt_part_elem->range_value;
4973 if (*fast_alter_partition)
4974 alt_part_elem->part_state= PART_TO_BE_ADDED;
4975 if (alt_part_count == 0)
4976 tab_it.replace(alt_part_elem);
4977 else
4978 tab_it.after(alt_part_elem);
4979 } while (++alt_part_count < no_parts_new);
4981 else if (found_last)
4983 my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
4984 DBUG_RETURN(TRUE);
4986 else
4987 tab_it.remove();
4989 else
4991 if (found_first)
4992 found_last= TRUE;
4994 } while (++part_count < tab_part_info->no_parts);
4995 if (drop_count != no_parts_reorged)
4997 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
4998 DBUG_RETURN(TRUE);
5000 if (tab_part_info->part_type == RANGE_PARTITION &&
5001 ((is_last_partition_reorged &&
5002 alt_max_range < tab_max_range) ||
5003 (!is_last_partition_reorged &&
5004 alt_max_range != tab_max_range)))
5007 For range partitioning the total resulting range before and
5008 after the change must be the same except in one case. This is
5009 when the last partition is reorganised, in this case it is
5010 acceptable to increase the total range.
5011 The reason is that it is not allowed to have "holes" in the
5012 middle of the ranges and thus we should not allow to reorganise
5013 to create "holes". Also we should not allow using REORGANIZE
5014 to drop data.
5016 my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
5017 DBUG_RETURN(TRUE);
5019 tab_part_info->no_parts= check_total_partitions;
5022 else
5024 DBUG_ASSERT(FALSE);
5026 *partition_changed= TRUE;
5027 thd->work_part_info= tab_part_info;
5028 if (alter_info->flags & ALTER_ADD_PARTITION ||
5029 alter_info->flags & ALTER_REORGANIZE_PARTITION)
5031 if (tab_part_info->use_default_subpartitions &&
5032 !alt_part_info->use_default_subpartitions)
5034 tab_part_info->use_default_subpartitions= FALSE;
5035 tab_part_info->use_default_no_subpartitions= FALSE;
5037 if (tab_part_info->check_partition_info(thd, (handlerton**)NULL,
5038 table->file, ULL(0), FALSE))
5040 DBUG_RETURN(TRUE);
5044 else
5047 When thd->lex->part_info has a reference to a partition_info the
5048 ALTER TABLE contained a definition of a partitioning.
5050 Case I:
5051 If there was a partition before and there is a new one defined.
5052 We use the new partitioning. The new partitioning is already
5053 defined in the correct variable so no work is needed to
5054 accomplish this.
5055 We do however need to update partition_changed to ensure that not
5056 only the frm file is changed in the ALTER TABLE command.
5058 Case IIa:
5059 There was a partitioning before and there is no new one defined.
5060 Also the user has not specified to remove partitioning explicitly.
5062 We use the old partitioning also for the new table. We do this
5063 by assigning the partition_info from the table loaded in
5064 open_table to the partition_info struct used by mysql_create_table
5065 later in this method.
5067 Case IIb:
5068 There was a partitioning before and there is no new one defined.
5069 The user has specified explicitly to remove partitioning
5071 Since the user has specified explicitly to remove partitioning
5072 we override the old partitioning info and create a new table using
5073 the specified engine.
5074 In this case the partition also is changed.
5076 Case III:
5077 There was no partitioning before altering the table, there is
5078 partitioning defined in the altered table. Use the new partitioning.
5079 No work needed since the partitioning info is already in the
5080 correct variable.
5082 In this case we discover one case where the new partitioning is using
5083 the same partition function as the default (PARTITION BY KEY or
5084 PARTITION BY LINEAR KEY with the list of fields equal to the primary
5085 key fields OR PARTITION BY [LINEAR] KEY() for tables without primary
5086 key)
5087 Also here partition has changed and thus a new table must be
5088 created.
5090 Case IV:
5091 There was no partitioning before and no partitioning defined.
5092 Obviously no work needed.
5094 if (table->part_info)
5096 if (alter_info->flags & ALTER_REMOVE_PARTITIONING)
5098 DBUG_PRINT("info", ("Remove partitioning"));
5099 if (!(create_info->used_fields & HA_CREATE_USED_ENGINE))
5101 DBUG_PRINT("info", ("No explicit engine used"));
5102 create_info->db_type= table->part_info->default_engine_type;
5104 DBUG_PRINT("info", ("New engine type: %s",
5105 ha_resolve_storage_engine_name(create_info->db_type)));
5106 thd->work_part_info= NULL;
5107 *partition_changed= TRUE;
5109 else if (!thd->work_part_info)
5112 Retain partitioning but possibly with a new storage engine
5113 beneath.
5115 thd->work_part_info= table->part_info;
5116 if (create_info->used_fields & HA_CREATE_USED_ENGINE &&
5117 create_info->db_type != table->part_info->default_engine_type)
5120 Make sure change of engine happens to all partitions.
5122 DBUG_PRINT("info", ("partition changed"));
5123 if (table->part_info->is_auto_partitioned)
5126 If the user originally didn't specify partitioning to be
5127 used we can remove it now.
5129 thd->work_part_info= NULL;
5131 else
5134 Ensure that all partitions have the proper engine set-up
5136 set_engine_all_partitions(thd->work_part_info,
5137 create_info->db_type);
5139 *partition_changed= TRUE;
5143 if (thd->work_part_info)
5145 partition_info *part_info= thd->work_part_info;
5146 bool is_native_partitioned= FALSE;
5148 Need to cater for engine types that can handle partition without
5149 using the partition handler.
5151 if (thd->work_part_info != table->part_info)
5153 DBUG_PRINT("info", ("partition changed"));
5154 *partition_changed= TRUE;
5157 Set up partition default_engine_type either from the create_info
5158 or from the previus table
5160 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5161 part_info->default_engine_type= create_info->db_type;
5162 else
5164 if (table->part_info)
5165 part_info->default_engine_type= table->part_info->default_engine_type;
5166 else
5167 part_info->default_engine_type= create_info->db_type;
5169 DBUG_ASSERT(part_info->default_engine_type &&
5170 part_info->default_engine_type != partition_hton);
5171 if (check_native_partitioned(create_info, &is_native_partitioned,
5172 part_info, thd))
5174 DBUG_RETURN(TRUE);
5176 if (!is_native_partitioned)
5178 DBUG_ASSERT(create_info->db_type);
5179 create_info->db_type= partition_hton;
5183 DBUG_RETURN(FALSE);
5188 Change partitions, used to implement ALTER TABLE ADD/REORGANIZE/COALESCE
5189 partitions. This method is used to implement both single-phase and multi-
5190 phase implementations of ADD/REORGANIZE/COALESCE partitions.
5192 SYNOPSIS
5193 mysql_change_partitions()
5194 lpt Struct containing parameters
5196 RETURN VALUES
5197 TRUE Failure
5198 FALSE Success
5200 DESCRIPTION
5201 Request handler to add partitions as set in states of the partition
5203 Elements of the lpt parameters used:
5204 create_info Create information used to create partitions
5205 db Database name
5206 table_name Table name
5207 copied Output parameter where number of copied
5208 records are added
5209 deleted Output parameter where number of deleted
5210 records are added
5213 static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
5215 char path[FN_REFLEN+1];
5216 int error;
5217 handler *file= lpt->table->file;
5218 DBUG_ENTER("mysql_change_partitions");
5220 build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
5221 if ((error= file->ha_change_partitions(lpt->create_info, path, &lpt->copied,
5222 &lpt->deleted, lpt->pack_frm_data,
5223 lpt->pack_frm_len)))
5225 if (error != ER_OUTOFMEMORY)
5226 file->print_error(error, MYF(0));
5227 else
5228 lpt->thd->fatal_error();
5229 DBUG_RETURN(TRUE);
5231 DBUG_RETURN(FALSE);
5236 Rename partitions in an ALTER TABLE of partitions
5238 SYNOPSIS
5239 mysql_rename_partitions()
5240 lpt Struct containing parameters
5242 RETURN VALUES
5243 TRUE Failure
5244 FALSE Success
5246 DESCRIPTION
5247 Request handler to rename partitions as set in states of the partition
5249 Parameters used:
5250 db Database name
5251 table_name Table name
5254 static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
5256 char path[FN_REFLEN+1];
5257 int error;
5258 DBUG_ENTER("mysql_rename_partitions");
5260 build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
5261 if ((error= lpt->table->file->ha_rename_partitions(path)))
5263 if (error != 1)
5264 lpt->table->file->print_error(error, MYF(0));
5265 DBUG_RETURN(TRUE);
5267 DBUG_RETURN(FALSE);
5272 Drop partitions in an ALTER TABLE of partitions
5274 SYNOPSIS
5275 mysql_drop_partitions()
5276 lpt Struct containing parameters
5278 RETURN VALUES
5279 TRUE Failure
5280 FALSE Success
5281 DESCRIPTION
5282 Drop the partitions marked with PART_TO_BE_DROPPED state and remove
5283 those partitions from the list.
5285 Parameters used:
5286 table Table object
5287 db Database name
5288 table_name Table name
5291 static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
5293 char path[FN_REFLEN+1];
5294 partition_info *part_info= lpt->table->part_info;
5295 List_iterator<partition_element> part_it(part_info->partitions);
5296 uint i= 0;
5297 uint remove_count= 0;
5298 int error;
5299 DBUG_ENTER("mysql_drop_partitions");
5301 build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
5302 if ((error= lpt->table->file->ha_drop_partitions(path)))
5304 lpt->table->file->print_error(error, MYF(0));
5305 DBUG_RETURN(TRUE);
5309 partition_element *part_elem= part_it++;
5310 if (part_elem->part_state == PART_IS_DROPPED)
5312 part_it.remove();
5313 remove_count++;
5315 } while (++i < part_info->no_parts);
5316 part_info->no_parts-= remove_count;
5317 DBUG_RETURN(FALSE);
5322 Insert log entry into list
5323 SYNOPSIS
5324 insert_part_info_log_entry_list()
5325 log_entry
5326 RETURN VALUES
5327 NONE
5330 static void insert_part_info_log_entry_list(partition_info *part_info,
5331 DDL_LOG_MEMORY_ENTRY *log_entry)
5333 log_entry->next_active_log_entry= part_info->first_log_entry;
5334 part_info->first_log_entry= log_entry;
5339 Release all log entries for this partition info struct
5340 SYNOPSIS
5341 release_part_info_log_entries()
5342 first_log_entry First log entry in list to release
5343 RETURN VALUES
5344 NONE
5347 static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY *log_entry)
5349 DBUG_ENTER("release_part_info_log_entries");
5351 while (log_entry)
5353 release_ddl_log_memory_entry(log_entry);
5354 log_entry= log_entry->next_active_log_entry;
5356 DBUG_VOID_RETURN;
5361 Log an delete/rename frm file
5362 SYNOPSIS
5363 write_log_replace_delete_frm()
5364 lpt Struct for parameters
5365 next_entry Next reference to use in log record
5366 from_path Name to rename from
5367 to_path Name to rename to
5368 replace_flag TRUE if replace, else delete
5369 RETURN VALUES
5370 TRUE Error
5371 FALSE Success
5372 DESCRIPTION
5373 Support routine that writes a replace or delete of an frm file into the
5374 ddl log. It also inserts an entry that keeps track of used space into
5375 the partition info object
5378 static bool write_log_replace_delete_frm(ALTER_PARTITION_PARAM_TYPE *lpt,
5379 uint next_entry,
5380 const char *from_path,
5381 const char *to_path,
5382 bool replace_flag)
5384 DDL_LOG_ENTRY ddl_log_entry;
5385 DDL_LOG_MEMORY_ENTRY *log_entry;
5386 DBUG_ENTER("write_log_replace_delete_frm");
5388 if (replace_flag)
5389 ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
5390 else
5391 ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
5392 ddl_log_entry.next_entry= next_entry;
5393 ddl_log_entry.handler_name= reg_ext;
5394 ddl_log_entry.name= to_path;
5395 if (replace_flag)
5396 ddl_log_entry.from_name= from_path;
5397 if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
5399 DBUG_RETURN(TRUE);
5401 insert_part_info_log_entry_list(lpt->part_info, log_entry);
5402 DBUG_RETURN(FALSE);
5407 Log final partition changes in change partition
5408 SYNOPSIS
5409 write_log_changed_partitions()
5410 lpt Struct containing parameters
5411 RETURN VALUES
5412 TRUE Error
5413 FALSE Success
5414 DESCRIPTION
5415 This code is used to perform safe ADD PARTITION for HASH partitions
5416 and COALESCE for HASH partitions and REORGANIZE for any type of
5417 partitions.
5418 We prepare entries for all partitions except the reorganised partitions
5419 in REORGANIZE partition, those are handled by
5420 write_log_dropped_partitions. For those partitions that are replaced
5421 special care is needed to ensure that this is performed correctly and
5422 this requires a two-phased approach with this log as a helper for this.
5424 This code is closely intertwined with the code in rename_partitions in
5425 the partition handler.
5428 static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
5429 uint *next_entry, const char *path)
5431 DDL_LOG_ENTRY ddl_log_entry;
5432 partition_info *part_info= lpt->part_info;
5433 DDL_LOG_MEMORY_ENTRY *log_entry;
5434 char tmp_path[FN_REFLEN];
5435 char normal_path[FN_REFLEN];
5436 List_iterator<partition_element> part_it(part_info->partitions);
5437 uint temp_partitions= part_info->temp_partitions.elements;
5438 uint no_elements= part_info->partitions.elements;
5439 uint i= 0;
5440 DBUG_ENTER("write_log_changed_partitions");
5444 partition_element *part_elem= part_it++;
5445 if (part_elem->part_state == PART_IS_CHANGED ||
5446 (part_elem->part_state == PART_IS_ADDED && temp_partitions))
5448 if (part_info->is_sub_partitioned())
5450 List_iterator<partition_element> sub_it(part_elem->subpartitions);
5451 uint no_subparts= part_info->no_subparts;
5452 uint j= 0;
5455 partition_element *sub_elem= sub_it++;
5456 ddl_log_entry.next_entry= *next_entry;
5457 ddl_log_entry.handler_name=
5458 ha_resolve_storage_engine_name(sub_elem->engine_type);
5459 create_subpartition_name(tmp_path, path,
5460 part_elem->partition_name,
5461 sub_elem->partition_name,
5462 TEMP_PART_NAME);
5463 create_subpartition_name(normal_path, path,
5464 part_elem->partition_name,
5465 sub_elem->partition_name,
5466 NORMAL_PART_NAME);
5467 ddl_log_entry.name= normal_path;
5468 ddl_log_entry.from_name= tmp_path;
5469 if (part_elem->part_state == PART_IS_CHANGED)
5470 ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
5471 else
5472 ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
5473 if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
5475 DBUG_RETURN(TRUE);
5477 *next_entry= log_entry->entry_pos;
5478 sub_elem->log_entry= log_entry;
5479 insert_part_info_log_entry_list(part_info, log_entry);
5480 } while (++j < no_subparts);
5482 else
5484 ddl_log_entry.next_entry= *next_entry;
5485 ddl_log_entry.handler_name=
5486 ha_resolve_storage_engine_name(part_elem->engine_type);
5487 create_partition_name(tmp_path, path,
5488 part_elem->partition_name,
5489 TEMP_PART_NAME, TRUE);
5490 create_partition_name(normal_path, path,
5491 part_elem->partition_name,
5492 NORMAL_PART_NAME, TRUE);
5493 ddl_log_entry.name= normal_path;
5494 ddl_log_entry.from_name= tmp_path;
5495 if (part_elem->part_state == PART_IS_CHANGED)
5496 ddl_log_entry.action_type= DDL_LOG_REPLACE_ACTION;
5497 else
5498 ddl_log_entry.action_type= DDL_LOG_RENAME_ACTION;
5499 if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
5501 DBUG_RETURN(TRUE);
5503 *next_entry= log_entry->entry_pos;
5504 part_elem->log_entry= log_entry;
5505 insert_part_info_log_entry_list(part_info, log_entry);
5508 } while (++i < no_elements);
5509 DBUG_RETURN(FALSE);
5514 Log dropped partitions
5515 SYNOPSIS
5516 write_log_dropped_partitions()
5517 lpt Struct containing parameters
5518 RETURN VALUES
5519 TRUE Error
5520 FALSE Success
5523 static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
5524 uint *next_entry,
5525 const char *path,
5526 bool temp_list)
5528 DDL_LOG_ENTRY ddl_log_entry;
5529 partition_info *part_info= lpt->part_info;
5530 DDL_LOG_MEMORY_ENTRY *log_entry;
5531 char tmp_path[FN_LEN];
5532 List_iterator<partition_element> part_it(part_info->partitions);
5533 List_iterator<partition_element> temp_it(part_info->temp_partitions);
5534 uint no_temp_partitions= part_info->temp_partitions.elements;
5535 uint no_elements= part_info->partitions.elements;
5536 DBUG_ENTER("write_log_dropped_partitions");
5538 ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION;
5539 if (temp_list)
5540 no_elements= no_temp_partitions;
5541 while (no_elements--)
5543 partition_element *part_elem;
5544 if (temp_list)
5545 part_elem= temp_it++;
5546 else
5547 part_elem= part_it++;
5548 if (part_elem->part_state == PART_TO_BE_DROPPED ||
5549 part_elem->part_state == PART_TO_BE_ADDED ||
5550 part_elem->part_state == PART_CHANGED)
5552 uint name_variant;
5553 if (part_elem->part_state == PART_CHANGED ||
5554 (part_elem->part_state == PART_TO_BE_ADDED &&
5555 no_temp_partitions))
5556 name_variant= TEMP_PART_NAME;
5557 else
5558 name_variant= NORMAL_PART_NAME;
5559 if (part_info->is_sub_partitioned())
5561 List_iterator<partition_element> sub_it(part_elem->subpartitions);
5562 uint no_subparts= part_info->no_subparts;
5563 uint j= 0;
5566 partition_element *sub_elem= sub_it++;
5567 ddl_log_entry.next_entry= *next_entry;
5568 ddl_log_entry.handler_name=
5569 ha_resolve_storage_engine_name(sub_elem->engine_type);
5570 create_subpartition_name(tmp_path, path,
5571 part_elem->partition_name,
5572 sub_elem->partition_name,
5573 name_variant);
5574 ddl_log_entry.name= tmp_path;
5575 if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
5577 DBUG_RETURN(TRUE);
5579 *next_entry= log_entry->entry_pos;
5580 sub_elem->log_entry= log_entry;
5581 insert_part_info_log_entry_list(part_info, log_entry);
5582 } while (++j < no_subparts);
5584 else
5586 ddl_log_entry.next_entry= *next_entry;
5587 ddl_log_entry.handler_name=
5588 ha_resolve_storage_engine_name(part_elem->engine_type);
5589 create_partition_name(tmp_path, path,
5590 part_elem->partition_name,
5591 name_variant, TRUE);
5592 ddl_log_entry.name= tmp_path;
5593 if (write_ddl_log_entry(&ddl_log_entry, &log_entry))
5595 DBUG_RETURN(TRUE);
5597 *next_entry= log_entry->entry_pos;
5598 part_elem->log_entry= log_entry;
5599 insert_part_info_log_entry_list(part_info, log_entry);
5603 DBUG_RETURN(FALSE);
5608 Set execute log entry in ddl log for this partitioned table
5609 SYNOPSIS
5610 set_part_info_exec_log_entry()
5611 part_info Partition info object
5612 exec_log_entry Log entry
5613 RETURN VALUES
5614 NONE
5617 static void set_part_info_exec_log_entry(partition_info *part_info,
5618 DDL_LOG_MEMORY_ENTRY *exec_log_entry)
5620 part_info->exec_log_entry= exec_log_entry;
5621 exec_log_entry->next_active_log_entry= NULL;
5626 Write the log entry to ensure that the shadow frm file is removed at
5627 crash.
5628 SYNOPSIS
5629 write_log_drop_shadow_frm()
5630 lpt Struct containing parameters
5631 install_frm Should we log action to install shadow frm or should
5632 the action be to remove the shadow frm file.
5633 RETURN VALUES
5634 TRUE Error
5635 FALSE Success
5636 DESCRIPTION
5637 Prepare an entry to the ddl log indicating a drop/install of the shadow frm
5638 file and its corresponding handler file.
5641 static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
5643 partition_info *part_info= lpt->part_info;
5644 DDL_LOG_MEMORY_ENTRY *log_entry;
5645 DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
5646 char shadow_path[FN_REFLEN + 1];
5647 DBUG_ENTER("write_log_drop_shadow_frm");
5649 build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
5650 pthread_mutex_lock(&LOCK_gdl);
5651 if (write_log_replace_delete_frm(lpt, 0UL, NULL,
5652 (const char*)shadow_path, FALSE))
5653 goto error;
5654 log_entry= part_info->first_log_entry;
5655 if (write_execute_ddl_log_entry(log_entry->entry_pos,
5656 FALSE, &exec_log_entry))
5657 goto error;
5658 pthread_mutex_unlock(&LOCK_gdl);
5659 set_part_info_exec_log_entry(part_info, exec_log_entry);
5660 DBUG_RETURN(FALSE);
5662 error:
5663 release_part_info_log_entries(part_info->first_log_entry);
5664 pthread_mutex_unlock(&LOCK_gdl);
5665 part_info->first_log_entry= NULL;
5666 my_error(ER_DDL_LOG_ERROR, MYF(0));
5667 DBUG_RETURN(TRUE);
5672 Log renaming of shadow frm to real frm name and dropping of old frm
5673 SYNOPSIS
5674 write_log_rename_frm()
5675 lpt Struct containing parameters
5676 RETURN VALUES
5677 TRUE Error
5678 FALSE Success
5679 DESCRIPTION
5680 Prepare an entry to ensure that we complete the renaming of the frm
5681 file if failure occurs in the middle of the rename process.
5684 static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
5686 partition_info *part_info= lpt->part_info;
5687 DDL_LOG_MEMORY_ENTRY *log_entry;
5688 DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
5689 char path[FN_REFLEN + 1];
5690 char shadow_path[FN_REFLEN + 1];
5691 DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
5692 DBUG_ENTER("write_log_rename_frm");
5694 part_info->first_log_entry= NULL;
5695 build_table_filename(path, sizeof(path) - 1, lpt->db,
5696 lpt->table_name, "", 0);
5697 build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
5698 pthread_mutex_lock(&LOCK_gdl);
5699 if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
5700 goto error;
5701 log_entry= part_info->first_log_entry;
5702 part_info->frm_log_entry= log_entry;
5703 if (write_execute_ddl_log_entry(log_entry->entry_pos,
5704 FALSE, &exec_log_entry))
5705 goto error;
5706 release_part_info_log_entries(old_first_log_entry);
5707 pthread_mutex_unlock(&LOCK_gdl);
5708 DBUG_RETURN(FALSE);
5710 error:
5711 release_part_info_log_entries(part_info->first_log_entry);
5712 pthread_mutex_unlock(&LOCK_gdl);
5713 part_info->first_log_entry= old_first_log_entry;
5714 part_info->frm_log_entry= NULL;
5715 my_error(ER_DDL_LOG_ERROR, MYF(0));
5716 DBUG_RETURN(TRUE);
5721 Write the log entries to ensure that the drop partition command is completed
5722 even in the presence of a crash.
5724 SYNOPSIS
5725 write_log_drop_partition()
5726 lpt Struct containing parameters
5727 RETURN VALUES
5728 TRUE Error
5729 FALSE Success
5730 DESCRIPTION
5731 Prepare entries to the ddl log indicating all partitions to drop and to
5732 install the shadow frm file and remove the old frm file.
5735 static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
5737 partition_info *part_info= lpt->part_info;
5738 DDL_LOG_MEMORY_ENTRY *log_entry;
5739 DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
5740 char tmp_path[FN_REFLEN + 1];
5741 char path[FN_REFLEN + 1];
5742 uint next_entry= 0;
5743 DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
5744 DBUG_ENTER("write_log_drop_partition");
5746 part_info->first_log_entry= NULL;
5747 build_table_filename(path, sizeof(path) - 1, lpt->db,
5748 lpt->table_name, "", 0);
5749 build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
5750 pthread_mutex_lock(&LOCK_gdl);
5751 if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
5752 FALSE))
5753 goto error;
5754 if (write_log_replace_delete_frm(lpt, next_entry, (const char*)tmp_path,
5755 (const char*)path, TRUE))
5756 goto error;
5757 log_entry= part_info->first_log_entry;
5758 part_info->frm_log_entry= log_entry;
5759 if (write_execute_ddl_log_entry(log_entry->entry_pos,
5760 FALSE, &exec_log_entry))
5761 goto error;
5762 release_part_info_log_entries(old_first_log_entry);
5763 pthread_mutex_unlock(&LOCK_gdl);
5764 DBUG_RETURN(FALSE);
5766 error:
5767 release_part_info_log_entries(part_info->first_log_entry);
5768 pthread_mutex_unlock(&LOCK_gdl);
5769 part_info->first_log_entry= old_first_log_entry;
5770 part_info->frm_log_entry= NULL;
5771 my_error(ER_DDL_LOG_ERROR, MYF(0));
5772 DBUG_RETURN(TRUE);
5777 Write the log entries to ensure that the add partition command is not
5778 executed at all if a crash before it has completed
5780 SYNOPSIS
5781 write_log_add_change_partition()
5782 lpt Struct containing parameters
5783 RETURN VALUES
5784 TRUE Error
5785 FALSE Success
5786 DESCRIPTION
5787 Prepare entries to the ddl log indicating all partitions to drop and to
5788 remove the shadow frm file.
5789 We always inject entries backwards in the list in the ddl log since we
5790 don't know the entry position until we have written it.
5793 static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
5795 partition_info *part_info= lpt->part_info;
5796 DDL_LOG_MEMORY_ENTRY *log_entry;
5797 DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
5798 char tmp_path[FN_REFLEN + 1];
5799 char path[FN_REFLEN + 1];
5800 uint next_entry= 0;
5801 DBUG_ENTER("write_log_add_change_partition");
5803 build_table_filename(path, sizeof(path) - 1, lpt->db,
5804 lpt->table_name, "", 0);
5805 build_table_shadow_filename(tmp_path, sizeof(tmp_path) - 1, lpt);
5806 pthread_mutex_lock(&LOCK_gdl);
5807 if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
5808 FALSE))
5809 goto error;
5810 if (write_log_replace_delete_frm(lpt, next_entry, NULL, tmp_path,
5811 FALSE))
5812 goto error;
5813 log_entry= part_info->first_log_entry;
5814 if (write_execute_ddl_log_entry(log_entry->entry_pos,
5815 FALSE, &exec_log_entry))
5816 goto error;
5817 pthread_mutex_unlock(&LOCK_gdl);
5818 set_part_info_exec_log_entry(part_info, exec_log_entry);
5819 DBUG_RETURN(FALSE);
5821 error:
5822 release_part_info_log_entries(part_info->first_log_entry);
5823 pthread_mutex_unlock(&LOCK_gdl);
5824 part_info->first_log_entry= NULL;
5825 my_error(ER_DDL_LOG_ERROR, MYF(0));
5826 DBUG_RETURN(TRUE);
5831 Write description of how to complete the operation after first phase of
5832 change partitions.
5834 SYNOPSIS
5835 write_log_final_change_partition()
5836 lpt Struct containing parameters
5837 RETURN VALUES
5838 TRUE Error
5839 FALSE Success
5840 DESCRIPTION
5841 We will write log entries that specify to remove all partitions reorganised,
5842 to rename others to reflect the new naming scheme and to install the shadow
5843 frm file.
5846 static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
5848 partition_info *part_info= lpt->part_info;
5849 DDL_LOG_MEMORY_ENTRY *log_entry;
5850 DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
5851 char path[FN_REFLEN + 1];
5852 char shadow_path[FN_REFLEN + 1];
5853 DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
5854 uint next_entry= 0;
5855 DBUG_ENTER("write_log_final_change_partition");
5857 part_info->first_log_entry= NULL;
5858 build_table_filename(path, sizeof(path) - 1, lpt->db,
5859 lpt->table_name, "", 0);
5860 build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
5861 pthread_mutex_lock(&LOCK_gdl);
5862 if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
5863 lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION))
5864 goto error;
5865 if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
5866 goto error;
5867 if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
5868 goto error;
5869 log_entry= part_info->first_log_entry;
5870 part_info->frm_log_entry= log_entry;
5871 if (write_execute_ddl_log_entry(log_entry->entry_pos,
5872 FALSE, &exec_log_entry))
5873 goto error;
5874 release_part_info_log_entries(old_first_log_entry);
5875 pthread_mutex_unlock(&LOCK_gdl);
5876 DBUG_RETURN(FALSE);
5878 error:
5879 release_part_info_log_entries(part_info->first_log_entry);
5880 pthread_mutex_unlock(&LOCK_gdl);
5881 part_info->first_log_entry= old_first_log_entry;
5882 part_info->frm_log_entry= NULL;
5883 my_error(ER_DDL_LOG_ERROR, MYF(0));
5884 DBUG_RETURN(TRUE);
5889 Remove entry from ddl log and release resources for others to use
5891 SYNOPSIS
5892 write_log_completed()
5893 lpt Struct containing parameters
5894 RETURN VALUES
5895 TRUE Error
5896 FALSE Success
5899 static void write_log_completed(ALTER_PARTITION_PARAM_TYPE *lpt,
5900 bool dont_crash)
5902 partition_info *part_info= lpt->part_info;
5903 DDL_LOG_MEMORY_ENTRY *log_entry= part_info->exec_log_entry;
5904 DBUG_ENTER("write_log_completed");
5906 DBUG_ASSERT(log_entry);
5907 pthread_mutex_lock(&LOCK_gdl);
5908 if (write_execute_ddl_log_entry(0UL, TRUE, &log_entry))
5911 Failed to write, Bad...
5912 We have completed the operation but have log records to REMOVE
5913 stuff that shouldn't be removed. What clever things could one do
5914 here? An error output was written to the error output by the
5915 above method so we don't do anything here.
5919 release_part_info_log_entries(part_info->first_log_entry);
5920 release_part_info_log_entries(part_info->exec_log_entry);
5921 pthread_mutex_unlock(&LOCK_gdl);
5922 part_info->exec_log_entry= NULL;
5923 part_info->first_log_entry= NULL;
5924 DBUG_VOID_RETURN;
5929 Release all log entries
5930 SYNOPSIS
5931 release_log_entries()
5932 part_info Partition info struct
5933 RETURN VALUES
5934 NONE
5937 static void release_log_entries(partition_info *part_info)
5939 pthread_mutex_lock(&LOCK_gdl);
5940 release_part_info_log_entries(part_info->first_log_entry);
5941 release_part_info_log_entries(part_info->exec_log_entry);
5942 pthread_mutex_unlock(&LOCK_gdl);
5943 part_info->first_log_entry= NULL;
5944 part_info->exec_log_entry= NULL;
5949 Final part of partition changes to handle things when under
5950 LOCK TABLES.
5951 SYNPOSIS
5952 alter_partition_lock_handling()
5953 lpt Struct carrying parameters
5954 RETURN VALUES
5955 NONE
5957 static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
5959 int err;
5960 if (lpt->thd->locked_tables)
5963 Close the table if open, to remove/destroy the already altered
5964 table->part_info object, so that it is not reused.
5966 if (lpt->table->db_stat)
5967 abort_and_upgrade_lock_and_close_table(lpt);
5969 When we have the table locked, it is necessary to reopen the table
5970 since all table objects were closed and removed as part of the
5971 ALTER TABLE of partitioning structure.
5973 pthread_mutex_lock(&LOCK_open);
5974 lpt->thd->in_lock_tables= 1;
5975 err= reopen_tables(lpt->thd, 1, 1);
5976 lpt->thd->in_lock_tables= 0;
5977 if (err)
5980 Issue a warning since we weren't able to regain the lock again.
5981 We also need to unlink table from thread's open list and from
5982 table_cache
5984 unlink_open_table(lpt->thd, lpt->table, FALSE);
5985 sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
5987 pthread_mutex_unlock(&LOCK_open);
5993 Handle errors for ALTER TABLE for partitioning
5994 SYNOPSIS
5995 handle_alter_part_error()
5996 lpt Struct carrying parameters
5997 not_completed Was request in complete phase when error occurred
5998 RETURN VALUES
5999 NONE
6002 void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt,
6003 bool not_completed,
6004 bool drop_partition,
6005 bool frm_install)
6007 partition_info *part_info= lpt->part_info;
6008 DBUG_ENTER("handle_alter_part_error");
6010 if (part_info->first_log_entry &&
6011 execute_ddl_log_entry(current_thd,
6012 part_info->first_log_entry->entry_pos))
6015 We couldn't recover from error, most likely manual interaction
6016 is required.
6018 write_log_completed(lpt, FALSE);
6019 release_log_entries(part_info);
6020 if (not_completed)
6022 if (drop_partition)
6024 /* Table is still ok, but we left a shadow frm file behind. */
6025 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,
6026 "%s %s",
6027 "Operation was unsuccessful, table is still intact,",
6028 "but it is possible that a shadow frm file was left behind");
6030 else
6032 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,
6033 "%s %s %s %s",
6034 "Operation was unsuccessful, table is still intact,",
6035 "but it is possible that a shadow frm file was left behind.",
6036 "It is also possible that temporary partitions are left behind,",
6037 "these could be empty or more or less filled with records");
6040 else
6042 if (frm_install)
6045 Failed during install of shadow frm file, table isn't intact
6046 and dropped partitions are still there
6048 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,
6049 "%s %s %s",
6050 "Failed during alter of partitions, table is no longer intact.",
6051 "The frm file is in an unknown state, and a backup",
6052 "is required.");
6054 else if (drop_partition)
6057 Table is ok, we have switched to new table but left dropped
6058 partitions still in their places. We remove the log records and
6059 ask the user to perform the action manually. We remove the log
6060 records and ask the user to perform the action manually.
6062 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,
6063 "%s %s",
6064 "Failed during drop of partitions, table is intact.",
6065 "Manual drop of remaining partitions is required");
6067 else
6070 We failed during renaming of partitions. The table is most
6071 certainly in a very bad state so we give user warning and disable
6072 the table by writing an ancient frm version into it.
6074 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,
6075 "%s %s %s",
6076 "Failed during renaming of partitions. We are now in a position",
6077 "where table is not reusable",
6078 "Table is disabled by writing ancient frm file version into it");
6082 else
6084 release_log_entries(part_info);
6085 if (not_completed)
6088 We hit an error before things were completed but managed
6089 to recover from the error. An error occurred and we have
6090 restored things to original so no need for further action.
6094 else
6097 We hit an error after we had completed most of the operation
6098 and were successful in a second attempt so the operation
6099 actually is successful now. We need to issue a warning that
6100 even though we reported an error the operation was successfully
6101 completed.
6103 push_warning_printf(lpt->thd, MYSQL_ERROR::WARN_LEVEL_WARN, 1,"%s %s",
6104 "Operation was successfully completed by failure handling,",
6105 "after failure of normal operation");
6108 DBUG_VOID_RETURN;
6113 Actually perform the change requested by ALTER TABLE of partitions
6114 previously prepared.
6116 SYNOPSIS
6117 fast_alter_partition_table()
6118 thd Thread object
6119 table Table object
6120 alter_info ALTER TABLE info
6121 create_info Create info for CREATE TABLE
6122 table_list List of the table involved
6123 db Database name of new table
6124 table_name Table name of new table
6126 RETURN VALUES
6127 TRUE Error
6128 FALSE Success
6130 DESCRIPTION
6131 Perform all ALTER TABLE operations for partitioned tables that can be
6132 performed fast without a full copy of the original table.
6135 uint fast_alter_partition_table(THD *thd, TABLE *table,
6136 Alter_info *alter_info,
6137 HA_CREATE_INFO *create_info,
6138 TABLE_LIST *table_list,
6139 char *db,
6140 const char *table_name,
6141 uint fast_alter_partition)
6143 /* Set-up struct used to write frm files */
6144 partition_info *part_info= table->part_info;
6145 ALTER_PARTITION_PARAM_TYPE lpt_obj;
6146 ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj;
6147 bool written_bin_log= TRUE;
6148 bool not_completed= TRUE;
6149 bool frm_install= FALSE;
6150 DBUG_ENTER("fast_alter_partition_table");
6152 lpt->thd= thd;
6153 lpt->part_info= part_info;
6154 lpt->alter_info= alter_info;
6155 lpt->create_info= create_info;
6156 lpt->db_options= create_info->table_options;
6157 if (create_info->row_type == ROW_TYPE_DYNAMIC)
6158 lpt->db_options|= HA_OPTION_PACK_RECORD;
6159 lpt->table= table;
6160 lpt->key_info_buffer= 0;
6161 lpt->key_count= 0;
6162 lpt->db= db;
6163 lpt->table_name= table_name;
6164 lpt->copied= 0;
6165 lpt->deleted= 0;
6166 lpt->pack_frm_data= NULL;
6167 lpt->pack_frm_len= 0;
6168 thd->work_part_info= part_info;
6170 /* Never update timestamp columns when alter */
6171 table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
6173 if (fast_alter_partition & HA_PARTITION_ONE_PHASE)
6176 In the case where the engine supports one phase online partition
6177 changes it is not necessary to have any exclusive locks. The
6178 correctness is upheld instead by transactions being aborted if they
6179 access the table after its partition definition has changed (if they
6180 are still using the old partition definition).
6182 The handler is in this case responsible to ensure that all users
6183 start using the new frm file after it has changed. To implement
6184 one phase it is necessary for the handler to have the master copy
6185 of the frm file and use discovery mechanisms to renew it. Thus
6186 write frm will write the frm, pack the new frm and finally
6187 the frm is deleted and the discovery mechanisms will either restore
6188 back to the old or installing the new after the change is activated.
6190 Thus all open tables will be discovered that they are old, if not
6191 earlier as soon as they try an operation using the old table. One
6192 should ensure that this is checked already when opening a table,
6193 even if it is found in the cache of open tables.
6195 change_partitions will perform all operations and it is the duty of
6196 the handler to ensure that the frm files in the system gets updated
6197 in synch with the changes made and if an error occurs that a proper
6198 error handling is done.
6200 If the MySQL Server crashes at this moment but the handler succeeds
6201 in performing the change then the binlog is not written for the
6202 change. There is no way to solve this as long as the binlog is not
6203 transactional and even then it is hard to solve it completely.
6205 The first approach here was to downgrade locks. Now a different approach
6206 is decided upon. The idea is that the handler will have access to the
6207 Alter_info when store_lock arrives with TL_WRITE_ALLOW_READ. So if the
6208 handler knows that this functionality can be handled with a lower lock
6209 level it will set the lock level to TL_WRITE_ALLOW_WRITE immediately.
6210 Thus the need to downgrade the lock disappears.
6211 1) Write the new frm, pack it and then delete it
6212 2) Perform the change within the handler
6214 if (mysql_write_frm(lpt, WFRM_WRITE_SHADOW | WFRM_PACK_FRM) ||
6215 mysql_change_partitions(lpt))
6217 goto err;
6220 else if (alter_info->flags & ALTER_DROP_PARTITION)
6223 Now after all checks and setting state on dropped partitions we can
6224 start the actual dropping of the partitions.
6226 Drop partition is actually two things happening. The first is that
6227 a lot of records are deleted. The second is that the behaviour of
6228 subsequent updates and writes and deletes will change. The delete
6229 part can be handled without any particular high lock level by
6230 transactional engines whereas non-transactional engines need to
6231 ensure that this change is done with an exclusive lock on the table.
6232 The second part, the change of partitioning does however require
6233 an exclusive lock to install the new partitioning as one atomic
6234 operation. If this is not the case, it is possible for two
6235 transactions to see the change in a different order than their
6236 serialisation order. Thus we need an exclusive lock for both
6237 transactional and non-transactional engines.
6239 For LIST partitions it could be possible to avoid the exclusive lock
6240 (and for RANGE partitions if they didn't rearrange range definitions
6241 after a DROP PARTITION) if one ensured that failed accesses to the
6242 dropped partitions was aborted for sure (thus only possible for
6243 transactional engines).
6245 0) Write an entry that removes the shadow frm file if crash occurs
6246 1) Write the new frm file as a shadow frm
6247 2) Write the ddl log to ensure that the operation is completed
6248 even in the presence of a MySQL Server crash
6249 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to
6250 the table have completed. This ensures that other threads can not
6251 execute on the table in parallel.
6252 4) Get a name lock on the table. This ensures that we can release all
6253 locks on the table and since no one can open the table, there can
6254 be no new threads accessing the table. They will be hanging on the
6255 name lock.
6256 5) Close all tables that have already been opened but didn't stumble on
6257 the abort locked previously. This is done as part of the
6258 close_data_files_and_morph_locks call.
6259 6) We are now ready to release all locks we got in this thread.
6260 7) Write the bin log
6261 Unfortunately the writing of the binlog is not synchronised with
6262 other logging activities. So no matter in which order the binlog
6263 is written compared to other activities there will always be cases
6264 where crashes make strange things occur. In this placement it can
6265 happen that the ALTER TABLE DROP PARTITION gets performed in the
6266 master but not in the slaves if we have a crash, after writing the
6267 ddl log but before writing the binlog. A solution to this would
6268 require writing the statement first in the ddl log and then
6269 when recovering from the crash read the binlog and insert it into
6270 the binlog if not written already.
6271 8) Install the previously written shadow frm file
6272 9) Prepare handlers for drop of partitions
6273 10) Drop the partitions
6274 11) Remove entries from ddl log
6275 12) Reopen table if under lock tables
6276 13) Complete query
6278 We insert Error injections at all places where it could be interesting
6279 to test if recovery is properly done.
6281 if (write_log_drop_shadow_frm(lpt) ||
6282 ERROR_INJECT_CRASH("crash_drop_partition_1") ||
6283 mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
6284 ERROR_INJECT_CRASH("crash_drop_partition_2") ||
6285 write_log_drop_partition(lpt) ||
6286 ERROR_INJECT_CRASH("crash_drop_partition_3") ||
6287 (not_completed= FALSE) ||
6288 abort_and_upgrade_lock_and_close_table(lpt) ||
6289 ERROR_INJECT_CRASH("crash_drop_partition_5") ||
6290 ((!thd->lex->no_write_to_binlog) &&
6291 (write_bin_log(thd, FALSE,
6292 thd->query(), thd->query_length()), FALSE)) ||
6293 ERROR_INJECT_CRASH("crash_drop_partition_6") ||
6294 ((frm_install= TRUE), FALSE) ||
6295 mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
6296 ((frm_install= FALSE), FALSE) ||
6297 ERROR_INJECT_CRASH("crash_drop_partition_7") ||
6298 mysql_drop_partitions(lpt) ||
6299 ERROR_INJECT_CRASH("crash_drop_partition_8") ||
6300 (write_log_completed(lpt, FALSE), FALSE) ||
6301 ERROR_INJECT_CRASH("crash_drop_partition_9") ||
6302 (alter_partition_lock_handling(lpt), FALSE))
6304 handle_alter_part_error(lpt, not_completed, TRUE, frm_install);
6305 goto err;
6308 else if ((alter_info->flags & ALTER_ADD_PARTITION) &&
6309 (part_info->part_type == RANGE_PARTITION ||
6310 part_info->part_type == LIST_PARTITION))
6313 ADD RANGE/LIST PARTITIONS
6314 In this case there are no tuples removed and no tuples are added.
6315 Thus the operation is merely adding a new partition. Thus it is
6316 necessary to perform the change as an atomic operation. Otherwise
6317 someone reading without seeing the new partition could potentially
6318 miss updates made by a transaction serialised before it that are
6319 inserted into the new partition.
6321 0) Write an entry that removes the shadow frm file if crash occurs
6322 1) Write the new frm file as a shadow frm file
6323 2) Log the changes to happen in ddl log
6324 2) Add the new partitions
6325 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
6326 are still using the old partitioning scheme. Wait until all
6327 ongoing users have completed before progressing.
6328 4) Get a name lock on the table. This ensures that we can release all
6329 locks on the table and since no one can open the table, there can
6330 be no new threads accessing the table. They will be hanging on the
6331 name lock.
6332 5) Close all tables that have already been opened but didn't stumble on
6333 the abort locked previously. This is done as part of the
6334 close_data_files_and_morph_locks call.
6335 6) Close all table handlers and unlock all handlers but retain name lock
6336 7) Write binlog
6337 8) Now the change is completed except for the installation of the
6338 new frm file. We thus write an action in the log to change to
6339 the shadow frm file
6340 9) Install the new frm file of the table where the partitions are
6341 added to the table.
6342 10)Wait until all accesses using the old frm file has completed
6343 11)Remove entries from ddl log
6344 12)Reopen tables if under lock tables
6345 13)Complete query
6347 if (write_log_add_change_partition(lpt) ||
6348 ERROR_INJECT_CRASH("crash_add_partition_1") ||
6349 mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
6350 ERROR_INJECT_CRASH("crash_add_partition_2") ||
6351 mysql_change_partitions(lpt) ||
6352 ERROR_INJECT_CRASH("crash_add_partition_3") ||
6353 abort_and_upgrade_lock_and_close_table(lpt) ||
6354 ERROR_INJECT_CRASH("crash_add_partition_5") ||
6355 ((!thd->lex->no_write_to_binlog) &&
6356 (write_bin_log(thd, FALSE,
6357 thd->query(), thd->query_length()), FALSE)) ||
6358 ERROR_INJECT_CRASH("crash_add_partition_6") ||
6359 write_log_rename_frm(lpt) ||
6360 (not_completed= FALSE) ||
6361 ERROR_INJECT_CRASH("crash_add_partition_7") ||
6362 ((frm_install= TRUE), FALSE) ||
6363 mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
6364 ERROR_INJECT_CRASH("crash_add_partition_8") ||
6365 (write_log_completed(lpt, FALSE), FALSE) ||
6366 ERROR_INJECT_CRASH("crash_add_partition_9") ||
6367 (alter_partition_lock_handling(lpt), FALSE))
6369 handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
6370 goto err;
6373 else
6376 ADD HASH PARTITION/
6377 COALESCE PARTITION/
6378 REBUILD PARTITION/
6379 REORGANIZE PARTITION
6381 In this case all records are still around after the change although
6382 possibly organised into new partitions, thus by ensuring that all
6383 updates go to both the old and the new partitioning scheme we can
6384 actually perform this operation lock-free. The only exception to
6385 this is when REORGANIZE PARTITION adds/drops ranges. In this case
6386 there needs to be an exclusive lock during the time when the range
6387 changes occur.
6388 This is only possible if the handler can ensure double-write for a
6389 period. The double write will ensure that it doesn't matter where the
6390 data is read from since both places are updated for writes. If such
6391 double writing is not performed then it is necessary to perform the
6392 change with the usual exclusive lock. With double writes it is even
6393 possible to perform writes in parallel with the reorganisation of
6394 partitions.
6396 Without double write procedure we get the following procedure.
6397 The only difference with using double write is that we can downgrade
6398 the lock to TL_WRITE_ALLOW_WRITE. Double write in this case only
6399 double writes from old to new. If we had double writing in both
6400 directions we could perform the change completely without exclusive
6401 lock for HASH partitions.
6402 Handlers that perform double writing during the copy phase can actually
6403 use a lower lock level. This can be handled inside store_lock in the
6404 respective handler.
6406 0) Write an entry that removes the shadow frm file if crash occurs
6407 1) Write the shadow frm file of new partitioning
6408 2) Log such that temporary partitions added in change phase are
6409 removed in a crash situation
6410 3) Add the new partitions
6411 Copy from the reorganised partitions to the new partitions
6412 4) Log that operation is completed and log all complete actions
6413 needed to complete operation from here
6414 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users
6415 are still using the old partitioning scheme. Wait until all
6416 ongoing users have completed before progressing.
6417 6) Get a name lock of the table
6418 7) Close all tables opened but not yet locked, after this call we are
6419 certain that no other thread is in the lock wait queue or has
6420 opened the table. The name lock will ensure that they are blocked
6421 on the open call.
6422 This is achieved also by close_data_files_and_morph_locks call.
6423 8) Close all partitions opened by this thread, but retain name lock.
6424 9) Write bin log
6425 10) Prepare handlers for rename and delete of partitions
6426 11) Rename and drop the reorged partitions such that they are no
6427 longer used and rename those added to their real new names.
6428 12) Install the shadow frm file
6429 13) Reopen the table if under lock tables
6430 14) Complete query
6432 if (write_log_add_change_partition(lpt) ||
6433 ERROR_INJECT_CRASH("crash_change_partition_1") ||
6434 mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
6435 ERROR_INJECT_CRASH("crash_change_partition_2") ||
6436 mysql_change_partitions(lpt) ||
6437 ERROR_INJECT_CRASH("crash_change_partition_3") ||
6438 write_log_final_change_partition(lpt) ||
6439 ERROR_INJECT_CRASH("crash_change_partition_4") ||
6440 (not_completed= FALSE) ||
6441 abort_and_upgrade_lock_and_close_table(lpt) ||
6442 ERROR_INJECT_CRASH("crash_change_partition_6") ||
6443 ((!thd->lex->no_write_to_binlog) &&
6444 (write_bin_log(thd, FALSE,
6445 thd->query(), thd->query_length()), FALSE)) ||
6446 ERROR_INJECT_CRASH("crash_change_partition_7") ||
6447 mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
6448 ERROR_INJECT_CRASH("crash_change_partition_8") ||
6449 mysql_drop_partitions(lpt) ||
6450 ERROR_INJECT_CRASH("crash_change_partition_9") ||
6451 mysql_rename_partitions(lpt) ||
6452 ((frm_install= TRUE), FALSE) ||
6453 ERROR_INJECT_CRASH("crash_change_partition_10") ||
6454 (write_log_completed(lpt, FALSE), FALSE) ||
6455 ERROR_INJECT_CRASH("crash_change_partition_11") ||
6456 (alter_partition_lock_handling(lpt), FALSE))
6458 handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
6459 goto err;
6463 A final step is to write the query to the binlog and send ok to the
6464 user
6466 DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted,
6467 table, table_list, FALSE, NULL,
6468 written_bin_log));
6469 err:
6470 if (thd->locked_tables)
6473 table->part_info was altered in prep_alter_part_table and must be
6474 destroyed and recreated, since otherwise it will be reused, since
6475 we are under LOCK TABLE.
6477 alter_partition_lock_handling(lpt);
6479 else
6481 /* Force the table to be closed to avoid reuse of the table->part_info */
6482 close_thread_tables(thd);
6484 DBUG_RETURN(TRUE);
6486 #endif
6490 Prepare for calling val_int on partition function by setting fields to
6491 point to the record where the values of the PF-fields are stored.
6493 SYNOPSIS
6494 set_field_ptr()
6495 ptr Array of fields to change ptr
6496 new_buf New record pointer
6497 old_buf Old record pointer
6499 DESCRIPTION
6500 Set ptr in field objects of field array to refer to new_buf record
6501 instead of previously old_buf. Used before calling val_int and after
6502 it is used to restore pointers to table->record[0].
6503 This routine is placed outside of partition code since it can be useful
6504 also for other programs.
6507 void set_field_ptr(Field **ptr, const uchar *new_buf,
6508 const uchar *old_buf)
6510 my_ptrdiff_t diff= (new_buf - old_buf);
6511 DBUG_ENTER("set_field_ptr");
6515 (*ptr)->move_field_offset(diff);
6516 } while (*(++ptr));
6517 DBUG_VOID_RETURN;
6522 Prepare for calling val_int on partition function by setting fields to
6523 point to the record where the values of the PF-fields are stored.
6524 This variant works on a key_part reference.
6525 It is not required that all fields are NOT NULL fields.
6527 SYNOPSIS
6528 set_key_field_ptr()
6529 key_info key info with a set of fields to change ptr
6530 new_buf New record pointer
6531 old_buf Old record pointer
6533 DESCRIPTION
6534 Set ptr in field objects of field array to refer to new_buf record
6535 instead of previously old_buf. Used before calling val_int and after
6536 it is used to restore pointers to table->record[0].
6537 This routine is placed outside of partition code since it can be useful
6538 also for other programs.
6541 void set_key_field_ptr(KEY *key_info, const uchar *new_buf,
6542 const uchar *old_buf)
6544 KEY_PART_INFO *key_part= key_info->key_part;
6545 uint key_parts= key_info->key_parts;
6546 uint i= 0;
6547 my_ptrdiff_t diff= (new_buf - old_buf);
6548 DBUG_ENTER("set_key_field_ptr");
6552 key_part->field->move_field_offset(diff);
6553 key_part++;
6554 } while (++i < key_parts);
6555 DBUG_VOID_RETURN;
6560 SYNOPSIS
6561 mem_alloc_error()
6562 size Size of memory attempted to allocate
6563 None
6565 RETURN VALUES
6566 None
6568 DESCRIPTION
6569 A routine to use for all the many places in the code where memory
6570 allocation error can happen, a tremendous amount of them, needs
6571 simple routine that signals this error.
6574 void mem_alloc_error(size_t size)
6576 my_error(ER_OUTOFMEMORY, MYF(0), static_cast<int>(size));
6579 #ifdef WITH_PARTITION_STORAGE_ENGINE
6581 Return comma-separated list of used partitions in the provided given string
6583 SYNOPSIS
6584 make_used_partitions_str()
6585 part_info IN Partitioning info
6586 parts_str OUT The string to fill
6588 DESCRIPTION
6589 Generate a list of used partitions (from bits in part_info->used_partitions
6590 bitmap), asd store it into the provided String object.
6592 NOTE
6593 The produced string must not be longer then MAX_PARTITIONS * (1 + FN_LEN).
6596 void make_used_partitions_str(partition_info *part_info, String *parts_str)
6598 parts_str->length(0);
6599 partition_element *pe;
6600 uint partition_id= 0;
6601 List_iterator<partition_element> it(part_info->partitions);
6603 if (part_info->is_sub_partitioned())
6605 partition_element *head_pe;
6606 while ((head_pe= it++))
6608 List_iterator<partition_element> it2(head_pe->subpartitions);
6609 while ((pe= it2++))
6611 if (bitmap_is_set(&part_info->used_partitions, partition_id))
6613 if (parts_str->length())
6614 parts_str->append(',');
6615 parts_str->append(head_pe->partition_name,
6616 strlen(head_pe->partition_name),
6617 system_charset_info);
6618 parts_str->append('_');
6619 parts_str->append(pe->partition_name,
6620 strlen(pe->partition_name),
6621 system_charset_info);
6623 partition_id++;
6627 else
6629 while ((pe= it++))
6631 if (bitmap_is_set(&part_info->used_partitions, partition_id))
6633 if (parts_str->length())
6634 parts_str->append(',');
6635 parts_str->append(pe->partition_name, strlen(pe->partition_name),
6636 system_charset_info);
6638 partition_id++;
6642 #endif
6644 /****************************************************************************
6645 * Partition interval analysis support
6646 ***************************************************************************/
6649 Setup partition_info::* members related to partitioning range analysis
6651 SYNOPSIS
6652 set_up_partition_func_pointers()
6653 part_info Partitioning info structure
6655 DESCRIPTION
6656 Assuming that passed partition_info structure already has correct values
6657 for members that specify [sub]partitioning type, table fields, and
6658 functions, set up partition_info::* members that are related to
6659 Partitioning Interval Analysis (see get_partitions_in_range_iter for its
6660 definition)
6662 IMPLEMENTATION
6663 There are two available interval analyzer functions:
6664 (1) get_part_iter_for_interval_via_mapping
6665 (2) get_part_iter_for_interval_via_walking
6667 They both have limited applicability:
6668 (1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
6669 func is a monotonic function.
6671 (2) is applicable for
6672 "[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
6674 If both are applicable, (1) is preferred over (2).
6676 This function sets part_info::get_part_iter_for_interval according to
6677 this criteria, and also sets some auxilary fields that the function
6678 uses.
6680 #ifdef WITH_PARTITION_STORAGE_ENGINE
6681 static void set_up_range_analysis_info(partition_info *part_info)
6683 /* Set the catch-all default */
6684 part_info->get_part_iter_for_interval= NULL;
6685 part_info->get_subpart_iter_for_interval= NULL;
6688 Check if get_part_iter_for_interval_via_mapping() can be used for
6689 partitioning
6691 switch (part_info->part_type) {
6692 case RANGE_PARTITION:
6693 case LIST_PARTITION:
6694 if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC)
6696 part_info->get_part_iter_for_interval=
6697 get_part_iter_for_interval_via_mapping;
6698 goto setup_subparts;
6700 default:
6705 Check if get_part_iter_for_interval_via_walking() can be used for
6706 partitioning
6708 if (part_info->no_part_fields == 1)
6710 Field *field= part_info->part_field_array[0];
6711 switch (field->type()) {
6712 case MYSQL_TYPE_TINY:
6713 case MYSQL_TYPE_SHORT:
6714 case MYSQL_TYPE_INT24:
6715 case MYSQL_TYPE_LONG:
6716 case MYSQL_TYPE_LONGLONG:
6717 part_info->get_part_iter_for_interval=
6718 get_part_iter_for_interval_via_walking;
6719 break;
6720 default:
6725 setup_subparts:
6727 Check if get_part_iter_for_interval_via_walking() can be used for
6728 subpartitioning
6730 if (part_info->no_subpart_fields == 1)
6732 Field *field= part_info->subpart_field_array[0];
6733 switch (field->type()) {
6734 case MYSQL_TYPE_TINY:
6735 case MYSQL_TYPE_SHORT:
6736 case MYSQL_TYPE_LONG:
6737 case MYSQL_TYPE_LONGLONG:
6738 part_info->get_subpart_iter_for_interval=
6739 get_part_iter_for_interval_via_walking;
6740 break;
6741 default:
6748 typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
6749 bool include_endpoint);
6752 Partitioning Interval Analysis: Initialize the iterator for "mapping" case
6754 SYNOPSIS
6755 get_part_iter_for_interval_via_mapping()
6756 part_info Partition info
6757 is_subpart TRUE - act for subpartitioning
6758 FALSE - act for partitioning
6759 min_value minimum field value, in opt_range key format.
6760 max_value minimum field value, in opt_range key format.
6761 flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
6762 NO_MAX_RANGE.
6763 part_iter Iterator structure to be initialized
6765 DESCRIPTION
6766 Initialize partition set iterator to walk over the interval in
6767 ordered-array-of-partitions (for RANGE partitioning) or
6768 ordered-array-of-list-constants (for LIST partitioning) space.
6770 IMPLEMENTATION
6771 This function is used when partitioning is done by
6772 <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
6773 t.field space into a sub-array of partition_info::range_int_array or
6774 partition_info::list_array (see get_partition_id_range_for_endpoint,
6775 get_list_array_idx_for_endpoint for details).
6777 The function performs this interval mapping, and sets the iterator to
6778 traverse the sub-array and return appropriate partitions.
6780 RETURN
6781 0 - No matching partitions (iterator not initialized)
6782 1 - Ok, iterator intialized for traversal of matching partitions.
6783 -1 - All partitions would match (iterator not initialized)
6786 int get_part_iter_for_interval_via_mapping(partition_info *part_info,
6787 bool is_subpart,
6788 uchar *min_value, uchar *max_value,
6789 uint flags,
6790 PARTITION_ITERATOR *part_iter)
6792 DBUG_ASSERT(!is_subpart);
6793 Field *field= part_info->part_field_array[0];
6794 uint32 UNINIT_VAR(max_endpoint_val);
6795 get_endpoint_func UNINIT_VAR(get_endpoint);
6796 bool can_match_multiple_values; /* is not '=' */
6797 uint field_len= field->pack_length_in_rec();
6798 MYSQL_TIME start_date;
6799 bool check_zero_dates= false;
6800 bool zero_in_start_date= true;
6801 part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
6803 if (part_info->part_type == RANGE_PARTITION)
6805 if (part_info->part_charset_field_array)
6806 get_endpoint= get_partition_id_range_for_endpoint_charset;
6807 else
6808 get_endpoint= get_partition_id_range_for_endpoint;
6809 max_endpoint_val= part_info->no_parts;
6810 part_iter->get_next= get_next_partition_id_range;
6812 else if (part_info->part_type == LIST_PARTITION)
6815 if (part_info->part_charset_field_array)
6816 get_endpoint= get_list_array_idx_for_endpoint_charset;
6817 else
6818 get_endpoint= get_list_array_idx_for_endpoint;
6819 max_endpoint_val= part_info->no_list_values;
6820 part_iter->get_next= get_next_partition_id_list;
6821 part_iter->part_info= part_info;
6822 if (max_endpoint_val == 0)
6825 We handle this special case without optimisations since it is
6826 of little practical value but causes a great number of complex
6827 checks later in the code.
6829 part_iter->part_nums.start= part_iter->part_nums.end= 0;
6830 part_iter->part_nums.cur= 0;
6831 part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
6832 return -1;
6835 else
6836 MY_ASSERT_UNREACHABLE();
6838 can_match_multiple_values= (flags || !min_value || !max_value ||
6839 memcmp(min_value, max_value, field_len));
6840 if (can_match_multiple_values &&
6841 (part_info->part_type == RANGE_PARTITION ||
6842 part_info->has_null_value))
6844 /* Range scan on RANGE or LIST partitioned table */
6845 enum_monotonicity_info monotonic;
6846 monotonic= part_info->part_expr->get_monotonicity_info();
6847 if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
6848 monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL)
6850 /* col is NOT NULL, but F(col) can return NULL, add NULL partition */
6851 part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
6852 check_zero_dates= true;
6857 Find minimum: Do special handling if the interval has left bound in form
6858 " NULL <= X ":
6860 if (field->real_maybe_null() && part_info->has_null_value &&
6861 !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value)
6863 part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
6864 part_iter->part_nums.start= part_iter->part_nums.cur= 0;
6865 if (*max_value && !(flags & NO_MAX_RANGE))
6867 /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
6868 part_iter->part_nums.end= 0;
6869 return 1;
6872 else
6874 if (flags & NO_MIN_RANGE)
6875 part_iter->part_nums.start= part_iter->part_nums.cur= 0;
6876 else
6879 Store the interval edge in the record buffer, and call the
6880 function that maps the edge in table-field space to an edge
6881 in ordered-set-of-partitions (for RANGE partitioning) or
6882 index-in-ordered-array-of-list-constants (for LIST) space.
6884 store_key_image_to_rec(field, min_value, field_len);
6885 bool include_endp= !test(flags & NEAR_MIN);
6886 part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp);
6887 if (!can_match_multiple_values && part_info->part_expr->null_value)
6889 /* col = x and F(x) = NULL -> only search NULL partition */
6890 part_iter->part_nums.cur= part_iter->part_nums.start= 0;
6891 part_iter->part_nums.end= 0;
6892 part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
6893 return 1;
6895 part_iter->part_nums.cur= part_iter->part_nums.start;
6896 if (check_zero_dates && !part_info->part_expr->null_value)
6898 if (!(flags & NO_MAX_RANGE) &&
6899 (field->type() == MYSQL_TYPE_DATE ||
6900 field->type() == MYSQL_TYPE_DATETIME))
6902 /* Monotonic, but return NULL for dates with zeros in month/day. */
6903 zero_in_start_date= field->get_date(&start_date, 0);
6904 DBUG_PRINT("info", ("zero start %u %04d-%02d-%02d",
6905 zero_in_start_date, start_date.year,
6906 start_date.month, start_date.day));
6909 if (part_iter->part_nums.start == max_endpoint_val)
6910 return 0; /* No partitions */
6914 /* Find maximum, do the same as above but for right interval bound */
6915 if (flags & NO_MAX_RANGE)
6916 part_iter->part_nums.end= max_endpoint_val;
6917 else
6919 store_key_image_to_rec(field, max_value, field_len);
6920 bool include_endp= !test(flags & NEAR_MAX);
6921 part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
6922 if (check_zero_dates &&
6923 !zero_in_start_date &&
6924 !part_info->part_expr->null_value)
6926 MYSQL_TIME end_date;
6927 bool zero_in_end_date= field->get_date(&end_date, 0);
6929 This is an optimization for TO_DAYS() to avoid scanning the NULL
6930 partition for ranges that cannot include a date with 0 as
6931 month/day.
6933 DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d",
6934 zero_in_end_date,
6935 end_date.year, end_date.month, end_date.day));
6936 DBUG_ASSERT(!memcmp(((Item_func*) part_info->part_expr)->func_name(),
6937 "to_days", 7));
6938 if (!zero_in_end_date &&
6939 start_date.month == end_date.month &&
6940 start_date.year == end_date.year)
6941 part_iter->ret_null_part= part_iter->ret_null_part_orig= false;
6943 if (part_iter->part_nums.start >= part_iter->part_nums.end &&
6944 !part_iter->ret_null_part)
6945 return 0; /* No partitions */
6947 return 1; /* Ok, iterator initialized */
6951 /* See get_part_iter_for_interval_via_walking for definition of what this is */
6952 #define MAX_RANGE_TO_WALK 10
6956 Partitioning Interval Analysis: Initialize iterator to walk field interval
6958 SYNOPSIS
6959 get_part_iter_for_interval_via_walking()
6960 part_info Partition info
6961 is_subpart TRUE - act for subpartitioning
6962 FALSE - act for partitioning
6963 min_value minimum field value, in opt_range key format.
6964 max_value minimum field value, in opt_range key format.
6965 flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
6966 NO_MAX_RANGE.
6967 part_iter Iterator structure to be initialized
6969 DESCRIPTION
6970 Initialize partition set iterator to walk over interval in integer field
6971 space. That is, for "const1 <=? t.field <=? const2" interval, initialize
6972 the iterator to return a set of [sub]partitions obtained with the
6973 following procedure:
6974 get partition id for t.field = const1, return it
6975 get partition id for t.field = const1+1, return it
6976 ... t.field = const1+2, ...
6977 ... ... ...
6978 ... t.field = const2 ...
6980 IMPLEMENTATION
6981 See get_partitions_in_range_iter for general description of interval
6982 analysis. We support walking over the following intervals:
6983 "t.field IS NULL"
6984 "c1 <=? t.field <=? c2", where c1 and c2 are finite.
6985 Intervals with +inf/-inf, and [NULL, c1] interval can be processed but
6986 that is more tricky and I don't have time to do it right now.
6988 Additionally we have these requirements:
6989 * number of values in the interval must be less then number of
6990 [sub]partitions, and
6991 * Number of values in the interval must be less then MAX_RANGE_TO_WALK.
6993 The rationale behind these requirements is that if they are not met
6994 we're likely to hit most of the partitions and traversing the interval
6995 will only add overhead. So it's better return "all partitions used" in
6996 that case.
6998 RETURN
6999 0 - No matching partitions, iterator not initialized
7000 1 - Some partitions would match, iterator intialized for traversing them
7001 -1 - All partitions would match, iterator not initialized
7004 int get_part_iter_for_interval_via_walking(partition_info *part_info,
7005 bool is_subpart,
7006 uchar *min_value, uchar *max_value,
7007 uint flags,
7008 PARTITION_ITERATOR *part_iter)
7010 Field *field;
7011 uint total_parts;
7012 partition_iter_func get_next_func;
7013 part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
7014 if (is_subpart)
7016 field= part_info->subpart_field_array[0];
7017 total_parts= part_info->no_subparts;
7018 get_next_func= get_next_subpartition_via_walking;
7020 else
7022 field= part_info->part_field_array[0];
7023 total_parts= part_info->no_parts;
7024 get_next_func= get_next_partition_via_walking;
7027 /* Handle the "t.field IS NULL" interval, it is a special case */
7028 if (field->real_maybe_null() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
7029 *min_value && *max_value)
7032 We don't have a part_iter->get_next() function that would find which
7033 partition "t.field IS NULL" belongs to, so find partition that contains
7034 NULL right here, and return an iterator over singleton set.
7036 uint32 part_id;
7037 field->set_null();
7038 if (is_subpart)
7040 if (!part_info->get_subpartition_id(part_info, &part_id))
7042 init_single_partition_iterator(part_id, part_iter);
7043 return 1; /* Ok, iterator initialized */
7046 else
7048 longlong dummy;
7049 int res= part_info->is_sub_partitioned() ?
7050 part_info->get_part_partition_id(part_info, &part_id,
7051 &dummy):
7052 part_info->get_partition_id(part_info, &part_id, &dummy);
7053 if (!res)
7055 init_single_partition_iterator(part_id, part_iter);
7056 return 1; /* Ok, iterator initialized */
7059 return 0; /* No partitions match */
7062 if ((field->real_maybe_null() &&
7063 ((!(flags & NO_MIN_RANGE) && *min_value) || // NULL <? X
7064 (!(flags & NO_MAX_RANGE) && *max_value))) || // X <? NULL
7065 (flags & (NO_MIN_RANGE | NO_MAX_RANGE))) // -inf at any bound
7067 return -1; /* Can't handle this interval, have to use all partitions */
7070 /* Get integers for left and right interval bound */
7071 longlong a, b;
7072 uint len= field->pack_length_in_rec();
7073 store_key_image_to_rec(field, min_value, len);
7074 a= field->val_int();
7076 store_key_image_to_rec(field, max_value, len);
7077 b= field->val_int();
7080 Handle a special case where the distance between interval bounds is
7081 exactly 4G-1. This interval is too big for range walking, and if it is an
7082 (x,y]-type interval then the following "b +=..." code will convert it to
7083 an empty interval by "wrapping around" a + 4G-1 + 1 = a.
7085 if ((ulonglong)b - (ulonglong)a == ~0ULL)
7086 return -1;
7088 a += test(flags & NEAR_MIN);
7089 b += test(!(flags & NEAR_MAX));
7090 ulonglong n_values= b - a;
7092 if (n_values > total_parts || n_values > MAX_RANGE_TO_WALK)
7093 return -1;
7095 part_iter->field_vals.start= part_iter->field_vals.cur= a;
7096 part_iter->field_vals.end= b;
7097 part_iter->part_info= part_info;
7098 part_iter->get_next= get_next_func;
7099 return 1;
7104 PARTITION_ITERATOR::get_next implementation: enumerate partitions in range
7106 SYNOPSIS
7107 get_next_partition_id_range()
7108 part_iter Partition set iterator structure
7110 DESCRIPTION
7111 This is implementation of PARTITION_ITERATOR::get_next() that returns
7112 [sub]partition ids in [min_partition_id, max_partition_id] range.
7113 The function conforms to partition_iter_func type.
7115 RETURN
7116 partition id
7117 NOT_A_PARTITION_ID if there are no more partitions
7120 uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter)
7122 if (part_iter->part_nums.cur >= part_iter->part_nums.end)
7124 if (part_iter->ret_null_part)
7126 part_iter->ret_null_part= FALSE;
7127 return 0; /* NULL always in first range partition */
7129 part_iter->part_nums.cur= part_iter->part_nums.start;
7130 part_iter->ret_null_part= part_iter->ret_null_part_orig;
7131 return NOT_A_PARTITION_ID;
7133 else
7134 return part_iter->part_nums.cur++;
7139 PARTITION_ITERATOR::get_next implementation for LIST partitioning
7141 SYNOPSIS
7142 get_next_partition_id_list()
7143 part_iter Partition set iterator structure
7145 DESCRIPTION
7146 This implementation of PARTITION_ITERATOR::get_next() is special for
7147 LIST partitioning: it enumerates partition ids in
7148 part_info->list_array[i] where i runs over [min_idx, max_idx] interval.
7149 The function conforms to partition_iter_func type.
7151 RETURN
7152 partition id
7153 NOT_A_PARTITION_ID if there are no more partitions
7156 uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter)
7158 if (part_iter->part_nums.cur >= part_iter->part_nums.end)
7160 if (part_iter->ret_null_part)
7162 part_iter->ret_null_part= FALSE;
7163 return part_iter->part_info->has_null_part_id;
7165 part_iter->part_nums.cur= part_iter->part_nums.start;
7166 part_iter->ret_null_part= part_iter->ret_null_part_orig;
7167 return NOT_A_PARTITION_ID;
7169 else
7170 return part_iter->part_info->list_array[part_iter->
7171 part_nums.cur++].partition_id;
7176 PARTITION_ITERATOR::get_next implementation: walk over field-space interval
7178 SYNOPSIS
7179 get_next_partition_via_walking()
7180 part_iter Partitioning iterator
7182 DESCRIPTION
7183 This implementation of PARTITION_ITERATOR::get_next() returns ids of
7184 partitions that contain records with partitioning field value within
7185 [start_val, end_val] interval.
7186 The function conforms to partition_iter_func type.
7188 RETURN
7189 partition id
7190 NOT_A_PARTITION_ID if there are no more partitioning.
7193 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter)
7195 uint32 part_id;
7196 Field *field= part_iter->part_info->part_field_array[0];
7197 while (part_iter->field_vals.cur != part_iter->field_vals.end)
7199 longlong dummy;
7200 field->store(part_iter->field_vals.cur++,
7201 ((Field_num*)field)->unsigned_flag);
7202 if ((part_iter->part_info->is_sub_partitioned() &&
7203 !part_iter->part_info->get_part_partition_id(part_iter->part_info,
7204 &part_id, &dummy)) ||
7205 !part_iter->part_info->get_partition_id(part_iter->part_info,
7206 &part_id, &dummy))
7207 return part_id;
7209 part_iter->field_vals.cur= part_iter->field_vals.start;
7210 return NOT_A_PARTITION_ID;
7214 /* Same as get_next_partition_via_walking, but for subpartitions */
7216 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter)
7218 Field *field= part_iter->part_info->subpart_field_array[0];
7219 uint32 res;
7220 if (part_iter->field_vals.cur == part_iter->field_vals.end)
7222 part_iter->field_vals.cur= part_iter->field_vals.start;
7223 return NOT_A_PARTITION_ID;
7225 field->store(part_iter->field_vals.cur++, FALSE);
7226 if (part_iter->part_info->get_subpartition_id(part_iter->part_info,
7227 &res))
7228 return NOT_A_PARTITION_ID;
7229 return res;
7235 Create partition names
7237 SYNOPSIS
7238 create_partition_name()
7239 out:out Created partition name string
7240 in1 First part
7241 in2 Second part
7242 name_variant Normal, temporary or renamed partition name
7244 RETURN VALUE
7245 NONE
7247 DESCRIPTION
7248 This method is used to calculate the partition name, service routine to
7249 the del_ren_cre_table method.
7252 void create_partition_name(char *out, const char *in1,
7253 const char *in2, uint name_variant,
7254 bool translate)
7256 char transl_part_name[FN_REFLEN];
7257 const char *transl_part;
7259 if (translate)
7261 tablename_to_filename(in2, transl_part_name, FN_REFLEN);
7262 transl_part= transl_part_name;
7264 else
7265 transl_part= in2;
7266 if (name_variant == NORMAL_PART_NAME)
7267 strxmov(out, in1, "#P#", transl_part, NullS);
7268 else if (name_variant == TEMP_PART_NAME)
7269 strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS);
7270 else if (name_variant == RENAMED_PART_NAME)
7271 strxmov(out, in1, "#P#", transl_part, "#REN#", NullS);
7276 Create subpartition name
7278 SYNOPSIS
7279 create_subpartition_name()
7280 out:out Created partition name string
7281 in1 First part
7282 in2 Second part
7283 in3 Third part
7284 name_variant Normal, temporary or renamed partition name
7286 RETURN VALUE
7287 NONE
7289 DESCRIPTION
7290 This method is used to calculate the subpartition name, service routine to
7291 the del_ren_cre_table method.
7294 void create_subpartition_name(char *out, const char *in1,
7295 const char *in2, const char *in3,
7296 uint name_variant)
7298 char transl_part_name[FN_REFLEN], transl_subpart_name[FN_REFLEN];
7300 tablename_to_filename(in2, transl_part_name, FN_REFLEN);
7301 tablename_to_filename(in3, transl_subpart_name, FN_REFLEN);
7302 if (name_variant == NORMAL_PART_NAME)
7303 strxmov(out, in1, "#P#", transl_part_name,
7304 "#SP#", transl_subpart_name, NullS);
7305 else if (name_variant == TEMP_PART_NAME)
7306 strxmov(out, in1, "#P#", transl_part_name,
7307 "#SP#", transl_subpart_name, "#TMP#", NullS);
7308 else if (name_variant == RENAMED_PART_NAME)
7309 strxmov(out, in1, "#P#", transl_part_name,
7310 "#SP#", transl_subpart_name, "#REN#", NullS);
7312 #endif