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