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