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