1 /* Copyright (c) 2006, 2015, Oracle and/or its affiliates.
2 Copyright (c) 2010, 2020, MariaDB Corporation.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
16
17 /* Some general useful functions */
18
19 #ifdef USE_PRAGMA_IMPLEMENTATION
20 #pragma implementation
21 #endif
22
23 #include "mariadb.h"
24 #include <my_global.h>
25 #include <tztime.h>
26 #include "sql_priv.h"
27 // Required to get server definitions for mysql/plugin.h right
28 #include "sql_plugin.h"
29 #include "sql_partition.h" // partition_info.h: LIST_PART_ENTRY
30 // NOT_A_PARTITION_ID
31 #include "partition_info.h"
32 #include "sql_parse.h"
33 #include "sql_base.h" // fill_record
34 #include "lock.h"
35 #include "table.h"
36 #include "sql_class.h"
37 #include "vers_string.h"
38
39 #ifdef WITH_PARTITION_STORAGE_ENGINE
40 #include "ha_partition.h"
41
42
get_clone(THD * thd,bool empty_data_and_index_file)43 partition_info *partition_info::get_clone(THD *thd, bool empty_data_and_index_file)
44 {
45 MEM_ROOT *mem_root= thd->mem_root;
46 DBUG_ENTER("partition_info::get_clone");
47
48 List_iterator<partition_element> part_it(partitions);
49 partition_element *part;
50 partition_info *clone= new (mem_root) partition_info(*this);
51 if (unlikely(!clone))
52 DBUG_RETURN(NULL);
53
54 memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions));
55 memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions));
56 clone->bitmaps_are_initialized= FALSE;
57 clone->partitions.empty();
58
59 while ((part= (part_it++)))
60 {
61 List_iterator<partition_element> subpart_it(part->subpartitions);
62 partition_element *subpart;
63 partition_element *part_clone= new (mem_root) partition_element(*part);
64 if (!part_clone)
65 DBUG_RETURN(NULL);
66 part_clone->subpartitions.empty();
67 while ((subpart= (subpart_it++)))
68 {
69 partition_element *subpart_clone= new (mem_root) partition_element(*subpart);
70 if (!subpart_clone)
71 DBUG_RETURN(NULL);
72 if (empty_data_and_index_file)
73 subpart_clone->data_file_name= subpart_clone->index_file_name= NULL;
74 part_clone->subpartitions.push_back(subpart_clone, mem_root);
75 }
76
77 if (empty_data_and_index_file)
78 part_clone->data_file_name= part_clone->index_file_name= NULL;
79 clone->partitions.push_back(part_clone, mem_root);
80 part_clone->list_val_list.empty();
81 List_iterator<part_elem_value> list_val_it(part->list_val_list);
82 part_elem_value *new_val_arr=
83 (part_elem_value *)alloc_root(mem_root, sizeof(part_elem_value) *
84 part->list_val_list.elements);
85 if (!new_val_arr)
86 DBUG_RETURN(NULL);
87
88 p_column_list_val *new_colval_arr=
89 (p_column_list_val*)alloc_root(mem_root, sizeof(p_column_list_val) *
90 num_columns *
91 part->list_val_list.elements);
92 if (!new_colval_arr)
93 DBUG_RETURN(NULL);
94
95 part_elem_value *val;
96 while ((val= list_val_it++))
97 {
98 part_elem_value *new_val= new_val_arr++;
99 memcpy(new_val, val, sizeof(part_elem_value));
100 if (!val->null_value)
101 {
102 p_column_list_val *new_colval= new_colval_arr;
103 new_colval_arr+= num_columns;
104 memcpy(new_colval, val->col_val_array,
105 sizeof(p_column_list_val) * num_columns);
106 new_val->col_val_array= new_colval;
107 }
108 part_clone->list_val_list.push_back(new_val, mem_root);
109 }
110 }
111 if (part_type == VERSIONING_PARTITION && vers_info)
112 {
113 // clone Vers_part_info; set now_part, hist_part
114 clone->vers_info= new (mem_root) Vers_part_info(*vers_info);
115 List_iterator<partition_element> it(clone->partitions);
116 while ((part= it++))
117 {
118 if (vers_info->now_part && part->id == vers_info->now_part->id)
119 clone->vers_info->now_part= part;
120 else if (vers_info->hist_part && part->id == vers_info->hist_part->id)
121 clone->vers_info->hist_part= part;
122 } // while ((part= it++))
123 } // if (part_type == VERSIONING_PARTITION ...
124 DBUG_RETURN(clone);
125 }
126
127 /**
128 Mark named [sub]partition to be used/locked.
129
130 @param part_name Partition name to match.
131 @param length Partition name length.
132
133 @return Success if partition found
134 @retval true Partition found
135 @retval false Partition not found
136 */
137
add_named_partition(const char * part_name,size_t length)138 bool partition_info::add_named_partition(const char *part_name, size_t length)
139 {
140 HASH *part_name_hash;
141 PART_NAME_DEF *part_def;
142 Partition_share *part_share;
143 DBUG_ENTER("partition_info::add_named_partition");
144 DBUG_ASSERT(table && table->s && table->s->ha_share);
145 part_share= static_cast<Partition_share*>((table->s->ha_share));
146 DBUG_ASSERT(part_share->partition_name_hash_initialized);
147 part_name_hash= &part_share->partition_name_hash;
148 DBUG_ASSERT(part_name_hash->records);
149
150 part_def= (PART_NAME_DEF*) my_hash_search(part_name_hash,
151 (const uchar*) part_name,
152 length);
153 if (!part_def)
154 {
155 my_error(ER_UNKNOWN_PARTITION, MYF(0), part_name, table->alias.c_ptr());
156 DBUG_RETURN(true);
157 }
158
159 if (part_def->is_subpart)
160 {
161 bitmap_set_bit(&read_partitions, part_def->part_id);
162 }
163 else
164 {
165 if (is_sub_partitioned())
166 {
167 /* Mark all subpartitions in the partition */
168 uint j, start= part_def->part_id;
169 uint end= start + num_subparts;
170 for (j= start; j < end; j++)
171 bitmap_set_bit(&read_partitions, j);
172 }
173 else
174 bitmap_set_bit(&read_partitions, part_def->part_id);
175 }
176 DBUG_PRINT("info", ("Found partition %u is_subpart %d for name %s",
177 part_def->part_id, part_def->is_subpart,
178 part_name));
179 DBUG_RETURN(false);
180 }
181
182
183 /**
184 Mark named [sub]partition to be used/locked.
185
186 @param part_elem Partition element that matched.
187 */
188
set_named_partition_bitmap(const char * part_name,size_t length)189 bool partition_info::set_named_partition_bitmap(const char *part_name, size_t length)
190 {
191 DBUG_ENTER("partition_info::set_named_partition_bitmap");
192 bitmap_clear_all(&read_partitions);
193 if (add_named_partition(part_name, length))
194 DBUG_RETURN(true);
195 bitmap_copy(&lock_partitions, &read_partitions);
196 DBUG_RETURN(false);
197 }
198
199
200 /**
201 Prune away partitions not mentioned in the PARTITION () clause,
202 if used.
203
204 @param partition_names list of names of partitions.
205
206 @return Operation status
207 @retval true Failure
208 @retval false Success
209 */
prune_partition_bitmaps(List<String> * partition_names)210 bool partition_info::prune_partition_bitmaps(List<String> *partition_names)
211 {
212 List_iterator<String> partition_names_it(*(partition_names));
213 uint num_names= partition_names->elements;
214 uint i= 0;
215 DBUG_ENTER("partition_info::prune_partition_bitmaps");
216
217 if (num_names < 1)
218 DBUG_RETURN(true);
219
220 /*
221 TODO: When adding support for FK in partitioned tables, the referenced
222 table must probably lock all partitions for read, and also write depending
223 of ON DELETE/UPDATE.
224 */
225 bitmap_clear_all(&read_partitions);
226
227 /* No check for duplicate names or overlapping partitions/subpartitions. */
228
229 DBUG_PRINT("info", ("Searching through partition_name_hash"));
230 do
231 {
232 String *part_name_str= partition_names_it++;
233 if (add_named_partition(part_name_str->c_ptr(), part_name_str->length()))
234 DBUG_RETURN(true);
235 } while (++i < num_names);
236 DBUG_RETURN(false);
237 }
238
239
240 /**
241 Set read/lock_partitions bitmap over non pruned partitions
242
243 @param partition_names list of partition names to query
244
245 @return Operation status
246 @retval FALSE OK
247 @retval TRUE Failed to allocate memory for bitmap or list of partitions
248 did not match
249
250 @note OK to call multiple times without the need for free_bitmaps.
251 */
252
set_partition_bitmaps(List<String> * partition_names)253 bool partition_info::set_partition_bitmaps(List<String> *partition_names)
254 {
255 DBUG_ENTER("partition_info::set_partition_bitmaps");
256
257 DBUG_ASSERT(bitmaps_are_initialized);
258 DBUG_ASSERT(table);
259 if (!bitmaps_are_initialized)
260 DBUG_RETURN(TRUE);
261
262 if (partition_names &&
263 partition_names->elements)
264 {
265 if (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)
266 {
267 my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
268 DBUG_RETURN(true);
269 }
270 if (prune_partition_bitmaps(partition_names))
271 DBUG_RETURN(TRUE);
272 }
273 else
274 {
275 bitmap_set_all(&read_partitions);
276 DBUG_PRINT("info", ("Set all partitions"));
277 }
278 bitmap_copy(&lock_partitions, &read_partitions);
279 DBUG_ASSERT(bitmap_get_first_set(&lock_partitions) != MY_BIT_NONE);
280 DBUG_RETURN(FALSE);
281 }
282
283
284 /**
285 Set read/lock_partitions bitmap over non pruned partitions
286
287 @param table_list Possible TABLE_LIST which can contain
288 list of partition names to query
289
290 @return Operation status
291 @retval FALSE OK
292 @retval TRUE Failed to allocate memory for bitmap or list of partitions
293 did not match
294
295 @note OK to call multiple times without the need for free_bitmaps.
296 */
set_partition_bitmaps_from_table(TABLE_LIST * table_list)297 bool partition_info::set_partition_bitmaps_from_table(TABLE_LIST *table_list)
298 {
299 List<String> *partition_names= table_list ?
300 NULL : table_list->partition_names;
301 return set_partition_bitmaps(partition_names);
302 }
303
304
305 /*
306 Create a memory area where default partition names are stored and fill it
307 up with the names.
308
309 SYNOPSIS
310 create_default_partition_names()
311 part_no Partition number for subparts
312 num_parts Number of partitions
313 start_no Starting partition number
314 subpart Is it subpartitions
315
316 RETURN VALUE
317 A pointer to the memory area of the default partition names
318
319 DESCRIPTION
320 A support routine for the partition code where default values are
321 generated.
322 The external routine needing this code is check_partition_info
323 */
324
325 #define MAX_PART_NAME_SIZE 8
326
create_default_partition_names(THD * thd,uint part_no,uint num_parts_arg,uint start_no)327 char *partition_info::create_default_partition_names(THD *thd, uint part_no,
328 uint num_parts_arg,
329 uint start_no)
330 {
331 char *ptr= (char*) thd->calloc(num_parts_arg * MAX_PART_NAME_SIZE);
332 char *move_ptr= ptr;
333 uint i= 0;
334 DBUG_ENTER("create_default_partition_names");
335
336 if (likely(ptr != 0))
337 {
338 do
339 {
340 if (make_partition_name(move_ptr, (start_no + i)))
341 DBUG_RETURN(NULL);
342 move_ptr+= MAX_PART_NAME_SIZE;
343 } while (++i < num_parts_arg);
344 }
345 DBUG_RETURN(ptr);
346 }
347
348
349 /*
350 Create a unique name for the subpartition as part_name'sp''subpart_no'
351
352 SYNOPSIS
353 create_default_subpartition_name()
354 subpart_no Number of subpartition
355 part_name Name of partition
356 RETURN VALUES
357 >0 A reference to the created name string
358 0 Memory allocation error
359 */
360
create_default_subpartition_name(THD * thd,uint subpart_no,const char * part_name)361 char *partition_info::create_default_subpartition_name(THD *thd, uint subpart_no,
362 const char *part_name)
363 {
364 size_t size_alloc= strlen(part_name) + MAX_PART_NAME_SIZE;
365 char *ptr= (char*) thd->calloc(size_alloc);
366 DBUG_ENTER("create_default_subpartition_name");
367
368 if (likely(ptr != NULL))
369 my_snprintf(ptr, size_alloc, "%ssp%u", part_name, subpart_no);
370
371 DBUG_RETURN(ptr);
372 }
373
374
375 /*
376 Set up all the default partitions not set-up by the user in the SQL
377 statement. Also perform a number of checks that the user hasn't tried
378 to use default values where no defaults exists.
379
380 SYNOPSIS
381 set_up_default_partitions()
382 file A reference to a handler of the table
383 info Create info
384 start_no Starting partition number
385
386 RETURN VALUE
387 TRUE Error, attempted default values not possible
388 FALSE Ok, default partitions set-up
389
390 DESCRIPTION
391 The routine uses the underlying handler of the partitioning to define
392 the default number of partitions. For some handlers this requires
393 knowledge of the maximum number of rows to be stored in the table.
394 This routine only accepts HASH and KEY partitioning and thus there is
395 no subpartitioning if this routine is successful.
396 The external routine needing this code is check_partition_info
397 */
398
set_up_default_partitions(THD * thd,handler * file,HA_CREATE_INFO * info,uint start_no)399 bool partition_info::set_up_default_partitions(THD *thd, handler *file,
400 HA_CREATE_INFO *info,
401 uint start_no)
402 {
403 uint i;
404 char *default_name;
405 bool result= TRUE;
406 DBUG_ENTER("partition_info::set_up_default_partitions");
407
408 if (part_type == VERSIONING_PARTITION)
409 {
410 if (start_no == 0 && use_default_num_partitions)
411 num_parts= 2;
412 use_default_num_partitions= false;
413 }
414 else if (part_type != HASH_PARTITION)
415 {
416 const char *error_string;
417 if (part_type == RANGE_PARTITION)
418 error_string= "RANGE";
419 else if (part_type == VERSIONING_PARTITION)
420 error_string= "SYSTEM_TIME";
421 else
422 error_string= "LIST";
423 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
424 goto end;
425 }
426
427 if ((num_parts == 0) &&
428 ((num_parts= file->get_default_no_partitions(info)) == 0))
429 {
430 my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
431 goto end;
432 }
433
434 if (unlikely(num_parts > MAX_PARTITIONS))
435 {
436 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
437 goto end;
438 }
439 if (unlikely((!(default_name= create_default_partition_names(thd, 0,
440 num_parts,
441 start_no)))))
442 goto end;
443 i= 0;
444 do
445 {
446 partition_element *part_elem= new partition_element();
447 if (likely(part_elem != 0 &&
448 (!partitions.push_back(part_elem))))
449 {
450 part_elem->engine_type= default_engine_type;
451 part_elem->partition_name= default_name;
452 part_elem->id= i;
453 default_name+=MAX_PART_NAME_SIZE;
454 if (part_type == VERSIONING_PARTITION)
455 {
456 if (start_no > 0 || i < num_parts - 1) {
457 part_elem->type= partition_element::HISTORY;
458 } else {
459 part_elem->type= partition_element::CURRENT;
460 part_elem->partition_name= "pn";
461 }
462 }
463 }
464 else
465 goto end;
466 } while (++i < num_parts);
467 result= FALSE;
468 end:
469 DBUG_RETURN(result);
470 }
471
472
473 /*
474 Set up all the default subpartitions not set-up by the user in the SQL
475 statement. Also perform a number of checks that the default partitioning
476 becomes an allowed partitioning scheme.
477
478 SYNOPSIS
479 set_up_default_subpartitions()
480 file A reference to a handler of the table
481 info Create info
482
483 RETURN VALUE
484 TRUE Error, attempted default values not possible
485 FALSE Ok, default partitions set-up
486
487 DESCRIPTION
488 The routine uses the underlying handler of the partitioning to define
489 the default number of partitions. For some handlers this requires
490 knowledge of the maximum number of rows to be stored in the table.
491 This routine is only called for RANGE or LIST partitioning and those
492 need to be specified so only subpartitions are specified.
493 The external routine needing this code is check_partition_info
494 */
495
set_up_default_subpartitions(THD * thd,handler * file,HA_CREATE_INFO * info)496 bool partition_info::set_up_default_subpartitions(THD *thd, handler *file,
497 HA_CREATE_INFO *info)
498 {
499 uint i, j;
500 bool result= TRUE;
501 partition_element *part_elem;
502 List_iterator<partition_element> part_it(partitions);
503 DBUG_ENTER("partition_info::set_up_default_subpartitions");
504
505 if (num_subparts == 0)
506 num_subparts= file->get_default_no_partitions(info);
507 if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS))
508 {
509 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
510 goto end;
511 }
512 i= 0;
513 do
514 {
515 part_elem= part_it++;
516 j= 0;
517 do
518 {
519 partition_element *subpart_elem= new partition_element(part_elem);
520 if (likely(subpart_elem != 0 &&
521 (!part_elem->subpartitions.push_back(subpart_elem))))
522 {
523 char *ptr= create_default_subpartition_name(thd, j,
524 part_elem->partition_name);
525 if (!ptr)
526 goto end;
527 subpart_elem->engine_type= default_engine_type;
528 subpart_elem->partition_name= ptr;
529 }
530 else
531 goto end;
532 } while (++j < num_subparts);
533 } while (++i < num_parts);
534 result= FALSE;
535 end:
536 DBUG_RETURN(result);
537 }
538
539
540 /*
541 Support routine for check_partition_info
542
543 SYNOPSIS
544 set_up_defaults_for_partitioning()
545 file A reference to a handler of the table
546 info Create info
547 start_no Starting partition number
548
549 RETURN VALUE
550 TRUE Error, attempted default values not possible
551 FALSE Ok, default partitions set-up
552
553 DESCRIPTION
554 Set up defaults for partition or subpartition (cannot set-up for both,
555 this will return an error.
556 */
557
set_up_defaults_for_partitioning(THD * thd,handler * file,HA_CREATE_INFO * info,uint start_no)558 bool partition_info::set_up_defaults_for_partitioning(THD *thd, handler *file,
559 HA_CREATE_INFO *info,
560 uint start_no)
561 {
562 DBUG_ENTER("partition_info::set_up_defaults_for_partitioning");
563
564 if (!default_partitions_setup)
565 {
566 default_partitions_setup= TRUE;
567 if (use_default_partitions &&
568 set_up_default_partitions(thd, file, info, start_no))
569 DBUG_RETURN(TRUE);
570 if (is_sub_partitioned() &&
571 use_default_subpartitions)
572 DBUG_RETURN(set_up_default_subpartitions(thd, file, info));
573 }
574 DBUG_RETURN(FALSE);
575 }
576
577
578 /*
579 Support routine for check_partition_info
580
581 SYNOPSIS
582 find_duplicate_field
583 no parameters
584
585 RETURN VALUE
586 Erroneus field name Error, there are two fields with same name
587 NULL Ok, no field defined twice
588
589 DESCRIPTION
590 Check that the user haven't defined the same field twice in
591 key or column list partitioning.
592 */
593
find_duplicate_field()594 const char* partition_info::find_duplicate_field()
595 {
596 const char *field_name_outer, *field_name_inner;
597 List_iterator<const char> it_outer(part_field_list);
598 uint num_fields= part_field_list.elements;
599 uint i,j;
600 DBUG_ENTER("partition_info::find_duplicate_field");
601
602 for (i= 0; i < num_fields; i++)
603 {
604 field_name_outer= it_outer++;
605 List_iterator<const char> it_inner(part_field_list);
606 for (j= 0; j < num_fields; j++)
607 {
608 field_name_inner= it_inner++;
609 if (i >= j)
610 continue;
611 if (!(my_strcasecmp(system_charset_info,
612 field_name_outer,
613 field_name_inner)))
614 {
615 DBUG_RETURN(field_name_outer);
616 }
617 }
618 }
619 DBUG_RETURN(NULL);
620 }
621
622
623 /**
624 @brief Get part_elem and part_id from partition name
625
626 @param partition_name Name of partition to search for.
627 @param file_name[out] Partition file name (part after table name,
628 #P#<part>[#SP#<subpart>]), skipped if NULL.
629 @param part_id[out] Id of found partition or NOT_A_PARTITION_ID.
630
631 @retval Pointer to part_elem of [sub]partition, if not found NULL
632
633 @note Since names of partitions AND subpartitions must be unique,
634 this function searches both partitions and subpartitions and if name of
635 a partition is given for a subpartitioned table, part_elem will be
636 the partition, but part_id will be NOT_A_PARTITION_ID and file_name not set.
637 */
get_part_elem(const char * partition_name,char * file_name,size_t file_name_size,uint32 * part_id)638 partition_element *partition_info::get_part_elem(const char *partition_name,
639 char *file_name,
640 size_t file_name_size,
641 uint32 *part_id)
642 {
643 List_iterator<partition_element> part_it(partitions);
644 uint i= 0;
645 DBUG_ENTER("partition_info::get_part_elem");
646 DBUG_ASSERT(part_id);
647 *part_id= NOT_A_PARTITION_ID;
648 do
649 {
650 partition_element *part_elem= part_it++;
651 if (is_sub_partitioned())
652 {
653 List_iterator<partition_element> sub_part_it(part_elem->subpartitions);
654 uint j= 0;
655 do
656 {
657 partition_element *sub_part_elem= sub_part_it++;
658 if (!my_strcasecmp(system_charset_info,
659 sub_part_elem->partition_name, partition_name))
660 {
661 if (file_name)
662 if (create_subpartition_name(file_name, file_name_size, "",
663 part_elem->partition_name,
664 partition_name, NORMAL_PART_NAME))
665 DBUG_RETURN(NULL);
666 *part_id= j + (i * num_subparts);
667 DBUG_RETURN(sub_part_elem);
668 }
669 } while (++j < num_subparts);
670
671 /* Naming a partition (first level) on a subpartitioned table. */
672 if (!my_strcasecmp(system_charset_info,
673 part_elem->partition_name, partition_name))
674 DBUG_RETURN(part_elem);
675 }
676 else if (!my_strcasecmp(system_charset_info,
677 part_elem->partition_name, partition_name))
678 {
679 if (file_name)
680 if (create_partition_name(file_name, file_name_size, "",
681 partition_name, NORMAL_PART_NAME, TRUE))
682 DBUG_RETURN(NULL);
683 *part_id= i;
684 DBUG_RETURN(part_elem);
685 }
686 } while (++i < num_parts);
687 DBUG_RETURN(NULL);
688 }
689
690
691 /**
692 Helper function to find_duplicate_name.
693 */
694
get_part_name_from_elem(const char * name,size_t * length,my_bool not_used)695 static const char *get_part_name_from_elem(const char *name, size_t *length,
696 my_bool not_used __attribute__((unused)))
697 {
698 *length= strlen(name);
699 return name;
700 }
701
702 /*
703 A support function to check partition names for duplication in a
704 partitioned table
705
706 SYNOPSIS
707 find_duplicate_name()
708
709 RETURN VALUES
710 NULL Has unique part and subpart names
711 !NULL Pointer to duplicated name
712
713 DESCRIPTION
714 Checks that the list of names in the partitions doesn't contain any
715 duplicated names.
716 */
717
find_duplicate_name()718 char *partition_info::find_duplicate_name()
719 {
720 HASH partition_names;
721 uint max_names;
722 const uchar *curr_name= NULL;
723 List_iterator<partition_element> parts_it(partitions);
724 partition_element *p_elem;
725
726 DBUG_ENTER("partition_info::find_duplicate_name");
727
728 /*
729 TODO: If table->s->ha_part_data->partition_name_hash.elements is > 0,
730 then we could just return NULL, but that has not been verified.
731 And this only happens when in ALTER TABLE with full table copy.
732 */
733
734 max_names= num_parts;
735 if (is_sub_partitioned())
736 max_names+= num_parts * num_subparts;
737 if (my_hash_init(PSI_INSTRUMENT_ME, &partition_names, system_charset_info, max_names, 0, 0,
738 (my_hash_get_key) get_part_name_from_elem, 0, HASH_UNIQUE))
739 {
740 DBUG_ASSERT(0);
741 curr_name= (const uchar*) "Internal failure";
742 goto error;
743 }
744 while ((p_elem= (parts_it++)))
745 {
746 curr_name= (const uchar*) p_elem->partition_name;
747 if (my_hash_insert(&partition_names, curr_name))
748 goto error;
749
750 if (!p_elem->subpartitions.is_empty())
751 {
752 List_iterator<partition_element> subparts_it(p_elem->subpartitions);
753 partition_element *subp_elem;
754 while ((subp_elem= (subparts_it++)))
755 {
756 curr_name= (const uchar*) subp_elem->partition_name;
757 if (my_hash_insert(&partition_names, curr_name))
758 goto error;
759 }
760 }
761 }
762 my_hash_free(&partition_names);
763 DBUG_RETURN(NULL);
764 error:
765 my_hash_free(&partition_names);
766 DBUG_RETURN((char*) curr_name);
767 }
768
769
770 /*
771 A support function to check if a partition element's name is unique
772
773 SYNOPSIS
774 has_unique_name()
775 partition_element element to check
776
777 RETURN VALUES
778 TRUE Has unique name
779 FALSE Doesn't
780 */
781
has_unique_name(partition_element * element)782 bool partition_info::has_unique_name(partition_element *element)
783 {
784 DBUG_ENTER("partition_info::has_unique_name");
785
786 const char *name_to_check= element->partition_name;
787 List_iterator<partition_element> parts_it(partitions);
788
789 partition_element *el;
790 while ((el= (parts_it++)))
791 {
792 if (!(my_strcasecmp(system_charset_info, el->partition_name,
793 name_to_check)) && el != element)
794 DBUG_RETURN(FALSE);
795
796 if (!el->subpartitions.is_empty())
797 {
798 partition_element *sub_el;
799 List_iterator<partition_element> subparts_it(el->subpartitions);
800 while ((sub_el= (subparts_it++)))
801 {
802 if (!(my_strcasecmp(system_charset_info, sub_el->partition_name,
803 name_to_check)) && sub_el != element)
804 DBUG_RETURN(FALSE);
805 }
806 }
807 }
808 DBUG_RETURN(TRUE);
809 }
810
811
812 /**
813 @brief Switch history partition according limit or interval
814
815 @note
816 vers_info->limit Limit by number of partition records
817 vers_info->interval Limit by fixed time interval
818 vers_info->hist_part (out) Working history partition
819 */
vers_set_hist_part(THD * thd)820 int partition_info::vers_set_hist_part(THD *thd)
821 {
822 if (table->pos_in_table_list &&
823 table->pos_in_table_list->partition_names)
824 {
825 return HA_ERR_PARTITION_LIST;
826 }
827 if (vers_info->limit)
828 {
829 ha_partition *hp= (ha_partition*)(table->file);
830 partition_element *next= NULL;
831 List_iterator<partition_element> it(partitions);
832 while (next != vers_info->hist_part)
833 next= it++;
834 DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
835 ha_rows records= hp->part_records(next);
836 while ((next= it++) != vers_info->now_part)
837 {
838 DBUG_ASSERT(bitmap_is_set(&read_partitions, next->id));
839 ha_rows next_records= hp->part_records(next);
840 if (next_records == 0)
841 break;
842 vers_info->hist_part= next;
843 records= next_records;
844 }
845 if (records >= vers_info->limit)
846 {
847 if (next == vers_info->now_part)
848 {
849 my_error(WARN_VERS_PART_FULL, MYF(ME_WARNING|ME_ERROR_LOG),
850 table->s->db.str, table->s->table_name.str,
851 vers_info->hist_part->partition_name, "LIMIT");
852 }
853 else
854 vers_info->hist_part= next;
855 }
856 return 0;
857 }
858
859 if (vers_info->interval.is_set())
860 {
861 if (vers_info->hist_part->range_value > thd->query_start())
862 return 0;
863
864 partition_element *next= NULL;
865 List_iterator<partition_element> it(partitions);
866 while (next != vers_info->hist_part)
867 next= it++;
868
869 while ((next= it++) != vers_info->now_part)
870 {
871 vers_info->hist_part= next;
872 if (next->range_value > thd->query_start())
873 return 0;
874 }
875 }
876 return 0;
877 }
878
879
880 /*
881 Check that the partition/subpartition is setup to use the correct
882 storage engine
883 SYNOPSIS
884 check_engine_condition()
885 p_elem Partition element
886 table_engine_set Have user specified engine on table level
887 inout::engine_type Current engine used
888 inout::first Is it first partition
889 RETURN VALUE
890 TRUE Failed check
891 FALSE Ok
892 DESCRIPTION
893 Specified engine for table and partitions p0 and pn
894 Must be correct both on CREATE and ALTER commands
895 table p0 pn res (0 - OK, 1 - FAIL)
896 - - - 0
897 - - x 1
898 - x - 1
899 - x x 0
900 x - - 0
901 x - x 0
902 x x - 0
903 x x x 0
904 i.e:
905 - All subpartitions must use the same engine
906 AND it must be the same as the partition.
907 - All partitions must use the same engine
908 AND it must be the same as the table.
909 - if one does NOT specify an engine on the table level
910 then one must either NOT specify any engine on any
911 partition/subpartition OR for ALL partitions/subpartitions
912 Note:
913 When ALTER a table, the engines are already set for all levels
914 (table, all partitions and subpartitions). So if one want to
915 change the storage engine, one must specify it on the table level
916
917 */
918
check_engine_condition(partition_element * p_elem,bool table_engine_set,handlerton ** engine_type,bool * first)919 static bool check_engine_condition(partition_element *p_elem,
920 bool table_engine_set,
921 handlerton **engine_type,
922 bool *first)
923 {
924 DBUG_ENTER("check_engine_condition");
925
926 DBUG_PRINT("enter", ("p_eng %s t_eng %s t_eng_set %u first %u state %u",
927 ha_resolve_storage_engine_name(p_elem->engine_type),
928 ha_resolve_storage_engine_name(*engine_type),
929 table_engine_set, *first, p_elem->part_state));
930 if (*first && !table_engine_set)
931 {
932 *engine_type= p_elem->engine_type;
933 DBUG_PRINT("info", ("setting table_engine = %s",
934 ha_resolve_storage_engine_name(*engine_type)));
935 }
936 *first= FALSE;
937 if ((table_engine_set &&
938 (p_elem->engine_type != (*engine_type) &&
939 p_elem->engine_type)) ||
940 (!table_engine_set &&
941 p_elem->engine_type != (*engine_type)))
942 {
943 DBUG_RETURN(TRUE);
944 }
945
946 DBUG_RETURN(FALSE);
947 }
948
949
950 /*
951 Check engine mix that it is correct
952 Current limitation is that all partitions and subpartitions
953 must use the same storage engine.
954 SYNOPSIS
955 check_engine_mix()
956 inout::engine_type Current engine used
957 table_engine_set Have user specified engine on table level
958 RETURN VALUE
959 TRUE Error, mixed engines
960 FALSE Ok, no mixed engines
961 DESCRIPTION
962 Current check verifies only that all handlers are the same.
963 Later this check will be more sophisticated.
964 (specified partition handler ) specified table handler
965 (MYISAM, MYISAM) - OK
966 (MYISAM, -) - NOT OK
967 (MYISAM, -) MYISAM OK
968 (- , MYISAM) - NOT OK
969 (- , -) MYISAM OK
970 (-,-) - OK
971 */
972
check_engine_mix(handlerton * engine_type,bool table_engine_set)973 bool partition_info::check_engine_mix(handlerton *engine_type,
974 bool table_engine_set)
975 {
976 handlerton *old_engine_type= engine_type;
977 bool first= TRUE;
978 uint n_parts= partitions.elements;
979 DBUG_ENTER("partition_info::check_engine_mix");
980 DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u",
981 ha_resolve_storage_engine_name(engine_type),
982 table_engine_set));
983 if (n_parts)
984 {
985 List_iterator<partition_element> part_it(partitions);
986 uint i= 0;
987 do
988 {
989 partition_element *part_elem= part_it++;
990 DBUG_PRINT("info", ("part = %d engine = %s table_engine_set %u",
991 i, ha_resolve_storage_engine_name(part_elem->engine_type),
992 table_engine_set));
993 if (is_sub_partitioned() &&
994 part_elem->subpartitions.elements)
995 {
996 uint n_subparts= part_elem->subpartitions.elements;
997 uint j= 0;
998 List_iterator<partition_element> sub_it(part_elem->subpartitions);
999 do
1000 {
1001 partition_element *sub_elem= sub_it++;
1002 DBUG_PRINT("info", ("sub = %d engine = %s table_engie_set %u",
1003 j, ha_resolve_storage_engine_name(sub_elem->engine_type),
1004 table_engine_set));
1005 if (check_engine_condition(sub_elem, table_engine_set,
1006 &engine_type, &first))
1007 goto error;
1008 } while (++j < n_subparts);
1009 /* ensure that the partition also has correct engine */
1010 if (check_engine_condition(part_elem, table_engine_set,
1011 &engine_type, &first))
1012 goto error;
1013 }
1014 else if (check_engine_condition(part_elem, table_engine_set,
1015 &engine_type, &first))
1016 goto error;
1017 } while (++i < n_parts);
1018 }
1019 DBUG_PRINT("info", ("engine_type = %s",
1020 ha_resolve_storage_engine_name(engine_type)));
1021 if (!engine_type)
1022 engine_type= old_engine_type;
1023 if (engine_type->flags & HTON_NO_PARTITION)
1024 {
1025 my_error(ER_PARTITION_MERGE_ERROR, MYF(0));
1026 DBUG_RETURN(TRUE);
1027 }
1028 DBUG_PRINT("info", ("out: engine_type = %s",
1029 ha_resolve_storage_engine_name(engine_type)));
1030 DBUG_ASSERT(engine_type != partition_hton);
1031 DBUG_RETURN(FALSE);
1032 error:
1033 /*
1034 Mixed engines not yet supported but when supported it will need
1035 the partition handler
1036 */
1037 DBUG_RETURN(TRUE);
1038 }
1039
1040
1041 /**
1042 Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL.
1043
1044 @param thd THD also containing sql_mode (looks from MODE_NO_DIR_IN_CREATE).
1045 @param part_elem partition_element to check.
1046 */
warn_if_dir_in_part_elem(THD * thd,partition_element * part_elem)1047 static void warn_if_dir_in_part_elem(THD *thd, partition_element *part_elem)
1048 {
1049 if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
1050 {
1051 if (part_elem->data_file_name)
1052 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1053 WARN_OPTION_IGNORED,
1054 ER_THD(thd, WARN_OPTION_IGNORED),
1055 "DATA DIRECTORY");
1056 if (part_elem->index_file_name)
1057 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1058 WARN_OPTION_IGNORED,
1059 ER_THD(thd, WARN_OPTION_IGNORED),
1060 "INDEX DIRECTORY");
1061 part_elem->data_file_name= part_elem->index_file_name= NULL;
1062 }
1063 }
1064
1065
1066 /*
1067 This code is used early in the CREATE TABLE and ALTER TABLE process.
1068
1069 SYNOPSIS
1070 check_partition_info()
1071 thd Thread object
1072 eng_type Return value for used engine in partitions
1073 file A reference to a handler of the table
1074 info Create info
1075 add_or_reorg_part Is it ALTER TABLE ADD/REORGANIZE command
1076
1077 RETURN VALUE
1078 TRUE Error, something went wrong
1079 FALSE Ok, full partition data structures are now generated
1080
1081 DESCRIPTION
1082 We will check that the partition info requested is possible to set-up in
1083 this version. This routine is an extension of the parser one could say.
1084 If defaults were used we will generate default data structures for all
1085 partitions.
1086
1087 */
1088
check_partition_info(THD * thd,handlerton ** eng_type,handler * file,HA_CREATE_INFO * info,partition_info * add_or_reorg_part)1089 bool partition_info::check_partition_info(THD *thd, handlerton **eng_type,
1090 handler *file, HA_CREATE_INFO *info,
1091 partition_info *add_or_reorg_part)
1092 {
1093 handlerton *table_engine= default_engine_type;
1094 uint i, tot_partitions;
1095 bool result= TRUE, table_engine_set;
1096 const char *same_name;
1097 uint32 hist_parts= 0;
1098 uint32 now_parts= 0;
1099 DBUG_ENTER("partition_info::check_partition_info");
1100 DBUG_ASSERT(default_engine_type != partition_hton);
1101
1102 DBUG_PRINT("info", ("default table_engine = %s",
1103 ha_resolve_storage_engine_name(table_engine)));
1104 if (!add_or_reorg_part)
1105 {
1106 int err= 0;
1107
1108 /* Check for partition expression. */
1109 if (!list_of_part_fields)
1110 {
1111 DBUG_ASSERT(part_expr);
1112 err= part_expr->walk(&Item::check_partition_func_processor, 0, NULL);
1113 }
1114
1115 /* Check for sub partition expression. */
1116 if (!err && is_sub_partitioned() && !list_of_subpart_fields)
1117 {
1118 DBUG_ASSERT(subpart_expr);
1119 err= subpart_expr->walk(&Item::check_partition_func_processor, 0,
1120 NULL);
1121 }
1122
1123 if (err)
1124 {
1125 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1126 goto end;
1127 }
1128 if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
1129 fix_parser_data(thd))
1130 goto end;
1131 }
1132 if (unlikely(!is_sub_partitioned() &&
1133 !(use_default_subpartitions && use_default_num_subpartitions)))
1134 {
1135 my_error(ER_SUBPARTITION_ERROR, MYF(0));
1136 goto end;
1137 }
1138 if (unlikely(is_sub_partitioned() &&
1139 (!(part_type == RANGE_PARTITION ||
1140 part_type == LIST_PARTITION ||
1141 part_type == VERSIONING_PARTITION))))
1142 {
1143 /* Only RANGE, LIST and SYSTEM_TIME partitioning can be subpartitioned */
1144 my_error(ER_SUBPARTITION_ERROR, MYF(0));
1145 goto end;
1146 }
1147 if (unlikely(set_up_defaults_for_partitioning(thd, file, info, (uint)0)))
1148 goto end;
1149 if (!(tot_partitions= get_tot_partitions()))
1150 {
1151 my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions");
1152 goto end;
1153 }
1154 if (unlikely(tot_partitions > MAX_PARTITIONS))
1155 {
1156 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
1157 goto end;
1158 }
1159 /*
1160 if NOT specified ENGINE = <engine>:
1161 If Create, always use create_info->db_type
1162 else, use previous tables db_type
1163 either ALL or NONE partition should be set to
1164 default_engine_type when not table_engine_set
1165 Note: after a table is created its storage engines for
1166 the table and all partitions/subpartitions are set.
1167 So when ALTER it is already set on table level
1168 */
1169 if (info && info->used_fields & HA_CREATE_USED_ENGINE)
1170 {
1171 table_engine_set= TRUE;
1172 table_engine= info->db_type;
1173 /* if partition_hton, use thd->lex->create_info */
1174 if (table_engine == partition_hton)
1175 table_engine= thd->lex->create_info.db_type;
1176 DBUG_ASSERT(table_engine != partition_hton);
1177 DBUG_PRINT("info", ("Using table_engine = %s",
1178 ha_resolve_storage_engine_name(table_engine)));
1179 }
1180 else
1181 {
1182 table_engine_set= FALSE;
1183 if (thd->lex->sql_command != SQLCOM_CREATE_TABLE)
1184 {
1185 table_engine_set= TRUE;
1186 DBUG_PRINT("info", ("No create, table_engine = %s",
1187 ha_resolve_storage_engine_name(table_engine)));
1188 DBUG_ASSERT(table_engine && table_engine != partition_hton);
1189 }
1190 }
1191
1192 if (part_field_list.elements > 0 &&
1193 (same_name= find_duplicate_field()))
1194 {
1195 my_error(ER_SAME_NAME_PARTITION_FIELD, MYF(0), same_name);
1196 goto end;
1197 }
1198 if ((same_name= find_duplicate_name()))
1199 {
1200 my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
1201 goto end;
1202 }
1203
1204 if (part_type == VERSIONING_PARTITION)
1205 {
1206 DBUG_ASSERT(vers_info);
1207 if (num_parts < 2 || !(use_default_partitions || vers_info->now_part))
1208 {
1209 DBUG_ASSERT(info);
1210 DBUG_ASSERT(info->alias.str);
1211 my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias.str);
1212 goto end;
1213 }
1214 DBUG_ASSERT(num_parts == partitions.elements);
1215 }
1216 i= 0;
1217 {
1218 List_iterator<partition_element> part_it(partitions);
1219 uint num_parts_not_set= 0;
1220 uint prev_num_subparts_not_set= num_subparts + 1;
1221 do
1222 {
1223 partition_element *part_elem= part_it++;
1224 warn_if_dir_in_part_elem(thd, part_elem);
1225 if (!is_sub_partitioned())
1226 {
1227 if (part_elem->engine_type == NULL)
1228 {
1229 num_parts_not_set++;
1230 part_elem->engine_type= default_engine_type;
1231 }
1232 if (check_table_name(part_elem->partition_name,
1233 strlen(part_elem->partition_name), FALSE))
1234 {
1235 my_error(ER_WRONG_PARTITION_NAME, MYF(0));
1236 goto end;
1237 }
1238 DBUG_PRINT("info", ("part = %d engine = %s",
1239 i, ha_resolve_storage_engine_name(part_elem->engine_type)));
1240 }
1241 else
1242 {
1243 uint j= 0;
1244 uint num_subparts_not_set= 0;
1245 List_iterator<partition_element> sub_it(part_elem->subpartitions);
1246 partition_element *sub_elem;
1247 do
1248 {
1249 sub_elem= sub_it++;
1250 warn_if_dir_in_part_elem(thd, sub_elem);
1251 if (check_table_name(sub_elem->partition_name,
1252 strlen(sub_elem->partition_name), FALSE))
1253 {
1254 my_error(ER_WRONG_PARTITION_NAME, MYF(0));
1255 goto end;
1256 }
1257 if (sub_elem->engine_type == NULL)
1258 {
1259 if (part_elem->engine_type != NULL)
1260 sub_elem->engine_type= part_elem->engine_type;
1261 else
1262 {
1263 sub_elem->engine_type= default_engine_type;
1264 num_subparts_not_set++;
1265 }
1266 }
1267 DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j,
1268 ha_resolve_storage_engine_name(sub_elem->engine_type)));
1269 } while (++j < num_subparts);
1270
1271 if (prev_num_subparts_not_set == (num_subparts + 1) &&
1272 (num_subparts_not_set == 0 ||
1273 num_subparts_not_set == num_subparts))
1274 prev_num_subparts_not_set= num_subparts_not_set;
1275
1276 if (!table_engine_set &&
1277 prev_num_subparts_not_set != num_subparts_not_set)
1278 {
1279 DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u",
1280 num_subparts_not_set, num_subparts));
1281 my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1282 goto end;
1283 }
1284
1285 if (part_elem->engine_type == NULL)
1286 {
1287 if (num_subparts_not_set == 0)
1288 part_elem->engine_type= sub_elem->engine_type;
1289 else
1290 {
1291 num_parts_not_set++;
1292 part_elem->engine_type= default_engine_type;
1293 }
1294 }
1295 }
1296 if (part_type == VERSIONING_PARTITION)
1297 {
1298 if (part_elem->type == partition_element::HISTORY)
1299 {
1300 hist_parts++;
1301 }
1302 else
1303 {
1304 DBUG_ASSERT(part_elem->type == partition_element::CURRENT);
1305 now_parts++;
1306 }
1307 }
1308 } while (++i < num_parts);
1309 if (!table_engine_set &&
1310 num_parts_not_set != 0 &&
1311 num_parts_not_set != num_parts)
1312 {
1313 DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u",
1314 num_parts_not_set, num_subparts));
1315 my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1316 goto end;
1317 }
1318 }
1319 if (unlikely(check_engine_mix(table_engine, table_engine_set)))
1320 {
1321 my_error(ER_MIX_HANDLER_ERROR, MYF(0));
1322 goto end;
1323 }
1324
1325 if (hist_parts > 1)
1326 {
1327 if (vers_info->limit == 0 && !vers_info->interval.is_set())
1328 {
1329 push_warning_printf(thd,
1330 Sql_condition::WARN_LEVEL_WARN,
1331 WARN_VERS_PARAMETERS,
1332 ER_THD(thd, WARN_VERS_PARAMETERS),
1333 "no rotation condition for multiple HISTORY partitions.");
1334 }
1335 }
1336 if (unlikely(now_parts > 1))
1337 {
1338 my_error(ER_VERS_WRONG_PARTS, MYF(0), info->alias.str);
1339 goto end;
1340 }
1341
1342
1343 DBUG_ASSERT(table_engine != partition_hton &&
1344 default_engine_type == table_engine);
1345 if (eng_type)
1346 *eng_type= table_engine;
1347
1348
1349 /*
1350 We need to check all constant expressions that they are of the correct
1351 type and that they are increasing for ranges and not overlapping for
1352 list constants.
1353 */
1354
1355 if (add_or_reorg_part)
1356 {
1357 if (part_type == VERSIONING_PARTITION && add_or_reorg_part->partitions.elements)
1358 vers_update_el_ids();
1359 if (check_constants(thd, this))
1360 goto end;
1361 }
1362
1363 result= FALSE;
1364 end:
1365 DBUG_RETURN(result);
1366 }
1367
1368
1369 /*
1370 Print error for no partition found
1371
1372 SYNOPSIS
1373 print_no_partition_found()
1374 table Table object
1375
1376 RETURN VALUES
1377 */
1378
print_no_partition_found(TABLE * table_arg,myf errflag)1379 void partition_info::print_no_partition_found(TABLE *table_arg, myf errflag)
1380 {
1381 char buf[100];
1382 char *buf_ptr= (char*)&buf;
1383 TABLE_LIST table_list;
1384 THD *thd= current_thd;
1385
1386 table_list.reset();
1387 table_list.db= table_arg->s->db;
1388 table_list.table_name= table_arg->s->table_name;
1389
1390 if (check_single_table_access(thd, SELECT_ACL, &table_list, TRUE))
1391 {
1392 my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
1393 ER_THD(thd, ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), errflag);
1394 }
1395 else
1396 {
1397 if (column_list)
1398 buf_ptr= (char*)"from column_list";
1399 else
1400 {
1401 MY_BITMAP *old_map= dbug_tmp_use_all_columns(table_arg, &table_arg->read_set);
1402 if (part_expr->null_value)
1403 buf_ptr= (char*)"NULL";
1404 else
1405 longlong10_to_str(err_value, buf,
1406 part_expr->unsigned_flag ? 10 : -10);
1407 dbug_tmp_restore_column_map(&table_arg->read_set, old_map);
1408 }
1409 my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, errflag, buf_ptr);
1410 }
1411 }
1412
1413
1414 /*
1415 Set fields related to partition expression
1416 SYNOPSIS
1417 set_part_expr()
1418 start_token Start of partition function string
1419 item_ptr Pointer to item tree
1420 end_token End of partition function string
1421 is_subpart Subpartition indicator
1422 RETURN VALUES
1423 TRUE Memory allocation error
1424 FALSE Success
1425 */
1426
set_part_expr(THD * thd,Item * item_ptr,bool is_subpart)1427 bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
1428 {
1429 if (is_subpart)
1430 {
1431 list_of_subpart_fields= FALSE;
1432 subpart_expr= item_ptr;
1433 }
1434 else
1435 {
1436 list_of_part_fields= FALSE;
1437 part_expr= item_ptr;
1438 }
1439 return FALSE;
1440 }
1441
1442
1443 /*
1444 Check that partition fields and subpartition fields are not too long
1445
1446 SYNOPSIS
1447 check_partition_field_length()
1448
1449 RETURN VALUES
1450 TRUE Total length was too big
1451 FALSE Length is ok
1452 */
1453
check_partition_field_length()1454 bool partition_info::check_partition_field_length()
1455 {
1456 uint store_length= 0;
1457 uint i;
1458 DBUG_ENTER("partition_info::check_partition_field_length");
1459
1460 for (i= 0; i < num_part_fields; i++)
1461 store_length+= get_partition_field_store_length(part_field_array[i]);
1462 if (store_length > MAX_DATA_LENGTH_FOR_KEY)
1463 DBUG_RETURN(TRUE);
1464 store_length= 0;
1465 for (i= 0; i < num_subpart_fields; i++)
1466 store_length+= get_partition_field_store_length(subpart_field_array[i]);
1467 if (store_length > MAX_DATA_LENGTH_FOR_KEY)
1468 DBUG_RETURN(TRUE);
1469 DBUG_RETURN(FALSE);
1470 }
1471
1472
1473 /*
1474 Set up buffers and arrays for fields requiring preparation
1475 SYNOPSIS
1476 set_up_charset_field_preps()
1477
1478 RETURN VALUES
1479 TRUE Memory Allocation error
1480 FALSE Success
1481
1482 DESCRIPTION
1483 Set up arrays and buffers for fields that require special care for
1484 calculation of partition id. This is used for string fields with
1485 variable length or string fields with fixed length that isn't using
1486 the binary collation.
1487 */
1488
set_up_charset_field_preps(THD * thd)1489 bool partition_info::set_up_charset_field_preps(THD *thd)
1490 {
1491 Field *field, **ptr;
1492 uchar **char_ptrs;
1493 unsigned i;
1494 size_t size;
1495 uint tot_fields= 0;
1496 uint tot_part_fields= 0;
1497 uint tot_subpart_fields= 0;
1498 DBUG_ENTER("set_up_charset_field_preps");
1499
1500 if (!(part_type == HASH_PARTITION &&
1501 list_of_part_fields) &&
1502 check_part_func_fields(part_field_array, FALSE))
1503 {
1504 ptr= part_field_array;
1505 /* Set up arrays and buffers for those fields */
1506 while ((field= *(ptr++)))
1507 {
1508 if (field_is_partition_charset(field))
1509 {
1510 tot_part_fields++;
1511 tot_fields++;
1512 }
1513 }
1514 size= tot_part_fields * sizeof(char*);
1515 if (!(char_ptrs= (uchar**)thd->calloc(size)))
1516 goto error;
1517 part_field_buffers= char_ptrs;
1518 if (!(char_ptrs= (uchar**)thd->calloc(size)))
1519 goto error;
1520 restore_part_field_ptrs= char_ptrs;
1521 size= (tot_part_fields + 1) * sizeof(Field*);
1522 if (!(char_ptrs= (uchar**)thd->alloc(size)))
1523 goto error;
1524 part_charset_field_array= (Field**)char_ptrs;
1525 ptr= part_field_array;
1526 i= 0;
1527 while ((field= *(ptr++)))
1528 {
1529 if (field_is_partition_charset(field))
1530 {
1531 uchar *field_buf;
1532 size= field->pack_length();
1533 if (!(field_buf= (uchar*) thd->calloc(size)))
1534 goto error;
1535 part_charset_field_array[i]= field;
1536 part_field_buffers[i++]= field_buf;
1537 }
1538 }
1539 part_charset_field_array[i]= NULL;
1540 }
1541 if (is_sub_partitioned() && !list_of_subpart_fields &&
1542 check_part_func_fields(subpart_field_array, FALSE))
1543 {
1544 /* Set up arrays and buffers for those fields */
1545 ptr= subpart_field_array;
1546 while ((field= *(ptr++)))
1547 {
1548 if (field_is_partition_charset(field))
1549 {
1550 tot_subpart_fields++;
1551 tot_fields++;
1552 }
1553 }
1554 size= tot_subpart_fields * sizeof(char*);
1555 if (!(char_ptrs= (uchar**) thd->calloc(size)))
1556 goto error;
1557 subpart_field_buffers= char_ptrs;
1558 if (!(char_ptrs= (uchar**) thd->calloc(size)))
1559 goto error;
1560 restore_subpart_field_ptrs= char_ptrs;
1561 size= (tot_subpart_fields + 1) * sizeof(Field*);
1562 if (!(char_ptrs= (uchar**) thd->alloc(size)))
1563 goto error;
1564 subpart_charset_field_array= (Field**)char_ptrs;
1565 ptr= subpart_field_array;
1566 i= 0;
1567 while ((field= *(ptr++)))
1568 {
1569 uchar *UNINIT_VAR(field_buf);
1570
1571 if (!field_is_partition_charset(field))
1572 continue;
1573 size= field->pack_length();
1574 if (!(field_buf= (uchar*) thd->calloc(size)))
1575 goto error;
1576 subpart_charset_field_array[i]= field;
1577 subpart_field_buffers[i++]= field_buf;
1578 }
1579 subpart_charset_field_array[i]= NULL;
1580 }
1581 DBUG_RETURN(FALSE);
1582 error:
1583 DBUG_RETURN(TRUE);
1584 }
1585
1586
1587 /*
1588 Check if path does not contain mysql data home directory
1589 for partition elements with data directory and index directory
1590
1591 SYNOPSIS
1592 check_partition_dirs()
1593 part_info partition_info struct
1594
1595 RETURN VALUES
1596 0 ok
1597 1 error
1598 */
1599
check_partition_dirs(partition_info * part_info)1600 bool check_partition_dirs(partition_info *part_info)
1601 {
1602 if (!part_info)
1603 return 0;
1604
1605 partition_element *part_elem;
1606 List_iterator<partition_element> part_it(part_info->partitions);
1607 while ((part_elem= part_it++))
1608 {
1609 if (part_elem->subpartitions.elements)
1610 {
1611 List_iterator<partition_element> sub_it(part_elem->subpartitions);
1612 partition_element *subpart_elem;
1613 while ((subpart_elem= sub_it++))
1614 {
1615 if (unlikely(error_if_data_home_dir(subpart_elem->data_file_name,
1616 "DATA DIRECTORY")) ||
1617 unlikely(error_if_data_home_dir(subpart_elem->index_file_name,
1618 "INDEX DIRECTORY")))
1619 return 1;
1620 }
1621 }
1622 else
1623 {
1624 if (unlikely(error_if_data_home_dir(part_elem->data_file_name,
1625 "DATA DIRECTORY")) ||
1626 unlikely(error_if_data_home_dir(part_elem->index_file_name,
1627 "INDEX DIRECTORY")))
1628 return 1;
1629 }
1630 }
1631 return 0;
1632 }
1633
1634
1635 /**
1636 Check what kind of error to report
1637
1638 @param use_subpart_expr Use the subpart_expr instead of part_expr
1639 @param part_str Name of partition to report error (or NULL)
1640 */
report_part_expr_error(bool use_subpart_expr)1641 void partition_info::report_part_expr_error(bool use_subpart_expr)
1642 {
1643 Item *expr= part_expr;
1644 DBUG_ENTER("partition_info::report_part_expr_error");
1645 if (use_subpart_expr)
1646 expr= subpart_expr;
1647
1648 if (expr->type() == Item::FIELD_ITEM)
1649 {
1650 partition_type type= part_type;
1651 bool list_of_fields= list_of_part_fields;
1652 Item_field *item_field= (Item_field*) expr;
1653 /*
1654 The expression consists of a single field.
1655 It must be of integer type unless KEY or COLUMNS partitioning.
1656 */
1657 if (use_subpart_expr)
1658 {
1659 type= subpart_type;
1660 list_of_fields= list_of_subpart_fields;
1661 }
1662 if (!column_list &&
1663 item_field->field &&
1664 item_field->field->result_type() != INT_RESULT &&
1665 !(type == HASH_PARTITION && list_of_fields))
1666 {
1667 my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
1668 item_field->name.str);
1669 DBUG_VOID_RETURN;
1670 }
1671 }
1672 if (use_subpart_expr)
1673 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "SUBPARTITION");
1674 else
1675 my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), "PARTITION");
1676 DBUG_VOID_RETURN;
1677 }
1678
1679
1680 /*
1681 Create a new column value in current list with maxvalue
1682 Called from parser
1683
1684 SYNOPSIS
1685 add_max_value()
1686 RETURN
1687 TRUE Error
1688 FALSE Success
1689 */
1690
add_max_value(THD * thd)1691 int partition_info::add_max_value(THD *thd)
1692 {
1693 DBUG_ENTER("partition_info::add_max_value");
1694
1695 part_column_list_val *col_val;
1696 /*
1697 Makes for LIST COLUMNS 'num_columns' DEFAULT tuples, 1 tuple for RANGEs
1698 */
1699 uint max_val= (num_columns && part_type == LIST_PARTITION) ?
1700 num_columns : 1;
1701 for (uint i= 0; i < max_val; i++)
1702 {
1703 if (!(col_val= add_column_value(thd)))
1704 {
1705 DBUG_RETURN(TRUE);
1706 }
1707 col_val->max_value= TRUE;
1708 }
1709 DBUG_RETURN(FALSE);
1710 }
1711
1712 /*
1713 Create a new column value in current list
1714 Called from parser
1715
1716 SYNOPSIS
1717 add_column_value()
1718 RETURN
1719 >0 A part_column_list_val object which have been
1720 inserted into its list
1721 0 Memory allocation failure
1722 */
1723
add_column_value(THD * thd)1724 part_column_list_val *partition_info::add_column_value(THD *thd)
1725 {
1726 uint max_val= num_columns ? num_columns : MAX_REF_PARTS;
1727 DBUG_ENTER("add_column_value");
1728 DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u",
1729 num_columns, curr_list_object, max_val));
1730 if (curr_list_object < max_val)
1731 {
1732 curr_list_val->added_items++;
1733 DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]);
1734 }
1735 if (!num_columns && part_type == LIST_PARTITION)
1736 {
1737 /*
1738 We're trying to add more than MAX_REF_PARTS, this can happen
1739 in ALTER TABLE using List partitions where the first partition
1740 uses VALUES IN (1,2,3...,17) where the number of fields in
1741 the list is more than MAX_REF_PARTS, in this case we know
1742 that the number of columns must be 1 and we thus reorganize
1743 into the structure used for 1 column. After this we call
1744 ourselves recursively which should always succeed.
1745 */
1746 num_columns= curr_list_object;
1747 if (!reorganize_into_single_field_col_val(thd))
1748 {
1749 if (!init_column_part(thd))
1750 DBUG_RETURN(add_column_value(thd));
1751 }
1752 DBUG_RETURN(NULL);
1753 }
1754 if (column_list)
1755 {
1756 my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
1757 }
1758 else
1759 {
1760 if (part_type == RANGE_PARTITION)
1761 my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "RANGE");
1762 else
1763 my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "LIST");
1764 }
1765 DBUG_RETURN(NULL);
1766 }
1767
1768
1769 /*
1770 Initialise part_elem_value object at setting of a new object
1771 (Helper functions to functions called by parser)
1772
1773 SYNOPSIS
1774 init_col_val
1775 col_val Column value object to be initialised
1776 item Item object representing column value
1777
1778 RETURN VALUES
1779 TRUE Failure
1780 FALSE Success
1781 */
init_col_val(part_column_list_val * col_val,Item * item)1782 void partition_info::init_col_val(part_column_list_val *col_val, Item *item)
1783 {
1784 DBUG_ENTER("partition_info::init_col_val");
1785
1786 col_val->item_expression= item;
1787 col_val->null_value= item->null_value;
1788 if (item->result_type() == INT_RESULT)
1789 {
1790 /*
1791 This could be both column_list partitioning and function
1792 partitioning, but it doesn't hurt to set the function
1793 partitioning flags about unsignedness.
1794 */
1795 curr_list_val->value= item->val_int();
1796 curr_list_val->unsigned_flag= TRUE;
1797 if (!item->unsigned_flag &&
1798 curr_list_val->value < 0)
1799 curr_list_val->unsigned_flag= FALSE;
1800 if (!curr_list_val->unsigned_flag)
1801 curr_part_elem->signed_flag= TRUE;
1802 }
1803 col_val->part_info= NULL;
1804 DBUG_VOID_RETURN;
1805 }
1806 /*
1807 Add a column value in VALUES LESS THAN or VALUES IN
1808 (Called from parser)
1809
1810 SYNOPSIS
1811 add_column_list_value()
1812 lex Parser's lex object
1813 thd Thread object
1814 item Item object representing column value
1815
1816 RETURN VALUES
1817 TRUE Failure
1818 FALSE Success
1819 */
add_column_list_value(THD * thd,Item * item)1820 bool partition_info::add_column_list_value(THD *thd, Item *item)
1821 {
1822 part_column_list_val *col_val;
1823 Name_resolution_context *context= &thd->lex->current_select->context;
1824 TABLE_LIST *save_list= context->table_list;
1825 const char *save_where= thd->where;
1826 DBUG_ENTER("partition_info::add_column_list_value");
1827
1828 if (part_type == LIST_PARTITION &&
1829 num_columns == 1U)
1830 {
1831 if (init_column_part(thd))
1832 {
1833 DBUG_RETURN(TRUE);
1834 }
1835 }
1836
1837 context->table_list= 0;
1838 if (column_list)
1839 thd->where= "field list";
1840 else
1841 thd->where= "partition function";
1842
1843 if (item->walk(&Item::check_partition_func_processor, 0, NULL))
1844 {
1845 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1846 DBUG_RETURN(TRUE);
1847 }
1848 if (item->fix_fields(thd, (Item**)0) ||
1849 ((context->table_list= save_list), FALSE) ||
1850 (!item->const_item()))
1851 {
1852 context->table_list= save_list;
1853 thd->where= save_where;
1854 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1855 DBUG_RETURN(TRUE);
1856 }
1857 thd->where= save_where;
1858
1859 if (!(col_val= add_column_value(thd)))
1860 {
1861 DBUG_RETURN(TRUE);
1862 }
1863 init_col_val(col_val, item);
1864 DBUG_RETURN(FALSE);
1865 }
1866
1867 /*
1868 Initialise part_info object for receiving a set of column values
1869 for a partition, called when parser reaches VALUES LESS THAN or
1870 VALUES IN.
1871
1872 SYNOPSIS
1873 init_column_part()
1874 lex Parser's lex object
1875
1876 RETURN VALUES
1877 TRUE Failure
1878 FALSE Success
1879 */
init_column_part(THD * thd)1880 bool partition_info::init_column_part(THD *thd)
1881 {
1882 partition_element *p_elem= curr_part_elem;
1883 part_column_list_val *col_val_array;
1884 part_elem_value *list_val;
1885 uint loc_num_columns;
1886 DBUG_ENTER("partition_info::init_column_part");
1887
1888 if (!(list_val=
1889 (part_elem_value*) thd->calloc(sizeof(part_elem_value))) ||
1890 p_elem->list_val_list.push_back(list_val, thd->mem_root))
1891 DBUG_RETURN(TRUE);
1892
1893 if (num_columns)
1894 loc_num_columns= num_columns;
1895 else
1896 loc_num_columns= MAX_REF_PARTS;
1897 if (!(col_val_array=
1898 (part_column_list_val*) thd->calloc(loc_num_columns *
1899 sizeof(part_column_list_val))))
1900 DBUG_RETURN(TRUE);
1901
1902 list_val->col_val_array= col_val_array;
1903 list_val->added_items= 0;
1904 curr_list_val= list_val;
1905 curr_list_object= 0;
1906 DBUG_RETURN(FALSE);
1907 }
1908
1909 /*
1910 In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST
1911 partitions we can specify list values as:
1912 VALUES IN (v1, v2,,,, v17) if we're using the first partitioning
1913 variant with a function or a column list partitioned table with
1914 one partition field. In this case the parser knows not the
1915 number of columns start with and allocates MAX_REF_PARTS in the
1916 array. If we try to allocate something beyond MAX_REF_PARTS we
1917 will call this function to reorganize into a structure with
1918 num_columns = 1. Also when the parser knows that we used LIST
1919 partitioning and we used a VALUES IN like above where number of
1920 values was smaller than MAX_REF_PARTS or equal, then we will
1921 reorganize after discovering this in the parser.
1922
1923 SYNOPSIS
1924 reorganize_into_single_field_col_val()
1925
1926 RETURN VALUES
1927 TRUE Failure
1928 FALSE Success
1929 */
1930
reorganize_into_single_field_col_val(THD * thd)1931 int partition_info::reorganize_into_single_field_col_val(THD *thd)
1932 {
1933 part_column_list_val *col_val, *new_col_val;
1934 part_elem_value *val= curr_list_val;
1935 uint loc_num_columns= num_columns;
1936 uint i;
1937 DBUG_ENTER("partition_info::reorganize_into_single_field_col_val");
1938
1939 num_columns= 1;
1940 val->added_items= 1U;
1941 col_val= &val->col_val_array[0];
1942 init_col_val(col_val, col_val->item_expression);
1943 for (i= 1; i < loc_num_columns; i++)
1944 {
1945 col_val= &val->col_val_array[i];
1946 DBUG_ASSERT(part_type == LIST_PARTITION);
1947 if (init_column_part(thd))
1948 {
1949 DBUG_RETURN(TRUE);
1950 }
1951 if (!(new_col_val= add_column_value(thd)))
1952 {
1953 DBUG_RETURN(TRUE);
1954 }
1955 memcpy(new_col_val, col_val, sizeof(*col_val));
1956 init_col_val(new_col_val, col_val->item_expression);
1957 }
1958 curr_list_val= val;
1959 DBUG_RETURN(FALSE);
1960 }
1961
1962 /*
1963 This function handles the case of function-based partitioning.
1964 It fixes some data structures created in the parser and puts
1965 them in the format required by the rest of the partitioning
1966 code.
1967
1968 SYNOPSIS
1969 fix_partition_values()
1970 thd Thread object
1971 col_val Array of one value
1972 part_elem The partition instance
1973 part_id Id of partition instance
1974
1975 RETURN VALUES
1976 TRUE Failure
1977 FALSE Success
1978 */
fix_partition_values(THD * thd,part_elem_value * val,partition_element * part_elem)1979 int partition_info::fix_partition_values(THD *thd,
1980 part_elem_value *val,
1981 partition_element *part_elem)
1982 {
1983 part_column_list_val *col_val= val->col_val_array;
1984 DBUG_ENTER("partition_info::fix_partition_values");
1985
1986 if (col_val->fixed)
1987 {
1988 DBUG_RETURN(FALSE);
1989 }
1990
1991 Item *item_expr= col_val->item_expression;
1992 if ((val->null_value= item_expr->null_value))
1993 {
1994 if (part_elem->has_null_value)
1995 {
1996 my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
1997 DBUG_RETURN(TRUE);
1998 }
1999 part_elem->has_null_value= TRUE;
2000 }
2001 else if (item_expr->result_type() != INT_RESULT)
2002 {
2003 my_error(ER_VALUES_IS_NOT_INT_TYPE_ERROR, MYF(0),
2004 part_elem->partition_name);
2005 DBUG_RETURN(TRUE);
2006 }
2007 if (part_type == RANGE_PARTITION)
2008 {
2009 if (part_elem->has_null_value)
2010 {
2011 my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
2012 DBUG_RETURN(TRUE);
2013 }
2014 part_elem->range_value= val->value;
2015 }
2016 col_val->fixed= 2;
2017 DBUG_RETURN(FALSE);
2018 }
2019
2020 /*
2021 Get column item with a proper character set according to the field
2022
2023 SYNOPSIS
2024 get_column_item()
2025 item Item object to start with
2026 field Field for which the item will be compared to
2027
2028 RETURN VALUES
2029 NULL Error
2030 item Returned item
2031 */
2032
get_column_item(Item * item,Field * field)2033 Item* partition_info::get_column_item(Item *item, Field *field)
2034 {
2035 if (field->result_type() == STRING_RESULT &&
2036 item->collation.collation != field->charset())
2037 {
2038 if (!(item= convert_charset_partition_constant(item,
2039 field->charset())))
2040 {
2041 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2042 return NULL;
2043 }
2044 }
2045 return item;
2046 }
2047
2048
2049 /*
2050 Evaluate VALUES functions for column list values
2051 SYNOPSIS
2052 fix_column_value_functions()
2053 thd Thread object
2054 col_val List of column values
2055 part_id Partition id we are fixing
2056
2057 RETURN VALUES
2058 TRUE Error
2059 FALSE Success
2060 DESCRIPTION
2061 Fix column VALUES and store in memory array adapted to the data type
2062 */
2063
fix_column_value_functions(THD * thd,part_elem_value * val,uint part_id)2064 bool partition_info::fix_column_value_functions(THD *thd,
2065 part_elem_value *val,
2066 uint part_id)
2067 {
2068 uint n_columns= part_field_list.elements;
2069 bool result= FALSE;
2070 uint i;
2071 part_column_list_val *col_val= val->col_val_array;
2072 DBUG_ENTER("partition_info::fix_column_value_functions");
2073
2074 if (col_val->fixed > 1)
2075 {
2076 DBUG_RETURN(FALSE);
2077 }
2078 for (i= 0; i < n_columns; col_val++, i++)
2079 {
2080 Item *column_item= col_val->item_expression;
2081 Field *field= part_field_array[i];
2082 col_val->part_info= this;
2083 col_val->partition_id= part_id;
2084 if (col_val->max_value)
2085 col_val->column_value= NULL;
2086 else
2087 {
2088 col_val->column_value= NULL;
2089 if (!col_val->null_value)
2090 {
2091 uchar *val_ptr;
2092 uint len= field->pack_length();
2093 bool save_got_warning;
2094
2095 if (!(column_item= get_column_item(column_item, field)))
2096 {
2097 result= TRUE;
2098 goto end;
2099 }
2100 Sql_mode_instant_set sms(thd, 0);
2101 save_got_warning= thd->got_warning;
2102 thd->got_warning= 0;
2103 if (column_item->save_in_field(field, TRUE) ||
2104 thd->got_warning)
2105 {
2106 my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
2107 result= TRUE;
2108 goto end;
2109 }
2110 thd->got_warning= save_got_warning;
2111 if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len)))
2112 {
2113 result= TRUE;
2114 goto end;
2115 }
2116 col_val->column_value= val_ptr;
2117 }
2118 }
2119 col_val->fixed= 2;
2120 }
2121 end:
2122 DBUG_RETURN(result);
2123 }
2124
2125
2126 /**
2127 Fix partition data from parser.
2128
2129 @details The parser generates generic data structures, we need to set them
2130 up as the rest of the code expects to find them. This is in reality part
2131 of the syntax check of the parser code.
2132
2133 It is necessary to call this function in the case of a CREATE TABLE
2134 statement, in this case we do it early in the check_partition_info
2135 function.
2136
2137 It is necessary to call this function for ALTER TABLE where we
2138 assign a completely new partition structure, in this case we do it
2139 in prep_alter_part_table after discovering that the partition
2140 structure is entirely redefined.
2141
2142 It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE
2143 of partitions, in this we call it in prep_alter_part_table after
2144 making some initial checks but before going deep to check the partition
2145 info, we also assign the column_list variable before calling this function
2146 here.
2147
2148 Finally we also call it immediately after returning from parsing the
2149 partitioning text found in the frm file.
2150
2151 This function mainly fixes the VALUES parts, these are handled differently
2152 whether or not we use column list partitioning. Since the parser doesn't
2153 know which we are using we need to set-up the old data structures after
2154 the parser is complete when we know if what type of partitioning the
2155 base table is using.
2156
2157 For column lists we will handle this in the fix_column_value_function.
2158 For column lists it is sufficient to verify that the number of columns
2159 and number of elements are in synch with each other. So only partitioning
2160 using functions need to be set-up to their data structures.
2161
2162 @param thd Thread object
2163
2164 @return Operation status
2165 @retval TRUE Failure
2166 @retval FALSE Success
2167 */
2168
fix_parser_data(THD * thd)2169 bool partition_info::fix_parser_data(THD *thd)
2170 {
2171 List_iterator<partition_element> it(partitions);
2172 partition_element *part_elem;
2173 uint num_elements;
2174 uint i= 0, j, k;
2175 DBUG_ENTER("partition_info::fix_parser_data");
2176
2177 if (!(part_type == RANGE_PARTITION ||
2178 part_type == LIST_PARTITION))
2179 {
2180 if (part_type == HASH_PARTITION && list_of_part_fields)
2181 {
2182 /* KEY partitioning, check ALGORITHM = N. Should not pass the parser! */
2183 if (key_algorithm > KEY_ALGORITHM_55)
2184 {
2185 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2186 DBUG_RETURN(true);
2187 }
2188 /* If not set, use DEFAULT = 2 for CREATE and ALTER! */
2189 if ((thd_sql_command(thd) == SQLCOM_CREATE_TABLE ||
2190 thd_sql_command(thd) == SQLCOM_ALTER_TABLE) &&
2191 key_algorithm == KEY_ALGORITHM_NONE)
2192 key_algorithm= KEY_ALGORITHM_55;
2193 }
2194 DBUG_RETURN(FALSE);
2195 }
2196 if (is_sub_partitioned() && list_of_subpart_fields)
2197 {
2198 /* KEY subpartitioning, check ALGORITHM = N. Should not pass the parser! */
2199 if (key_algorithm > KEY_ALGORITHM_55)
2200 {
2201 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2202 DBUG_RETURN(true);
2203 }
2204 /* If not set, use DEFAULT = 2 for CREATE and ALTER! */
2205 if ((thd_sql_command(thd) == SQLCOM_CREATE_TABLE ||
2206 thd_sql_command(thd) == SQLCOM_ALTER_TABLE) &&
2207 key_algorithm == KEY_ALGORITHM_NONE)
2208 key_algorithm= KEY_ALGORITHM_55;
2209 }
2210 defined_max_value= FALSE; // in case it already set (CREATE TABLE LIKE)
2211 do
2212 {
2213 part_elem= it++;
2214 List_iterator<part_elem_value> list_val_it(part_elem->list_val_list);
2215 num_elements= part_elem->list_val_list.elements;
2216 if (unlikely(!num_elements && error_if_requires_values()))
2217 DBUG_RETURN(true);
2218 DBUG_ASSERT(part_type == RANGE_PARTITION ?
2219 num_elements == 1U : TRUE);
2220
2221 for (j= 0; j < num_elements; j++)
2222 {
2223 part_elem_value *val= list_val_it++;
2224
2225 if (val->added_items != (column_list ? num_columns : 1))
2226 {
2227 my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
2228 DBUG_RETURN(TRUE);
2229 }
2230
2231 /*
2232 Check the last MAX_VALUE for range partitions and DEFAULT value
2233 for LIST partitions.
2234 Both values are marked with defined_max_value and
2235 default_partition_id.
2236
2237 This is a max_value/default is max_value is set and this is
2238 a normal RANGE (no column list) or if it's a LIST partition:
2239
2240 PARTITION p3 VALUES LESS THAN MAXVALUE
2241 or
2242 PARTITION p3 VALUES DEFAULT
2243 */
2244 if (val->added_items && val->col_val_array[0].max_value &&
2245 (!column_list || part_type == LIST_PARTITION))
2246 {
2247 DBUG_ASSERT(part_type == RANGE_PARTITION ||
2248 part_type == LIST_PARTITION);
2249 if (defined_max_value)
2250 {
2251 my_error((part_type == RANGE_PARTITION) ?
2252 ER_PARTITION_MAXVALUE_ERROR :
2253 ER_PARTITION_DEFAULT_ERROR, MYF(0));
2254 DBUG_RETURN(TRUE);
2255 }
2256
2257 /* For RANGE PARTITION MAX_VALUE must be last */
2258 if (i != (num_parts - 1) &&
2259 part_type != LIST_PARTITION)
2260 {
2261 my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
2262 DBUG_RETURN(TRUE);
2263 }
2264
2265 defined_max_value= TRUE;
2266 default_partition_id= i;
2267 part_elem->max_value= TRUE;
2268 part_elem->range_value= LONGLONG_MAX;
2269 continue;
2270 }
2271
2272 if (column_list)
2273 {
2274 for (k= 0; k < num_columns; k++)
2275 {
2276 part_column_list_val *col_val= &val->col_val_array[k];
2277 if (col_val->null_value && part_type == RANGE_PARTITION)
2278 {
2279 my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0));
2280 DBUG_RETURN(TRUE);
2281 }
2282 }
2283 }
2284 else
2285 {
2286 if (fix_partition_values(thd, val, part_elem))
2287 DBUG_RETURN(TRUE);
2288 if (val->null_value)
2289 {
2290 /*
2291 Null values aren't required in the value part, they are kept per
2292 partition instance, only LIST partitions have NULL values.
2293 */
2294 list_val_it.remove();
2295 }
2296 }
2297 }
2298 } while (++i < num_parts);
2299 DBUG_RETURN(FALSE);
2300 }
2301
2302
2303 /**
2304 helper function to compare strings that can also be
2305 a NULL pointer.
2306
2307 @param a char pointer (can be NULL).
2308 @param b char pointer (can be NULL).
2309
2310 @return false if equal
2311 @retval true strings differs
2312 @retval false strings is equal
2313 */
2314
strcmp_null(const char * a,const char * b)2315 static bool strcmp_null(const char *a, const char *b)
2316 {
2317 if (!a && !b)
2318 return false;
2319 if (a && b && !strcmp(a, b))
2320 return false;
2321 return true;
2322 }
2323
2324
2325 /**
2326 Check if the new part_info has the same partitioning.
2327
2328 @param new_part_info New partition definition to compare with.
2329
2330 @return True if not considered to have changed the partitioning.
2331 @retval true Allowed change (only .frm change, compatible distribution).
2332 @retval false Different partitioning, will need redistribution of rows.
2333
2334 @note Currently only used to allow changing from non-set key_algorithm
2335 to a specified key_algorithm, to avoid rebuild when upgrading from 5.1 of
2336 such partitioned tables using numeric colums in the partitioning expression.
2337 For more info see bug#14521864.
2338 Does not check if columns etc has changed, i.e. only for
2339 alter_info->partition_flags == ALTER_PARTITION_INFO.
2340 */
2341
has_same_partitioning(partition_info * new_part_info)2342 bool partition_info::has_same_partitioning(partition_info *new_part_info)
2343 {
2344 DBUG_ENTER("partition_info::has_same_partitioning");
2345
2346 DBUG_ASSERT(part_field_array && part_field_array[0]);
2347
2348 /*
2349 Only consider pre 5.5.3 .frm's to have same partitioning as
2350 a new one with KEY ALGORITHM = 1 ().
2351 */
2352
2353 if (part_field_array[0]->table->s->mysql_version >= 50503)
2354 DBUG_RETURN(false);
2355
2356 if (!new_part_info ||
2357 part_type != new_part_info->part_type ||
2358 num_parts != new_part_info->num_parts ||
2359 use_default_partitions != new_part_info->use_default_partitions ||
2360 new_part_info->is_sub_partitioned() != is_sub_partitioned())
2361 DBUG_RETURN(false);
2362
2363 if (part_type != HASH_PARTITION)
2364 {
2365 /*
2366 RANGE or LIST partitioning, check if KEY subpartitioned.
2367 Also COLUMNS partitioning was added in 5.5, so treat that as different.
2368 */
2369 if (!is_sub_partitioned() ||
2370 !new_part_info->is_sub_partitioned() ||
2371 column_list ||
2372 new_part_info->column_list ||
2373 !list_of_subpart_fields ||
2374 !new_part_info->list_of_subpart_fields ||
2375 new_part_info->num_subparts != num_subparts ||
2376 new_part_info->subpart_field_list.elements !=
2377 subpart_field_list.elements ||
2378 new_part_info->use_default_subpartitions !=
2379 use_default_subpartitions)
2380 DBUG_RETURN(false);
2381 }
2382 else
2383 {
2384 /* Check if KEY partitioned. */
2385 if (!new_part_info->list_of_part_fields ||
2386 !list_of_part_fields ||
2387 new_part_info->part_field_list.elements != part_field_list.elements)
2388 DBUG_RETURN(false);
2389 }
2390
2391 /* Check that it will use the same fields in KEY (fields) list. */
2392 List_iterator<const char> old_field_name_it(part_field_list);
2393 List_iterator<const char> new_field_name_it(new_part_info->part_field_list);
2394 const char *old_name, *new_name;
2395 while ((old_name= old_field_name_it++))
2396 {
2397 new_name= new_field_name_it++;
2398 if (!new_name || my_strcasecmp(system_charset_info,
2399 new_name,
2400 old_name))
2401 DBUG_RETURN(false);
2402 }
2403
2404 if (is_sub_partitioned())
2405 {
2406 /* Check that it will use the same fields in KEY subpart fields list. */
2407 List_iterator<const char> old_field_name_it(subpart_field_list);
2408 List_iterator<const char> new_field_name_it(new_part_info->subpart_field_list);
2409 const char *old_name, *new_name;
2410 while ((old_name= old_field_name_it++))
2411 {
2412 new_name= new_field_name_it++;
2413 if (!new_name || my_strcasecmp(system_charset_info,
2414 new_name,
2415 old_name))
2416 DBUG_RETURN(false);
2417 }
2418 }
2419
2420 if (!use_default_partitions)
2421 {
2422 /*
2423 Loop over partitions/subpartition to verify that they are
2424 the same, including state and name.
2425 */
2426 List_iterator<partition_element> part_it(partitions);
2427 List_iterator<partition_element> new_part_it(new_part_info->partitions);
2428 uint i= 0;
2429 do
2430 {
2431 partition_element *part_elem= part_it++;
2432 partition_element *new_part_elem= new_part_it++;
2433 /*
2434 The following must match:
2435 partition_name, tablespace_name, data_file_name, index_file_name,
2436 engine_type, part_max_rows, part_min_rows, nodegroup_id.
2437 (max_value, signed_flag, has_null_value only on partition level,
2438 RANGE/LIST)
2439 The following can differ:
2440 - part_comment
2441 part_state must be PART_NORMAL!
2442 */
2443 if (!part_elem || !new_part_elem ||
2444 strcmp(part_elem->partition_name,
2445 new_part_elem->partition_name) ||
2446 part_elem->part_state != PART_NORMAL ||
2447 new_part_elem->part_state != PART_NORMAL ||
2448 part_elem->max_value != new_part_elem->max_value ||
2449 part_elem->signed_flag != new_part_elem->signed_flag ||
2450 part_elem->has_null_value != new_part_elem->has_null_value)
2451 DBUG_RETURN(false);
2452
2453 /* new_part_elem may not have engine_type set! */
2454 if (new_part_elem->engine_type &&
2455 part_elem->engine_type != new_part_elem->engine_type)
2456 DBUG_RETURN(false);
2457
2458 if (is_sub_partitioned())
2459 {
2460 /*
2461 Check that both old and new partition has the same definition
2462 (VALUES IN/VALUES LESS THAN) (No COLUMNS partitioning, see above)
2463 */
2464 if (part_type == LIST_PARTITION)
2465 {
2466 List_iterator<part_elem_value> list_vals(part_elem->list_val_list);
2467 List_iterator<part_elem_value>
2468 new_list_vals(new_part_elem->list_val_list);
2469 part_elem_value *val;
2470 part_elem_value *new_val;
2471 while ((val= list_vals++))
2472 {
2473 new_val= new_list_vals++;
2474 if (!new_val)
2475 DBUG_RETURN(false);
2476 if ((!val->null_value && !new_val->null_value) &&
2477 val->value != new_val->value)
2478 DBUG_RETURN(false);
2479 }
2480 if (new_list_vals++)
2481 DBUG_RETURN(false);
2482 }
2483 else
2484 {
2485 DBUG_ASSERT(part_type == RANGE_PARTITION);
2486 if (new_part_elem->range_value != part_elem->range_value)
2487 DBUG_RETURN(false);
2488 }
2489
2490 if (!use_default_subpartitions)
2491 {
2492 List_iterator<partition_element>
2493 sub_part_it(part_elem->subpartitions);
2494 List_iterator<partition_element>
2495 new_sub_part_it(new_part_elem->subpartitions);
2496 uint j= 0;
2497 do
2498 {
2499 partition_element *sub_part_elem= sub_part_it++;
2500 partition_element *new_sub_part_elem= new_sub_part_it++;
2501 /* new_part_elem may not have engine_type set! */
2502 if (new_sub_part_elem->engine_type &&
2503 sub_part_elem->engine_type != new_sub_part_elem->engine_type)
2504 DBUG_RETURN(false);
2505
2506 if (strcmp(sub_part_elem->partition_name,
2507 new_sub_part_elem->partition_name) ||
2508 sub_part_elem->part_state != PART_NORMAL ||
2509 new_sub_part_elem->part_state != PART_NORMAL ||
2510 sub_part_elem->part_min_rows !=
2511 new_sub_part_elem->part_min_rows ||
2512 sub_part_elem->part_max_rows !=
2513 new_sub_part_elem->part_max_rows ||
2514 sub_part_elem->nodegroup_id !=
2515 new_sub_part_elem->nodegroup_id)
2516 DBUG_RETURN(false);
2517
2518 if (strcmp_null(sub_part_elem->data_file_name,
2519 new_sub_part_elem->data_file_name) ||
2520 strcmp_null(sub_part_elem->index_file_name,
2521 new_sub_part_elem->index_file_name) ||
2522 strcmp_null(sub_part_elem->tablespace_name,
2523 new_sub_part_elem->tablespace_name))
2524 DBUG_RETURN(false);
2525
2526 } while (++j < num_subparts);
2527 }
2528 }
2529 else
2530 {
2531 if (part_elem->part_min_rows != new_part_elem->part_min_rows ||
2532 part_elem->part_max_rows != new_part_elem->part_max_rows ||
2533 part_elem->nodegroup_id != new_part_elem->nodegroup_id)
2534 DBUG_RETURN(false);
2535
2536 if (strcmp_null(part_elem->data_file_name,
2537 new_part_elem->data_file_name) ||
2538 strcmp_null(part_elem->index_file_name,
2539 new_part_elem->index_file_name) ||
2540 strcmp_null(part_elem->tablespace_name,
2541 new_part_elem->tablespace_name))
2542 DBUG_RETURN(false);
2543 }
2544 } while (++i < num_parts);
2545 }
2546
2547 /*
2548 Only if key_algorithm was not specified before and it is now set,
2549 consider this as nothing was changed, and allow change without rebuild!
2550 */
2551 if (key_algorithm != partition_info::KEY_ALGORITHM_NONE ||
2552 new_part_info->key_algorithm == partition_info::KEY_ALGORITHM_NONE)
2553 DBUG_RETURN(false);
2554
2555 DBUG_RETURN(true);
2556 }
2557
2558
print_debug(const char * str,uint * value)2559 void partition_info::print_debug(const char *str, uint *value)
2560 {
2561 DBUG_ENTER("print_debug");
2562 if (value)
2563 DBUG_PRINT("info", ("parser: %s, val = %u", str, *value));
2564 else
2565 DBUG_PRINT("info", ("parser: %s", str));
2566 DBUG_VOID_RETURN;
2567 }
2568
field_in_partition_expr(Field * field) const2569 bool partition_info::field_in_partition_expr(Field *field) const
2570 {
2571 uint i;
2572 for (i= 0; i < num_part_fields; i++)
2573 {
2574 if (field->eq(part_field_array[i]))
2575 return TRUE;
2576 }
2577 for (i= 0; i < num_subpart_fields; i++)
2578 {
2579 if (field->eq(subpart_field_array[i]))
2580 return TRUE;
2581 }
2582 return FALSE;
2583 }
2584
2585 #else /* WITH_PARTITION_STORAGE_ENGINE */
2586 /*
2587 For builds without partitioning we need to define these functions
2588 since we they are called from the parser. The parser cannot
2589 remove code parts using ifdef, but the code parts cannot be called
2590 so we simply need to add empty functions to make the linker happy.
2591 */
add_column_value(THD * thd)2592 part_column_list_val *partition_info::add_column_value(THD *thd)
2593 {
2594 return NULL;
2595 }
2596
set_part_expr(THD * thd,Item * item_ptr,bool is_subpart)2597 bool partition_info::set_part_expr(THD *thd, Item *item_ptr, bool is_subpart)
2598 {
2599 (void)item_ptr;
2600 (void)is_subpart;
2601 return FALSE;
2602 }
2603
reorganize_into_single_field_col_val(THD * thd)2604 int partition_info::reorganize_into_single_field_col_val(THD *thd)
2605 {
2606 return 0;
2607 }
2608
init_column_part(THD * thd)2609 bool partition_info::init_column_part(THD *thd)
2610 {
2611 return FALSE;
2612 }
2613
add_column_list_value(THD * thd,Item * item)2614 bool partition_info::add_column_list_value(THD *thd, Item *item)
2615 {
2616 return FALSE;
2617 }
add_max_value(THD * thd)2618 int partition_info::add_max_value(THD *thd)
2619 {
2620 return 0;
2621 }
2622
print_debug(const char * str,uint * value)2623 void partition_info::print_debug(const char *str, uint *value)
2624 {
2625 }
2626
check_partition_dirs(partition_info * part_info)2627 bool check_partition_dirs(partition_info *part_info)
2628 {
2629 return 0;
2630 }
2631
2632 #endif /* WITH_PARTITION_STORAGE_ENGINE */
2633
vers_init_info(THD * thd)2634 bool partition_info::vers_init_info(THD * thd)
2635 {
2636 part_type= VERSIONING_PARTITION;
2637 list_of_part_fields= true;
2638 column_list= false;
2639 vers_info= new (thd->mem_root) Vers_part_info;
2640 if (unlikely(!vers_info))
2641 return true;
2642
2643 return false;
2644 }
2645
2646
2647 /**
2648 Assign INTERVAL and STARTS for SYSTEM_TIME partitions.
2649
2650 @return true on error
2651 */
2652
vers_set_interval(THD * thd,Item * interval,interval_type int_type,Item * starts,const char * table_name)2653 bool partition_info::vers_set_interval(THD* thd, Item* interval,
2654 interval_type int_type, Item* starts,
2655 const char *table_name)
2656 {
2657 DBUG_ASSERT(part_type == VERSIONING_PARTITION);
2658
2659 MYSQL_TIME ltime;
2660 uint err;
2661 vers_info->interval.type= int_type;
2662
2663 /* 1. assign INTERVAL to interval.step */
2664 if (interval->fix_fields_if_needed_for_scalar(thd, &interval))
2665 return true;
2666 bool error= get_interval_value(thd, interval, int_type, &vers_info->interval.step) ||
2667 vers_info->interval.step.neg || vers_info->interval.step.second_part ||
2668 !(vers_info->interval.step.year || vers_info->interval.step.month ||
2669 vers_info->interval.step.day || vers_info->interval.step.hour ||
2670 vers_info->interval.step.minute || vers_info->interval.step.second);
2671 if (error)
2672 {
2673 my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "INTERVAL");
2674 return true;
2675 }
2676
2677 /* 2. assign STARTS to interval.start */
2678 if (starts)
2679 {
2680 if (starts->fix_fields_if_needed_for_scalar(thd, &starts))
2681 return true;
2682 switch (starts->result_type())
2683 {
2684 case INT_RESULT:
2685 case DECIMAL_RESULT:
2686 case REAL_RESULT:
2687 /* When table member is defined, we are inside mysql_unpack_partition(). */
2688 if (!table || starts->val_int() > TIMESTAMP_MAX_VALUE)
2689 goto interval_starts_error;
2690 vers_info->interval.start= (my_time_t) starts->val_int();
2691 break;
2692 case STRING_RESULT:
2693 case TIME_RESULT:
2694 {
2695 Datetime::Options opt(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE, thd);
2696 starts->get_date(thd, <ime, opt);
2697 vers_info->interval.start= TIME_to_timestamp(thd, <ime, &err);
2698 if (err)
2699 goto interval_starts_error;
2700 break;
2701 }
2702 case ROW_RESULT:
2703 default:
2704 goto interval_starts_error;
2705 }
2706 if (!table)
2707 {
2708 if (thd->query_start() < vers_info->interval.start) {
2709 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
2710 ER_PART_STARTS_BEYOND_INTERVAL,
2711 ER_THD(thd, ER_PART_STARTS_BEYOND_INTERVAL),
2712 table_name);
2713 }
2714 }
2715 }
2716 else // calculate default STARTS depending on INTERVAL
2717 {
2718 thd->variables.time_zone->gmt_sec_to_TIME(<ime, thd->query_start());
2719 if (vers_info->interval.step.second)
2720 goto interval_set_starts;
2721 ltime.second= 0;
2722 if (vers_info->interval.step.minute)
2723 goto interval_set_starts;
2724 ltime.minute= 0;
2725 if (vers_info->interval.step.hour)
2726 goto interval_set_starts;
2727 ltime.hour= 0;
2728
2729 interval_set_starts:
2730 vers_info->interval.start= TIME_to_timestamp(thd, <ime, &err);
2731 if (err)
2732 goto interval_starts_error;
2733 }
2734
2735 return false;
2736
2737 interval_starts_error:
2738 my_error(ER_PART_WRONG_VALUE, MYF(0), table_name, "STARTS");
2739 return true;
2740 }
2741
2742
error_if_requires_values() const2743 bool partition_info::error_if_requires_values() const
2744 {
2745 switch (part_type) {
2746 case NOT_A_PARTITION:
2747 case HASH_PARTITION:
2748 case VERSIONING_PARTITION:
2749 break;
2750 case RANGE_PARTITION:
2751 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN");
2752 return true;
2753 case LIST_PARTITION:
2754 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
2755 return true;
2756 }
2757 return false;
2758 }
2759