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