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