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