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
30 There are quite a few defaults that can be used as well.
33 /* Some general useful functions */
36 #include "mysql_priv.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
,
66 longlong
*func_value
);
67 static int get_part_id_charset_func_part(partition_info
*part_info
,
69 longlong
*func_value
);
70 static int get_part_id_charset_func_subpart(partition_info
*part_info
,
72 longlong
*func_value
);
73 static int get_part_part_id_charset_func(partition_info
*part_info
,
75 longlong
*func_value
);
76 static int get_subpart_id_charset_func(partition_info
*part_info
,
78 int get_partition_id_list(partition_info
*part_info
,
80 longlong
*func_value
);
81 int get_partition_id_range(partition_info
*part_info
,
83 longlong
*func_value
);
84 int get_partition_id_hash_nosub(partition_info
*part_info
,
86 longlong
*func_value
);
87 int get_partition_id_key_nosub(partition_info
*part_info
,
89 longlong
*func_value
);
90 int get_partition_id_linear_hash_nosub(partition_info
*part_info
,
92 longlong
*func_value
);
93 int get_partition_id_linear_key_nosub(partition_info
*part_info
,
95 longlong
*func_value
);
96 int get_partition_id_range_sub_hash(partition_info
*part_info
,
98 longlong
*func_value
);
99 int get_partition_id_range_sub_key(partition_info
*part_info
,
101 longlong
*func_value
);
102 int get_partition_id_range_sub_linear_hash(partition_info
*part_info
,
104 longlong
*func_value
);
105 int get_partition_id_range_sub_linear_key(partition_info
*part_info
,
107 longlong
*func_value
);
108 int get_partition_id_list_sub_hash(partition_info
*part_info
,
110 longlong
*func_value
);
111 int get_partition_id_list_sub_key(partition_info
*part_info
,
113 longlong
*func_value
);
114 int get_partition_id_list_sub_linear_hash(partition_info
*part_info
,
116 longlong
*func_value
);
117 int get_partition_id_list_sub_linear_key(partition_info
*part_info
,
119 longlong
*func_value
);
120 int get_partition_id_hash_sub(partition_info
*part_info
,
122 int get_partition_id_key_sub(partition_info
*part_info
,
124 int get_partition_id_linear_hash_sub(partition_info
*part_info
,
126 int get_partition_id_linear_key_sub(partition_info
*part_info
,
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
*);
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
,
137 uchar
*min_value
, uchar
*max_value
,
139 PARTITION_ITERATOR
*part_iter
);
140 int get_part_iter_for_interval_via_walking(partition_info
*part_info
,
142 uchar
*min_value
, uchar
*max_value
,
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
152 name String searched for
153 list_names A list of names searched in
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
;
169 char *list_name
= names_it
++;
170 if (!(my_strcasecmp(system_charset_info
, name
, list_name
)))
172 } while (++i
< no_names
);
179 Set-up defaults for partitions.
182 partition_default_handling()
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
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
))
208 else if (part_info
->is_sub_partitioned() &&
209 part_info
->use_default_no_subpartitions
)
212 if (table
->file
->get_no_parts(normalized_path
, &no_parts
))
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);
228 Check that the reorganized table will not have duplicate partitions.
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.
238 TRUE Inacceptable name conflict detected.
239 FALSE New names are OK.
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");
261 List_iterator
<partition_element
> old_parts_it(old_part_info
->partitions
);
262 char *new_name
= (new_parts_it
++)->partition_name
;
267 char *old_name
= (old_parts_it
++)->partition_name
;
269 if (same_part_info
&& old_count
== new_count
)
271 if (!(my_strcasecmp(system_charset_info
, old_name
, new_name
)))
273 if (!is_name_in_list(old_name
, list_part_names
))
276 } while (old_count
< no_old_parts
);
277 } while (new_count
< no_new_parts
);
283 A useful routine used by update_row for partition handlers to calculate
284 the partition ids of the old and the new record.
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
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
;
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
,
314 set_field_ptr(part_field_array
, rec0
, old_data
);
315 if (unlikely(error
)) // Should never happen
321 if (new_data
== rec0
)
324 if (unlikely(error
= part_info
->get_partition_id(part_info
,
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
,
342 set_field_ptr(part_field_array
, rec0
, new_data
);
354 A useful routine used by delete_row for partition handlers to calculate
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
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
)
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
,
388 DBUG_PRINT("info", ("Delete from partition %d", *part_id
));
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
);
400 DBUG_PRINT("info", ("Delete from partition %d (path2)", *part_id
));
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.
413 table TABLE object for which partition fields are set-up
414 sub_part Is the table subpartitioned as well
417 TRUE Error, some field didn't meet requirements
418 FALSE Ok, partition field array set-up
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.
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
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
448 static bool set_up_field_array(TABLE
*table
,
451 Field
**ptr
, *field
, **field_array
;
453 uint size_field_array
;
455 partition_info
*part_info
= table
->part_info
;
457 DBUG_ENTER("set_up_field_array");
460 while ((field
= *(ptr
++)))
462 if (field
->flags
& GET_FIXED_FIELDS_FLAG
)
468 We are using hidden key as partitioning field
470 DBUG_ASSERT(!is_sub_part
);
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
);
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
;
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
499 if (unlikely(field
->flags
& BLOB_FLAG
))
501 my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR
, MYF(0));
507 field_array
[no_fields
]= 0;
510 part_info
->part_field_array
= field_array
;
511 part_info
->no_part_fields
= no_fields
;
515 part_info
->subpart_field_array
= field_array
;
516 part_info
->no_subpart_fields
= no_fields
;
524 Create a field array including all fields of both the partitioning and the
525 subpartitioning functions.
528 create_full_part_field_array()
530 table TABLE object for which partition fields are set-up
531 part_info Reference to partitioning data structure
534 TRUE Memory allocation of field array failed
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
)
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
;
559 Field
*field
, **field_array
;
560 uint no_part_fields
=0, size_field_array
;
562 while ((field
= *(ptr
++)))
564 if (field
->flags
& FIELD_IN_PART_FUNC_FLAG
)
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
);
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
));
600 if (bitmap_init(&part_info
->full_part_field_set
, bitmap_buf
,
601 table
->s
->fields
, FALSE
))
603 mem_alloc_error(table
->s
->fields
);
608 full_part_field_array may be NULL if storage engine supports native
611 if ((ptr
= part_info
->full_part_field_array
))
613 bitmap_set_bit(&part_info
->full_part_field_set
, (*ptr
)->field_index
);
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).
626 clear_indicator_in_key_fields()
627 key_info Reference to find the key fields
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.
655 set_indicator_in_key_fields
656 key_info Reference to find the key fields
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.
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
682 all_fields, some_fields
685 static void check_fields_in_PF(Field
**ptr
, bool *all_fields
,
688 DBUG_ENTER("check_fields_in_PF");
692 if ((!ptr
) || !(*ptr
))
699 /* Check if the field of the PF is part of the current key investigated */
700 if ((*ptr
)->flags
& GET_FIXED_FIELDS_FLAG
)
710 Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
711 This routine is used for error handling purposes.
715 table TABLE object for which partition fields are set-up
721 static void clear_field_flag(TABLE
*table
)
724 DBUG_ENTER("clear_field_flag");
726 for (ptr
= table
->field
; *ptr
; ptr
++)
727 (*ptr
)->flags
&= (~GET_FIXED_FIELDS_FLAG
);
733 find_field_in_table_sef finds the field given its name. All fields get
734 GET_FIXED_FIELDS_FLAG set.
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
744 TRUE Fields in list of fields not part of table
745 FALSE All fields ok and array created
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
755 static bool handle_list_of_fields(List_iterator
<char> it
,
757 partition_info
*part_info
,
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
;
777 my_error(ER_FIELD_NOT_FOUND_PART_ERROR
, MYF(0));
778 clear_field_flag(table
);
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));
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
;
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.
833 my_error(ER_FIELD_NOT_FOUND_PART_ERROR
, MYF(0));
838 result
= set_up_field_array(table
, is_sub_part
);
845 Support function to check if all VALUES * (expression) is of the
846 right sign (no signed constants when unsigned partition function)
850 part_info Partition info object
853 0 No errors due to sign errors
857 int check_signed_flag(partition_info
*part_info
)
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
;
875 } while (++i
< part_info
->no_parts
);
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.
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
899 TRUE An error occurred, something was wrong with the
901 FALSE Ok, a partition field array was created
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
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
;
927 TABLE_LIST
*save_table_list
, *save_first_table
, *save_last_table
;
929 Name_resolution_context
*context
;
930 const char *save_where
;
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
))))
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
;
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
];
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
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
);
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
);
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
,
1048 if (is_create_table_ind
)
1050 my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR
, MYF(0));
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
)))
1062 if (is_field_to_be_setup
)
1063 result
= set_up_field_array(table
, is_sub_part
);
1065 part_info
->fixed
= TRUE
;
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
1078 table TABLE object for which partition fields are set-up
1081 TRUE Not all fields in partitioning function was part
1083 FALSE Ok, all fields of partitioning function were part
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
1093 static bool check_primary_key(TABLE
*table
)
1095 uint primary_key
= table
->s
->primary_key
;
1096 bool all_fields
, some_fields
;
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");
1112 DBUG_RETURN(result
);
1117 Check that unique keys contains all partition fields
1121 table TABLE object for which partition fields are set-up
1124 TRUE Not all fields in partitioning function was part
1126 FALSE Ok, all fields of partitioning function were part
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
1136 static bool check_unique_keys(TABLE
*table
)
1138 bool all_fields
, some_fields
;
1140 uint keys
= table
->s
->keys
;
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");
1160 DBUG_RETURN(result
);
1165 An important optimisation is whether a range on a field can select a subset
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
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
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
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.
1209 check_range_capable_PF()
1210 table TABLE object for which partition fields are set-up
1213 Support for this is not implemented yet.
1216 void check_range_capable_PF(TABLE
*table
)
1218 DBUG_ENTER("check_range_capable_PF");
1225 Set up partition bitmap
1228 set_up_partition_bitmap()
1230 part_info Reference to partitioning data structure
1233 TRUE Memory allocation failure
1237 Allocate memory for bitmap of the partitioned table
1241 static bool set_up_partition_bitmap(THD
*thd
, partition_info
*part_info
)
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
);
1255 bitmap_init(&part_info
->used_partitions
, bitmap_buf
, bitmap_bytes
*8, FALSE
);
1256 bitmap_set_all(&part_info
->used_partitions
);
1262 Set up partition key maps
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
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
;
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
);
1303 part_info
->all_fields_in_PF
.set_bit(i
);
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
);
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
);
1315 part_info
->all_fields_in_SPF
.set_bit(i
);
1317 clear_indicator_in_key_fields(table
->key_info
+i
);
1324 Set up function pointers for partition function
1327 set_up_partition_func_pointers()
1328 part_info Reference to partitioning data structure
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
;
1358 part_info
->get_partition_id
= get_partition_id_range_sub_key
;
1359 part_info
->get_subpartition_id
= get_partition_id_key_sub
;
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
;
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
;
1388 part_info
->get_partition_id
= get_partition_id_list_sub_key
;
1389 part_info
->get_subpartition_id
= get_partition_id_key_sub
;
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
;
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
;
1422 part_info
->get_partition_id
= get_partition_id_key_nosub
;
1426 if (part_info
->linear_hash_ind
)
1427 part_info
->get_partition_id
= get_partition_id_linear_hash_nosub
;
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
;
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
;
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.
1469 set_linear_hash_mask()
1470 part_info Reference to partitioning data structure
1471 no_parts Number of parts in linear hash partitioning
1477 void set_linear_hash_mask(partition_info
*part_info
, uint no_parts
)
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.
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
1498 part_id The calculated partition identity (starting at 0)
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
,
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
);
1522 Check if a particular field is in need of character set
1523 handling for partition functions.
1526 field_is_partition_charset()
1527 field The field to check
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
))
1540 CHARSET_INFO
*cs
= ((Field_str
*)field
)->charset();
1541 if (!(field
->type() == MYSQL_TYPE_STRING
) ||
1542 !(cs
->state
& MY_CS_BINSORT
))
1550 Check that partition function doesn't contain any forbidden
1551 character sets and collations.
1554 check_part_func_fields()
1555 ptr Array of Field pointers
1556 ok_with_charsets Will we report allowed charset
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
)
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
||
1586 cs
->strxfrm_multiply
> 1)
1597 fix partition functions
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
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.
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
)
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
)
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
))
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
)))
1665 if (unlikely(fix_fields_part_func(thd
, part_info
->subpart_expr
,
1667 is_create_table_ind
)))
1669 if (unlikely(part_info
->subpart_expr
->result_type() != INT_RESULT
))
1671 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
, MYF(0),
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
)))
1694 if (unlikely(fix_fields_part_func(thd
, part_info
->part_expr
,
1696 is_create_table_ind
)))
1698 if (unlikely(part_info
->part_expr
->result_type() != INT_RESULT
))
1700 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
, MYF(0), part_str
);
1703 part_info
->part_result_type
= INT_RESULT
;
1708 const char *error_str
;
1709 if (unlikely(fix_fields_part_func(thd
, part_info
->part_expr
,
1711 is_create_table_ind
)))
1713 if (part_info
->part_type
== RANGE_PARTITION
)
1715 error_str
= partition_keywords
[PKW_RANGE
].str
;
1716 if (unlikely(part_info
->check_range_constants()))
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()))
1728 my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR
, MYF(0));
1731 if (unlikely(part_info
->no_parts
< 1))
1733 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR
, MYF(0), error_str
);
1736 if (unlikely(part_info
->part_expr
->result_type() != INT_RESULT
))
1738 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR
, MYF(0), part_str
);
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));
1752 if (unlikely(create_full_part_field_array(thd
, table
, part_info
)))
1754 if (unlikely(check_primary_key(table
)))
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
)))
1760 if (unlikely(set_up_partition_bitmap(thd
, part_info
)))
1762 if (unlikely(part_info
->set_up_charset_field_preps()))
1764 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED
, MYF(0));
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
);
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
))
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
)
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
)
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
)
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
;
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
;
1894 append_identifier(thd
, &field_string
, 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
);
1905 static int add_name_string(File fptr
, const char *name
)
1908 String
name_string("", 0, system_charset_info
);
1909 THD
*thd
= current_thd
;
1910 ulonglong save_options
= thd
->options
;
1913 append_identifier(thd
, &name_string
, name
,
1915 thd
->options
= save_options
;
1916 err
= add_string_object(fptr
, &name_string
);
1920 static int add_int(File fptr
, longlong number
)
1923 llstr(number
, buff
);
1924 return add_string(fptr
, buff
);
1927 static int add_uint(File fptr
, ulonglong number
)
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
);
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
,
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
);
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
)
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
)
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
);
2024 err
+= add_uint(fptr
, p_elem
->range_value
);
2025 err
+= add_end_parenthesis(fptr
);
2028 err
+= add_string(fptr
, partition_keywords
[PKW_MAXVALUE
].str
);
2030 else if (part_info
->part_type
== LIST_PARTITION
)
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");
2043 err
+= add_end_parenthesis(fptr
);
2046 err
+= add_comma(fptr
);
2051 part_elem_value
*list_value
= list_val_it
++;
2053 if (!list_value
->unsigned_flag
)
2054 err
+= add_int(fptr
, list_value
->value
);
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
);
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.
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
2081 buf, buf_length Buffer and its length
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
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
2103 char *generate_partition_syntax(partition_info
*part_info
,
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
];
2113 List_iterator
<partition_element
> part_it(part_info
->partitions
);
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))
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
);
2132 case LIST_PARTITION
:
2133 err
+= add_part_key_word(fptr
, partition_keywords
[PKW_LIST
].str
);
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
);
2141 err
+= add_hash(fptr
);
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();
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
);
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
)
2190 err
+= add_string(fptr
, "\n");
2191 err
+= add_begin_parenthesis(fptr
);
2195 part_elem
= part_it
++;
2196 if (part_elem
->part_state
!= PART_TO_BE_DROPPED
&&
2197 part_elem
->part_state
!= PART_REORGED_DROPPED
)
2201 err
+= add_comma(fptr
);
2202 err
+= add_string(fptr
, "\n");
2203 err
+= add_space(fptr
);
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
);
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
);
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
);
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
);
2247 buffer_length
= my_seek(fptr
, 0L,MY_SEEK_END
,MYF(0));
2248 if (unlikely(buffer_length
== MY_FILEPOS_ERROR
))
2250 if (unlikely(my_seek(fptr
, 0L, MY_SEEK_SET
, MYF(0)) == MY_FILEPOS_ERROR
))
2252 *buf_length
= (uint
)buffer_length
;
2254 buf
= (char*) sql_alloc(*buf_length
+1);
2256 buf
= (char*) my_malloc(*buf_length
+1, MYF(MY_WME
));
2260 if (unlikely(my_read(fptr
, (uchar
*)buf
, *buf_length
, MYF(MY_FNABP
))))
2263 my_free(buf
, MYF(0));
2268 buf
[*buf_length
]= 0;
2271 my_close(fptr
, MYF(0));
2277 Check if partition key fields are modified and if it can be handled by the
2278 underlying storage engine.
2281 partition_key_modified
2282 table TABLE object for which partition fields are set-up
2283 fields Bitmap representing fields to be modified
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
)
2293 partition_info
*part_info
= table
->part_info
;
2294 DBUG_ENTER("partition_key_modified");
2298 if (table
->s
->db_type()->partition_flags
&&
2299 (table
->s
->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY
))
2301 for (fld
= part_info
->full_part_field_array
; *fld
; fld
++)
2302 if (bitmap_is_set(fields
, (*fld
)->field_index
))
2309 A function to handle correct handling of NULL values in partition
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
2317 TRUE Error in val_int()
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())
2329 *result
= LONGLONG_MIN
;
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
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.
2357 calculate_key_value()
2358 field_array An array of the fields in KEY partitioning
2361 hash_value calculated
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
)
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
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
2394 static uint32
get_part_id_for_sub(uint32 loc_part_id
, uint32 sub_part_id
,
2397 return (uint32
)((loc_part_id
* no_subparts
) + sub_part_id
);
2402 Calculate part_id for (SUB)PARTITION BY 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
2416 static int get_part_id_hash(uint no_parts
,
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
;
2435 Calculate part_id for (SUB)PARTITION BY LINEAR HASH
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
2451 static int get_part_id_linear_hash(partition_info
*part_info
,
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
,
2470 Calculate part_id for (SUB)PARTITION BY KEY
2474 field_array Array of fields for PARTTION KEY
2475 no_parts Number of KEY partitions
2478 Calculated partition id
2482 static uint32
get_part_id_key(Field
**field_array
,
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
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
2503 Calculated partition id
2507 static uint32
get_part_id_linear_key(partition_info
*part_info
,
2508 Field
**field_array
,
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
,
2521 Copy to field buffers and set up field pointers
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
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
,
2541 uchar
**restore_ptr
)
2544 while ((field
= *(ptr
++)))
2546 *restore_ptr
= field
->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
);
2566 *field_buf
= (uchar
) field
->field_length
;
2568 int2store(field_buf
, field
->field_length
);
2572 my_strnxfrm(cs
, field_buf
, len
,
2573 field
->ptr
, field
->field_length
);
2575 field
->ptr
= field_buf
;
2583 Restore field pointers
2585 restore_part_field_pointers()
2586 ptr Array of fields to restore
2587 restore_ptr Array of field pointers to restore to
2592 static void restore_part_field_pointers(Field
**ptr
, uchar
**restore_ptr
)
2595 while ((field
= *(ptr
++)))
2597 field
->ptr
= *restore_ptr
;
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
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
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.
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
,
2637 longlong
*func_value
)
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
);
2650 static int get_part_id_charset_func_part(partition_info
*part_info
,
2652 longlong
*func_value
)
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
);
2665 static int get_part_id_charset_func_all(partition_info
*part_info
,
2667 longlong
*func_value
)
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
);
2680 static int get_part_part_id_charset_func(partition_info
*part_info
,
2682 longlong
*func_value
)
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
);
2696 static int get_subpart_id_charset_func(partition_info
*part_info
,
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
);
2710 int get_partition_id_list(partition_info
*part_info
,
2712 longlong
*func_value
)
2714 LIST_PART_ENTRY
*list_array
= part_info
->list_array
;
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");
2727 if (part_info
->part_expr
->null_value
)
2729 if (part_info
->has_null_value
)
2731 *part_id
= part_info
->has_null_part_id
;
2736 *func_value
= part_func_value
;
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
)
2749 max_list_index
= list_index
- 1;
2753 *part_id
= (uint32
)list_array
[list_index
].partition_id
;
2759 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND
);
2764 Find the sub-array part_info->list_array that corresponds to given interval
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
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
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
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.
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
,
2803 bool include_endpoint
)
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
,
2811 restore_part_field_pointers(part_info
->part_field_array
,
2812 part_info
->restore_part_field_ptrs
);
2816 uint32
get_list_array_idx_for_endpoint(partition_info
*part_info
,
2818 bool include_endpoint
)
2820 LIST_PART_ENTRY
*list_array
= part_info
->list_array
;
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 */
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
)
2863 max_list_index
= list_index
- 1;
2867 DBUG_RETURN(list_index
+ test(left_endpoint
^ include_endpoint
));
2869 } while (max_list_index
>= min_list_index
);
2871 if (list_value
< part_func_value
)
2873 DBUG_RETURN(list_index
);
2877 int get_partition_id_range(partition_info
*part_info
,
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
;
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");
2892 DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND
);
2894 if (part_info
->part_expr
->null_value
)
2899 *func_value
= part_func_value
;
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;
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
));
2924 Find the sub-array of part_info->range_int_array that covers given interval
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
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
2953 The function returns first number idx, such that the interval
2954 represented by range_int_array[idx] has EMPTY intersection with the
2956 If the interval represented by the last array element has non-empty
2957 intersection with the passed interval, part_info->no_parts is
2961 The edge of corresponding part_info->range_int_array sub-array.
2965 get_partition_id_range_for_endpoint_charset(partition_info
*part_info
,
2967 bool include_endpoint
)
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
,
2975 restore_part_field_pointers(part_info
->part_field_array
,
2976 part_info
->restore_part_field_ptrs
);
2980 uint32
get_partition_id_range_for_endpoint(partition_info
*part_info
,
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
)
3020 part_func_value
-= 0x8000000000000000ULL
;
3021 if (left_endpoint
&& !include_endpoint
)
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;
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
];
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
))
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
)
3063 /* Right endpoint, set end after correct partition */
3066 DBUG_RETURN(loc_part_id
);
3070 int get_partition_id_hash_nosub(partition_info
*part_info
,
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
,
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
,
3090 longlong
*func_value
)
3092 *part_id
= get_part_id_key(part_info
->part_field_array
,
3093 part_info
->no_parts
, func_value
);
3098 int get_partition_id_linear_key_nosub(partition_info
*part_info
,
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
);
3109 int get_partition_id_range_sub_hash(partition_info
*part_info
,
3111 longlong
*func_value
)
3113 uint32 loc_part_id
, sub_part_id
;
3115 longlong local_func_value
;
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
,
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
))))
3133 *part_id
= get_part_id_for_sub(loc_part_id
, sub_part_id
, no_subparts
);
3138 int get_partition_id_range_sub_linear_hash(partition_info
*part_info
,
3140 longlong
*func_value
)
3142 uint32 loc_part_id
, sub_part_id
;
3144 longlong local_func_value
;
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
,
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
,
3159 &local_func_value
))))
3164 *part_id
= get_part_id_for_sub(loc_part_id
, sub_part_id
, no_subparts
);
3169 int get_partition_id_range_sub_key(partition_info
*part_info
,
3171 longlong
*func_value
)
3173 uint32 loc_part_id
, sub_part_id
;
3175 longlong local_func_value
;
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
,
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
);
3193 int get_partition_id_range_sub_linear_key(partition_info
*part_info
,
3195 longlong
*func_value
)
3197 uint32 loc_part_id
, sub_part_id
;
3199 longlong local_func_value
;
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
,
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
);
3218 int get_partition_id_list_sub_hash(partition_info
*part_info
,
3220 longlong
*func_value
)
3222 uint32 loc_part_id
, sub_part_id
;
3224 longlong local_func_value
;
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
,
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
))))
3241 *part_id
= get_part_id_for_sub(loc_part_id
, sub_part_id
, no_subparts
);
3246 int get_partition_id_list_sub_linear_hash(partition_info
*part_info
,
3248 longlong
*func_value
)
3250 uint32 loc_part_id
, sub_part_id
;
3252 longlong local_func_value
;
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
,
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
,
3266 &local_func_value
))))
3271 *part_id
= get_part_id_for_sub(loc_part_id
, sub_part_id
, no_subparts
);
3276 int get_partition_id_list_sub_key(partition_info
*part_info
,
3278 longlong
*func_value
)
3280 uint32 loc_part_id
, sub_part_id
;
3282 longlong local_func_value
;
3284 DBUG_ENTER("get_partition_id_range_sub_key");
3286 if (unlikely((error
= get_partition_id_list(part_info
, &loc_part_id
,
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
);
3299 int get_partition_id_list_sub_linear_key(partition_info
*part_info
,
3301 longlong
*func_value
)
3303 uint32 loc_part_id
, sub_part_id
;
3305 longlong local_func_value
;
3307 DBUG_ENTER("get_partition_id_list_sub_linear_key");
3309 if (unlikely((error
= get_partition_id_list(part_info
, &loc_part_id
,
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
);
3324 This function is used to calculate the subpartition id
3327 get_subpartition_id()
3328 part_info A reference to the partition_info struct where all the
3329 desired information is given
3332 part_id The subpartition identity
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
,
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
,
3359 longlong func_value
;
3360 return get_part_id_linear_hash(part_info
, part_info
->no_subparts
,
3361 part_info
->subpart_expr
, part_id
,
3366 int get_partition_id_key_sub(partition_info
*part_info
,
3369 longlong func_value
;
3370 *part_id
= get_part_id_key(part_info
->subpart_field_array
,
3371 part_info
->no_subparts
, &func_value
);
3376 int get_partition_id_linear_key_sub(partition_info
*part_info
,
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
);
3388 Set an indicator on all partition fields that are set by the key
3391 set_PF_fields_in_key()
3392 key_info Information about the index
3393 key_length Length of key
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
)
3410 if (key_part
->type
== HA_KEYTYPE_BIT
)
3412 if (((Field_bit
*)key_part
->field
)->bit_len
)
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
)
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.
3437 check_part_func_bound()
3438 ptr Array of fields NULL terminated (partition fields)
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
)
3448 DBUG_ENTER("check_part_func_bound");
3452 if (!((*ptr
)->flags
& GET_FIXED_FIELDS_FLAG
))
3458 DBUG_RETURN(result
);
3463 Get the id of the subpartitioning part by using the key buffer of the
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
3475 TRUE All fields in partition function are set
3476 FALSE Not all fields in partition function are set
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
,
3485 const key_range
*key_spec
,
3488 uchar
*rec0
= table
->record
[0];
3489 partition_info
*part_info
= table
->part_info
;
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
);
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
);
3509 Get the id of the partitioning part by using the key buffer of the
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
3521 TRUE Partition to use not found
3522 FALSE Ok, part_id indicates partition to use
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
)
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
,
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
,
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
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
3569 No partitions to scan is indicated by end_part > start_part when returning
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
,
3578 const key_range
*key_spec
,
3579 part_id_range
*part_spec
)
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
,
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
,
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
++;
3608 Prune the set of partitions to use in query
3611 prune_partition_set()
3612 table The table object
3613 out:part_spec Contains start part, end part
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.
3625 void prune_partition_set(const TABLE
*table
, part_id_range
*part_spec
)
3627 int last_partition
= -1;
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
;
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
;
3653 Get the set of partitions to use in query.
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
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.
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();
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
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
);
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
;
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
3741 part_spec
->start_part
= no_parts
;
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
,
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
);
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
);
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
);
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;
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
);
3845 If the table is partitioned we will read the partition info into the
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 |
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 -------------------------------
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.
3876 mysql_unpack_partition()
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
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
)
3909 partition_info
*part_info
;
3910 CHARSET_INFO
*old_character_set_client
= thd
->variables
.character_set_client
;
3911 LEX
*old_lex
= thd
->lex
;
3913 DBUG_ENTER("mysql_unpack_partition");
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
))
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
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
))
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 */
3949 mem_alloc_error(sizeof(partition_info
));
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
))
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
))
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
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
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
);
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
,
4052 part_info
->part_func_string
= part_func_string
;
4053 part_info
->subpart_func_string
= subpart_func_string
;
4060 thd
->variables
.character_set_client
= old_character_set_client
;
4061 DBUG_RETURN(result
);
4066 Set engine type on all partition element objects
4068 set_engine_all_partitions()
4069 part_info Partition info
4070 engine_type Handlerton reference of engine
4077 set_engine_all_partitions(partition_info
*part_info
,
4078 handlerton
*engine_type
)
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
);
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
);
4103 fast_end_partition()
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
4116 Support routine to handle the successful cases for partition
4120 static int fast_end_partition(THD
*thd
, ulonglong copied
,
4123 TABLE_LIST
*table_list
, bool is_empty
,
4124 ALTER_PARTITION_PARAM_TYPE
*lpt
,
4125 bool written_bin_log
)
4129 DBUG_ENTER("fast_end_partition");
4131 thd
->proc_info
="end";
4134 query_cache_invalidate3(thd
, table_list
, 0);
4136 error
= ha_autocommit_or_rollback(thd
, 0);
4137 if (end_active_trans(thd
))
4142 /* If error during commit, no need to rollback, it's done. */
4143 table
->file
->print_error(error
, MYF(0));
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()))
4152 my_snprintf(tmp_name
, sizeof(tmp_name
), ER(ER_INSERT_INFO
),
4153 (ulong
) (copied
+ deleted
),
4156 my_ok(thd
, (ha_rows
) (copied
+deleted
),0L, tmp_name
);
4162 We need to check if engine used by all partitions can handle
4163 partitioning natively.
4166 check_native_partitioned()
4167 create_info Create info in CREATE TABLE
4168 out:ret_val Return value
4169 part_info Partition info
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
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
;
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
),
4207 if (part_info
->check_engine_mix(engine_type
, table_engine_set
))
4211 All engines are of the same type. Check if this engine supports
4212 native partitioning.
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"));
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));
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
)
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
)))
4257 I.e mark the partition as a partition to be "changed" by
4258 analyzing/optimizing/rebuilding/checking/repairing
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
4274 prep_alter_part_table()
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
4288 fast_alter_partition
4291 This method handles all preparations for ALTER TABLE for partitioned
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
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));
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()))
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
;
4341 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED
, MYF(0));
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));
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
;
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
;
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));
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),
4409 else if (tab_part_info
->part_type
== RANGE_PARTITION
)
4411 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR
, MYF(0),
4412 "RANGE", "LESS THAN");
4416 DBUG_ASSERT(tab_part_info
->part_type
== LIST_PARTITION
);
4417 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR
, MYF(0),
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));
4444 if (tab_part_info
->defined_max_value
)
4446 my_error(ER_PARTITION_MAXVALUE_ERROR
, MYF(0));
4449 if (no_new_partitions
== 0)
4451 my_error(ER_ADD_PARTITION_NO_NEW_PARTITION
, MYF(0));
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));
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));
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
,
4475 tab_part_info
->no_parts
))
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
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
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
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.
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
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);
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
4613 start_part
= no_orig_partitions
- lower_2n
;
4614 end_part
= upper_2n
- 1;
4616 end_sec_part
= new_total_partitions
- (upper_2n
+ 1);
4619 List_iterator
<partition_element
> tab_it(tab_part_info
->partitions
);
4623 partition_element
*p_elem
= tab_it
++;
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
);
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
))
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.
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");
4694 if (no_parts_dropped
>= tab_part_info
->no_parts
)
4696 my_error(ER_DROP_LAST_PARTITION
, MYF(0));
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.
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");
4717 if (table
->file
->is_fk_defined_on_table_or_index(MAX_KEY
))
4719 my_error(ER_ROW_IS_REFERENCED
, MYF(0));
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");
4737 if (!(*fast_alter_partition
))
4739 table
->file
->print_error(HA_ERR_WRONG_COMMAND
, MYF(0));
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));
4753 if (no_parts_coalesced
== 0)
4755 my_error(ER_COALESCE_PARTITION_NO_PARTITION
, MYF(0));
4758 if (no_parts_coalesced
>= tab_part_info
->no_parts
)
4760 my_error(ER_DROP_LAST_PARTITION
, MYF(0));
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
4774 Using linear hash then all remaining partitions will have a new reorganised
4777 Existing partitions Coalesced partition
4778 ------ ------ ------ | ------
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
4792 p0 - p3 is in the partitions list.
4793 The p1' partition will actually not be in any list it is deduced from the
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;
4806 if (no_parts_coalesced
>= lower_2n
)
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
;
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
&&
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
;
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));
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));
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));
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));
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
,
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).
4914 ------ ------ ------ ------
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)
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
);
4940 bool found_first
= FALSE
;
4941 bool found_last
= FALSE
;
4942 bool is_last_partition_reorged
;
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
;
4954 tab_max_range
= part_elem
->range_value
;
4955 if (*fast_alter_partition
&&
4956 tab_part_info
->temp_partitions
.push_back(part_elem
))
4961 if (*fast_alter_partition
)
4962 part_elem
->part_state
= PART_TO_BE_REORGED
;
4965 uint alt_part_count
= 0;
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
);
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));
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");
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
5016 my_error(ER_REORG_OUTSIDE_RANGE
, MYF(0));
5019 tab_part_info
->no_parts
= check_total_partitions
;
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
))
5047 When thd->lex->part_info has a reference to a partition_info the
5048 ALTER TABLE contained a definition of a partitioning.
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
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.
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.
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.
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
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
5087 Also here partition has changed and thus a new table must be
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
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
;
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
;
5164 if (table
->part_info
)
5165 part_info
->default_engine_type
= table
->part_info
->default_engine_type
;
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
,
5176 if (!is_native_partitioned
)
5178 DBUG_ASSERT(create_info
->db_type
);
5179 create_info
->db_type
= partition_hton
;
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.
5193 mysql_change_partitions()
5194 lpt Struct containing parameters
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
5206 table_name Table name
5207 copied Output parameter where number of copied
5209 deleted Output parameter where number of deleted
5213 static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE
*lpt
)
5215 char path
[FN_REFLEN
+1];
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));
5228 lpt
->thd
->fatal_error();
5236 Rename partitions in an ALTER TABLE of partitions
5239 mysql_rename_partitions()
5240 lpt Struct containing parameters
5247 Request handler to rename partitions as set in states of the partition
5251 table_name Table name
5254 static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE
*lpt
)
5256 char path
[FN_REFLEN
+1];
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
)))
5264 lpt
->table
->file
->print_error(error
, MYF(0));
5272 Drop partitions in an ALTER TABLE of partitions
5275 mysql_drop_partitions()
5276 lpt Struct containing parameters
5282 Drop the partitions marked with PART_TO_BE_DROPPED state and remove
5283 those partitions from the list.
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
);
5297 uint remove_count
= 0;
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));
5309 partition_element
*part_elem
= part_it
++;
5310 if (part_elem
->part_state
== PART_IS_DROPPED
)
5315 } while (++i
< part_info
->no_parts
);
5316 part_info
->no_parts
-= remove_count
;
5322 Insert log entry into list
5324 insert_part_info_log_entry_list()
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
5341 release_part_info_log_entries()
5342 first_log_entry First log entry in list to release
5347 static void release_part_info_log_entries(DDL_LOG_MEMORY_ENTRY
*log_entry
)
5349 DBUG_ENTER("release_part_info_log_entries");
5353 release_ddl_log_memory_entry(log_entry
);
5354 log_entry
= log_entry
->next_active_log_entry
;
5361 Log an delete/rename frm file
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
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
,
5380 const char *from_path
,
5381 const char *to_path
,
5384 DDL_LOG_ENTRY ddl_log_entry
;
5385 DDL_LOG_MEMORY_ENTRY
*log_entry
;
5386 DBUG_ENTER("write_log_replace_delete_frm");
5389 ddl_log_entry
.action_type
= DDL_LOG_REPLACE_ACTION
;
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
;
5396 ddl_log_entry
.from_name
= from_path
;
5397 if (write_ddl_log_entry(&ddl_log_entry
, &log_entry
))
5401 insert_part_info_log_entry_list(lpt
->part_info
, log_entry
);
5407 Log final partition changes in change partition
5409 write_log_changed_partitions()
5410 lpt Struct containing parameters
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
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
;
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
;
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
,
5463 create_subpartition_name(normal_path
, path
,
5464 part_elem
->partition_name
,
5465 sub_elem
->partition_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
;
5472 ddl_log_entry
.action_type
= DDL_LOG_RENAME_ACTION
;
5473 if (write_ddl_log_entry(&ddl_log_entry
, &log_entry
))
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
);
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
;
5498 ddl_log_entry
.action_type
= DDL_LOG_RENAME_ACTION
;
5499 if (write_ddl_log_entry(&ddl_log_entry
, &log_entry
))
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
);
5514 Log dropped partitions
5516 write_log_dropped_partitions()
5517 lpt Struct containing parameters
5523 static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE
*lpt
,
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
;
5540 no_elements
= no_temp_partitions
;
5541 while (no_elements
--)
5543 partition_element
*part_elem
;
5545 part_elem
= temp_it
++;
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
)
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
;
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
;
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
,
5574 ddl_log_entry
.name
= tmp_path
;
5575 if (write_ddl_log_entry(&ddl_log_entry
, &log_entry
))
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
);
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
))
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
);
5608 Set execute log entry in ddl log for this partitioned table
5610 set_part_info_exec_log_entry()
5611 part_info Partition info object
5612 exec_log_entry Log entry
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
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.
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
))
5654 log_entry
= part_info
->first_log_entry
;
5655 if (write_execute_ddl_log_entry(log_entry
->entry_pos
,
5656 FALSE
, &exec_log_entry
))
5658 pthread_mutex_unlock(&LOCK_gdl
);
5659 set_part_info_exec_log_entry(part_info
, exec_log_entry
);
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));
5672 Log renaming of shadow frm to real frm name and dropping of old frm
5674 write_log_rename_frm()
5675 lpt Struct containing parameters
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
))
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
))
5706 release_part_info_log_entries(old_first_log_entry
);
5707 pthread_mutex_unlock(&LOCK_gdl
);
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));
5721 Write the log entries to ensure that the drop partition command is completed
5722 even in the presence of a crash.
5725 write_log_drop_partition()
5726 lpt Struct containing parameters
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];
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
,
5754 if (write_log_replace_delete_frm(lpt
, next_entry
, (const char*)tmp_path
,
5755 (const char*)path
, TRUE
))
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
))
5762 release_part_info_log_entries(old_first_log_entry
);
5763 pthread_mutex_unlock(&LOCK_gdl
);
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));
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
5781 write_log_add_change_partition()
5782 lpt Struct containing parameters
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];
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
,
5810 if (write_log_replace_delete_frm(lpt
, next_entry
, NULL
, tmp_path
,
5813 log_entry
= part_info
->first_log_entry
;
5814 if (write_execute_ddl_log_entry(log_entry
->entry_pos
,
5815 FALSE
, &exec_log_entry
))
5817 pthread_mutex_unlock(&LOCK_gdl
);
5818 set_part_info_exec_log_entry(part_info
, exec_log_entry
);
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));
5831 Write description of how to complete the operation after first phase of
5835 write_log_final_change_partition()
5836 lpt Struct containing parameters
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
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
;
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
))
5865 if (write_log_changed_partitions(lpt
, &next_entry
, (const char*)path
))
5867 if (write_log_replace_delete_frm(lpt
, 0UL, shadow_path
, path
, TRUE
))
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
))
5874 release_part_info_log_entries(old_first_log_entry
);
5875 pthread_mutex_unlock(&LOCK_gdl
);
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));
5889 Remove entry from ddl log and release resources for others to use
5892 write_log_completed()
5893 lpt Struct containing parameters
5899 static void write_log_completed(ALTER_PARTITION_PARAM_TYPE
*lpt
,
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
;
5929 Release all log entries
5931 release_log_entries()
5932 part_info Partition info struct
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
5952 alter_partition_lock_handling()
5953 lpt Struct carrying parameters
5957 static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE
*lpt
)
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;
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
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
5995 handle_alter_part_error()
5996 lpt Struct carrying parameters
5997 not_completed Was request in complete phase when error occurred
6002 void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE
*lpt
,
6004 bool drop_partition
,
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
6018 write_log_completed(lpt
, FALSE
);
6019 release_log_entries(part_info
);
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,
6027 "Operation was unsuccessful, table is still intact,",
6028 "but it is possible that a shadow frm file was left behind");
6032 push_warning_printf(lpt
->thd
, MYSQL_ERROR::WARN_LEVEL_WARN
, 1,
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");
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,
6050 "Failed during alter of partitions, table is no longer intact.",
6051 "The frm file is in an unknown state, and a backup",
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,
6064 "Failed during drop of partitions, table is intact.",
6065 "Manual drop of remaining partitions is required");
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,
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");
6084 release_log_entries(part_info
);
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.
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
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");
6113 Actually perform the change requested by ALTER TABLE of partitions
6114 previously prepared.
6117 fast_alter_partition_table()
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
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
,
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");
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
;
6160 lpt
->key_info_buffer
= 0;
6163 lpt
->table_name
= table_name
;
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
))
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
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
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
);
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
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
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
6340 9) Install the new frm file of the table where the partitions are
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
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
);
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
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
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
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
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.
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
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
);
6463 A final step is to write the query to the binlog and send ok to the
6466 DBUG_RETURN(fast_end_partition(thd
, lpt
->copied
, lpt
->deleted
,
6467 table
, table_list
, FALSE
, NULL
,
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
);
6481 /* Force the table to be closed to avoid reuse of the table->part_info */
6482 close_thread_tables(thd
);
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.
6495 ptr Array of fields to change ptr
6496 new_buf New record pointer
6497 old_buf Old record pointer
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
);
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.
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
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
;
6547 my_ptrdiff_t diff
= (new_buf
- old_buf
);
6548 DBUG_ENTER("set_key_field_ptr");
6552 key_part
->field
->move_field_offset(diff
);
6554 } while (++i
< key_parts
);
6562 size Size of memory attempted to allocate
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
6584 make_used_partitions_str()
6585 part_info IN Partitioning info
6586 parts_str OUT The string to fill
6589 Generate a list of used partitions (from bits in part_info->used_partitions
6590 bitmap), asd store it into the provided String object.
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
);
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
);
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
);
6644 /****************************************************************************
6645 * Partition interval analysis support
6646 ***************************************************************************/
6649 Setup partition_info::* members related to partitioning range analysis
6652 set_up_partition_func_pointers()
6653 part_info Partitioning info structure
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
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
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
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
;
6705 Check if get_part_iter_for_interval_via_walking() can be used for
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
;
6727 Check if get_part_iter_for_interval_via_walking() can be used for
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
;
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
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,
6763 part_iter Iterator structure to be initialized
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.
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.
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
,
6788 uchar
*min_value
, uchar
*max_value
,
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
;
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
;
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
;
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
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;
6874 if (flags
& NO_MIN_RANGE
)
6875 part_iter
->part_nums
.start
= part_iter
->part_nums
.cur
= 0;
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
;
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
;
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
6933 DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d",
6935 end_date
.year
, end_date
.month
, end_date
.day
));
6936 DBUG_ASSERT(!memcmp(((Item_func
*) part_info
->part_expr
)->func_name(),
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
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,
6967 part_iter Iterator structure to be initialized
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, ...
6978 ... t.field = const2 ...
6981 See get_partitions_in_range_iter for general description of interval
6982 analysis. We support walking over the following intervals:
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
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
,
7006 uchar
*min_value
, uchar
*max_value
,
7008 PARTITION_ITERATOR
*part_iter
)
7012 partition_iter_func get_next_func
;
7013 part_iter
->ret_null_part
= part_iter
->ret_null_part_orig
= FALSE
;
7016 field
= part_info
->subpart_field_array
[0];
7017 total_parts
= part_info
->no_subparts
;
7018 get_next_func
= get_next_subpartition_via_walking
;
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.
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 */
7049 int res
= part_info
->is_sub_partitioned() ?
7050 part_info
->get_part_partition_id(part_info
, &part_id
,
7052 part_info
->get_partition_id(part_info
, &part_id
, &dummy
);
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 */
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)
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
)
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
;
7104 PARTITION_ITERATOR::get_next implementation: enumerate partitions in range
7107 get_next_partition_id_range()
7108 part_iter Partition set iterator structure
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.
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
;
7134 return part_iter
->part_nums
.cur
++;
7139 PARTITION_ITERATOR::get_next implementation for LIST partitioning
7142 get_next_partition_id_list()
7143 part_iter Partition set iterator structure
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.
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
;
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
7179 get_next_partition_via_walking()
7180 part_iter Partitioning iterator
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.
7190 NOT_A_PARTITION_ID if there are no more partitioning.
7193 static uint32
get_next_partition_via_walking(PARTITION_ITERATOR
*part_iter
)
7196 Field
*field
= part_iter
->part_info
->part_field_array
[0];
7197 while (part_iter
->field_vals
.cur
!= part_iter
->field_vals
.end
)
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
,
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];
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
,
7228 return NOT_A_PARTITION_ID
;
7235 Create partition names
7238 create_partition_name()
7239 out:out Created partition name string
7242 name_variant Normal, temporary or renamed partition name
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
,
7256 char transl_part_name
[FN_REFLEN
];
7257 const char *transl_part
;
7261 tablename_to_filename(in2
, transl_part_name
, FN_REFLEN
);
7262 transl_part
= transl_part_name
;
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
7279 create_subpartition_name()
7280 out:out Created partition name string
7284 name_variant Normal, temporary or renamed partition name
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
,
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
);