1 /* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /*
24 This file is a container for general functionality related
25 to partitioning. It contains functionality used by all handlers that
26 support partitioning, such as the partitioning handler itself and the NDB
27 handler. (Much of the code in this file has been split into partition_info.cc
28 and the header files partition_info.h + partition_element.h + sql_partition.h)
29
30 The first version supports RANGE partitioning, LIST partitioning, HASH
31 partitioning and composite partitioning (hereafter called subpartitioning)
32 where each RANGE/LIST partitioning is HASH partitioned. The hash function
33 can either be supplied by the user or by only a list of fields (also
34 called KEY partitioning), where the MySQL server will use an internal
35 hash function.
36 There are quite a few defaults that can be used as well.
37
38 The second version introduces a new variant of RANGE and LIST partitioning
39 which is often referred to as column lists in the code variables. This
40 enables a user to specify a set of columns and their concatenated value
41 as the partition value. By comparing the concatenation of these values
42 the proper partition can be choosen.
43 */
44
45 #include "sql/sql_partition.h"
46
47 #include <assert.h>
48 #include <limits.h>
49 #include <string.h>
50 #include <algorithm>
51
52 #include "field_types.h" // enum_field_types
53 #include "m_string.h"
54 #include "my_bitmap.h"
55 #include "my_byteorder.h"
56 #include "my_compiler.h"
57 #include "my_dbug.h"
58 #include "my_io.h"
59 #include "my_sqlcommand.h"
60 #include "my_sys.h"
61 #include "mysql/components/services/psi_statement_bits.h"
62 #include "mysql/plugin.h"
63 #include "mysql/psi/mysql_file.h"
64 #include "mysql/service_mysql_alloc.h"
65 #include "mysql/udf_registration_types.h"
66 #include "mysql_com.h"
67 #include "mysql_time.h"
68 #include "mysqld_error.h"
69 #include "sql/create_field.h"
70 #include "sql/current_thd.h"
71 #include "sql/debug_sync.h" // DEBUG_SYNC
72 #include "sql/derror.h" // ER_THD
73 #include "sql/enum_query_type.h"
74 #include "sql/field.h"
75 #include "sql/handler.h"
76 #include "sql/item.h" // enum_monotoncity_info
77 #include "sql/item_func.h" // Item_func
78 #include "sql/key.h"
79 #include "sql/mdl.h"
80 #include "sql/mysqld.h" // mysql_tmpdir
81 #include "sql/opt_range.h" // store_key_image_to_rec
82 #include "sql/parse_tree_node_base.h"
83 #include "sql/partition_info.h" // partition_info
84 #include "sql/partitioning/partition_handler.h" // Partition_handler
85 #include "sql/psi_memory_key.h"
86 #include "sql/query_options.h"
87 #include "sql/sql_alter.h"
88 #include "sql/sql_base.h" // wait_while_table_is_used
89 #include "sql/sql_class.h" // THD
90 #include "sql/sql_const.h"
91 #include "sql/sql_digest_stream.h"
92 #include "sql/sql_error.h"
93 #include "sql/sql_lex.h"
94 #include "sql/sql_list.h"
95 #include "sql/sql_parse.h" // parse_sql
96 #include "sql/sql_show.h"
97 #include "sql/sql_table.h" // build_table_filename
98 #include "sql/system_variables.h"
99 #include "sql/table.h"
100 #include "sql/thd_raii.h"
101 #include "sql_string.h"
102
103 struct MEM_ROOT;
104
105 using std::max;
106 using std::min;
107
108 /*
109 Partition related functions declarations and some static constants;
110 */
111 const LEX_CSTRING partition_keywords[] = {{STRING_WITH_LEN("HASH")},
112 {STRING_WITH_LEN("RANGE")},
113 {STRING_WITH_LEN("LIST")},
114 {STRING_WITH_LEN("KEY")},
115 {STRING_WITH_LEN("MAXVALUE")},
116 {STRING_WITH_LEN("LINEAR ")},
117 {STRING_WITH_LEN(" COLUMNS")},
118 {STRING_WITH_LEN("ALGORITHM")}
119
120 };
121 static const char *part_str = "PARTITION";
122 static const char *sub_str = "SUB";
123 static const char *by_str = "BY";
124 static const char *space_str = " ";
125 static const char *equal_str = "=";
126 static const char *end_paren_str = ")";
127 static const char *begin_paren_str = "(";
128 static const char *comma_str = ",";
129
130 static int get_partition_id_list_col(partition_info *part_info, uint32 *part_id,
131 longlong *func_value);
132 static int get_partition_id_list(partition_info *part_info, uint32 *part_id,
133 longlong *func_value);
134 static int get_partition_id_range_col(partition_info *part_info,
135 uint32 *part_id, longlong *func_value);
136 static int get_partition_id_range(partition_info *part_info, uint32 *part_id,
137 longlong *func_value);
138 static int get_part_id_charset_func_part(partition_info *part_info,
139 uint32 *part_id, longlong *func_value);
140 static int get_part_id_charset_func_subpart(partition_info *part_info,
141 uint32 *part_id);
142 static int get_partition_id_hash_nosub(partition_info *part_info,
143 uint32 *part_id, longlong *func_value);
144 static int get_partition_id_key_nosub(partition_info *part_info,
145 uint32 *part_id, longlong *func_value);
146 static int get_partition_id_linear_hash_nosub(partition_info *part_info,
147 uint32 *part_id,
148 longlong *func_value);
149 static int get_partition_id_linear_key_nosub(partition_info *part_info,
150 uint32 *part_id,
151 longlong *func_value);
152 static int get_partition_id_with_sub(partition_info *part_info, uint32 *part_id,
153 longlong *func_value);
154 static int get_partition_id_hash_sub(partition_info *part_info,
155 uint32 *part_id);
156 static int get_partition_id_key_sub(partition_info *part_info, uint32 *part_id);
157 static int get_partition_id_linear_hash_sub(partition_info *part_info,
158 uint32 *part_id);
159 static int get_partition_id_linear_key_sub(partition_info *part_info,
160 uint32 *part_id);
161 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *);
162 static void set_up_range_analysis_info(partition_info *part_info);
163 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *);
164
165 static uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
166 bool left_endpoint,
167 bool include_endpoint);
168 static uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter);
169 static int get_part_iter_for_interval_via_mapping(
170 partition_info *part_info, bool is_subpart, uint32 *store_length_array,
171 uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
172 PARTITION_ITERATOR *part_iter);
173 static int get_part_iter_for_interval_cols_via_map(
174 partition_info *part_info, bool is_subpart, uint32 *store_length_array,
175 uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
176 PARTITION_ITERATOR *part_iter);
177 static int get_part_iter_for_interval_via_walking(
178 partition_info *part_info, bool is_subpart, uint32 *store_length_array,
179 uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
180 PARTITION_ITERATOR *part_iter);
181
182 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec);
183 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
184 uint32 n_vals_in_rec, bool is_left_endpoint,
185 bool include_endpoint);
186
187 static void set_field_ptr(Field **ptr, const uchar *new_buf,
188 const uchar *old_buf);
189
190 static uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
191 bool left_endpoint,
192 bool include_endpoint);
193
194 /*
195 Convert constants in VALUES definition to the character set the
196 corresponding field uses.
197
198 SYNOPSIS
199 convert_charset_partition_constant()
200 item Item to convert
201 cs Character set to convert to
202
203 RETURN VALUE
204 NULL Error
205 item New converted item
206 */
207
convert_charset_partition_constant(Item * item,const CHARSET_INFO * cs)208 Item *convert_charset_partition_constant(Item *item, const CHARSET_INFO *cs) {
209 THD *thd = current_thd;
210 Name_resolution_context *context = &thd->lex->current_select()->context;
211 TABLE_LIST *save_list = context->table_list;
212 const char *save_where = thd->where;
213
214 item = item->safe_charset_converter(thd, cs);
215 context->table_list = nullptr;
216 thd->where = "convert character set partition constant";
217 if (!item || item->fix_fields(thd, (Item **)nullptr)) item = nullptr;
218 thd->where = save_where;
219 context->table_list = save_list;
220 return item;
221 }
222
223 /**
224 A support function to check if a name is in a list of strings.
225
226 @param name String searched for
227 @param list_names A list of names searched in
228
229 @return True if if the name is in the list.
230 @retval true String found
231 @retval false String not found
232 */
233
is_name_in_list(const char * name,List<String> list_names)234 static bool is_name_in_list(const char *name, List<String> list_names) {
235 List_iterator<String> names_it(list_names);
236 uint num_names = list_names.elements;
237 uint i = 0;
238
239 do {
240 String *list_name = names_it++;
241 if (!(my_strcasecmp(system_charset_info, name, list_name->c_ptr())))
242 return true;
243 } while (++i < num_names);
244 return false;
245 }
246
247 /*
248 Set-up defaults for partitions.
249
250 SYNOPSIS
251 partition_default_handling()
252 table Table object
253 part_info Partition info to set up
254 is_create_table_ind Is this part of a table creation
255 normalized_path Normalized path name of table and database
256
257 RETURN VALUES
258 true Error
259 false Success
260 */
261
partition_default_handling(TABLE * table,partition_info * part_info,bool is_create_table_ind,const char * normalized_path)262 static bool partition_default_handling(TABLE *table, partition_info *part_info,
263 bool is_create_table_ind,
264 const char *normalized_path) {
265 Partition_handler *part_handler = table->file->get_partition_handler();
266 DBUG_TRACE;
267
268 if (!part_handler) {
269 DBUG_ASSERT(0);
270 my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
271 return true;
272 }
273
274 if (!is_create_table_ind) {
275 if (part_info->use_default_num_partitions) {
276 if (part_handler->get_num_parts(normalized_path, &part_info->num_parts)) {
277 return true;
278 }
279 } else if (part_info->is_sub_partitioned() &&
280 part_info->use_default_num_subpartitions) {
281 uint num_parts;
282 if (part_handler->get_num_parts(normalized_path, &num_parts)) {
283 return true;
284 }
285 DBUG_ASSERT(part_info->num_parts > 0);
286 DBUG_ASSERT((num_parts % part_info->num_parts) == 0);
287 part_info->num_subparts = num_parts / part_info->num_parts;
288 }
289 }
290 part_info->set_up_defaults_for_partitioning(part_handler, nullptr, 0U);
291 return false;
292 }
293
294 /*
295 A useful routine used by update_row for partition handlers to calculate
296 the partition ids of the old and the new record.
297
298 SYNOPSIS
299 get_parts_for_update()
300 old_data Buffer of old record
301 new_data Buffer of new record
302 rec0 Reference to table->record[0]
303 part_info Reference to partition information
304 out:old_part_id The returned partition id of old record
305 out:new_part_id The returned partition id of new record
306
307 RETURN VALUE
308 0 Success
309 > 0 Error code
310 */
311
get_parts_for_update(const uchar * old_data,const uchar * new_data MY_ATTRIBUTE ((unused)),const uchar * rec0,partition_info * part_info,uint32 * old_part_id,uint32 * new_part_id,longlong * new_func_value)312 int get_parts_for_update(const uchar *old_data,
313 const uchar *new_data MY_ATTRIBUTE((unused)),
314 const uchar *rec0, partition_info *part_info,
315 uint32 *old_part_id, uint32 *new_part_id,
316 longlong *new_func_value) {
317 Field **part_field_array = part_info->full_part_field_array;
318 int error;
319 longlong old_func_value;
320 DBUG_TRACE;
321
322 DBUG_ASSERT(new_data == rec0); // table->record[0]
323 set_field_ptr(part_field_array, old_data, rec0);
324 error = part_info->get_partition_id(part_info, old_part_id, &old_func_value);
325 set_field_ptr(part_field_array, rec0, old_data);
326 if (unlikely(error)) {
327 part_info->err_value = old_func_value;
328 return error;
329 }
330 if (unlikely((error = part_info->get_partition_id(part_info, new_part_id,
331 new_func_value)))) {
332 part_info->err_value = *new_func_value;
333 return error;
334 }
335 return 0;
336 }
337
338 /*
339 A useful routine used by delete_row for partition handlers to calculate
340 the partition id.
341
342 SYNOPSIS
343 get_part_for_delete()
344 buf Buffer of old record
345 rec0 Reference to table->record[0]
346 part_info Reference to partition information
347 out:part_id The returned partition id to delete from
348
349 RETURN VALUE
350 0 Success
351 > 0 Error code
352
353 DESCRIPTION
354 Dependent on whether buf is not record[0] we need to prepare the
355 fields. Then we call the function pointer get_partition_id to
356 calculate the partition id.
357 */
358
get_part_for_delete(const uchar * buf,const uchar * rec0,partition_info * part_info,uint32 * part_id)359 int get_part_for_delete(const uchar *buf, const uchar *rec0,
360 partition_info *part_info, uint32 *part_id) {
361 int error;
362 longlong func_value;
363 DBUG_TRACE;
364
365 if (likely(buf == rec0)) {
366 if (unlikely((error = part_info->get_partition_id(part_info, part_id,
367 &func_value)))) {
368 part_info->err_value = func_value;
369 return error;
370 }
371 DBUG_PRINT("info", ("Delete from partition %d", *part_id));
372 } else {
373 Field **part_field_array = part_info->full_part_field_array;
374 set_field_ptr(part_field_array, buf, rec0);
375 error = part_info->get_partition_id(part_info, part_id, &func_value);
376 set_field_ptr(part_field_array, rec0, buf);
377 if (unlikely(error)) {
378 part_info->err_value = func_value;
379 return error;
380 }
381 DBUG_PRINT("info", ("Delete from partition %d (path2)", *part_id));
382 }
383 return 0;
384 }
385
386 /*
387 This method is used to set-up both partition and subpartitioning
388 field array and used for all types of partitioning.
389 It is part of the logic around fix_partition_func.
390
391 SYNOPSIS
392 set_up_field_array()
393 table TABLE object for which partition fields are set-up
394 sub_part Is the table subpartitioned as well
395
396 RETURN VALUE
397 true Error, some field didn't meet requirements
398 false Ok, partition field array set-up
399
400 DESCRIPTION
401
402 A great number of functions below here is part of the fix_partition_func
403 method. It is used to set up the partition structures for execution from
404 openfrm. It is called at the end of the openfrm when the table struct has
405 been set-up apart from the partition information.
406 It involves:
407 1) Setting arrays of fields for the partition functions.
408 2) Setting up binary search array for LIST partitioning
409 3) Setting up array for binary search for RANGE partitioning
410 4) Setting up key_map's to assist in quick evaluation whether one
411 can deduce anything from a given index of what partition to use
412 5) Checking whether a set of partitions can be derived from a range on
413 a field in the partition function.
414 As part of doing this there is also a great number of error controls.
415 This is actually the place where most of the things are checked for
416 partition information when creating a table.
417 Things that are checked includes
418 1) All fields of partition function in Primary keys and unique indexes
419 (if not supported)
420
421
422 Create an array of partition fields (NULL terminated). Before this method
423 is called fix_fields or find_table_in_sef has been called to set
424 GET_FIXED_FIELDS_FLAG on all fields that are part of the partition
425 function.
426 */
427
set_up_field_array(TABLE * table,bool is_sub_part)428 static bool set_up_field_array(TABLE *table, bool is_sub_part) {
429 Field **ptr, *field, **field_array;
430 uint num_fields = 0;
431 uint size_field_array;
432 uint i = 0;
433 uint inx;
434 partition_info *part_info = table->part_info;
435 int result = false;
436 DBUG_TRACE;
437
438 ptr = table->field;
439 while ((field = *(ptr++))) {
440 if (field->is_flag_set(GET_FIXED_FIELDS_FLAG)) num_fields++;
441 }
442 if (num_fields > MAX_REF_PARTS) {
443 const char *err_str;
444 if (is_sub_part)
445 err_str = "subpartition function";
446 else
447 err_str = "partition function";
448 my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), err_str);
449 return true;
450 }
451 if (num_fields == 0) {
452 /*
453 We are using hidden key as partitioning field
454 */
455 DBUG_ASSERT(!is_sub_part);
456 return result;
457 }
458 size_field_array = (num_fields + 1) * sizeof(Field *);
459 field_array = (Field **)sql_calloc(size_field_array);
460 if (unlikely(!field_array)) {
461 mem_alloc_error(size_field_array);
462 result = true;
463 }
464 ptr = table->field;
465 while ((field = *(ptr++))) {
466 if (field->is_flag_set(GET_FIXED_FIELDS_FLAG)) {
467 field->clear_flag(GET_FIXED_FIELDS_FLAG);
468 field->set_flag(FIELD_IN_PART_FUNC_FLAG);
469 if (likely(!result)) {
470 if (!is_sub_part && part_info->column_list) {
471 List_iterator<char> it(part_info->part_field_list);
472 char *field_name;
473
474 DBUG_ASSERT(num_fields == part_info->part_field_list.elements);
475 inx = 0;
476 do {
477 field_name = it++;
478 if (!my_strcasecmp(system_charset_info, field_name,
479 field->field_name))
480 break;
481 } while (++inx < num_fields);
482 if (inx == num_fields) {
483 /*
484 Should not occur since it should already been checked in either
485 add_column_list_values, handle_list_of_fields,
486 check_partition_info etc.
487 */
488 DBUG_ASSERT(0);
489 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
490 result = true;
491 continue;
492 }
493 } else
494 inx = i;
495 field_array[inx] = field;
496 i++;
497
498 /*
499 We check that the fields are proper. It is required for each
500 field in a partition function to:
501 1) Not be a BLOB of any type
502 A BLOB takes too long time to evaluate so we don't want it for
503 performance reasons.
504 */
505
506 if (field->is_flag_set(BLOB_FLAG)) {
507 my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
508 result = true;
509 }
510 }
511 }
512 }
513 field_array[num_fields] = nullptr;
514 if (!is_sub_part) {
515 part_info->part_field_array = field_array;
516 part_info->num_part_fields = num_fields;
517 } else {
518 part_info->subpart_field_array = field_array;
519 part_info->num_subpart_fields = num_fields;
520 }
521 return result;
522 }
523
524 /*
525 Create a field array including all fields of both the partitioning and the
526 subpartitioning functions.
527
528 SYNOPSIS
529 create_full_part_field_array()
530 thd Thread handle
531 table TABLE object for which partition fields are set-up
532 part_info Reference to partitioning data structure
533
534 RETURN VALUE
535 true Memory allocation of field array failed
536 false Ok
537
538 DESCRIPTION
539 If there is no subpartitioning then the same array is used as for the
540 partitioning. Otherwise a new array is built up using the flag
541 FIELD_IN_PART_FUNC in the field object.
542 This function is called from fix_partition_func
543 */
544
create_full_part_field_array(THD * thd,TABLE * table,partition_info * part_info)545 static bool create_full_part_field_array(THD *thd, TABLE *table,
546 partition_info *part_info) {
547 bool result = false;
548 Field **ptr;
549 my_bitmap_map *bitmap_buf;
550 DBUG_TRACE;
551
552 if (!part_info->is_sub_partitioned()) {
553 part_info->full_part_field_array = part_info->part_field_array;
554 part_info->num_full_part_fields = part_info->num_part_fields;
555 } else {
556 Field *field, **field_array;
557 uint num_part_fields = 0, size_field_array;
558 ptr = table->field;
559 while ((field = *(ptr++))) {
560 if (field->is_flag_set(FIELD_IN_PART_FUNC_FLAG)) num_part_fields++;
561 }
562 size_field_array = (num_part_fields + 1) * sizeof(Field *);
563 field_array = (Field **)sql_calloc(size_field_array);
564 if (unlikely(!field_array)) {
565 mem_alloc_error(size_field_array);
566 result = true;
567 goto end;
568 }
569 num_part_fields = 0;
570 ptr = table->field;
571 while ((field = *(ptr++))) {
572 if (field->is_flag_set(FIELD_IN_PART_FUNC_FLAG))
573 field_array[num_part_fields++] = field;
574 }
575 field_array[num_part_fields] = nullptr;
576 part_info->full_part_field_array = field_array;
577 part_info->num_full_part_fields = num_part_fields;
578 }
579
580 /*
581 Initialize the set of all fields used in partition and subpartition
582 expression. Required for testing of partition fields in write_set
583 when updating. We need to set all bits in read_set because the row
584 may need to be inserted in a different [sub]partition.
585 */
586 if (!(bitmap_buf = (my_bitmap_map *)thd->alloc(
587 bitmap_buffer_size(table->s->fields)))) {
588 mem_alloc_error(bitmap_buffer_size(table->s->fields));
589 result = true;
590 goto end;
591 }
592 if (bitmap_init(&part_info->full_part_field_set, bitmap_buf,
593 table->s->fields)) {
594 mem_alloc_error(table->s->fields);
595 result = true;
596 goto end;
597 }
598 /*
599 full_part_field_array may be NULL if storage engine supports native
600 partitioning.
601 */
602 if ((ptr = part_info->full_part_field_array))
603 for (; *ptr; ptr++)
604 bitmap_set_bit(&part_info->full_part_field_set, (*ptr)->field_index());
605
606 end:
607 return result;
608 }
609
610 /*
611
612 Clear flag GET_FIXED_FIELDS_FLAG in all fields of a key previously set by
613 set_indicator_in_key_fields (always used in pairs).
614
615 SYNOPSIS
616 clear_indicator_in_key_fields()
617 key_info Reference to find the key fields
618
619 RETURN VALUE
620 NONE
621
622 DESCRIPTION
623 These support routines is used to set/reset an indicator of all fields
624 in a certain key. It is used in conjunction with another support routine
625 that traverse all fields in the PF to find if all or some fields in the
626 PF is part of the key. This is used to check primary keys and unique
627 keys involve all fields in PF (unless supported) and to derive the
628 key_map's used to quickly decide whether the index can be used to
629 derive which partitions are needed to scan.
630 */
631
clear_indicator_in_key_fields(KEY * key_info)632 static void clear_indicator_in_key_fields(KEY *key_info) {
633 KEY_PART_INFO *key_part;
634 uint key_parts = key_info->user_defined_key_parts, i;
635 for (i = 0, key_part = key_info->key_part; i < key_parts; i++, key_part++)
636 key_part->field->clear_flag(GET_FIXED_FIELDS_FLAG);
637 }
638
639 /*
640 Set flag GET_FIXED_FIELDS_FLAG in all fields of a key.
641
642 SYNOPSIS
643 set_indicator_in_key_fields
644 key_info Reference to find the key fields
645
646 RETURN VALUE
647 NONE
648 */
649
set_indicator_in_key_fields(KEY * key_info)650 static void set_indicator_in_key_fields(KEY *key_info) {
651 KEY_PART_INFO *key_part;
652 uint key_parts = key_info->user_defined_key_parts, i;
653 for (i = 0, key_part = key_info->key_part; i < key_parts; i++, key_part++)
654 key_part->field->set_flag(GET_FIXED_FIELDS_FLAG);
655 }
656
657 /*
658 Check if all or some fields in partition field array is part of a key
659 previously used to tag key fields.
660
661 SYNOPSIS
662 check_fields_in_PF()
663 ptr Partition field array
664 out:all_fields Is all fields of partition field array used in key
665 out:some_fields Is some fields of partition field array used in key
666
667 RETURN VALUE
668 all_fields, some_fields
669 */
670
check_fields_in_PF(Field ** ptr,bool * all_fields,bool * some_fields)671 static void check_fields_in_PF(Field **ptr, bool *all_fields,
672 bool *some_fields) {
673 DBUG_TRACE;
674
675 *all_fields = true;
676 *some_fields = false;
677 if ((!ptr) || !(*ptr)) {
678 *all_fields = false;
679 return;
680 }
681 do {
682 /* Check if the field of the PF is part of the current key investigated */
683 if ((*ptr)->is_flag_set(GET_FIXED_FIELDS_FLAG))
684 *some_fields = true;
685 else
686 *all_fields = false;
687 } while (*(++ptr));
688 }
689
690 /*
691 Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
692 This routine is used for error handling purposes.
693
694 SYNOPSIS
695 clear_field_flag()
696 table TABLE object for which partition fields are set-up
697
698 RETURN VALUE
699 NONE
700 */
701
clear_field_flag(TABLE * table)702 static void clear_field_flag(TABLE *table) {
703 Field **ptr;
704 DBUG_TRACE;
705
706 for (ptr = table->field; *ptr; ptr++)
707 (*ptr)->clear_flag(GET_FIXED_FIELDS_FLAG);
708 }
709
710 /*
711 find_field_in_table_sef finds the field given its name. All fields get
712 GET_FIXED_FIELDS_FLAG set.
713
714 SYNOPSIS
715 handle_list_of_fields()
716 it A list of field names for the partition function
717 table TABLE object for which partition fields are set-up
718 part_info Reference to partitioning data structure
719 sub_part Is the table subpartitioned as well
720
721 RETURN VALUE
722 true Fields in list of fields not part of table
723 false All fields ok and array created
724
725 DESCRIPTION
726 This routine sets-up the partition field array for KEY partitioning, it
727 also verifies that all fields in the list of fields is actually a part of
728 the table.
729
730 */
731
handle_list_of_fields(List_iterator<char> it,TABLE * table,partition_info * part_info,bool is_sub_part)732 static bool handle_list_of_fields(List_iterator<char> it, TABLE *table,
733 partition_info *part_info, bool is_sub_part) {
734 bool result;
735 char *field_name;
736 bool is_list_empty = true;
737 DBUG_TRACE;
738
739 while ((field_name = it++)) {
740 is_list_empty = false;
741 Field *field = find_field_in_table_sef(table, field_name);
742 if (likely(field != nullptr))
743 field->set_flag(GET_FIXED_FIELDS_FLAG);
744 else {
745 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
746 clear_field_flag(table);
747 result = true;
748 goto end;
749 }
750 }
751 if (is_list_empty && part_info->part_type == partition_type::HASH) {
752 uint primary_key = table->s->primary_key;
753 if (primary_key != MAX_KEY) {
754 uint num_key_parts = table->key_info[primary_key].user_defined_key_parts,
755 i;
756 /*
757 In the case of an empty list we use primary key as partition key.
758 */
759 for (i = 0; i < num_key_parts; i++) {
760 Field *field = table->key_info[primary_key].key_part[i].field;
761 field->set_flag(GET_FIXED_FIELDS_FLAG);
762 }
763 } else {
764 if (table->s->db_type()->partition_flags &&
765 (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)) {
766 /*
767 This engine can handle automatic partitioning and there is no
768 primary key. In this case we rely on that the engine handles
769 partitioning based on a hidden key. Thus we allocate no
770 array for partitioning fields.
771 */
772 return false;
773 } else {
774 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
775 return true;
776 }
777 }
778 }
779 result = set_up_field_array(table, is_sub_part);
780 end:
781 return result;
782 }
783
784 /*
785 Support function to check if all VALUES * (expression) is of the
786 right sign (no signed constants when unsigned partition function)
787
788 SYNOPSIS
789 check_signed_flag()
790 part_info Partition info object
791
792 RETURN VALUES
793 0 No errors due to sign errors
794 >0 Sign error
795 */
796
check_signed_flag(partition_info * part_info)797 static int check_signed_flag(partition_info *part_info) {
798 int error = 0;
799 uint i = 0;
800 if (part_info->part_type != partition_type::HASH &&
801 part_info->part_expr->unsigned_flag) {
802 List_iterator<partition_element> part_it(part_info->partitions);
803 do {
804 partition_element *part_elem = part_it++;
805
806 if (part_elem->signed_flag) {
807 my_error(ER_PARTITION_CONST_DOMAIN_ERROR, MYF(0));
808 error = ER_PARTITION_CONST_DOMAIN_ERROR;
809 break;
810 }
811 } while (++i < part_info->num_parts);
812 }
813 return error;
814 }
815
816 /**
817 Initialize lex object for use in fix_fields and parsing.
818
819 @param thd The thread object
820 @param table The table object
821 @param lex The LEX object, must be initialized and contain select_lex.
822
823 @returns false if success, true if error
824
825 @details
826 This function is used to set up a lex object on the
827 stack for resolving of fields from a single table.
828 */
829
init_lex_with_single_table(THD * thd,TABLE * table,LEX * lex)830 static bool init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) {
831 SELECT_LEX *select_lex = lex->select_lex;
832 Name_resolution_context *context = &select_lex->context;
833 /*
834 We will call the parser to create a part_info struct based on the
835 partition string stored in the frm file.
836 We will use a local lex object for this purpose. However we also
837 need to set the Name_resolution_object for this lex object. We
838 do this by using add_table_to_list where we add the table that
839 we're working with to the Name_resolution_context.
840 */
841 thd->lex = lex;
842 auto table_ident = new (thd->mem_root) Table_ident(
843 thd->get_protocol(), table->s->db, table->s->table_name, true);
844 if (table_ident == nullptr) return true;
845
846 TABLE_LIST *table_list =
847 select_lex->add_table_to_list(thd, table_ident, nullptr, 0);
848 if (table_list == nullptr) return true;
849
850 context->resolve_in_table_list_only(table_list);
851 lex->use_only_table_context = true;
852 table->get_fields_in_item_tree = true;
853 table_list->table = table;
854 table_list->cacheable_table = false;
855 return false;
856 }
857
858 /**
859 End use of local lex with single table
860
861 SYNOPSIS
862 end_lex_with_single_table()
863 @param thd The thread object
864 @param table The table object
865 @param old_lex The real lex object connected to THD
866
867 DESCRIPTION
868 This function restores the real lex object after calling
869 init_lex_with_single_table and also restores some table
870 variables temporarily set.
871 */
872
end_lex_with_single_table(THD * thd,TABLE * table,LEX * old_lex)873 static void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex) {
874 LEX *lex = thd->lex;
875 table->get_fields_in_item_tree = false;
876 lex_end(lex);
877 thd->lex = old_lex;
878 }
879
880 /*
881 The function uses a new feature in fix_fields where the flag
882 GET_FIXED_FIELDS_FLAG is set for all fields in the item tree.
883 This field must always be reset before returning from the function
884 since it is used for other purposes as well.
885
886 SYNOPSIS
887 fix_fields_part_func()
888 thd The thread object
889 func_expr The item tree reference of the partition function
890 table The table object
891 part_info Reference to partitioning data structure
892 is_sub_part Is the table subpartitioned as well
893 is_create_table_ind Indicator of whether openfrm was called as part of
894 CREATE or ALTER TABLE
895
896 RETURN VALUE
897 true An error occurred, something was wrong with the
898 partition function.
899 false Ok, a partition field array was created
900
901 DESCRIPTION
902 This function is used to build an array of partition fields for the
903 partitioning function and subpartitioning function. The partitioning
904 function is an item tree that must reference at least one field in the
905 table. This is checked first in the parser that the function doesn't
906 contain non-cacheable parts (like a random function) and by checking
907 here that the function isn't a constant function.
908
909 Calculate the number of fields in the partition function.
910 Use it allocate memory for array of Field pointers.
911 Initialise array of field pointers. Use information set when
912 calling fix_fields and reset it immediately after.
913 The get_fields_in_item_tree activates setting of bit in flags
914 on the field object.
915 */
916
fix_fields_part_func(THD * thd,Item * func_expr,TABLE * table,bool is_sub_part,bool is_create_table_ind)917 static bool fix_fields_part_func(THD *thd, Item *func_expr, TABLE *table,
918 bool is_sub_part, bool is_create_table_ind) {
919 partition_info *part_info = table->part_info;
920 bool result = true;
921 int error;
922 LEX *old_lex = thd->lex;
923 LEX lex;
924 SELECT_LEX_UNIT unit(CTX_NONE);
925 SELECT_LEX select(thd->mem_root, nullptr, nullptr);
926 lex.new_static_query(&unit, &select);
927
928 DBUG_TRACE;
929
930 if (init_lex_with_single_table(thd, table, &lex)) goto end;
931
932 {
933 Item_ident::Change_context ctx(&lex.select_lex->context);
934 func_expr->walk(&Item::change_context_processor, enum_walk::POSTFIX,
935 (uchar *)&ctx);
936 }
937 thd->where = "partition function";
938 /*
939 In execution we must avoid the use of thd->change_item_tree since
940 we might release memory before statement is completed. We do this
941 by temporarily setting the stmt_arena->mem_root to be the mem_root
942 of the table object, this also ensures that any memory allocated
943 during fix_fields will not be released at end of execution of this
944 statement. Thus the item tree will remain valid also in subsequent
945 executions of this table object. We do however not at the moment
946 support allocations during execution of val_int so any item class
947 that does this during val_int must be disallowed as partition
948 function.
949 SEE Bug #21658
950
951 This is a tricky call to prepare for since it can have a large number
952 of interesting side effects, both desirable and undesirable.
953 */
954 {
955 const bool save_agg_func = thd->lex->current_select()->agg_func_used();
956
957 error = func_expr->fix_fields(thd, &func_expr);
958
959 /*
960 Restore agg_func.
961 fix_fields should not affect the optimizer later, see Bug#46923.
962 */
963 thd->lex->current_select()->set_agg_func_used(save_agg_func);
964 }
965 if (unlikely(error)) {
966 DBUG_PRINT("info", ("Field in partition function not part of table"));
967 clear_field_flag(table);
968 goto end;
969 }
970 if (unlikely(func_expr->const_item())) {
971 my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
972 clear_field_flag(table);
973 goto end;
974 }
975
976 /*
977 We don't allow creating partitions with expressions with non matching
978 arguments as a (sub)partitioning function,
979 but we want to allow such expressions when opening existing tables for
980 easier maintenance. This exception should be deprecated at some point
981 in future so that we always throw an error.
982 */
983 if (func_expr->walk(&Item::check_valid_arguments_processor,
984 enum_walk::POSTFIX, nullptr)) {
985 if (is_create_table_ind) {
986 my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0));
987 goto end;
988 } else
989 push_warning(thd, Sql_condition::SL_WARNING,
990 ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR,
991 ER_THD(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR));
992 }
993
994 if ((!is_sub_part) && (error = check_signed_flag(part_info))) goto end;
995 result = set_up_field_array(table, is_sub_part);
996 end:
997 end_lex_with_single_table(thd, table, old_lex);
998 #if !defined(DBUG_OFF)
999 Item_ident::Change_context nul_ctx(nullptr);
1000 func_expr->walk(&Item::change_context_processor, enum_walk::POSTFIX,
1001 (uchar *)&nul_ctx);
1002 #endif
1003 return result;
1004 }
1005
1006 /*
1007 Check that the primary key contains all partition fields if defined
1008
1009 SYNOPSIS
1010 check_primary_key()
1011 table TABLE object for which partition fields are set-up
1012
1013 RETURN VALUES
1014 true Not all fields in partitioning function was part
1015 of primary key
1016 false Ok, all fields of partitioning function were part
1017 of primary key
1018
1019 DESCRIPTION
1020 This function verifies that if there is a primary key that it contains
1021 all the fields of the partition function.
1022 This is a temporary limitation that will hopefully be removed after a
1023 while.
1024 */
1025
check_primary_key(TABLE * table)1026 static bool check_primary_key(TABLE *table) {
1027 uint primary_key = table->s->primary_key;
1028 bool all_fields, some_fields;
1029 bool result = false;
1030 DBUG_TRACE;
1031
1032 if (primary_key < MAX_KEY) {
1033 set_indicator_in_key_fields(table->key_info + primary_key);
1034 check_fields_in_PF(table->part_info->full_part_field_array, &all_fields,
1035 &some_fields);
1036 clear_indicator_in_key_fields(table->key_info + primary_key);
1037 if (unlikely(!all_fields)) {
1038 my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, MYF(0), "PRIMARY KEY");
1039 result = true;
1040 }
1041 }
1042 return result;
1043 }
1044
1045 /*
1046 Check that unique keys contains all partition fields
1047
1048 SYNOPSIS
1049 check_unique_keys()
1050 table TABLE object for which partition fields are set-up
1051
1052 RETURN VALUES
1053 true Not all fields in partitioning function was part
1054 of all unique keys
1055 false Ok, all fields of partitioning function were part
1056 of unique keys
1057
1058 DESCRIPTION
1059 This function verifies that if there is a unique index that it contains
1060 all the fields of the partition function.
1061 This is a temporary limitation that will hopefully be removed after a
1062 while.
1063 */
1064
check_unique_keys(TABLE * table)1065 static bool check_unique_keys(TABLE *table) {
1066 bool all_fields, some_fields;
1067 bool result = false;
1068 uint keys = table->s->keys;
1069 uint i;
1070 DBUG_TRACE;
1071
1072 for (i = 0; i < keys; i++) {
1073 if (table->key_info[i].flags & HA_NOSAME) // Unique index
1074 {
1075 set_indicator_in_key_fields(table->key_info + i);
1076 check_fields_in_PF(table->part_info->full_part_field_array, &all_fields,
1077 &some_fields);
1078 clear_indicator_in_key_fields(table->key_info + i);
1079 if (unlikely(!all_fields)) {
1080 my_error(ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, MYF(0), "UNIQUE INDEX");
1081 result = true;
1082 break;
1083 }
1084 }
1085 }
1086 return result;
1087 }
1088
1089 /*
1090 An important optimisation is whether a range on a field can select a subset
1091 of the partitions.
1092 A prerequisite for this to happen is that the PF is a growing function OR
1093 a shrinking function.
1094 This can never happen for a multi-dimensional PF. Thus this can only happen
1095 with PF with at most one field involved in the PF.
1096 The idea is that if the function is a growing function and you know that
1097 the field of the PF is 4 <= A <= 6 then we can convert this to a range
1098 in the PF instead by setting the range to PF(4) <= PF(A) <= PF(6). In the
1099 case of RANGE PARTITIONING and LIST PARTITIONING this can be used to
1100 calculate a set of partitions rather than scanning all of them.
1101 Thus the following prerequisites are there to check if sets of partitions
1102 can be found.
1103 1) Only possible for RANGE and LIST partitioning (not for subpartitioning)
1104 2) Only possible if PF only contains 1 field
1105 3) Possible if PF is a growing function of the field
1106 4) Possible if PF is a shrinking function of the field
1107 OBSERVATION:
1108 1) IF f1(A) is a growing function AND f2(A) is a growing function THEN
1109 f1(A) + f2(A) is a growing function
1110 f1(A) * f2(A) is a growing function if f1(A) >= 0 and f2(A) >= 0
1111 2) IF f1(A) is a growing function and f2(A) is a shrinking function THEN
1112 f1(A) / f2(A) is a growing function if f1(A) >= 0 and f2(A) > 0
1113 3) IF A is a growing function then a function f(A) that removes the
1114 least significant portion of A is a growing function
1115 E.g. DATE(datetime) is a growing function
1116 MONTH(datetime) is not a growing/shrinking function
1117 4) IF f1(A) is a growing function and f2(A) is a growing function THEN
1118 f1(f2(A)) and f2(f1(A)) are also growing functions
1119 5) IF f1(A) is a shrinking function and f2(A) is a growing function THEN
1120 f1(f2(A)) is a shrinking function and f2(f1(A)) is a shrinking function
1121 6) f1(A) = A is a growing function
1122 7) f1(A) = A*a + b (where a and b are constants) is a growing function
1123
1124 By analysing the item tree of the PF we can use these deducements and
1125 derive whether the PF is a growing function or a shrinking function or
1126 neither of it.
1127
1128 If the PF is range capable then a flag is set on the table object
1129 indicating this to notify that we can use also ranges on the field
1130 of the PF to deduce a set of partitions if the fields of the PF were
1131 not all fully bound.
1132
1133 SYNOPSIS
1134 check_range_capable_PF()
1135
1136 DESCRIPTION
1137 Support for this is not implemented yet.
1138 */
1139
check_range_capable_PF(TABLE *)1140 static void check_range_capable_PF(TABLE *) { DBUG_TRACE; }
1141
1142 /**
1143 Set up partition bitmaps
1144
1145 @param part_info Reference to partitioning data structure
1146
1147 @return Operation status
1148 @retval true Memory allocation failure
1149 @retval false Success
1150
1151 Allocate memory for bitmaps of the partitioned table
1152 and initialise it.
1153 */
1154
set_up_partition_bitmaps(partition_info * part_info)1155 static bool set_up_partition_bitmaps(partition_info *part_info) {
1156 DBUG_TRACE;
1157
1158 DBUG_ASSERT(!part_info->bitmaps_are_initialized);
1159
1160 if (part_info->init_partition_bitmap(&part_info->read_partitions,
1161 &part_info->table->mem_root))
1162 return true;
1163 if (part_info->init_partition_bitmap(&part_info->lock_partitions,
1164 &part_info->table->mem_root))
1165 return true;
1166
1167 part_info->bitmaps_are_initialized = true;
1168 part_info->set_partition_bitmaps(nullptr);
1169 return false;
1170 }
1171
1172 /*
1173 Set up partition key maps
1174
1175 SYNOPSIS
1176 set_up_partition_key_maps()
1177 table TABLE object for which partition fields are set-up
1178 part_info Reference to partitioning data structure
1179
1180 RETURN VALUES
1181 None
1182
1183 DESCRIPTION
1184 This function sets up a couple of key maps to be able to quickly check
1185 if an index ever can be used to deduce the partition fields or even
1186 a part of the fields of the partition function.
1187 We set up the following key_map's.
1188 PF = Partition Function
1189 1) All fields of the PF is set even by equal on the first fields in the
1190 key
1191 2) All fields of the PF is set if all fields of the key is set
1192 3) At least one field in the PF is set if all fields is set
1193 4) At least one field in the PF is part of the key
1194 */
1195
set_up_partition_key_maps(TABLE * table,partition_info * part_info)1196 static void set_up_partition_key_maps(TABLE *table, partition_info *part_info) {
1197 uint keys = table->s->keys;
1198 uint i;
1199 bool all_fields, some_fields;
1200 DBUG_TRACE;
1201
1202 part_info->all_fields_in_PF.clear_all();
1203 part_info->all_fields_in_PPF.clear_all();
1204 part_info->all_fields_in_SPF.clear_all();
1205 part_info->some_fields_in_PF.clear_all();
1206 for (i = 0; i < keys; i++) {
1207 set_indicator_in_key_fields(table->key_info + i);
1208 check_fields_in_PF(part_info->full_part_field_array, &all_fields,
1209 &some_fields);
1210 if (all_fields) part_info->all_fields_in_PF.set_bit(i);
1211 if (some_fields) part_info->some_fields_in_PF.set_bit(i);
1212 if (part_info->is_sub_partitioned()) {
1213 check_fields_in_PF(part_info->part_field_array, &all_fields,
1214 &some_fields);
1215 if (all_fields) part_info->all_fields_in_PPF.set_bit(i);
1216 check_fields_in_PF(part_info->subpart_field_array, &all_fields,
1217 &some_fields);
1218 if (all_fields) part_info->all_fields_in_SPF.set_bit(i);
1219 }
1220 clear_indicator_in_key_fields(table->key_info + i);
1221 }
1222 }
1223
1224 /*
1225 Set up function pointers for partition function
1226
1227 SYNOPSIS
1228 set_up_partition_func_pointers()
1229 part_info Reference to partitioning data structure
1230
1231 RETURN VALUE
1232 NONE
1233
1234 DESCRIPTION
1235 Set-up all function pointers for calculation of partition id,
1236 subpartition id and the upper part in subpartitioning. This is to speed up
1237 execution of get_partition_id which is executed once every record to be
1238 written and deleted and twice for updates.
1239 */
1240
set_up_partition_func_pointers(partition_info * part_info)1241 static void set_up_partition_func_pointers(partition_info *part_info) {
1242 DBUG_TRACE;
1243
1244 if (part_info->is_sub_partitioned()) {
1245 part_info->get_partition_id = get_partition_id_with_sub;
1246 if (part_info->part_type == partition_type::RANGE) {
1247 if (part_info->column_list)
1248 part_info->get_part_partition_id = get_partition_id_range_col;
1249 else
1250 part_info->get_part_partition_id = get_partition_id_range;
1251 if (part_info->list_of_subpart_fields) {
1252 if (part_info->linear_hash_ind)
1253 part_info->get_subpartition_id = get_partition_id_linear_key_sub;
1254 else
1255 part_info->get_subpartition_id = get_partition_id_key_sub;
1256 } else {
1257 if (part_info->linear_hash_ind)
1258 part_info->get_subpartition_id = get_partition_id_linear_hash_sub;
1259 else
1260 part_info->get_subpartition_id = get_partition_id_hash_sub;
1261 }
1262 } else /* LIST Partitioning */
1263 {
1264 if (part_info->column_list)
1265 part_info->get_part_partition_id = get_partition_id_list_col;
1266 else
1267 part_info->get_part_partition_id = get_partition_id_list;
1268 if (part_info->list_of_subpart_fields) {
1269 if (part_info->linear_hash_ind)
1270 part_info->get_subpartition_id = get_partition_id_linear_key_sub;
1271 else
1272 part_info->get_subpartition_id = get_partition_id_key_sub;
1273 } else {
1274 if (part_info->linear_hash_ind)
1275 part_info->get_subpartition_id = get_partition_id_linear_hash_sub;
1276 else
1277 part_info->get_subpartition_id = get_partition_id_hash_sub;
1278 }
1279 }
1280 } else /* No subpartitioning */
1281 {
1282 part_info->get_part_partition_id = nullptr;
1283 part_info->get_subpartition_id = nullptr;
1284 if (part_info->part_type == partition_type::RANGE) {
1285 if (part_info->column_list)
1286 part_info->get_partition_id = get_partition_id_range_col;
1287 else
1288 part_info->get_partition_id = get_partition_id_range;
1289 } else if (part_info->part_type == partition_type::LIST) {
1290 if (part_info->column_list)
1291 part_info->get_partition_id = get_partition_id_list_col;
1292 else
1293 part_info->get_partition_id = get_partition_id_list;
1294 } else /* HASH partitioning */
1295 {
1296 if (part_info->list_of_part_fields) {
1297 if (part_info->linear_hash_ind)
1298 part_info->get_partition_id = get_partition_id_linear_key_nosub;
1299 else
1300 part_info->get_partition_id = get_partition_id_key_nosub;
1301 } else {
1302 if (part_info->linear_hash_ind)
1303 part_info->get_partition_id = get_partition_id_linear_hash_nosub;
1304 else
1305 part_info->get_partition_id = get_partition_id_hash_nosub;
1306 }
1307 }
1308 }
1309 /*
1310 We need special functions to handle character sets since they require copy
1311 of field pointers and restore afterwards. For subpartitioned tables we do
1312 the copy and restore individually on the part and subpart parts. For non-
1313 subpartitioned tables we use the same functions as used for the parts part
1314 of subpartioning.
1315 Thus for subpartitioned tables the get_partition_id is always
1316 get_partition_id_with_sub, even when character sets exists.
1317 */
1318 if (part_info->part_charset_field_array) {
1319 if (part_info->is_sub_partitioned()) {
1320 DBUG_ASSERT(part_info->get_part_partition_id);
1321 if (!part_info->column_list) {
1322 part_info->get_part_partition_id_charset =
1323 part_info->get_part_partition_id;
1324 part_info->get_part_partition_id = get_part_id_charset_func_part;
1325 }
1326 } else {
1327 DBUG_ASSERT(part_info->get_partition_id);
1328 if (!part_info->column_list) {
1329 part_info->get_part_partition_id_charset = part_info->get_partition_id;
1330 part_info->get_part_partition_id = get_part_id_charset_func_part;
1331 }
1332 }
1333 }
1334 if (part_info->subpart_charset_field_array) {
1335 DBUG_ASSERT(part_info->get_subpartition_id);
1336 part_info->get_subpartition_id_charset = part_info->get_subpartition_id;
1337 part_info->get_subpartition_id = get_part_id_charset_func_subpart;
1338 }
1339 }
1340
1341 /*
1342 For linear hashing we need a mask which is on the form 2**n - 1 where
1343 2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7.
1344
1345 SYNOPSIS
1346 set_linear_hash_mask()
1347 part_info Reference to partitioning data structure
1348 num_parts Number of parts in linear hash partitioning
1349
1350 RETURN VALUE
1351 NONE
1352 */
1353
set_linear_hash_mask(partition_info * part_info,uint num_parts)1354 void set_linear_hash_mask(partition_info *part_info, uint num_parts) {
1355 uint mask;
1356
1357 for (mask = 1; mask < num_parts; mask <<= 1)
1358 ;
1359 part_info->linear_hash_mask = mask - 1;
1360 }
1361
1362 /*
1363 This function calculates the partition id provided the result of the hash
1364 function using linear hashing parameters, mask and number of partitions.
1365
1366 SYNOPSIS
1367 get_part_id_from_linear_hash()
1368 hash_value Hash value calculated by HASH function or KEY function
1369 mask Mask calculated previously by set_linear_hash_mask
1370 num_parts Number of partitions in HASH partitioned part
1371
1372 RETURN VALUE
1373 part_id The calculated partition identity (starting at 0)
1374
1375 DESCRIPTION
1376 The partition is calculated according to the theory of linear hashing.
1377 See e.g. Linear hashing: a new tool for file and table addressing,
1378 Reprinted from VLDB-80 in Readings Database Systems, 2nd ed, M. Stonebraker
1379 (ed.), Morgan Kaufmann 1994.
1380 */
1381
get_part_id_from_linear_hash(longlong hash_value,uint mask,uint num_parts)1382 static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask,
1383 uint num_parts) {
1384 uint32 part_id = (uint32)(hash_value & mask);
1385
1386 if (part_id >= num_parts) {
1387 uint new_mask = ((mask + 1) >> 1) - 1;
1388 part_id = (uint32)(hash_value & new_mask);
1389 }
1390 return part_id;
1391 }
1392
1393 /*
1394 Check if a particular field is in need of character set
1395 handling for partition functions.
1396
1397 SYNOPSIS
1398 field_is_partition_charset()
1399 field The field to check
1400
1401 RETURN VALUES
1402 false Not in need of character set handling
1403 true In need of character set handling
1404 */
1405
field_is_partition_charset(Field * field)1406 bool field_is_partition_charset(Field *field) {
1407 if (!(field->type() == MYSQL_TYPE_STRING) &&
1408 !(field->type() == MYSQL_TYPE_VARCHAR))
1409 return false;
1410 {
1411 const CHARSET_INFO *cs = field->charset();
1412 if (!(field->type() == MYSQL_TYPE_STRING) || !(cs->state & MY_CS_BINSORT))
1413 return true;
1414 return false;
1415 }
1416 }
1417
1418 /*
1419 Check that partition function doesn't contain any forbidden
1420 character sets and collations.
1421
1422 SYNOPSIS
1423 check_part_func_fields()
1424 ptr Array of Field pointers
1425 ok_with_charsets Will we report allowed charset
1426 fields as ok
1427 RETURN VALUES
1428 false Success
1429 true Error
1430
1431 DESCRIPTION
1432 We will check in this routine that the fields of the partition functions
1433 do not contain unallowed parts. It can also be used to check if there
1434 are fields that require special care by calling my_strnxfrm before
1435 calling the functions to calculate partition id.
1436 */
1437
check_part_func_fields(Field ** ptr,bool ok_with_charsets)1438 bool check_part_func_fields(Field **ptr, bool ok_with_charsets) {
1439 Field *field;
1440 DBUG_TRACE;
1441
1442 while ((field = *(ptr++))) {
1443 /*
1444 For CHAR/VARCHAR fields we need to take special precautions.
1445 Binary collation with CHAR is automatically supported. Other
1446 types need some kind of standardisation function handling
1447 */
1448 if (field_is_partition_charset(field)) {
1449 const CHARSET_INFO *cs = field->charset();
1450 if (!ok_with_charsets || cs->mbmaxlen > 1 || cs->strxfrm_multiply > 1) {
1451 return true;
1452 }
1453 }
1454 }
1455 return false;
1456 }
1457
1458 /*
1459 fix partition functions
1460
1461 SYNOPSIS
1462 fix_partition_func()
1463 thd The thread object
1464 table TABLE object for which partition fields are set-up
1465 is_create_table_ind Indicator of whether openfrm was called as part of
1466 CREATE or ALTER TABLE
1467
1468 RETURN VALUE
1469 true Error
1470 false Success
1471
1472 DESCRIPTION
1473 The name parameter contains the full table name and is used to get the
1474 database name of the table which is used to set-up a correct
1475 TABLE_LIST object for use in fix_fields.
1476
1477 NOTES
1478 This function is called as part of opening the table by opening the .frm
1479 file. It is a part of CREATE TABLE to do this so it is quite permissible
1480 that errors due to erroneus syntax isn't found until we come here.
1481 If the user has used a non-existing field in the table is one such example
1482 of an error that is not discovered until here.
1483 */
1484
fix_partition_func(THD * thd,TABLE * table,bool is_create_table_ind)1485 bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) {
1486 bool result = true;
1487 partition_info *part_info = table->part_info;
1488 enum_mark_columns save_mark_used_columns = thd->mark_used_columns;
1489 Partition_handler *part_handler;
1490 const ulong save_want_privilege = thd->want_privilege;
1491 DBUG_TRACE;
1492
1493 if (part_info->fixed) {
1494 return false;
1495 }
1496 thd->mark_used_columns = MARK_COLUMNS_NONE;
1497 thd->want_privilege = 0;
1498
1499 if (!is_create_table_ind || thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
1500 if (partition_default_handling(table, part_info, is_create_table_ind,
1501 table->s->normalized_path.str)) {
1502 return true;
1503 }
1504 }
1505 if (part_info->is_sub_partitioned()) {
1506 DBUG_ASSERT(part_info->subpart_type == partition_type::HASH);
1507 /*
1508 Subpartition is defined. We need to verify that subpartitioning
1509 function is correct.
1510 */
1511 if (part_info->linear_hash_ind)
1512 set_linear_hash_mask(part_info, part_info->num_subparts);
1513 if (part_info->list_of_subpart_fields) {
1514 List_iterator<char> it(part_info->subpart_field_list);
1515 if (unlikely(handle_list_of_fields(it, table, part_info, true))) goto end;
1516 } else {
1517 if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr, table,
1518 true, is_create_table_ind)))
1519 goto end;
1520 if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) {
1521 part_info->report_part_expr_error(true);
1522 goto end;
1523 }
1524 }
1525 }
1526 DBUG_ASSERT(part_info->part_type != partition_type::NONE);
1527 /*
1528 Partition is defined. We need to verify that partitioning
1529 function is correct.
1530 */
1531 if (part_info->part_type == partition_type::HASH) {
1532 if (part_info->linear_hash_ind)
1533 set_linear_hash_mask(part_info, part_info->num_parts);
1534 if (part_info->list_of_part_fields) {
1535 List_iterator<char> it(part_info->part_field_list);
1536 if (unlikely(handle_list_of_fields(it, table, part_info, false)))
1537 goto end;
1538 } else {
1539 if (unlikely(fix_fields_part_func(thd, part_info->part_expr, table, false,
1540 is_create_table_ind)))
1541 goto end;
1542 if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) {
1543 part_info->report_part_expr_error(false);
1544 goto end;
1545 }
1546 }
1547 part_info->fixed = true;
1548 } else {
1549 const char *error_str;
1550 if (part_info->column_list) {
1551 List_iterator<char> it(part_info->part_field_list);
1552 if (unlikely(handle_list_of_fields(it, table, part_info, false)))
1553 goto end;
1554 } else {
1555 if (unlikely(fix_fields_part_func(thd, part_info->part_expr, table, false,
1556 is_create_table_ind)))
1557 goto end;
1558 }
1559 part_info->fixed = true;
1560 if (part_info->part_type == partition_type::RANGE) {
1561 error_str = partition_keywords[PKW_RANGE].str;
1562 if (unlikely(part_info->check_range_constants(thd))) goto end;
1563 } else if (part_info->part_type == partition_type::LIST) {
1564 error_str = partition_keywords[PKW_LIST].str;
1565 if (unlikely(part_info->check_list_constants(thd))) goto end;
1566 } else {
1567 DBUG_ASSERT(0);
1568 my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0));
1569 goto end;
1570 }
1571 if (unlikely(part_info->num_parts < 1)) {
1572 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str);
1573 goto end;
1574 }
1575 if (unlikely(!part_info->column_list &&
1576 part_info->part_expr->result_type() != INT_RESULT)) {
1577 part_info->report_part_expr_error(false);
1578 goto end;
1579 }
1580 }
1581 if (((part_info->part_type != partition_type::HASH ||
1582 part_info->list_of_part_fields == false) &&
1583 !part_info->column_list &&
1584 check_part_func_fields(part_info->part_field_array, true)) ||
1585 (part_info->list_of_subpart_fields == false &&
1586 part_info->is_sub_partitioned() &&
1587 check_part_func_fields(part_info->subpart_field_array, true))) {
1588 /*
1589 Range/List/HASH (but not KEY) and not COLUMNS or HASH subpartitioning
1590 with columns in the partitioning expression using unallowed charset.
1591 */
1592 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1593 goto end;
1594 }
1595 if (unlikely(create_full_part_field_array(thd, table, part_info))) goto end;
1596 if (unlikely(check_primary_key(table))) goto end;
1597 if (unlikely((!(table->s->db_type()->partition_flags &&
1598 (table->s->db_type()->partition_flags() &
1599 HA_CAN_PARTITION_UNIQUE))) &&
1600 check_unique_keys(table)))
1601 goto end;
1602 if (unlikely(set_up_partition_bitmaps(part_info))) goto end;
1603 if (unlikely(part_info->set_up_charset_field_preps())) {
1604 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
1605 goto end;
1606 }
1607 if (unlikely(part_info->check_partition_field_length())) {
1608 my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0));
1609 goto end;
1610 }
1611 check_range_capable_PF(table);
1612 set_up_partition_key_maps(table, part_info);
1613 set_up_partition_func_pointers(part_info);
1614 set_up_range_analysis_info(part_info);
1615 part_handler = table->file->get_partition_handler();
1616 if (part_handler) {
1617 part_handler->set_part_info(part_info, false);
1618 result = false;
1619 } else {
1620 DBUG_ASSERT(0);
1621 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
1622 }
1623 end:
1624 thd->mark_used_columns = save_mark_used_columns;
1625 thd->want_privilege = save_want_privilege;
1626 DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
1627 return result;
1628 }
1629
1630 // TODO: Change this to use streams instead, to make it possible to skip
1631 // temporary files etc. and write directly to a string if wanted.
1632 /*
1633 The code below is support routines for the reverse parsing of the
1634 partitioning syntax. This feature is very useful to generate syntax for
1635 all default values to avoid all default checking when opening the frm
1636 file. It is also used when altering the partitioning by use of various
1637 ALTER TABLE commands. Finally it is used for SHOW CREATE TABLES.
1638 */
1639
add_write(File fptr,const char * buf,size_t len)1640 static int add_write(File fptr, const char *buf, size_t len) {
1641 size_t ret_code =
1642 mysql_file_write(fptr, (const uchar *)buf, len, MYF(MY_FNABP));
1643
1644 if (likely(ret_code == 0))
1645 return 0;
1646 else
1647 return 1;
1648 }
1649
add_string_object(File fptr,String * string)1650 static int add_string_object(File fptr, String *string) {
1651 return add_write(fptr, string->ptr(), string->length());
1652 }
1653
add_string(File fptr,const char * string)1654 static int add_string(File fptr, const char *string) {
1655 return add_write(fptr, string, strlen(string));
1656 }
1657
add_string_len(File fptr,const char * string,size_t len)1658 static int add_string_len(File fptr, const char *string, size_t len) {
1659 return add_write(fptr, string, len);
1660 }
1661
add_space(File fptr)1662 static int add_space(File fptr) { return add_string(fptr, space_str); }
1663
add_comma(File fptr)1664 static int add_comma(File fptr) { return add_string(fptr, comma_str); }
1665
add_equal(File fptr)1666 static int add_equal(File fptr) { return add_string(fptr, equal_str); }
1667
add_end_parenthesis(File fptr)1668 static int add_end_parenthesis(File fptr) {
1669 return add_string(fptr, end_paren_str);
1670 }
1671
add_begin_parenthesis(File fptr)1672 static int add_begin_parenthesis(File fptr) {
1673 return add_string(fptr, begin_paren_str);
1674 }
1675
add_part_key_word(File fptr,const char * key_string)1676 static int add_part_key_word(File fptr, const char *key_string) {
1677 int err = add_string(fptr, key_string);
1678 err += add_space(fptr);
1679 return err;
1680 }
1681
add_partition(File fptr)1682 static int add_partition(File fptr) {
1683 char buff[22];
1684 strxmov(buff, part_str, space_str, NullS);
1685 return add_string(fptr, buff);
1686 }
1687
add_subpartition(File fptr)1688 static int add_subpartition(File fptr) {
1689 int err = add_string(fptr, sub_str);
1690
1691 return err + add_partition(fptr);
1692 }
1693
add_partition_by(File fptr)1694 static int add_partition_by(File fptr) {
1695 char buff[22];
1696 strxmov(buff, part_str, space_str, by_str, space_str, NullS);
1697 return add_string(fptr, buff);
1698 }
1699
add_subpartition_by(File fptr)1700 static int add_subpartition_by(File fptr) {
1701 int err = add_string(fptr, sub_str);
1702
1703 return err + add_partition_by(fptr);
1704 }
1705
1706 /**
1707 Append field list to string.
1708
1709 Used by KEY and COLUMNS partitioning.
1710
1711 @param[in] thd Thread handle.
1712 @param[in,out] str String to append.
1713 @param[in] field_list List of field names to append.
1714
1715 @return false if success, else true.
1716 */
1717
append_field_list(THD * thd,String * str,List<char> field_list)1718 static bool append_field_list(THD *thd, String *str, List<char> field_list) {
1719 uint i, num_fields;
1720
1721 List_iterator<char> part_it(field_list);
1722 num_fields = field_list.elements;
1723 i = 0;
1724 ulonglong save_options = thd->variables.option_bits;
1725 thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
1726 while (i < num_fields) {
1727 const char *field_str = part_it++;
1728 append_identifier(thd, str, field_str, strlen(field_str));
1729 if (i != (num_fields - 1)) {
1730 if (str->append(',')) {
1731 thd->variables.option_bits = save_options;
1732 return true;
1733 }
1734 }
1735 i++;
1736 }
1737 thd->variables.option_bits = save_options;
1738 return false;
1739 }
1740
add_part_field_list(File fptr,List<char> field_list)1741 static int add_part_field_list(File fptr, List<char> field_list) {
1742 int err = 0;
1743 THD *thd = current_thd;
1744 String str("", 0, system_charset_info);
1745
1746 err += add_begin_parenthesis(fptr);
1747 if (append_field_list(thd, &str, field_list)) {
1748 err++;
1749 }
1750 err += add_string_object(fptr, &str);
1751 err += add_end_parenthesis(fptr);
1752 return err;
1753 }
1754
add_ident_string(File fptr,const char * name)1755 static int add_ident_string(File fptr, const char *name) {
1756 String name_string("", 0, system_charset_info);
1757 append_identifier(current_thd, &name_string, name, strlen(name));
1758 return add_string_object(fptr, &name_string);
1759 }
1760
add_name_string(File fptr,const char * name)1761 static int add_name_string(File fptr, const char *name) {
1762 int err;
1763 THD *thd = current_thd;
1764 ulonglong save_options = thd->variables.option_bits;
1765 thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;
1766 err = add_ident_string(fptr, name);
1767 thd->variables.option_bits = save_options;
1768 return err;
1769 }
1770
add_int(File fptr,longlong number)1771 static int add_int(File fptr, longlong number) {
1772 char buff[32];
1773 llstr(number, buff);
1774 return add_string(fptr, buff);
1775 }
1776
add_uint(File fptr,ulonglong number)1777 static int add_uint(File fptr, ulonglong number) {
1778 char buff[32];
1779 ullstr(number, buff);
1780 return add_string(fptr, buff);
1781 }
1782
1783 /*
1784 Must escape strings in partitioned tables frm-files,
1785 parsing it later with mysql_unpack_partition will fail otherwise.
1786 */
add_quoted_string(File fptr,const char * quotestr)1787 static int add_quoted_string(File fptr, const char *quotestr) {
1788 String orgstr(quotestr, system_charset_info);
1789 String escapedstr;
1790 int err = add_string(fptr, "'");
1791 err += append_escaped(&escapedstr, &orgstr);
1792 err += add_string(fptr, escapedstr.c_ptr_safe());
1793 return err + add_string(fptr, "'");
1794 }
1795
1796 /** Truncate the partition file name from a path if it exists.
1797
1798 A partition file name will contain one or more '#' characters.
1799 One of the occurrences of '#' will be either "#P#" or "#p#" depending
1800 on whether the storage engine has converted the filename to lower case.
1801 If we need to truncate the name, we will allocate a new string and replace
1802 with, in case the original string was owned by something else.
1803
1804 @param[in] root MEM_ROOT to allocate from. If NULL alter the string
1805 directly.
1806 @param[in,out] path Pointer to string to check and truncate.
1807 */
truncate_partition_filename(MEM_ROOT * root,const char ** path)1808 void truncate_partition_filename(MEM_ROOT *root, const char **path) {
1809 if (*path) {
1810 const char *last_slash = strrchr(*path, FN_LIBCHAR);
1811
1812 #ifdef _WIN32
1813 if (!last_slash) last_slash = strrchr(*path, FN_LIBCHAR2);
1814 #endif
1815
1816 if (last_slash) {
1817 /* Look for a partition-type filename */
1818 for (const char *pound = strchr(last_slash, '#'); pound;
1819 pound = strchr(pound + 1, '#')) {
1820 if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#') {
1821 if (root == nullptr) {
1822 char *p = const_cast<char *>(last_slash);
1823 *p = '\0';
1824 } else {
1825 *path = strmake_root(root, *path, last_slash - *path);
1826 }
1827 break;
1828 }
1829 }
1830 }
1831 }
1832 }
1833
1834 /**
1835 @brief Output a filepath. Similar to add_keyword_string except it
1836 also converts \ to / on Windows and skips the partition file name at
1837 the end if found.
1838
1839 @note When Mysql sends a DATA DIRECTORY from SQL for partitions it does
1840 not use a file name, but it does for DATA DIRECTORY on a non-partitioned
1841 table. So when the storage engine is asked for the DATA DIRECTORY string
1842 after a restart through Handler::update_create_options(), the storage
1843 engine may include the filename.
1844 */
add_keyword_path(File fptr,const char * keyword,const char * path)1845 static int add_keyword_path(File fptr, const char *keyword, const char *path) {
1846 if (strlen(path) >= FN_REFLEN) {
1847 my_error(ER_PATH_LENGTH, MYF(0), keyword);
1848 return 1;
1849 }
1850
1851 int err = add_string(fptr, keyword);
1852
1853 err += add_space(fptr);
1854 err += add_equal(fptr);
1855 err += add_space(fptr);
1856
1857 char temp_path[FN_REFLEN];
1858 const char *temp_path_p[1];
1859 temp_path_p[0] = temp_path;
1860 strncpy(temp_path, path, FN_REFLEN - 1);
1861 temp_path[FN_REFLEN - 1] = '\0';
1862 #ifdef _WIN32
1863 /* Convert \ to / to be able to create table on unix */
1864 char *pos, *end;
1865 size_t length = strlen(temp_path);
1866 for (pos = temp_path, end = pos + length; pos < end; pos++) {
1867 if (*pos == '\\') *pos = '/';
1868 }
1869 #endif
1870
1871 /*
1872 If the partition file name with its "#P#" identifier
1873 is found after the last slash, truncate that filename.
1874 */
1875 truncate_partition_filename(nullptr, temp_path_p);
1876
1877 err += add_quoted_string(fptr, temp_path);
1878
1879 return err + add_space(fptr);
1880 }
1881
add_keyword_string(File fptr,const char * keyword,bool should_use_quotes,const char * keystr)1882 static int add_keyword_string(File fptr, const char *keyword,
1883 bool should_use_quotes, const char *keystr) {
1884 int err = add_string(fptr, keyword);
1885
1886 err += add_space(fptr);
1887 err += add_equal(fptr);
1888 err += add_space(fptr);
1889 if (should_use_quotes)
1890 err += add_quoted_string(fptr, keystr);
1891 else
1892 err += add_string(fptr, keystr);
1893 return err + add_space(fptr);
1894 }
1895
add_keyword_int(File fptr,const char * keyword,longlong num)1896 static int add_keyword_int(File fptr, const char *keyword, longlong num) {
1897 int err = add_string(fptr, keyword);
1898
1899 err += add_space(fptr);
1900 err += add_equal(fptr);
1901 err += add_space(fptr);
1902 err += add_int(fptr, num);
1903 return err + add_space(fptr);
1904 }
1905
add_engine(File fptr,handlerton * engine_type)1906 static int add_engine(File fptr, handlerton *engine_type) {
1907 const char *engine_str = ha_resolve_storage_engine_name(engine_type);
1908 DBUG_ASSERT(engine_type != nullptr);
1909 DBUG_PRINT("info", ("ENGINE: %s", engine_str));
1910 int err = add_string(fptr, "ENGINE = ");
1911 return err + add_string(fptr, engine_str);
1912 }
1913
add_partition_options(File fptr,partition_element * p_elem)1914 static int add_partition_options(File fptr, partition_element *p_elem) {
1915 int err = 0;
1916
1917 err += add_space(fptr);
1918 if (p_elem->tablespace_name) {
1919 err += add_string(fptr, "TABLESPACE = ");
1920 err += add_ident_string(fptr, p_elem->tablespace_name);
1921 err += add_space(fptr);
1922 }
1923 if (p_elem->nodegroup_id != UNDEF_NODEGROUP)
1924 err += add_keyword_int(fptr, "NODEGROUP", (longlong)p_elem->nodegroup_id);
1925 if (p_elem->part_max_rows)
1926 err += add_keyword_int(fptr, "MAX_ROWS", (longlong)p_elem->part_max_rows);
1927 if (p_elem->part_min_rows)
1928 err += add_keyword_int(fptr, "MIN_ROWS", (longlong)p_elem->part_min_rows);
1929 if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) {
1930 if (p_elem->data_file_name)
1931 err += add_keyword_path(fptr, "DATA DIRECTORY", p_elem->data_file_name);
1932 if (p_elem->index_file_name)
1933 err += add_keyword_path(fptr, "INDEX DIRECTORY", p_elem->index_file_name);
1934 }
1935 if (p_elem->part_comment)
1936 err += add_keyword_string(fptr, "COMMENT", true, p_elem->part_comment);
1937 return err + add_engine(fptr, p_elem->engine_type);
1938 }
1939
1940 /*
1941 Check partition fields for result type and if they need
1942 to check the character set.
1943
1944 SYNOPSIS
1945 check_part_field()
1946 sql_type Type provided by user
1947 field_name Name of field, used for error handling
1948 result_type Out value: Result type of field
1949 need_cs_check Out value: Do we need character set check
1950
1951 RETURN VALUES
1952 true Error
1953 false Ok
1954 */
1955
check_part_field(enum_field_types sql_type,const char * field_name,Item_result * result_type,bool * need_cs_check)1956 static int check_part_field(enum_field_types sql_type, const char *field_name,
1957 Item_result *result_type, bool *need_cs_check) {
1958 if (sql_type >= MYSQL_TYPE_TINY_BLOB && sql_type <= MYSQL_TYPE_BLOB) {
1959 my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
1960 return true;
1961 }
1962 switch (sql_type) {
1963 case MYSQL_TYPE_TINY:
1964 case MYSQL_TYPE_SHORT:
1965 case MYSQL_TYPE_LONG:
1966 case MYSQL_TYPE_LONGLONG:
1967 case MYSQL_TYPE_INT24:
1968 *result_type = INT_RESULT;
1969 *need_cs_check = false;
1970 return false;
1971 case MYSQL_TYPE_NEWDATE:
1972 case MYSQL_TYPE_DATE:
1973 case MYSQL_TYPE_TIME:
1974 case MYSQL_TYPE_DATETIME:
1975 case MYSQL_TYPE_TIME2:
1976 case MYSQL_TYPE_DATETIME2:
1977 *result_type = STRING_RESULT;
1978 *need_cs_check = true;
1979 return false;
1980 case MYSQL_TYPE_VARCHAR:
1981 case MYSQL_TYPE_STRING:
1982 case MYSQL_TYPE_VAR_STRING:
1983 *result_type = STRING_RESULT;
1984 *need_cs_check = true;
1985 return false;
1986 case MYSQL_TYPE_NEWDECIMAL:
1987 case MYSQL_TYPE_DECIMAL:
1988 case MYSQL_TYPE_TIMESTAMP:
1989 case MYSQL_TYPE_TIMESTAMP2:
1990 case MYSQL_TYPE_NULL:
1991 case MYSQL_TYPE_FLOAT:
1992 case MYSQL_TYPE_DOUBLE:
1993 case MYSQL_TYPE_BIT:
1994 case MYSQL_TYPE_ENUM:
1995 case MYSQL_TYPE_SET:
1996 case MYSQL_TYPE_GEOMETRY:
1997 goto error;
1998 default:
1999 goto error;
2000 }
2001 error:
2002 my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), field_name);
2003 return true;
2004 }
2005
2006 /*
2007 Find the given field's Create_field object using name of field
2008
2009 SYNOPSIS
2010 get_sql_field()
2011 field_name Field name
2012 create_fields Info from ALTER TABLE/CREATE TABLE
2013
2014 RETURN VALUE
2015 sql_field Object filled in by parser about field
2016 NULL No field found
2017 */
2018
get_sql_field(const char * field_name,List<Create_field> * create_fields)2019 static Create_field *get_sql_field(const char *field_name,
2020 List<Create_field> *create_fields) {
2021 List_iterator<Create_field> it(*create_fields);
2022 Create_field *sql_field;
2023 DBUG_TRACE;
2024
2025 while ((sql_field = it++)) {
2026 if (!(my_strcasecmp(system_charset_info, sql_field->field_name,
2027 field_name))) {
2028 return sql_field;
2029 }
2030 }
2031 return nullptr;
2032 }
2033
expr_to_string(String * val_conv,Item * item_expr,Field * field,const char * field_name,const HA_CREATE_INFO * create_info,List<Create_field> * create_fields)2034 int expr_to_string(String *val_conv, Item *item_expr, Field *field,
2035 const char *field_name, const HA_CREATE_INFO *create_info,
2036 List<Create_field> *create_fields) {
2037 char buffer[MAX_KEY_LENGTH];
2038 String str(buffer, sizeof(buffer), &my_charset_bin);
2039 String *res;
2040 const CHARSET_INFO *field_cs;
2041 bool need_cs_check = false;
2042 Item_result result_type = STRING_RESULT;
2043
2044 /*
2045 This function is called at a very early stage, even before
2046 we have prepared the sql_field objects. Thus we have to
2047 find the proper sql_field object and get the character set
2048 from that object.
2049 */
2050 if (create_info) {
2051 Create_field *sql_field;
2052
2053 if (!(sql_field = get_sql_field(field_name, create_fields))) {
2054 my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
2055 return 1;
2056 }
2057 if (check_part_field(sql_field->sql_type, sql_field->field_name,
2058 &result_type, &need_cs_check))
2059 return 1;
2060 if (need_cs_check)
2061 field_cs = get_sql_field_charset(sql_field, create_info);
2062 else
2063 field_cs = nullptr;
2064 } else {
2065 result_type = field->result_type();
2066 if (check_part_field(field->real_type(), field->field_name, &result_type,
2067 &need_cs_check))
2068 return 1;
2069 DBUG_ASSERT(result_type == field->result_type());
2070 if (need_cs_check)
2071 field_cs = field->charset();
2072 else
2073 field_cs = nullptr;
2074 }
2075 if (result_type != item_expr->result_type()) {
2076 my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
2077 return 1;
2078 }
2079 if (field_cs && field_cs != item_expr->collation.collation) {
2080 if (!(item_expr =
2081 convert_charset_partition_constant(item_expr, field_cs))) {
2082 my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
2083 return 1;
2084 }
2085 }
2086 val_conv->set_charset(system_charset_info);
2087 res = item_expr->val_str(&str);
2088 if (get_cs_converted_part_value_from_string(current_thd, item_expr, res,
2089 val_conv, field_cs, false)) {
2090 return 1;
2091 }
2092 return 0;
2093 }
2094
add_column_list_values(File fptr,partition_info * part_info,part_elem_value * list_value)2095 static int add_column_list_values(File fptr, partition_info *part_info,
2096 part_elem_value *list_value) {
2097 int err = 0;
2098 uint i;
2099 uint num_elements = part_info->part_field_list.elements;
2100 bool use_parenthesis = (part_info->part_type == partition_type::LIST &&
2101 part_info->num_columns > 1U);
2102
2103 if (use_parenthesis) err += add_begin_parenthesis(fptr);
2104 for (i = 0; i < num_elements; i++) {
2105 part_column_list_val *col_val = &list_value->col_val_array[i];
2106 if (col_val->max_value)
2107 err += add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
2108 else if (col_val->null_value)
2109 err += add_string(fptr, "NULL");
2110 else {
2111 char buffer[MAX_KEY_LENGTH];
2112 String str(buffer, sizeof(buffer), &my_charset_bin);
2113 Item *item_expr = col_val->item_expression;
2114 if (!item_expr) {
2115 /*
2116 The values are not from the parser, but from the
2117 dd::Partition_values table. See fill_partitioning_from_dd().
2118 */
2119 DBUG_ASSERT(col_val->column_value.value_str);
2120 err += add_string(fptr, col_val->column_value.value_str);
2121 } else if (item_expr->null_value) {
2122 err += add_string(fptr, "NULL");
2123 } else {
2124 String val_conv;
2125 err +=
2126 expr_to_string(&val_conv, item_expr, part_info->part_field_array[i],
2127 nullptr, nullptr, nullptr);
2128 err += add_string_object(fptr, &val_conv);
2129 }
2130 }
2131 if (i != (num_elements - 1)) err += add_string(fptr, comma_str);
2132 }
2133 if (use_parenthesis) err += add_end_parenthesis(fptr);
2134 return err;
2135 }
2136
add_partition_values(File fptr,partition_info * part_info,partition_element * p_elem)2137 static int add_partition_values(File fptr, partition_info *part_info,
2138 partition_element *p_elem) {
2139 int err = 0;
2140
2141 if (part_info->part_type == partition_type::RANGE) {
2142 err += add_string(fptr, " VALUES LESS THAN ");
2143 if (part_info->column_list) {
2144 List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2145 part_elem_value *list_value = list_val_it++;
2146 err += add_begin_parenthesis(fptr);
2147 err += add_column_list_values(fptr, part_info, list_value);
2148 err += add_end_parenthesis(fptr);
2149 } else {
2150 if (!p_elem->max_value) {
2151 err += add_begin_parenthesis(fptr);
2152 if (p_elem->signed_flag)
2153 err += add_int(fptr, p_elem->range_value);
2154 else
2155 err += add_uint(fptr, p_elem->range_value);
2156 err += add_end_parenthesis(fptr);
2157 } else
2158 err += add_string(fptr, partition_keywords[PKW_MAXVALUE].str);
2159 }
2160 } else if (part_info->part_type == partition_type::LIST) {
2161 uint i;
2162 List_iterator<part_elem_value> list_val_it(p_elem->list_val_list);
2163 err += add_string(fptr, " VALUES IN ");
2164 uint num_items = p_elem->list_val_list.elements;
2165
2166 err += add_begin_parenthesis(fptr);
2167 if (p_elem->has_null_value) {
2168 err += add_string(fptr, "NULL");
2169 if (num_items == 0) {
2170 err += add_end_parenthesis(fptr);
2171 goto end;
2172 }
2173 err += add_comma(fptr);
2174 }
2175 i = 0;
2176 do {
2177 part_elem_value *list_value = list_val_it++;
2178
2179 if (part_info->column_list)
2180 err += add_column_list_values(fptr, part_info, list_value);
2181 else {
2182 if (!list_value->unsigned_flag)
2183 err += add_int(fptr, list_value->value);
2184 else
2185 err += add_uint(fptr, list_value->value);
2186 }
2187 if (i != (num_items - 1)) err += add_comma(fptr);
2188 } while (++i < num_items);
2189 err += add_end_parenthesis(fptr);
2190 }
2191 end:
2192 return err;
2193 }
2194
2195 /**
2196 Add 'KEY' word, with optional 'ALGORTIHM = N'.
2197
2198 @param fptr File to write to.
2199 @param part_info partition_info holding the used key_algorithm
2200 @param current_comment_start NULL, or comment string encapsulating the
2201 PARTITION BY clause.
2202
2203 @return Operation status.
2204 @retval 0 Success
2205 @retval != 0 Failure
2206 */
2207
add_key_with_algorithm(File fptr,partition_info * part_info,const char * current_comment_start)2208 static int add_key_with_algorithm(File fptr, partition_info *part_info,
2209 const char *current_comment_start) {
2210 int err = 0;
2211 err += add_part_key_word(fptr, partition_keywords[PKW_KEY].str);
2212
2213 /*
2214 current_comment_start is given when called from SHOW CREATE TABLE,
2215 Then only add ALGORITHM = 1, not the default 2 or non-set 0!
2216 For .frm current_comment_start is NULL, then add ALGORITHM if != 0.
2217 */
2218 if (part_info->key_algorithm ==
2219 enum_key_algorithm::KEY_ALGORITHM_51 || // SHOW
2220 (!current_comment_start && // .frm
2221 (part_info->key_algorithm != enum_key_algorithm::KEY_ALGORITHM_NONE))) {
2222 /* If we already are within a comment, end that comment first. */
2223 if (current_comment_start) err += add_string(fptr, "*/ ");
2224 err += add_string(fptr, "/*!50611 ");
2225 err += add_part_key_word(fptr, partition_keywords[PKW_ALGORITHM].str);
2226 err += add_equal(fptr);
2227 err += add_space(fptr);
2228 err += add_int(fptr, static_cast<longlong>(part_info->key_algorithm));
2229 err += add_space(fptr);
2230 err += add_string(fptr, "*/ ");
2231 if (current_comment_start) {
2232 /* Skip new line. */
2233 if (current_comment_start[0] == '\n') current_comment_start++;
2234 err += add_string(fptr, current_comment_start);
2235 err += add_space(fptr);
2236 }
2237 }
2238 return err;
2239 }
2240
get_file_content(File fptr,uint * buf_length,bool use_sql_alloc)2241 static char *get_file_content(File fptr, uint *buf_length, bool use_sql_alloc) {
2242 my_off_t buffer_length;
2243 char *buf;
2244 buffer_length = mysql_file_seek(fptr, 0L, MY_SEEK_END, MYF(0));
2245 if (unlikely(buffer_length == MY_FILEPOS_ERROR)) return nullptr;
2246 if (unlikely(mysql_file_seek(fptr, 0L, MY_SEEK_SET, MYF(0)) ==
2247 MY_FILEPOS_ERROR))
2248 return nullptr;
2249 *buf_length = (uint)buffer_length;
2250 if (use_sql_alloc)
2251 buf = (char *)(*THR_MALLOC)->Alloc(*buf_length + 1);
2252 else
2253 buf = (char *)my_malloc(key_memory_partition_syntax_buffer, *buf_length + 1,
2254 MYF(MY_WME));
2255 if (!buf) return nullptr;
2256
2257 if (unlikely(
2258 mysql_file_read(fptr, (uchar *)buf, *buf_length, MYF(MY_FNABP)))) {
2259 if (!use_sql_alloc) my_free(buf);
2260 buf = nullptr;
2261 } else
2262 buf[*buf_length] = 0;
2263 return buf;
2264 }
2265
2266 /**
2267 Generate the partition syntax from the partition data structure.
2268 Useful for support of generating defaults, SHOW CREATE TABLES
2269 and easy partition management.
2270
2271 @param part_info The partitioning data structure
2272 @param buf_length A pointer to the returned buffer length
2273 @param use_sql_alloc Allocate buffer from sql_alloc if true
2274 otherwise use my_malloc
2275 @param show_partition_options Should we display partition options
2276 @param print_expr Indicates whether partitioning expressions
2277 should be re-printed to get quoting according
2278 to current sql_mode.
2279 @param current_comment_start NULL, or comment string encapsulating the
2280 PARTITION BY clause.
2281
2282 @retval NULL - error
2283
2284 @note
2285 Here we will generate the full syntax for the given command where all
2286 defaults have been expanded. By so doing the it is also possible to
2287 make lots of checks of correctness while at it.
2288 This could will also be reused for SHOW CREATE TABLES and also for all
2289 type ALTER TABLE commands focusing on changing the PARTITION structure
2290 in any fashion.
2291
2292 The implementation writes the syntax to a temporary file (essentially
2293 an abstraction of a dynamic array) and if all writes goes well it
2294 allocates a buffer and writes the syntax into this one and returns it.
2295
2296 As a security precaution the file is deleted before writing into it. This
2297 means that no other processes on the machine can open and read the file
2298 while this processing is ongoing.
2299
2300 The code is optimised for minimal code size since it is not used in any
2301 common queries.
2302 */
2303
generate_partition_syntax(partition_info * part_info,uint * buf_length,bool use_sql_alloc,bool show_partition_options,bool print_expr,const char * current_comment_start)2304 char *generate_partition_syntax(partition_info *part_info, uint *buf_length,
2305 bool use_sql_alloc, bool show_partition_options,
2306 bool print_expr,
2307 const char *current_comment_start) {
2308 uint i, j, tot_num_parts, num_subparts;
2309 partition_element *part_elem;
2310 int err = 0;
2311 List_iterator<partition_element> part_it(part_info->partitions);
2312 File fptr;
2313 char *buf = nullptr; // Return buffer
2314 DBUG_TRACE;
2315
2316 if (!(fptr = mysql_tmpfile("psy"))) {
2317 return nullptr;
2318 }
2319 err += add_space(fptr);
2320 err += add_partition_by(fptr);
2321 switch (part_info->part_type) {
2322 case partition_type::RANGE:
2323 err += add_part_key_word(fptr, partition_keywords[PKW_RANGE].str);
2324 break;
2325 case partition_type::LIST:
2326 err += add_part_key_word(fptr, partition_keywords[PKW_LIST].str);
2327 break;
2328 case partition_type::HASH:
2329 if (part_info->linear_hash_ind)
2330 err += add_string(fptr, partition_keywords[PKW_LINEAR].str);
2331 if (part_info->list_of_part_fields) {
2332 err += add_key_with_algorithm(fptr, part_info, current_comment_start);
2333 err += add_part_field_list(fptr, part_info->part_field_list);
2334 } else
2335 err += add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
2336 break;
2337 default:
2338 DBUG_ASSERT(0);
2339 /* We really shouldn't get here, no use in continuing from here */
2340 my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
2341 return nullptr;
2342 }
2343 if (part_info->part_func_len) {
2344 err += add_begin_parenthesis(fptr);
2345 if (print_expr) {
2346 // Default on-stack buffer which allows to avoid malloc() in most cases.
2347 char expr_buff[256];
2348 String tmp(expr_buff, sizeof(expr_buff), system_charset_info);
2349 tmp.length(0);
2350
2351 // No point in including schema and table name for identifiers
2352 // since any columns must be in this table.
2353 part_info->part_expr->print(
2354 current_thd, &tmp,
2355 enum_query_type(QT_TO_SYSTEM_CHARSET | QT_NO_DB | QT_NO_TABLE));
2356 err += add_string_len(fptr, tmp.ptr(), tmp.length());
2357 } else {
2358 err += add_string_len(fptr, part_info->part_func_string,
2359 part_info->part_func_len);
2360 }
2361 err += add_end_parenthesis(fptr);
2362 } else if (part_info->column_list) {
2363 err += add_string(fptr, partition_keywords[PKW_COLUMNS].str);
2364 err += add_part_field_list(fptr, part_info->part_field_list);
2365 }
2366 if ((!part_info->use_default_num_partitions) &&
2367 part_info->use_default_partitions) {
2368 err += add_string(fptr, "\n");
2369 err += add_string(fptr, "PARTITIONS ");
2370 err += add_int(fptr, part_info->num_parts);
2371 }
2372 if (part_info->is_sub_partitioned()) {
2373 err += add_string(fptr, "\n");
2374 err += add_subpartition_by(fptr);
2375 /* Must be hash partitioning for subpartitioning */
2376 if (part_info->linear_hash_ind)
2377 err += add_string(fptr, partition_keywords[PKW_LINEAR].str);
2378 if (part_info->list_of_subpart_fields) {
2379 err += add_key_with_algorithm(fptr, part_info, current_comment_start);
2380 err += add_part_field_list(fptr, part_info->subpart_field_list);
2381 } else
2382 err += add_part_key_word(fptr, partition_keywords[PKW_HASH].str);
2383 if (part_info->subpart_func_len) {
2384 err += add_begin_parenthesis(fptr);
2385 if (print_expr) {
2386 // Default on-stack buffer which allows to avoid malloc() in most cases.
2387 char expr_buff[256];
2388 String tmp(expr_buff, sizeof(expr_buff), system_charset_info);
2389 tmp.length(0);
2390
2391 // No point in including schema and table name for identifiers
2392 // since any columns must be in this table.
2393 part_info->subpart_expr->print(
2394 current_thd, &tmp,
2395 enum_query_type(QT_TO_SYSTEM_CHARSET | QT_NO_DB | QT_NO_TABLE));
2396 err += add_string_len(fptr, tmp.ptr(), tmp.length());
2397 } else {
2398 err += add_string_len(fptr, part_info->subpart_func_string,
2399 part_info->subpart_func_len);
2400 }
2401 err += add_end_parenthesis(fptr);
2402 }
2403 if ((!part_info->use_default_num_subpartitions) &&
2404 part_info->use_default_subpartitions) {
2405 err += add_string(fptr, "\n");
2406 err += add_string(fptr, "SUBPARTITIONS ");
2407 err += add_int(fptr, part_info->num_subparts);
2408 }
2409 }
2410 tot_num_parts = part_info->partitions.elements;
2411 num_subparts = part_info->num_subparts;
2412
2413 if (!part_info->use_default_partitions) {
2414 bool first = true;
2415 err += add_string(fptr, "\n");
2416 err += add_begin_parenthesis(fptr);
2417 i = 0;
2418 do {
2419 part_elem = part_it++;
2420 if (part_elem->part_state != PART_TO_BE_DROPPED &&
2421 part_elem->part_state != PART_REORGED_DROPPED) {
2422 if (!first) {
2423 err += add_comma(fptr);
2424 err += add_string(fptr, "\n");
2425 err += add_space(fptr);
2426 }
2427 first = false;
2428 err += add_partition(fptr);
2429 err += add_name_string(fptr, part_elem->partition_name);
2430 err += add_partition_values(fptr, part_info, part_elem);
2431 if (!part_info->is_sub_partitioned() ||
2432 part_info->use_default_subpartitions) {
2433 if (show_partition_options)
2434 err += add_partition_options(fptr, part_elem);
2435 } else {
2436 err += add_string(fptr, "\n");
2437 err += add_space(fptr);
2438 err += add_begin_parenthesis(fptr);
2439 List_iterator<partition_element> sub_it(part_elem->subpartitions);
2440 partition_element *sub_elem;
2441 j = 0;
2442 do {
2443 sub_elem = sub_it++;
2444 err += add_subpartition(fptr);
2445 err += add_name_string(fptr, sub_elem->partition_name);
2446 if (show_partition_options)
2447 err += add_partition_options(fptr, sub_elem);
2448 if (j != (num_subparts - 1)) {
2449 err += add_comma(fptr);
2450 err += add_string(fptr, "\n");
2451 err += add_space(fptr);
2452 err += add_space(fptr);
2453 } else
2454 err += add_end_parenthesis(fptr);
2455 } while (++j < num_subparts);
2456 }
2457 }
2458 if (i == (tot_num_parts - 1)) err += add_end_parenthesis(fptr);
2459 } while (++i < tot_num_parts);
2460 }
2461 if (err) goto close_file;
2462 buf = get_file_content(fptr, buf_length, use_sql_alloc);
2463 close_file:
2464 if (buf == nullptr) {
2465 my_error(ER_INTERNAL_ERROR, MYF(0), "Failed to generate partition syntax");
2466 }
2467 mysql_file_close(fptr, MYF(0));
2468 return buf;
2469 }
2470
2471 /*
2472 Check if partition key fields are modified and if it can be handled by the
2473 underlying storage engine.
2474
2475 SYNOPSIS
2476 partition_key_modified
2477 table TABLE object for which partition fields are set-up
2478 fields Bitmap representing fields to be modified
2479
2480 RETURN VALUES
2481 true Need special handling of UPDATE
2482 false Normal UPDATE handling is ok
2483 */
2484
partition_key_modified(TABLE * table,const MY_BITMAP * fields)2485 bool partition_key_modified(TABLE *table, const MY_BITMAP *fields) {
2486 Field **fld;
2487 partition_info *part_info = table->part_info;
2488 DBUG_TRACE;
2489
2490 if (!part_info) return false;
2491 if (table->s->db_type()->partition_flags &&
2492 (table->s->db_type()->partition_flags() & HA_CAN_UPDATE_PARTITION_KEY))
2493 return false;
2494 for (fld = part_info->full_part_field_array; *fld; fld++)
2495 if (bitmap_is_set(fields, (*fld)->field_index())) return true;
2496 return false;
2497 }
2498
2499 /*
2500 A function to handle correct handling of NULL values in partition
2501 functions.
2502 SYNOPSIS
2503 part_val_int()
2504 item_expr The item expression to evaluate
2505 out:result The value of the partition function,
2506 LLONG_MIN if any null value in function
2507 RETURN VALUES
2508 true Error in val_int()
2509 false ok
2510 */
2511
part_val_int(Item * item_expr,longlong * result)2512 static inline int part_val_int(Item *item_expr, longlong *result) {
2513 *result = item_expr->val_int();
2514 if (item_expr->null_value) {
2515 if (current_thd->is_error())
2516 return true;
2517 else
2518 *result = LLONG_MIN;
2519 }
2520 return false;
2521 }
2522
2523 /*
2524 The next set of functions are used to calculate the partition identity.
2525 A handler sets up a variable that corresponds to one of these functions
2526 to be able to quickly call it whenever the partition id needs to calculated
2527 based on the record in table->record[0] (or set up to fake that).
2528 There are 4 functions for hash partitioning and 2 for RANGE/LIST partitions.
2529 In addition there are 4 variants for RANGE subpartitioning and 4 variants
2530 for LIST subpartitioning thus in total there are 14 variants of this
2531 function.
2532
2533 We have a set of support functions for these 14 variants. There are 4
2534 variants of hash functions and there is a function for each. The KEY
2535 partitioning uses the function calculate_key_hash_value to calculate the hash
2536 value based on an array of fields. The linear hash variants uses the
2537 method get_part_id_from_linear_hash to get the partition id using the
2538 hash value and some parameters calculated from the number of partitions.
2539 */
2540
2541 /*
2542 A simple support function to calculate part_id given local part and
2543 sub part.
2544
2545 SYNOPSIS
2546 get_part_id_for_sub()
2547 loc_part_id Local partition id
2548 sub_part_id Subpartition id
2549 num_subparts Number of subparts
2550 */
2551
get_part_id_for_sub(uint32 loc_part_id,uint32 sub_part_id,uint num_subparts)2552 inline static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id,
2553 uint num_subparts) {
2554 return (uint32)((loc_part_id * num_subparts) + sub_part_id);
2555 }
2556
2557 /*
2558 Calculate part_id for (SUB)PARTITION BY HASH
2559
2560 SYNOPSIS
2561 get_part_id_hash()
2562 num_parts Number of hash partitions
2563 part_expr Item tree of hash function
2564 out:part_id The returned partition id
2565 out:func_value Value of hash function
2566
2567 RETURN VALUE
2568 != 0 Error code
2569 false Success
2570 */
2571
get_part_id_hash(uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2572 static int get_part_id_hash(uint num_parts, Item *part_expr, uint32 *part_id,
2573 longlong *func_value) {
2574 longlong int_hash_id;
2575 DBUG_TRACE;
2576
2577 if (part_val_int(part_expr, func_value)) return HA_ERR_NO_PARTITION_FOUND;
2578
2579 int_hash_id = *func_value % num_parts;
2580
2581 *part_id = int_hash_id < 0 ? (uint32)-int_hash_id : (uint32)int_hash_id;
2582 return false;
2583 }
2584
2585 /*
2586 Calculate part_id for (SUB)PARTITION BY LINEAR HASH
2587
2588 SYNOPSIS
2589 get_part_id_linear_hash()
2590 part_info A reference to the partition_info struct where all the
2591 desired information is given
2592 num_parts Number of hash partitions
2593 part_expr Item tree of hash function
2594 out:part_id The returned partition id
2595 out:func_value Value of hash function
2596
2597 RETURN VALUE
2598 != 0 Error code
2599 0 OK
2600 */
2601
get_part_id_linear_hash(partition_info * part_info,uint num_parts,Item * part_expr,uint32 * part_id,longlong * func_value)2602 static int get_part_id_linear_hash(partition_info *part_info, uint num_parts,
2603 Item *part_expr, uint32 *part_id,
2604 longlong *func_value) {
2605 DBUG_TRACE;
2606
2607 if (part_val_int(part_expr, func_value)) return HA_ERR_NO_PARTITION_FOUND;
2608
2609 *part_id = get_part_id_from_linear_hash(
2610 *func_value, part_info->linear_hash_mask, num_parts);
2611 return false;
2612 }
2613
2614 /**
2615 Calculate part_id for (SUB)PARTITION BY KEY
2616
2617 @param file Handler to storage engine
2618 @param field_array Array of fields for PARTTION KEY
2619 @param num_parts Number of KEY partitions
2620 @param [out] func_value Returns calculated hash value
2621
2622 @return Calculated partition id
2623 */
2624
get_part_id_key(handler * file,Field ** field_array,uint num_parts,longlong * func_value)2625 inline static uint32 get_part_id_key(handler *file, Field **field_array,
2626 uint num_parts, longlong *func_value) {
2627 DBUG_TRACE;
2628 *func_value = file->calculate_key_hash_value(field_array);
2629 return (uint32)(*func_value % num_parts);
2630 }
2631
2632 /*
2633 Calculate part_id for (SUB)PARTITION BY LINEAR KEY
2634
2635 SYNOPSIS
2636 get_part_id_linear_key()
2637 part_info A reference to the partition_info struct where all the
2638 desired information is given
2639 field_array Array of fields for PARTTION KEY
2640 num_parts Number of KEY partitions
2641
2642 RETURN VALUE
2643 Calculated partition id
2644 */
2645
get_part_id_linear_key(partition_info * part_info,Field ** field_array,uint num_parts,longlong * func_value)2646 inline static uint32 get_part_id_linear_key(partition_info *part_info,
2647 Field **field_array, uint num_parts,
2648 longlong *func_value) {
2649 DBUG_TRACE;
2650
2651 *func_value = part_info->table->file->calculate_key_hash_value(field_array);
2652 return get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask,
2653 num_parts);
2654 }
2655
2656 /*
2657 Copy to field buffers and set up field pointers
2658
2659 SYNOPSIS
2660 copy_to_part_field_buffers()
2661 ptr Array of fields to copy
2662 field_bufs Array of field buffers to copy to
2663 restore_ptr Array of pointers to restore to
2664
2665 RETURN VALUES
2666 NONE
2667 DESCRIPTION
2668 This routine is used to take the data from field pointer, convert
2669 it to a standard format and store this format in a field buffer
2670 allocated for this purpose. Next the field pointers are moved to
2671 point to the field buffers. There is a separate to restore the
2672 field pointers after this call.
2673 */
2674
copy_to_part_field_buffers(Field ** ptr,uchar ** field_bufs,uchar ** restore_ptr)2675 static void copy_to_part_field_buffers(Field **ptr, uchar **field_bufs,
2676 uchar **restore_ptr) {
2677 Field *field;
2678 while ((field = *(ptr++))) {
2679 *restore_ptr = field->field_ptr();
2680 restore_ptr++;
2681 if (!field->is_null()) {
2682 const CHARSET_INFO *cs = field->charset();
2683 uint max_len = field->pack_length();
2684 uint data_len = field->data_length();
2685 uchar *field_buf = *field_bufs;
2686 /*
2687 We only use the field buffer for VARCHAR and CHAR strings
2688 which isn't of a binary collation. We also only use the
2689 field buffer for fields which are not currently NULL.
2690 The field buffer will store a normalised string. We use
2691 the strnxfrm method to normalise the string.
2692 */
2693 if (field->type() == MYSQL_TYPE_VARCHAR) {
2694 uint len_bytes = field->get_length_bytes();
2695 my_strnxfrm(cs, field_buf + len_bytes, max_len, field->data_ptr(),
2696 data_len);
2697 if (len_bytes == 1)
2698 *field_buf = (uchar)data_len;
2699 else
2700 int2store(field_buf, data_len);
2701 } else {
2702 my_strnxfrm(cs, field_buf, max_len, field->field_ptr(), max_len);
2703 }
2704 field->set_field_ptr(field_buf);
2705 }
2706 field_bufs++;
2707 }
2708 return;
2709 }
2710
2711 /*
2712 Restore field pointers
2713 SYNOPSIS
2714 restore_part_field_pointers()
2715 ptr Array of fields to restore
2716 restore_ptr Array of field pointers to restore to
2717
2718 RETURN VALUES
2719 */
2720
restore_part_field_pointers(Field ** ptr,uchar ** restore_ptr)2721 static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) {
2722 Field *field;
2723 while ((field = *(ptr++))) {
2724 field->set_field_ptr(*restore_ptr);
2725 restore_ptr++;
2726 }
2727 return;
2728 }
2729
2730 /*
2731 This function is used to calculate the partition id where all partition
2732 fields have been prepared to point to a record where the partition field
2733 values are bound.
2734
2735 SYNOPSIS
2736 get_partition_id()
2737 part_info A reference to the partition_info struct where all the
2738 desired information is given
2739 out:part_id The partition id is returned through this pointer
2740 out:func_value Value of partition function (longlong)
2741
2742 RETURN VALUE
2743 part_id Partition id of partition that would contain
2744 row with given values of PF-fields
2745 HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
2746 fit into any partition and thus the values of
2747 the PF-fields are not allowed.
2748
2749 DESCRIPTION
2750 A routine used from write_row, update_row and delete_row from any
2751 handler supporting partitioning. It is also a support routine for
2752 get_partition_set used to find the set of partitions needed to scan
2753 for a certain index scan or full table scan.
2754
2755 It is actually 9 different variants of this function which are called
2756 through a function pointer.
2757
2758 get_partition_id_list
2759 get_partition_id_list_col
2760 get_partition_id_range
2761 get_partition_id_range_col
2762 get_partition_id_hash_nosub
2763 get_partition_id_key_nosub
2764 get_partition_id_linear_hash_nosub
2765 get_partition_id_linear_key_nosub
2766 get_partition_id_with_sub
2767 */
2768
2769 /*
2770 This function is used to calculate the main partition to use in the case of
2771 subpartitioning and we don't know enough to get the partition identity in
2772 total.
2773
2774 SYNOPSIS
2775 get_part_partition_id()
2776 part_info A reference to the partition_info struct where all the
2777 desired information is given
2778 out:part_id The partition id is returned through this pointer
2779 out:func_value The value calculated by partition function
2780
2781 RETURN VALUE
2782 HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't
2783 fit into any partition and thus the values of
2784 the PF-fields are not allowed.
2785 0 OK
2786
2787 DESCRIPTION
2788
2789 It is actually 8 different variants of this function which are called
2790 through a function pointer.
2791
2792 get_partition_id_list
2793 get_partition_id_list_col
2794 get_partition_id_range
2795 get_partition_id_range_col
2796 get_partition_id_hash_nosub
2797 get_partition_id_key_nosub
2798 get_partition_id_linear_hash_nosub
2799 get_partition_id_linear_key_nosub
2800 */
2801
get_part_id_charset_func_part(partition_info * part_info,uint32 * part_id,longlong * func_value)2802 static int get_part_id_charset_func_part(partition_info *part_info,
2803 uint32 *part_id,
2804 longlong *func_value) {
2805 int res;
2806 DBUG_TRACE;
2807
2808 copy_to_part_field_buffers(part_info->part_charset_field_array,
2809 part_info->part_field_buffers,
2810 part_info->restore_part_field_ptrs);
2811 res =
2812 part_info->get_part_partition_id_charset(part_info, part_id, func_value);
2813 restore_part_field_pointers(part_info->part_charset_field_array,
2814 part_info->restore_part_field_ptrs);
2815 return res;
2816 }
2817
get_part_id_charset_func_subpart(partition_info * part_info,uint32 * part_id)2818 static int get_part_id_charset_func_subpart(partition_info *part_info,
2819 uint32 *part_id) {
2820 int res;
2821 DBUG_TRACE;
2822
2823 copy_to_part_field_buffers(part_info->subpart_charset_field_array,
2824 part_info->subpart_field_buffers,
2825 part_info->restore_subpart_field_ptrs);
2826 res = part_info->get_subpartition_id_charset(part_info, part_id);
2827 restore_part_field_pointers(part_info->subpart_charset_field_array,
2828 part_info->restore_subpart_field_ptrs);
2829 return res;
2830 }
2831
get_partition_id_list_col(partition_info * part_info,uint32 * part_id,longlong *)2832 static int get_partition_id_list_col(partition_info *part_info, uint32 *part_id,
2833 longlong *) {
2834 part_column_list_val *list_col_array = part_info->list_col_array;
2835 uint num_columns = part_info->part_field_list.elements;
2836 int list_index, cmp;
2837 int min_list_index = 0;
2838 int max_list_index = part_info->num_list_values - 1;
2839 DBUG_TRACE;
2840
2841 while (max_list_index >= min_list_index) {
2842 list_index = (max_list_index + min_list_index) >> 1;
2843 cmp = cmp_rec_and_tuple(list_col_array + list_index * num_columns,
2844 num_columns);
2845 if (cmp > 0)
2846 min_list_index = list_index + 1;
2847 else if (cmp < 0) {
2848 if (!list_index) goto notfound;
2849 max_list_index = list_index - 1;
2850 } else {
2851 *part_id = (uint32)list_col_array[list_index * num_columns].partition_id;
2852 return 0;
2853 }
2854 }
2855 notfound:
2856 *part_id = 0;
2857 return HA_ERR_NO_PARTITION_FOUND;
2858 }
2859
get_partition_id_list(partition_info * part_info,uint32 * part_id,longlong * func_value)2860 static int get_partition_id_list(partition_info *part_info, uint32 *part_id,
2861 longlong *func_value) {
2862 LIST_PART_ENTRY *list_array = part_info->list_array;
2863 int list_index;
2864 int min_list_index = 0;
2865 int max_list_index = part_info->num_list_values - 1;
2866 longlong part_func_value;
2867 int error = part_val_int(part_info->part_expr, &part_func_value);
2868 longlong list_value;
2869 bool unsigned_flag = part_info->part_expr->unsigned_flag;
2870 DBUG_TRACE;
2871
2872 if (error) goto notfound;
2873
2874 if (part_info->part_expr->null_value) {
2875 if (part_info->has_null_value) {
2876 *part_id = part_info->has_null_part_id;
2877 return 0;
2878 }
2879 goto notfound;
2880 }
2881 *func_value = part_func_value;
2882 if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
2883 while (max_list_index >= min_list_index) {
2884 list_index = (max_list_index + min_list_index) >> 1;
2885 list_value = list_array[list_index].list_value;
2886 if (list_value < part_func_value)
2887 min_list_index = list_index + 1;
2888 else if (list_value > part_func_value) {
2889 if (!list_index) goto notfound;
2890 max_list_index = list_index - 1;
2891 } else {
2892 *part_id = (uint32)list_array[list_index].partition_id;
2893 return 0;
2894 }
2895 }
2896 notfound:
2897 *part_id = 0;
2898 return HA_ERR_NO_PARTITION_FOUND;
2899 }
2900
get_partition_id_cols_list_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint,uint32 nparts)2901 static uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info,
2902 bool left_endpoint,
2903 bool include_endpoint,
2904 uint32 nparts) {
2905 part_column_list_val *list_col_array = part_info->list_col_array;
2906 uint num_columns = part_info->part_field_list.elements;
2907 uint list_index;
2908 uint min_list_index = 0;
2909 int cmp;
2910 /* Notice that max_list_index = last_index + 1 here! */
2911 uint max_list_index = part_info->num_list_values;
2912 DBUG_TRACE;
2913
2914 /* Find the matching partition (including taking endpoint into account). */
2915 do {
2916 /* Midpoint, adjusted down, so it can never be >= max_list_index. */
2917 list_index = (max_list_index + min_list_index) >> 1;
2918 cmp = cmp_rec_and_tuple_prune(list_col_array + list_index * num_columns,
2919 nparts, left_endpoint, include_endpoint);
2920 if (cmp > 0) {
2921 min_list_index = list_index + 1;
2922 } else {
2923 max_list_index = list_index;
2924 if (cmp == 0) break;
2925 }
2926 } while (max_list_index > min_list_index);
2927 list_index = max_list_index;
2928
2929 /* Given value must be LESS THAN or EQUAL to the found partition. */
2930 DBUG_ASSERT(
2931 list_index == part_info->num_list_values ||
2932 (0 >= cmp_rec_and_tuple_prune(list_col_array + list_index * num_columns,
2933 nparts, left_endpoint, include_endpoint)));
2934 /* Given value must be GREATER THAN the previous partition. */
2935 DBUG_ASSERT(list_index == 0 ||
2936 (0 < cmp_rec_and_tuple_prune(
2937 list_col_array + (list_index - 1) * num_columns, nparts,
2938 left_endpoint, include_endpoint)));
2939
2940 /* Include the right endpoint if not already passed end of array. */
2941 if (!left_endpoint && include_endpoint && cmp == 0 &&
2942 list_index < part_info->num_list_values)
2943 list_index++;
2944
2945 return list_index;
2946 }
2947
2948 /**
2949 Find the sub-array part_info->list_array that corresponds to given interval.
2950
2951 @param part_info Partitioning info (partitioning type must be LIST)
2952 @param left_endpoint true - the interval is [a; +inf) or (a; +inf)
2953 false - the interval is (-inf; a] or (-inf; a)
2954 @param include_endpoint true iff the interval includes the endpoint
2955
2956 This function finds the sub-array of part_info->list_array where values of
2957 list_array[idx].list_value are contained within the specifed interval.
2958 list_array is ordered by list_value, so
2959 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==true), the
2960 sought sub-array starts at some index idx and continues till array end.
2961 The function returns first number idx, such that
2962 list_array[idx].list_value is contained within the passed interval.
2963
2964 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==false), the
2965 sought sub-array starts at array start and continues till some last
2966 index idx.
2967 The function returns first number idx, such that
2968 list_array[idx].list_value is NOT contained within the passed interval.
2969 If all array elements are contained, part_info->num_list_values is
2970 returned.
2971
2972 @note The caller will call this function and then will run along the
2973 sub-array of list_array to collect partition ids. If the number of list
2974 values is significantly higher then number of partitions, this could be slow
2975 and we could invent some other approach. The "run over list array" part is
2976 already wrapped in a get_next()-like function.
2977
2978 @return The index of corresponding sub-array of part_info->list_array.
2979 */
2980
get_list_array_idx_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)2981 static uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info,
2982 bool left_endpoint,
2983 bool include_endpoint) {
2984 uint32 res;
2985 copy_to_part_field_buffers(part_info->part_field_array,
2986 part_info->part_field_buffers,
2987 part_info->restore_part_field_ptrs);
2988 res = get_list_array_idx_for_endpoint(part_info, left_endpoint,
2989 include_endpoint);
2990 restore_part_field_pointers(part_info->part_field_array,
2991 part_info->restore_part_field_ptrs);
2992 return res;
2993 }
2994
get_list_array_idx_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)2995 static uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
2996 bool left_endpoint,
2997 bool include_endpoint) {
2998 LIST_PART_ENTRY *list_array = part_info->list_array;
2999 uint list_index;
3000 uint min_list_index = 0, max_list_index = part_info->num_list_values - 1;
3001 longlong list_value;
3002 /* Get the partitioning function value for the endpoint */
3003 longlong part_func_value =
3004 part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3005 bool unsigned_flag = part_info->part_expr->unsigned_flag;
3006 DBUG_TRACE;
3007
3008 if (part_info->part_expr->null_value) {
3009 /*
3010 Special handling for MONOTONIC functions that can return NULL for
3011 values that are comparable. I.e.
3012 '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3013 returns NULL which cannot be compared used <, >, <=, >= etc.
3014
3015 Otherwise, just return the the first index (lowest value).
3016 */
3017 enum_monotonicity_info monotonic;
3018 monotonic = part_info->part_expr->get_monotonicity_info();
3019 if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3020 monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) {
3021 /* F(col) can not return NULL, return index with lowest value */
3022 return 0;
3023 }
3024 }
3025
3026 if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3027 DBUG_ASSERT(part_info->num_list_values);
3028 do {
3029 list_index = (max_list_index + min_list_index) >> 1;
3030 list_value = list_array[list_index].list_value;
3031 if (list_value < part_func_value)
3032 min_list_index = list_index + 1;
3033 else if (list_value > part_func_value) {
3034 if (!list_index) goto notfound;
3035 max_list_index = list_index - 1;
3036 } else {
3037 return list_index + ((left_endpoint ^ include_endpoint) ? 1 : 0);
3038 }
3039 } while (max_list_index >= min_list_index);
3040 notfound:
3041 if (list_value < part_func_value) list_index++;
3042 return list_index;
3043 }
3044
get_partition_id_range_col(partition_info * part_info,uint32 * part_id,longlong *)3045 static int get_partition_id_range_col(partition_info *part_info,
3046 uint32 *part_id, longlong *) {
3047 part_column_list_val *range_col_array = part_info->range_col_array;
3048 uint num_columns = part_info->part_field_list.elements;
3049 uint max_partition = part_info->num_parts - 1;
3050 uint min_part_id = 0;
3051 uint max_part_id = max_partition;
3052 uint loc_part_id;
3053 DBUG_TRACE;
3054
3055 while (max_part_id > min_part_id) {
3056 loc_part_id = (max_part_id + min_part_id + 1) >> 1;
3057 if (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3058 num_columns) >= 0)
3059 min_part_id = loc_part_id + 1;
3060 else
3061 max_part_id = loc_part_id - 1;
3062 }
3063 loc_part_id = max_part_id;
3064 if (loc_part_id != max_partition)
3065 if (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3066 num_columns) >= 0)
3067 loc_part_id++;
3068 *part_id = (uint32)loc_part_id;
3069 if (loc_part_id == max_partition &&
3070 (cmp_rec_and_tuple(range_col_array + loc_part_id * num_columns,
3071 num_columns) >= 0))
3072 return HA_ERR_NO_PARTITION_FOUND;
3073
3074 DBUG_PRINT("exit", ("partition: %d", *part_id));
3075 return 0;
3076 }
3077
get_partition_id_range(partition_info * part_info,uint32 * part_id,longlong * func_value)3078 int get_partition_id_range(partition_info *part_info, uint32 *part_id,
3079 longlong *func_value) {
3080 longlong *range_array = part_info->range_int_array;
3081 uint max_partition = part_info->num_parts - 1;
3082 uint min_part_id = 0;
3083 uint max_part_id = max_partition;
3084 uint loc_part_id;
3085 longlong part_func_value;
3086 int error = part_val_int(part_info->part_expr, &part_func_value);
3087 bool unsigned_flag = part_info->part_expr->unsigned_flag;
3088 DBUG_TRACE;
3089
3090 if (error) return HA_ERR_NO_PARTITION_FOUND;
3091
3092 if (part_info->part_expr->null_value) {
3093 *part_id = 0;
3094 return 0;
3095 }
3096 *func_value = part_func_value;
3097 if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3098 /* Search for the partition containing part_func_value */
3099 while (max_part_id > min_part_id) {
3100 loc_part_id = (max_part_id + min_part_id) / 2;
3101 if (range_array[loc_part_id] <= part_func_value)
3102 min_part_id = loc_part_id + 1;
3103 else
3104 max_part_id = loc_part_id;
3105 }
3106 loc_part_id = max_part_id;
3107 *part_id = (uint32)loc_part_id;
3108 if (loc_part_id == max_partition &&
3109 part_func_value >= range_array[loc_part_id] &&
3110 !part_info->defined_max_value)
3111 return HA_ERR_NO_PARTITION_FOUND;
3112
3113 DBUG_PRINT("exit", ("partition: %d", *part_id));
3114 return 0;
3115 }
3116
3117 /*
3118 Find the sub-array of part_info->range_int_array that covers given interval
3119
3120 SYNOPSIS
3121 get_partition_id_range_for_endpoint()
3122 part_info Partitioning info (partitioning type must be RANGE)
3123 left_endpoint true - the interval is [a; +inf) or (a; +inf)
3124 false - the interval is (-inf; a] or (-inf; a).
3125 include_endpoint true <=> the endpoint itself is included in the
3126 interval
3127
3128 DESCRIPTION
3129 This function finds the sub-array of part_info->range_int_array where the
3130 elements have non-empty intersections with the given interval.
3131
3132 A range_int_array element at index idx represents the interval
3133
3134 [range_int_array[idx-1], range_int_array[idx]),
3135
3136 intervals are disjoint and ordered by their right bound, so
3137
3138 1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==true), the
3139 sought sub-array starts at some index idx and continues till array end.
3140 The function returns first number idx, such that the interval
3141 represented by range_int_array[idx] has non empty intersection with
3142 the passed interval.
3143
3144 2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==false), the
3145 sought sub-array starts at array start and continues till some last
3146 index idx.
3147 The function returns first number idx, such that the interval
3148 represented by range_int_array[idx] has EMPTY intersection with the
3149 passed interval.
3150 If the interval represented by the last array element has non-empty
3151 intersection with the passed interval, part_info->num_parts is
3152 returned.
3153
3154 RETURN
3155 The edge of corresponding part_info->range_int_array sub-array.
3156 */
3157
get_partition_id_range_for_endpoint_charset(partition_info * part_info,bool left_endpoint,bool include_endpoint)3158 static uint32 get_partition_id_range_for_endpoint_charset(
3159 partition_info *part_info, bool left_endpoint, bool include_endpoint) {
3160 uint32 res;
3161 copy_to_part_field_buffers(part_info->part_field_array,
3162 part_info->part_field_buffers,
3163 part_info->restore_part_field_ptrs);
3164 res = get_partition_id_range_for_endpoint(part_info, left_endpoint,
3165 include_endpoint);
3166 restore_part_field_pointers(part_info->part_field_array,
3167 part_info->restore_part_field_ptrs);
3168 return res;
3169 }
3170
get_partition_id_range_for_endpoint(partition_info * part_info,bool left_endpoint,bool include_endpoint)3171 static uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
3172 bool left_endpoint,
3173 bool include_endpoint) {
3174 longlong *range_array = part_info->range_int_array;
3175 longlong part_end_val;
3176 uint max_partition = part_info->num_parts - 1;
3177 uint min_part_id = 0, max_part_id = max_partition, loc_part_id;
3178 /* Get the partitioning function value for the endpoint */
3179 longlong part_func_value =
3180 part_info->part_expr->val_int_endpoint(left_endpoint, &include_endpoint);
3181
3182 bool unsigned_flag = part_info->part_expr->unsigned_flag;
3183 DBUG_TRACE;
3184
3185 if (part_info->part_expr->null_value) {
3186 /*
3187 Special handling for MONOTONIC functions that can return NULL for
3188 values that are comparable. I.e.
3189 '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00')
3190 returns NULL which cannot be compared used <, >, <=, >= etc.
3191
3192 Otherwise, just return the first partition
3193 (may be included if not left endpoint)
3194 */
3195 enum_monotonicity_info monotonic;
3196 monotonic = part_info->part_expr->get_monotonicity_info();
3197 if (monotonic != MONOTONIC_INCREASING_NOT_NULL &&
3198 monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) {
3199 /* F(col) can not return NULL, return partition with lowest value */
3200 if (!left_endpoint && include_endpoint) return 1;
3201 return 0;
3202 }
3203 }
3204
3205 if (unsigned_flag) part_func_value -= 0x8000000000000000ULL;
3206 if (left_endpoint && !include_endpoint) part_func_value++;
3207
3208 /*
3209 Search for the partition containing part_func_value
3210 (including the right endpoint).
3211 */
3212 while (max_part_id > min_part_id) {
3213 loc_part_id = (max_part_id + min_part_id) / 2;
3214 if (range_array[loc_part_id] < part_func_value)
3215 min_part_id = loc_part_id + 1;
3216 else
3217 max_part_id = loc_part_id;
3218 }
3219 loc_part_id = max_part_id;
3220
3221 /* Adjust for endpoints */
3222 part_end_val = range_array[loc_part_id];
3223 if (left_endpoint) {
3224 DBUG_ASSERT(
3225 part_func_value > part_end_val
3226 ? (loc_part_id == max_partition && !part_info->defined_max_value)
3227 : 1);
3228 /*
3229 In case of PARTITION p VALUES LESS THAN MAXVALUE
3230 the maximum value is in the current (last) partition.
3231 If value is equal or greater than the endpoint,
3232 the range starts from the next partition.
3233 */
3234 if (part_func_value >= part_end_val &&
3235 (loc_part_id < max_partition || !part_info->defined_max_value))
3236 loc_part_id++;
3237 } else {
3238 /* if 'WHERE <= X' and partition is LESS THAN (X) include next partition */
3239 if (include_endpoint && loc_part_id < max_partition &&
3240 part_func_value == part_end_val)
3241 loc_part_id++;
3242
3243 /* Right endpoint, set end after correct partition */
3244 loc_part_id++;
3245 }
3246 return loc_part_id;
3247 }
3248
get_partition_id_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3249 static int get_partition_id_hash_nosub(partition_info *part_info,
3250 uint32 *part_id, longlong *func_value) {
3251 return get_part_id_hash(part_info->num_parts, part_info->part_expr, part_id,
3252 func_value);
3253 }
3254
get_partition_id_linear_hash_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3255 static int get_partition_id_linear_hash_nosub(partition_info *part_info,
3256 uint32 *part_id,
3257 longlong *func_value) {
3258 return get_part_id_linear_hash(part_info, part_info->num_parts,
3259 part_info->part_expr, part_id, func_value);
3260 }
3261
get_partition_id_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3262 static int get_partition_id_key_nosub(partition_info *part_info,
3263 uint32 *part_id, longlong *func_value) {
3264 *part_id =
3265 get_part_id_key(part_info->table->file, part_info->part_field_array,
3266 part_info->num_parts, func_value);
3267 return 0;
3268 }
3269
get_partition_id_linear_key_nosub(partition_info * part_info,uint32 * part_id,longlong * func_value)3270 static int get_partition_id_linear_key_nosub(partition_info *part_info,
3271 uint32 *part_id,
3272 longlong *func_value) {
3273 *part_id = get_part_id_linear_key(part_info, part_info->part_field_array,
3274 part_info->num_parts, func_value);
3275 return 0;
3276 }
3277
get_partition_id_with_sub(partition_info * part_info,uint32 * part_id,longlong * func_value)3278 static int get_partition_id_with_sub(partition_info *part_info, uint32 *part_id,
3279 longlong *func_value) {
3280 uint32 loc_part_id, sub_part_id;
3281 uint num_subparts;
3282 int error;
3283 DBUG_TRACE;
3284
3285 if (unlikely((error = part_info->get_part_partition_id(
3286 part_info, &loc_part_id, func_value)))) {
3287 return error;
3288 }
3289 num_subparts = part_info->num_subparts;
3290 if (unlikely(
3291 (error = part_info->get_subpartition_id(part_info, &sub_part_id)))) {
3292 return error;
3293 }
3294 *part_id = get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts);
3295 return 0;
3296 }
3297
3298 /*
3299 This function is used to calculate the subpartition id
3300
3301 SYNOPSIS
3302 get_subpartition_id()
3303 part_info A reference to the partition_info struct where all the
3304 desired information is given
3305
3306 RETURN VALUE
3307 part_id The subpartition identity
3308
3309 DESCRIPTION
3310 A routine used in some SELECT's when only partial knowledge of the
3311 partitions is known.
3312
3313 It is actually 4 different variants of this function which are called
3314 through a function pointer.
3315
3316 get_partition_id_hash_sub
3317 get_partition_id_key_sub
3318 get_partition_id_linear_hash_sub
3319 get_partition_id_linear_key_sub
3320 */
3321
get_partition_id_hash_sub(partition_info * part_info,uint32 * part_id)3322 static int get_partition_id_hash_sub(partition_info *part_info,
3323 uint32 *part_id) {
3324 longlong func_value;
3325 return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr,
3326 part_id, &func_value);
3327 }
3328
get_partition_id_linear_hash_sub(partition_info * part_info,uint32 * part_id)3329 static int get_partition_id_linear_hash_sub(partition_info *part_info,
3330 uint32 *part_id) {
3331 longlong func_value;
3332 return get_part_id_linear_hash(part_info, part_info->num_subparts,
3333 part_info->subpart_expr, part_id, &func_value);
3334 }
3335
get_partition_id_key_sub(partition_info * part_info,uint32 * part_id)3336 static int get_partition_id_key_sub(partition_info *part_info,
3337 uint32 *part_id) {
3338 longlong func_value;
3339 *part_id =
3340 get_part_id_key(part_info->table->file, part_info->subpart_field_array,
3341 part_info->num_subparts, &func_value);
3342 return false;
3343 }
3344
get_partition_id_linear_key_sub(partition_info * part_info,uint32 * part_id)3345 static int get_partition_id_linear_key_sub(partition_info *part_info,
3346 uint32 *part_id) {
3347 longlong func_value;
3348 *part_id = get_part_id_linear_key(part_info, part_info->subpart_field_array,
3349 part_info->num_subparts, &func_value);
3350 return false;
3351 }
3352
3353 /*
3354 Set an indicator on all partition fields that are set by the key
3355
3356 SYNOPSIS
3357 set_PF_fields_in_key()
3358 key_info Information about the index
3359 key_length Length of key
3360
3361 RETURN VALUE
3362 true Found partition field set by key
3363 false No partition field set by key
3364 */
3365
set_PF_fields_in_key(KEY * key_info,uint key_length)3366 static bool set_PF_fields_in_key(KEY *key_info, uint key_length) {
3367 KEY_PART_INFO *key_part;
3368 bool found_part_field = false;
3369 DBUG_TRACE;
3370
3371 for (key_part = key_info->key_part; (int)key_length > 0; key_part++) {
3372 if (key_part->null_bit) key_length--;
3373 if (key_part->type == HA_KEYTYPE_BIT) {
3374 if (((Field_bit *)key_part->field)->bit_len) key_length--;
3375 }
3376 if (key_part->key_part_flag & (HA_BLOB_PART + HA_VAR_LENGTH_PART)) {
3377 key_length -= HA_KEY_BLOB_LENGTH;
3378 }
3379 if (key_length < key_part->length) break;
3380 key_length -= key_part->length;
3381 if (key_part->field->is_flag_set(FIELD_IN_PART_FUNC_FLAG)) {
3382 found_part_field = true;
3383 key_part->field->set_flag(GET_FIXED_FIELDS_FLAG);
3384 }
3385 }
3386 return found_part_field;
3387 }
3388
3389 /*
3390 We have found that at least one partition field was set by a key, now
3391 check if a partition function has all its fields bound or not.
3392
3393 SYNOPSIS
3394 check_part_func_bound()
3395 ptr Array of fields NULL terminated (partition fields)
3396
3397 RETURN VALUE
3398 true All fields in partition function are set
3399 false Not all fields in partition function are set
3400 */
3401
check_part_func_bound(Field ** ptr)3402 static bool check_part_func_bound(Field **ptr) {
3403 bool result = true;
3404 DBUG_TRACE;
3405
3406 for (; *ptr; ptr++) {
3407 if (!(*ptr)->is_flag_set(GET_FIXED_FIELDS_FLAG)) {
3408 result = false;
3409 break;
3410 }
3411 }
3412 return result;
3413 }
3414
3415 /*
3416 Get the id of the subpartitioning part by using the key buffer of the
3417 index scan.
3418
3419 SYNOPSIS
3420 get_sub_part_id_from_key()
3421 table The table object
3422 buf A buffer that can be used to evaluate the partition function
3423 key_info The index object
3424 key_spec A key_range containing key and key length
3425 out:part_id The returned partition id
3426
3427 RETURN VALUES
3428 true All fields in partition function are set
3429 false Not all fields in partition function are set
3430
3431 DESCRIPTION
3432 Use key buffer to set-up record in buf, move field pointers and
3433 get the partition identity and restore field pointers afterwards.
3434 */
3435
get_sub_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)3436 static int get_sub_part_id_from_key(const TABLE *table, uchar *buf,
3437 KEY *key_info, const key_range *key_spec,
3438 uint32 *part_id) {
3439 uchar *rec0 = table->record[0];
3440 partition_info *part_info = table->part_info;
3441 int res;
3442 DBUG_TRACE;
3443
3444 key_restore(buf, key_spec->key, key_info, key_spec->length);
3445 if (likely(rec0 == buf)) {
3446 res = part_info->get_subpartition_id(part_info, part_id);
3447 } else {
3448 Field **part_field_array = part_info->subpart_field_array;
3449 set_field_ptr(part_field_array, buf, rec0);
3450 res = part_info->get_subpartition_id(part_info, part_id);
3451 set_field_ptr(part_field_array, rec0, buf);
3452 }
3453 return res;
3454 }
3455
3456 /*
3457 Get the id of the partitioning part by using the key buffer of the
3458 index scan.
3459
3460 SYNOPSIS
3461 get_part_id_from_key()
3462 table The table object
3463 buf A buffer that can be used to evaluate the partition function
3464 key_info The index object
3465 key_spec A key_range containing key and key length
3466 out:part_id Partition to use
3467
3468 RETURN VALUES
3469 true Partition to use not found
3470 false Ok, part_id indicates partition to use
3471
3472 DESCRIPTION
3473 Use key buffer to set-up record in buf, move field pointers and
3474 get the partition identity and restore field pointers afterwards.
3475 */
3476
get_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,uint32 * part_id)3477 static bool get_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
3478 const key_range *key_spec, uint32 *part_id) {
3479 bool result;
3480 uchar *rec0 = table->record[0];
3481 partition_info *part_info = table->part_info;
3482 longlong func_value;
3483 DBUG_TRACE;
3484
3485 key_restore(buf, key_spec->key, key_info, key_spec->length);
3486 if (likely(rec0 == buf)) {
3487 result = part_info->get_part_partition_id(part_info, part_id, &func_value);
3488 } else {
3489 Field **part_field_array = part_info->part_field_array;
3490 set_field_ptr(part_field_array, buf, rec0);
3491 result = part_info->get_part_partition_id(part_info, part_id, &func_value);
3492 set_field_ptr(part_field_array, rec0, buf);
3493 }
3494 return result;
3495 }
3496
3497 /*
3498 Get the partitioning id of the full PF by using the key buffer of the
3499 index scan.
3500
3501 SYNOPSIS
3502 get_full_part_id_from_key()
3503 table The table object
3504 buf A buffer that is used to evaluate the partition function
3505 key_info The index object
3506 key_spec A key_range containing key and key length
3507 out:part_spec A partition id containing start part and end part
3508
3509 RETURN VALUES
3510 part_spec
3511 No partitions to scan is indicated by end_part > start_part when returning
3512
3513 DESCRIPTION
3514 Use key buffer to set-up record in buf, move field pointers if needed and
3515 get the partition identity and restore field pointers afterwards.
3516 */
3517
get_full_part_id_from_key(const TABLE * table,uchar * buf,KEY * key_info,const key_range * key_spec,part_id_range * part_spec)3518 void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info,
3519 const key_range *key_spec,
3520 part_id_range *part_spec) {
3521 bool result;
3522 partition_info *part_info = table->part_info;
3523 uchar *rec0 = table->record[0];
3524 longlong func_value;
3525 DBUG_TRACE;
3526
3527 key_restore(buf, key_spec->key, key_info, key_spec->length);
3528 if (likely(rec0 == buf)) {
3529 result = part_info->get_partition_id(part_info, &part_spec->start_part,
3530 &func_value);
3531 } else {
3532 Field **part_field_array = part_info->full_part_field_array;
3533 set_field_ptr(part_field_array, buf, rec0);
3534 result = part_info->get_partition_id(part_info, &part_spec->start_part,
3535 &func_value);
3536 set_field_ptr(part_field_array, rec0, buf);
3537 }
3538 part_spec->end_part = part_spec->start_part;
3539 if (unlikely(result)) part_spec->start_part++;
3540 }
3541
3542 /**
3543 @brief Verify that all rows in a table is in the given partition
3544
3545 @param table Table which contains the data that will be checked if
3546 it is matching the partition definition.
3547 @param part_table Partitioned table containing the partition to check.
3548 @param part_id Which partition to match with.
3549
3550 @return Operation status
3551 @retval true Not all rows match the given partition
3552 @retval false OK
3553 */
verify_data_with_partition(TABLE * table,TABLE * part_table,uint32 part_id)3554 bool verify_data_with_partition(TABLE *table, TABLE *part_table,
3555 uint32 part_id) {
3556 uint32 found_part_id;
3557 longlong func_value; /* Unused */
3558 handler *file;
3559 int error;
3560 uchar *old_rec;
3561 partition_info *part_info;
3562 DBUG_TRACE;
3563 DBUG_ASSERT(table && table->file && part_table && part_table->part_info &&
3564 part_table->file);
3565
3566 /*
3567 Verify all table rows.
3568 First implementation uses full scan + evaluates partition functions for
3569 every row. TODO: add optimization to use index if possible, see WL#5397.
3570
3571 1) Open both tables (already done) and set the row buffers to use
3572 the same buffer (to avoid copy).
3573 2) Init rnd on table.
3574 3) loop over all rows.
3575 3.1) verify that partition_id on the row is correct. Break if error.
3576 */
3577 file = table->file;
3578 part_info = part_table->part_info;
3579 bitmap_union(table->read_set, &part_info->full_part_field_set);
3580 old_rec = part_table->record[0];
3581 part_table->record[0] = table->record[0];
3582 set_field_ptr(part_info->full_part_field_array, table->record[0], old_rec);
3583 if ((error = file->ha_rnd_init(true))) {
3584 file->print_error(error, MYF(0));
3585 goto err;
3586 }
3587
3588 do {
3589 if ((error = file->ha_rnd_next(table->record[0]))) {
3590 if (error == HA_ERR_RECORD_DELETED) continue;
3591 if (error == HA_ERR_END_OF_FILE)
3592 error = 0;
3593 else
3594 file->print_error(error, MYF(0));
3595 break;
3596 }
3597 if ((error = part_info->get_partition_id(part_info, &found_part_id,
3598 &func_value))) {
3599 part_info->err_value = func_value;
3600 part_table->file->print_error(error, MYF(0));
3601 break;
3602 }
3603 DEBUG_SYNC(current_thd, "swap_partition_first_row_read");
3604 if (found_part_id != part_id) {
3605 my_error(ER_ROW_DOES_NOT_MATCH_PARTITION, MYF(0));
3606 error = 1;
3607 break;
3608 }
3609 } while (true);
3610 (void)file->ha_rnd_end();
3611 err:
3612 set_field_ptr(part_info->full_part_field_array, old_rec, table->record[0]);
3613 part_table->record[0] = old_rec;
3614 if (error) return true;
3615 return false;
3616 }
3617
3618 /*
3619 Prune the set of partitions to use in query
3620
3621 SYNOPSIS
3622 prune_partition_set()
3623 table The table object
3624 out:part_spec Contains start part, end part
3625
3626 DESCRIPTION
3627 This function is called to prune the range of partitions to scan by
3628 checking the read_partitions bitmap.
3629 If start_part > end_part at return it means no partition needs to be
3630 scanned. If start_part == end_part it always means a single partition
3631 needs to be scanned.
3632
3633 RETURN VALUE
3634 part_spec
3635 */
prune_partition_set(const TABLE * table,part_id_range * part_spec)3636 void prune_partition_set(const TABLE *table, part_id_range *part_spec) {
3637 int last_partition = -1;
3638 uint i = part_spec->start_part;
3639 partition_info *part_info = table->part_info;
3640 DBUG_TRACE;
3641
3642 if (i)
3643 i = bitmap_get_next_set(&part_info->read_partitions, i - 1);
3644 else
3645 i = bitmap_get_first_set(&part_info->read_partitions);
3646
3647 part_spec->start_part = i;
3648
3649 /* TODO: Only check next bit, no need to prune end if >= 2 partitions. */
3650 for (; i <= part_spec->end_part;
3651 i = bitmap_get_next_set(&part_info->read_partitions, i)) {
3652 DBUG_PRINT("info", ("Partition %d is set", i));
3653 if (last_partition == -1)
3654 /* First partition found in set and pruned bitmap */
3655 part_spec->start_part = i;
3656 last_partition = i;
3657 }
3658 if (last_partition == -1) /* No partition found in pruned bitmap */
3659 part_spec->start_part = part_spec->end_part + 1;
3660 else // if (last_partition != -1)
3661 part_spec->end_part = last_partition;
3662 }
3663
3664 /*
3665 Get the set of partitions to use in query.
3666
3667 SYNOPSIS
3668 get_partition_set()
3669 table The table object
3670 buf A buffer that can be used to evaluate the partition function
3671 index The index of the key used, if MAX_KEY no index used
3672 key_spec A key_range containing key and key length
3673 out:part_spec Contains start part, end part and indicator if bitmap is
3674 used for which partitions to scan
3675
3676 DESCRIPTION
3677 This function is called to discover which partitions to use in an index
3678 scan or a full table scan.
3679 It returns a range of partitions to scan. If there are holes in this
3680 range with partitions that are not needed to scan a bit array is used
3681 to signal which partitions to use and which not to use.
3682 If start_part > end_part at return it means no partition needs to be
3683 scanned. If start_part == end_part it always means a single partition
3684 needs to be scanned.
3685
3686 RETURN VALUE
3687 part_spec
3688 */
get_partition_set(const TABLE * table,uchar * buf,const uint index,const key_range * key_spec,part_id_range * part_spec)3689 void get_partition_set(const TABLE *table, uchar *buf, const uint index,
3690 const key_range *key_spec, part_id_range *part_spec) {
3691 partition_info *part_info = table->part_info;
3692 uint num_parts = part_info->get_tot_partitions();
3693 uint i, part_id;
3694 uint sub_part = num_parts;
3695 uint32 part_part = num_parts;
3696 KEY *key_info = nullptr;
3697 bool found_part_field = false;
3698 DBUG_TRACE;
3699
3700 part_spec->start_part = 0;
3701 part_spec->end_part = num_parts - 1;
3702 if ((index < MAX_KEY) && key_spec &&
3703 key_spec->flag == (uint)HA_READ_KEY_EXACT &&
3704 part_info->some_fields_in_PF.is_set(index)) {
3705 key_info = table->key_info + index;
3706 /*
3707 The index can potentially provide at least one PF-field (field in the
3708 partition function). Thus it is interesting to continue our probe.
3709 */
3710 if (key_spec->length == key_info->key_length) {
3711 /*
3712 The entire key is set so we can check whether we can immediately
3713 derive either the complete PF or if we can derive either
3714 the top PF or the subpartitioning PF. This can be established by
3715 checking precalculated bits on each index.
3716 */
3717 if (part_info->all_fields_in_PF.is_set(index)) {
3718 /*
3719 We can derive the exact partition to use, no more than this one
3720 is needed.
3721 */
3722 get_full_part_id_from_key(table, buf, key_info, key_spec, part_spec);
3723 /*
3724 Check if range can be adjusted by looking in read_partitions
3725 */
3726 prune_partition_set(table, part_spec);
3727 return;
3728 } else if (part_info->is_sub_partitioned()) {
3729 if (part_info->all_fields_in_SPF.is_set(index)) {
3730 if (get_sub_part_id_from_key(table, buf, key_info, key_spec,
3731 &sub_part)) {
3732 part_spec->start_part = num_parts;
3733 return;
3734 }
3735 } else if (part_info->all_fields_in_PPF.is_set(index)) {
3736 if (get_part_id_from_key(table, buf, key_info, key_spec,
3737 &part_part)) {
3738 /*
3739 The value of the RANGE or LIST partitioning was outside of
3740 allowed values. Thus it is certain that the result of this
3741 scan will be empty.
3742 */
3743 part_spec->start_part = num_parts;
3744 return;
3745 }
3746 }
3747 }
3748 } else {
3749 /*
3750 Set an indicator on all partition fields that are bound.
3751 If at least one PF-field was bound it pays off to check whether
3752 the PF or PPF or SPF has been bound.
3753 (PF = Partition Function, SPF = Subpartition Function and
3754 PPF = Partition Function part of subpartitioning)
3755 */
3756 if ((found_part_field =
3757 set_PF_fields_in_key(key_info, key_spec->length))) {
3758 if (check_part_func_bound(part_info->full_part_field_array)) {
3759 /*
3760 We were able to bind all fields in the partition function even
3761 by using only a part of the key. Calculate the partition to use.
3762 */
3763 get_full_part_id_from_key(table, buf, key_info, key_spec, part_spec);
3764 clear_indicator_in_key_fields(key_info);
3765 /*
3766 Check if range can be adjusted by looking in read_partitions
3767 */
3768 prune_partition_set(table, part_spec);
3769 return;
3770 } else if (part_info->is_sub_partitioned()) {
3771 if (check_part_func_bound(part_info->subpart_field_array)) {
3772 if (get_sub_part_id_from_key(table, buf, key_info, key_spec,
3773 &sub_part)) {
3774 part_spec->start_part = num_parts;
3775 clear_indicator_in_key_fields(key_info);
3776 return;
3777 }
3778 } else if (check_part_func_bound(part_info->part_field_array)) {
3779 if (get_part_id_from_key(table, buf, key_info, key_spec,
3780 &part_part)) {
3781 part_spec->start_part = num_parts;
3782 clear_indicator_in_key_fields(key_info);
3783 return;
3784 }
3785 }
3786 }
3787 }
3788 }
3789 }
3790 {
3791 /*
3792 The next step is to analyse the table condition to see whether any
3793 information about which partitions to scan can be derived from there.
3794 Currently not implemented.
3795 */
3796 }
3797 /*
3798 If we come here we have found a range of sorts we have either discovered
3799 nothing or we have discovered a range of partitions with possible holes
3800 in it. We need a bitvector to further the work here.
3801 */
3802 if (!(part_part == num_parts && sub_part == num_parts)) {
3803 /*
3804 We can only arrive here if we are using subpartitioning.
3805 */
3806 if (part_part != num_parts) {
3807 /*
3808 We know the top partition and need to scan all underlying
3809 subpartitions. This is a range without holes.
3810 */
3811 DBUG_ASSERT(sub_part == num_parts);
3812 part_spec->start_part = part_part * part_info->num_subparts;
3813 part_spec->end_part = part_spec->start_part + part_info->num_subparts - 1;
3814 } else {
3815 DBUG_ASSERT(sub_part != num_parts);
3816 part_spec->start_part = sub_part;
3817 part_spec->end_part =
3818 sub_part + (part_info->num_subparts * (part_info->num_parts - 1));
3819 for (i = 0, part_id = sub_part; i < part_info->num_parts;
3820 i++, part_id += part_info->num_subparts)
3821 ; // Set bit part_id in bit array
3822 }
3823 }
3824 if (found_part_field) clear_indicator_in_key_fields(key_info);
3825 /*
3826 Check if range can be adjusted by looking in read_partitions
3827 */
3828 prune_partition_set(table, part_spec);
3829 }
3830
3831 /*
3832 If the table is partitioned we will read the partition info into the
3833 .frm file here.
3834 -------------------------------
3835 | Fileinfo 64 bytes |
3836 -------------------------------
3837 | Formnames 7 bytes |
3838 -------------------------------
3839 | Not used 4021 bytes |
3840 -------------------------------
3841 | Keyinfo + record |
3842 -------------------------------
3843 | Padded to next multiple |
3844 | of IO_SIZE |
3845 -------------------------------
3846 | Forminfo 288 bytes |
3847 -------------------------------
3848 | Screen buffer, to make |
3849 |field names readable |
3850 -------------------------------
3851 | Packed field info |
3852 |17 + 1 + strlen(field_name) |
3853 | + 1 end of file character |
3854 -------------------------------
3855 | Partition info |
3856 -------------------------------
3857 We provide the length of partition length in Fileinfo[55-58].
3858
3859 Read the partition syntax from the frm file and parse it to get the
3860 data structures of the partitioning.
3861
3862 SYNOPSIS
3863 mysql_unpack_partition()
3864 thd Thread object
3865 part_buf Partition info from frm file
3866 part_info_len Length of partition syntax
3867 table Table object of partitioned table
3868 create_table_ind Is it called from CREATE TABLE
3869 default_db_type What is the default engine of the table
3870 work_part_info_used Flag is raised if we don't create new
3871 part_info, but used thd->work_part_info
3872
3873 RETURN VALUE
3874 true Error
3875 false Sucess
3876
3877 DESCRIPTION
3878 Read the partition syntax from the current position in the frm file.
3879 Initiate a LEX object, save the list of item tree objects to free after
3880 the query is done. Set-up partition info object such that parser knows
3881 it is called from internally. Call parser to create data structures
3882 (best possible recreation of item trees and so forth since there is no
3883 serialisation of these objects other than in parseable text format).
3884 We need to save the text of the partition functions since it is not
3885 possible to retrace this given an item tree.
3886 */
3887
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)3888 bool mysql_unpack_partition(THD *thd, char *part_buf, uint part_info_len,
3889 TABLE *table, bool is_create_table_ind,
3890 handlerton *default_db_type,
3891 bool *work_part_info_used) {
3892 bool result = true;
3893 partition_info *part_info;
3894 const CHARSET_INFO *old_character_set_client =
3895 thd->variables.character_set_client;
3896 LEX *old_lex = thd->lex;
3897 LEX lex;
3898 SELECT_LEX_UNIT unit(CTX_NONE);
3899 SELECT_LEX select(thd->mem_root, nullptr, nullptr);
3900 lex.new_static_query(&unit, &select);
3901
3902 sql_digest_state *parent_digest = thd->m_digest;
3903 PSI_statement_locker *parent_locker = thd->m_statement_psi;
3904 Partition_handler *part_handler;
3905 DBUG_TRACE;
3906
3907 thd->variables.character_set_client = system_charset_info;
3908 // This isn't strictly needed, but here for consistency.
3909 Sql_mode_parse_guard parse_guard(thd);
3910
3911 Partition_expr_parser_state parser_state;
3912 if (parser_state.init(thd, part_buf, part_info_len)) goto end;
3913
3914 if (init_lex_with_single_table(thd, table, &lex)) goto end;
3915
3916 /*
3917 All Items created is put into a free list on the THD object. This list
3918 is used to free all Item objects after completing a query. We don't
3919 want that to happen with the Item tree created as part of the partition
3920 info. This should be attached to the table object and remain so until
3921 the table object is released.
3922 Thus we move away the current list temporarily and start a new list that
3923 we then save in the partition info structure.
3924 */
3925 *work_part_info_used = false;
3926 DBUG_PRINT("info", ("Parse: %s", part_buf));
3927
3928 thd->m_digest = nullptr;
3929 thd->m_statement_psi = nullptr;
3930 if (parse_sql(thd, &parser_state, nullptr) ||
3931 parser_state.result->fix_parser_data(thd)) {
3932 thd->free_items();
3933 thd->m_digest = parent_digest;
3934 thd->m_statement_psi = parent_locker;
3935 goto end;
3936 }
3937 part_info = parser_state.result;
3938 thd->m_digest = parent_digest;
3939 thd->m_statement_psi = parent_locker;
3940 /*
3941 The parsed syntax residing in the frm file can still contain defaults.
3942 The reason is that the frm file is sometimes saved outside of this
3943 MySQL Server and used in backup and restore of clusters or partitioned
3944 tables. It is not certain that the restore will restore exactly the
3945 same default partitioning.
3946
3947 The easiest manner of handling this is to simply continue using the
3948 part_info we already built up during mysql_create_table if we are
3949 in the process of creating a table. If the table already exists we
3950 need to discover the number of partitions for the default parts. Since
3951 the handler object hasn't been created here yet we need to postpone this
3952 to the fix_partition_func method.
3953 */
3954
3955 DBUG_PRINT("info", ("Successful parse"));
3956 DBUG_PRINT("info",
3957 ("default engine = %s, default_db_type = %s",
3958 ha_resolve_storage_engine_name(part_info->default_engine_type),
3959 ha_resolve_storage_engine_name(default_db_type)));
3960 if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE) {
3961 /*
3962 When we come here we are doing a create table. In this case we
3963 have already done some preparatory work on the old part_info
3964 object. We don't really need this new partition_info object.
3965 Thus we go back to the old partition info object.
3966 We need to free any memory objects allocated on item_free_list
3967 by the parser since we are keeping the old info from the first
3968 parser call in CREATE TABLE.
3969
3970 This table object can not be used any more. However, since
3971 this is CREATE TABLE, we know that it will be destroyed by the
3972 caller, and rely on that.
3973 */
3974 thd->free_items();
3975 part_info = thd->work_part_info;
3976 *work_part_info_used = true;
3977 }
3978 table->part_info = part_info;
3979 part_info->table = table;
3980 part_handler = table->file->get_partition_handler();
3981 DBUG_ASSERT(part_handler != nullptr);
3982 part_handler->set_part_info(part_info, true);
3983 if (!part_info->default_engine_type)
3984 part_info->default_engine_type = default_db_type;
3985 DBUG_ASSERT(part_info->default_engine_type == default_db_type);
3986 DBUG_ASSERT(part_info->default_engine_type->db_type != DB_TYPE_UNKNOWN);
3987
3988 {
3989 /*
3990 This code part allocates memory for the serialised item information for
3991 the partition functions. In most cases this is not needed but if the
3992 table is used for SHOW CREATE TABLES or ALTER TABLE that modifies
3993 partition information it is needed and the info is lost if we don't
3994 save it here so unfortunately we have to do it here even if in most
3995 cases it is not needed. This is a consequence of that item trees are
3996 not serialisable.
3997 */
3998 size_t part_func_len = part_info->part_func_len;
3999 size_t subpart_func_len = part_info->subpart_func_len;
4000 char *part_func_string = nullptr;
4001 char *subpart_func_string = nullptr;
4002 /*
4003 TODO: Verify that it really should be allocated on the thd?
4004 Or simply remove it and use part_expr->print() instead?
4005 */
4006 if ((part_func_len &&
4007 !((part_func_string = (char *)thd->alloc(part_func_len)))) ||
4008 (subpart_func_len &&
4009 !((subpart_func_string = (char *)thd->alloc(subpart_func_len))))) {
4010 mem_alloc_error(part_func_len);
4011 thd->free_items();
4012 goto end;
4013 }
4014 if (part_func_len)
4015 memcpy(part_func_string, part_info->part_func_string, part_func_len);
4016 if (subpart_func_len)
4017 memcpy(subpart_func_string, part_info->subpart_func_string,
4018 subpart_func_len);
4019 part_info->part_func_string = part_func_string;
4020 part_info->subpart_func_string = subpart_func_string;
4021 }
4022
4023 result = false;
4024 end:
4025 end_lex_with_single_table(thd, table, old_lex);
4026 thd->variables.character_set_client = old_character_set_client;
4027 return result;
4028 }
4029
4030 /*
4031 Set engine type on all partition element objects
4032 SYNOPSIS
4033 set_engine_all_partitions()
4034 part_info Partition info
4035 engine_type Handlerton reference of engine
4036 RETURN VALUES
4037 NONE
4038 */
4039
set_engine_all_partitions(partition_info * part_info,handlerton * engine_type)4040 static void set_engine_all_partitions(partition_info *part_info,
4041 handlerton *engine_type) {
4042 uint i = 0;
4043 List_iterator<partition_element> part_it(part_info->partitions);
4044 do {
4045 partition_element *part_elem = part_it++;
4046
4047 part_elem->engine_type = engine_type;
4048 if (part_info->is_sub_partitioned()) {
4049 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4050 uint j = 0;
4051
4052 do {
4053 partition_element *sub_elem = sub_it++;
4054
4055 sub_elem->engine_type = engine_type;
4056 } while (++j < part_info->num_subparts);
4057 }
4058 } while (++i < part_info->num_parts);
4059 }
4060
4061 /*
4062 We need to check if engine used by all partitions can handle
4063 partitioning natively.
4064
4065 SYNOPSIS
4066 check_native_partitioned()
4067 create_info Create info in CREATE TABLE
4068 out:ret_val Return value
4069 part_info Partition info
4070 thd Thread object
4071
4072 RETURN VALUES
4073 Value returned in bool ret_value
4074 true Native partitioning supported by engine
4075 false Need to use partition handler
4076
4077 Return value from function
4078 true Error
4079 false Success
4080 */
4081
check_native_partitioned(HA_CREATE_INFO * create_info,bool * ret_val,partition_info * part_info,THD * thd)4082 static bool check_native_partitioned(HA_CREATE_INFO *create_info, bool *ret_val,
4083 partition_info *part_info, THD *thd) {
4084 bool table_engine_set;
4085 handlerton *engine_type = part_info->default_engine_type;
4086 handlerton *old_engine_type = engine_type;
4087 DBUG_TRACE;
4088
4089 if (create_info->used_fields & HA_CREATE_USED_ENGINE) {
4090 table_engine_set = true;
4091 engine_type = create_info->db_type;
4092 } else {
4093 table_engine_set = false;
4094 if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
4095 table_engine_set = true;
4096 }
4097 }
4098 DBUG_PRINT("info",
4099 ("engine_type = %s, table_engine_set = %u",
4100 ha_resolve_storage_engine_name(engine_type), table_engine_set));
4101 if (part_info->check_engine_mix(engine_type, table_engine_set)) goto error;
4102
4103 /*
4104 All engines are of the same type. Check if this engine supports
4105 native partitioning.
4106 */
4107
4108 if (!engine_type) engine_type = old_engine_type;
4109 DBUG_PRINT("info",
4110 ("engine_type = %s", ha_resolve_storage_engine_name(engine_type)));
4111 if (engine_type->partition_flags) {
4112 create_info->db_type = engine_type;
4113 DBUG_PRINT("info", ("Changed to native partitioning"));
4114 *ret_val = true;
4115 }
4116 return false;
4117 error:
4118 /*
4119 Mixed engines not yet supported but when supported it will need
4120 the partition handler
4121 */
4122 my_error(ER_MIX_HANDLER_ERROR, MYF(0));
4123 *ret_val = false;
4124 return true;
4125 }
4126
4127 /**
4128 Set part_state for all partitions to given state.
4129
4130 @param tab_part_info partition_info holding all partitions.
4131 @param part_state Which state to set for the named partitions.
4132 */
4133
set_all_part_state(partition_info * tab_part_info,enum partition_state part_state)4134 void set_all_part_state(partition_info *tab_part_info,
4135 enum partition_state part_state) {
4136 uint part_count = 0;
4137 List_iterator<partition_element> part_it(tab_part_info->partitions);
4138
4139 do {
4140 partition_element *part_elem = part_it++;
4141 part_elem->part_state = part_state;
4142 if (tab_part_info->is_sub_partitioned()) {
4143 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4144 partition_element *sub_elem;
4145 while ((sub_elem = sub_it++)) {
4146 sub_elem->part_state = part_state;
4147 }
4148 }
4149 } while (++part_count < tab_part_info->num_parts);
4150 }
4151
4152 /**
4153 Sets which partitions to be used in the command.
4154
4155 @param alter_info Alter_info pointer holding partition names and flags.
4156 @param tab_part_info partition_info holding all partitions.
4157 @param part_state Which state to set for the named partitions.
4158 @param include_subpartitions Also include subpartitions in the search.
4159
4160 @return Operation status
4161 @retval false Success
4162 @retval true Failure
4163 */
4164
set_part_state(Alter_info * alter_info,partition_info * tab_part_info,enum partition_state part_state,bool include_subpartitions)4165 bool set_part_state(Alter_info *alter_info, partition_info *tab_part_info,
4166 enum partition_state part_state,
4167 bool include_subpartitions) {
4168 uint part_count = 0;
4169 uint num_parts_found = 0;
4170 List_iterator<partition_element> part_it(tab_part_info->partitions);
4171
4172 do {
4173 partition_element *part_elem = part_it++;
4174 if ((alter_info->flags & Alter_info::ALTER_ALL_PARTITION) ||
4175 (is_name_in_list(part_elem->partition_name,
4176 alter_info->partition_names))) {
4177 /*
4178 Mark the partition.
4179 I.e mark the partition as a partition to be "changed" by
4180 analyzing/optimizing/rebuilding/checking/repairing/...
4181 */
4182 num_parts_found++;
4183 part_elem->part_state = part_state;
4184 DBUG_PRINT("info", ("Setting part_state to %u for partition %s",
4185 part_state, part_elem->partition_name));
4186 } else if (include_subpartitions && tab_part_info->is_sub_partitioned()) {
4187 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4188 partition_element *sub_elem;
4189 while ((sub_elem = sub_it++)) {
4190 if (is_name_in_list(sub_elem->partition_name,
4191 alter_info->partition_names)) {
4192 num_parts_found++;
4193 sub_elem->part_state = part_state;
4194 DBUG_PRINT("info", ("Setting part_state to %u for subpartition %s",
4195 part_state, sub_elem->partition_name));
4196 } else
4197 sub_elem->part_state = PART_NORMAL;
4198 }
4199 part_elem->part_state = PART_NORMAL;
4200 } else
4201 part_elem->part_state = PART_NORMAL;
4202 } while (++part_count < tab_part_info->num_parts);
4203
4204 if (num_parts_found != alter_info->partition_names.elements &&
4205 !(alter_info->flags & Alter_info::ALTER_ALL_PARTITION)) {
4206 /* Not all given partitions found, revert and return failure */
4207 set_all_part_state(tab_part_info, PART_NORMAL);
4208 return true;
4209 }
4210 return false;
4211 }
4212
4213 /**
4214 @brief Check if partition is exchangable with table by checking table options
4215
4216 @param table_create_info Table options from table.
4217 @param part_elem All the info of the partition.
4218
4219 @retval false if they are equal, otherwise true.
4220
4221 @note Any differens that would cause a change in the frm file is prohibited.
4222 Such options as data_file_name, index_file_name, min_rows, max_rows etc. are
4223 not allowed to differ. But comment is allowed to differ.
4224 */
compare_partition_options(HA_CREATE_INFO * table_create_info,partition_element * part_elem)4225 bool compare_partition_options(HA_CREATE_INFO *table_create_info,
4226 partition_element *part_elem) {
4227 #define MAX_COMPARE_PARTITION_OPTION_ERRORS 5
4228 const char *option_diffs[MAX_COMPARE_PARTITION_OPTION_ERRORS + 1];
4229 int i, errors = 0;
4230 DBUG_TRACE;
4231 // TODO: Add test for EXCHANGE PARTITION with TABLESPACES!
4232 // Then if all works, simply remove the check for TABLESPACE (and eventually
4233 // DATA/INDEX DIRECTORY too).
4234
4235 /*
4236 Note that there are not yet any engine supporting tablespace together
4237 with partitioning. TODO: when there are, add compare.
4238 */
4239 if (part_elem->tablespace_name || table_create_info->tablespace)
4240 option_diffs[errors++] = "TABLESPACE";
4241 if (part_elem->part_max_rows != table_create_info->max_rows)
4242 option_diffs[errors++] = "MAX_ROWS";
4243 if (part_elem->part_min_rows != table_create_info->min_rows)
4244 option_diffs[errors++] = "MIN_ROWS";
4245 if (part_elem->index_file_name || table_create_info->index_file_name)
4246 option_diffs[errors++] = "INDEX DIRECTORY";
4247
4248 for (i = 0; i < errors; i++)
4249 my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0), option_diffs[i]);
4250 return errors != 0;
4251 }
4252
4253 /*
4254 Prepare for ALTER TABLE of partition structure
4255
4256 @param[in] thd Thread object
4257 @param[in] table Table object
4258 @param[in,out] alter_info Alter information
4259 @param[in,out] create_info Create info for CREATE TABLE
4260 @param[in] alter_ctx ALTER TABLE runtime context
4261 @param[out] partition_changed Boolean indicating whether partition changed
4262 @param[out] new_part_info New partition_info object if in-place alter
4263 which requires mark-up in partition_info is
4264 possible.
4265
4266 @return Operation status
4267 @retval true Error
4268 @retval false Success
4269
4270 @note
4271 This method handles all preparations for ALTER TABLE for partitioned
4272 tables.
4273 We need to handle both partition management command such as Add Partition
4274 and others here as well as an ALTER TABLE that completely changes the
4275 partitioning and yet others that don't change anything at all. We start
4276 by checking the partition management variants and then check the general
4277 change patterns.
4278 */
4279
prep_alter_part_table(THD * thd,TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,Alter_table_ctx * alter_ctx MY_ATTRIBUTE ((unused)),bool * partition_changed,partition_info ** new_part_info)4280 uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info,
4281 HA_CREATE_INFO *create_info,
4282 Alter_table_ctx *alter_ctx MY_ATTRIBUTE((unused)),
4283 bool *partition_changed,
4284 partition_info **new_part_info) {
4285 DBUG_TRACE;
4286 DBUG_ASSERT(new_part_info);
4287
4288 /* Remove partitioning on a not partitioned table is not possible */
4289 if (!table->part_info &&
4290 (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING)) {
4291 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4292 return true;
4293 }
4294
4295 if (thd->work_part_info &&
4296 !(thd->work_part_info = thd->lex->part_info->get_clone(thd, true)))
4297 return true;
4298
4299 /* ALTER_ADMIN_PARTITION is handled in mysql_admin_table */
4300 DBUG_ASSERT(!(alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION));
4301
4302 if (alter_info->flags &
4303 (Alter_info::ALTER_ADD_PARTITION | Alter_info::ALTER_DROP_PARTITION |
4304 Alter_info::ALTER_COALESCE_PARTITION |
4305 Alter_info::ALTER_REORGANIZE_PARTITION | Alter_info::ALTER_TABLE_REORG |
4306 Alter_info::ALTER_REBUILD_PARTITION)) {
4307 partition_info *tab_part_info;
4308 partition_info *alt_part_info = thd->work_part_info;
4309 uint flags = 0;
4310 bool is_last_partition_reorged = false;
4311 part_elem_value *tab_max_elem_val = nullptr;
4312 part_elem_value *alt_max_elem_val = nullptr;
4313 longlong tab_max_range = 0, alt_max_range = 0;
4314 Partition_handler *part_handler = table->file->get_partition_handler();
4315
4316 if (!table->part_info) {
4317 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4318 return true;
4319 }
4320 if (!part_handler) {
4321 DBUG_ASSERT(0);
4322 my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
4323 return true;
4324 }
4325
4326 /*
4327 Open our intermediate table, we will operate on a temporary instance
4328 of the original table, to be able to skip copying all partitions.
4329 Open it as a copy of the original table, and modify its partition_info
4330 object to allow in-place ALTER implementation to perform the changes.
4331 */
4332 DBUG_ASSERT(thd->mdl_context.owns_equal_or_stronger_lock(
4333 MDL_key::TABLE, alter_ctx->db, alter_ctx->table_name,
4334 MDL_INTENTION_EXCLUSIVE));
4335
4336 /*
4337 We will operate on a cached instance of the original table,
4338 to be able to skip copying all non-changed partitions
4339 while allowing concurrent access.
4340
4341 We create a new partition_info object which will carry
4342 the new state of the partitions. It will only be temporary
4343 attached to the handler when needed and then detached afterwards
4344 (through handler::set_part_info()). That way it will not get reused
4345 by next statement, even if the table object is reused due to LOCK TABLE.
4346 */
4347 tab_part_info = table->part_info->get_full_clone(thd);
4348 if (!tab_part_info) {
4349 mem_alloc_error(sizeof(partition_info));
4350 return true;
4351 }
4352
4353 if (alter_info->flags & Alter_info::ALTER_TABLE_REORG) {
4354 uint new_part_no, curr_part_no;
4355 /*
4356 'ALTER TABLE t REORG PARTITION' only allowed with auto partition
4357 if default partitioning is used.
4358 */
4359
4360 if (tab_part_info->part_type != partition_type::HASH ||
4361 ((table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) &&
4362 !tab_part_info->use_default_num_partitions) ||
4363 ((!(table->s->db_type()->partition_flags() &
4364 HA_USE_AUTO_PARTITION)) &&
4365 tab_part_info->use_default_num_partitions)) {
4366 my_error(ER_REORG_NO_PARAM_ERROR, MYF(0));
4367 goto err;
4368 }
4369 new_part_no = part_handler->get_default_num_partitions(create_info);
4370 curr_part_no = tab_part_info->num_parts;
4371 if (new_part_no == curr_part_no) {
4372 /*
4373 No change is needed, we will have the same number of partitions
4374 after the change as before. Thus we can reply ok immediately
4375 without any changes at all.
4376 */
4377 flags = part_handler->alter_flags(alter_info->flags);
4378 if (flags & HA_INPLACE_CHANGE_PARTITION) {
4379 *new_part_info = tab_part_info;
4380 /* Force table re-open for consistency with the main case. */
4381 table->m_needs_reopen = true;
4382 }
4383
4384 thd->work_part_info = tab_part_info;
4385 return false;
4386 } else if (new_part_no > curr_part_no) {
4387 /*
4388 We will add more partitions, we use the ADD PARTITION without
4389 setting the flag for no default number of partitions
4390 */
4391 alter_info->flags |= Alter_info::ALTER_ADD_PARTITION;
4392 thd->work_part_info->num_parts = new_part_no - curr_part_no;
4393 } else {
4394 /*
4395 We will remove hash partitions, we use the COALESCE PARTITION
4396 without setting the flag for no default number of partitions
4397 */
4398 alter_info->flags |= Alter_info::ALTER_COALESCE_PARTITION;
4399 alter_info->num_parts = curr_part_no - new_part_no;
4400 }
4401 }
4402 if (!(flags = part_handler->alter_flags(alter_info->flags))) {
4403 my_error(ER_PARTITION_FUNCTION_FAILURE, MYF(0));
4404 goto err;
4405 }
4406 if (flags & HA_INPLACE_CHANGE_PARTITION) {
4407 /*
4408 "Inplace" change of partitioning is supported in this
4409 case. We will change TABLE::part_info (as this is how we pass
4410 information to storage engine in this case), so the table
4411 must be reopened.
4412 */
4413 *new_part_info = tab_part_info;
4414 table->m_needs_reopen = true;
4415 }
4416 DBUG_PRINT("info", ("*fast_alter_table flags: 0x%x", flags));
4417 if ((alter_info->flags & Alter_info::ALTER_ADD_PARTITION) ||
4418 (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION)) {
4419 if (thd->work_part_info->part_type != tab_part_info->part_type) {
4420 if (thd->work_part_info->part_type == partition_type::NONE) {
4421 if (tab_part_info->part_type == partition_type::RANGE) {
4422 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE");
4423 goto err;
4424 } else if (tab_part_info->part_type == partition_type::LIST) {
4425 my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST");
4426 goto err;
4427 }
4428 /*
4429 Hash partitions can be altered without parser finds out about
4430 that it is HASH partitioned. So no error here.
4431 */
4432 } else {
4433 if (thd->work_part_info->part_type == partition_type::RANGE) {
4434 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "RANGE",
4435 "LESS THAN");
4436 } else if (thd->work_part_info->part_type == partition_type::LIST) {
4437 DBUG_ASSERT(thd->work_part_info->part_type == partition_type::LIST);
4438 my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN");
4439 } else if (tab_part_info->part_type == partition_type::RANGE) {
4440 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE",
4441 "LESS THAN");
4442 } else {
4443 DBUG_ASSERT(tab_part_info->part_type == partition_type::LIST);
4444 my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN");
4445 }
4446 goto err;
4447 }
4448 }
4449 if ((tab_part_info->column_list &&
4450 alt_part_info->num_columns != tab_part_info->num_columns) ||
4451 (!tab_part_info->column_list &&
4452 (tab_part_info->part_type == partition_type::RANGE ||
4453 tab_part_info->part_type == partition_type::LIST) &&
4454 alt_part_info->num_columns != 1U) ||
4455 (!tab_part_info->column_list &&
4456 tab_part_info->part_type == partition_type::HASH &&
4457 alt_part_info->num_columns != 0)) {
4458 my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0));
4459 goto err;
4460 }
4461 alt_part_info->column_list = tab_part_info->column_list;
4462 if (alt_part_info->fix_parser_data(thd)) {
4463 goto err;
4464 }
4465 }
4466 if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION) {
4467 /*
4468 We start by moving the new partitions to the list of temporary
4469 partitions. We will then check that the new partitions fit in the
4470 partitioning scheme as currently set-up.
4471 Partitions are always added at the end in ADD PARTITION.
4472 */
4473 uint num_new_partitions = alt_part_info->num_parts;
4474 uint num_orig_partitions = tab_part_info->num_parts;
4475 uint check_total_partitions = num_new_partitions + num_orig_partitions;
4476 uint new_total_partitions = check_total_partitions;
4477 /*
4478 We allow quite a lot of values to be supplied by defaults, however we
4479 must know the number of new partitions in this case.
4480 */
4481 if (thd->lex->no_write_to_binlog &&
4482 tab_part_info->part_type != partition_type::HASH) {
4483 my_error(ER_NO_BINLOG_ERROR, MYF(0));
4484 goto err;
4485 }
4486 if (tab_part_info->defined_max_value) {
4487 my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0));
4488 goto err;
4489 }
4490 if (num_new_partitions == 0) {
4491 my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
4492 goto err;
4493 }
4494 if (tab_part_info->is_sub_partitioned()) {
4495 if (alt_part_info->num_subparts == 0)
4496 alt_part_info->num_subparts = tab_part_info->num_subparts;
4497 else if (alt_part_info->num_subparts != tab_part_info->num_subparts) {
4498 my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
4499 goto err;
4500 }
4501 check_total_partitions =
4502 new_total_partitions * alt_part_info->num_subparts;
4503 }
4504 if (check_total_partitions > MAX_PARTITIONS) {
4505 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4506 goto err;
4507 }
4508 alt_part_info->part_type = tab_part_info->part_type;
4509 alt_part_info->subpart_type = tab_part_info->subpart_type;
4510 if (alt_part_info->set_up_defaults_for_partitioning(
4511 part_handler, nullptr, tab_part_info->num_parts)) {
4512 goto err;
4513 }
4514 /*
4515 Handling of on-line cases:
4516
4517 ADD PARTITION for RANGE/LIST PARTITIONING:
4518 ------------------------------------------
4519 For range and list partitions add partition is simply adding a
4520 new empty partition to the table. If the handler support this we
4521 will use the simple method of doing this. The figure below shows
4522 an example of this and the states involved in making this change.
4523
4524 Existing partitions New added
4525 partitions
4526 ------ ------ ------ ------ | ------ ------
4527 | | | | | | | | | | | | |
4528 | p0 | | p1 | | p2 | | p3 | | | p4 | | p5 |
4529 ------ ------ ------ ------ | ------ ------
4530 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_TO_BE_ADDED*2
4531 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_ADDED*2
4532
4533 The first line is the states before adding the new partitions and the
4534 second line is after the new partitions are added. All the partitions are
4535 in the partitions list, no partitions are placed in the temp_partitions
4536 list.
4537
4538 ADD PARTITION for HASH PARTITIONING
4539 -----------------------------------
4540 This little figure tries to show the various partitions involved when
4541 adding two new partitions to a linear hash based partitioned table with
4542 four partitions to start with, which lists are used and the states they
4543 pass through. Adding partitions to a normal hash based is similar except
4544 that it is always all the existing partitions that are reorganised not
4545 only a subset of them.
4546
4547 Existing partitions New added
4548 partitions
4549 ------ ------ ------ ------ | ------ ------
4550 | | | | | | | | | | | | |
4551 | p0 | | p1 | | p2 | | p3 | | | p4 | | p5 |
4552 ------ ------ ------ ------ | ------ ------
4553 PART_CHANGED PART_CHANGED PART_NORMAL PART_NORMAL PART_TO_BE_ADDED
4554 PART_IS_CHANGED*2 PART_NORMAL PART_NORMAL PART_IS_ADDED
4555 PART_NORMAL PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_ADDED
4556
4557 Reorganised existing partitions
4558 ------ ------
4559 | | | |
4560 | p0'| | p1'|
4561 ------ ------
4562
4563 p0 - p5 will be in the partitions list of partitions.
4564 p0' and p1' will actually not exist as separate objects, there presence
4565 can be deduced from the state of the partition and also the names of those
4566 partitions can be deduced this way.
4567
4568 After adding the partitions and copying the partition data to p0', p1',
4569 p4 and p5 from p0 and p1 the states change to adapt for the new situation
4570 where p0 and p1 is dropped and replaced by p0' and p1' and the new p4 and
4571 p5 are in the table again.
4572
4573 The first line above shows the states of the partitions before we start
4574 adding and copying partitions, the second after completing the adding
4575 and copying and finally the third line after also dropping the partitions
4576 that are reorganised.
4577 */
4578 if (*new_part_info && tab_part_info->part_type == partition_type::HASH) {
4579 uint part_no = 0, start_part = 1, start_sec_part = 1;
4580 uint end_part = 0, end_sec_part = 0;
4581 uint upper_2n = tab_part_info->linear_hash_mask + 1;
4582 uint lower_2n = upper_2n >> 1;
4583 bool all_parts = true;
4584 if (tab_part_info->linear_hash_ind && num_new_partitions < upper_2n) {
4585 /*
4586 An analysis of which parts needs reorganisation shows that it is
4587 divided into two intervals. The first interval is those parts
4588 that are reorganised up until upper_2n - 1. From upper_2n and
4589 onwards it starts again from partition 0 and goes on until
4590 it reaches p(upper_2n - 1). If the last new partition reaches
4591 beyond upper_2n - 1 then the first interval will end with
4592 p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n).
4593 If lower_2n partitions are added then p0 to p(lower_2n - 1) will
4594 be reorganised which means that the two interval becomes one
4595 interval at this point. Thus only when adding less than
4596 lower_2n partitions and going beyond a total of upper_2n we
4597 actually get two intervals.
4598
4599 To exemplify this assume we have 6 partitions to start with and
4600 add 1, 2, 3, 5, 6, 7, 8, 9 partitions.
4601 The first to add after p5 is p6 = 110 in bit numbers. Thus we
4602 can see that 10 = p2 will be partition to reorganise if only one
4603 partition.
4604 If 2 partitions are added we reorganise [p2, p3]. Those two
4605 cases are covered by the second if part below.
4606 If 3 partitions are added we reorganise [p2, p3] U [p0,p0]. This
4607 part is covered by the else part below.
4608 If 5 partitions are added we get [p2,p3] U [p0, p2] = [p0, p3].
4609 This is covered by the first if part where we need the max check
4610 to here use lower_2n - 1.
4611 If 7 partitions are added we get [p2,p3] U [p0, p4] = [p0, p4].
4612 This is covered by the first if part but here we use the first
4613 calculated end_part.
4614 Finally with 9 new partitions we would also reorganise p6 if we
4615 used the method below but we cannot reorganise more partitions
4616 than what we had from the start and thus we simply set all_parts
4617 to true. In this case we don't get into this if-part at all.
4618 */
4619 all_parts = false;
4620 if (num_new_partitions >= lower_2n) {
4621 /*
4622 In this case there is only one interval since the two intervals
4623 overlap and this starts from zero to last_part_no - upper_2n
4624 */
4625 start_part = 0;
4626 end_part = new_total_partitions - (upper_2n + 1);
4627 end_part = max(lower_2n - 1, end_part);
4628 } else if (new_total_partitions <= upper_2n) {
4629 /*
4630 Also in this case there is only one interval since we are not
4631 going over a 2**n boundary
4632 */
4633 start_part = num_orig_partitions - lower_2n;
4634 end_part = start_part + (num_new_partitions - 1);
4635 } else {
4636 /* We have two non-overlapping intervals since we are not
4637 passing a 2**n border and we have not at least lower_2n
4638 new parts that would ensure that the intervals become
4639 overlapping.
4640 */
4641 start_part = num_orig_partitions - lower_2n;
4642 end_part = upper_2n - 1;
4643 start_sec_part = 0;
4644 end_sec_part = new_total_partitions - (upper_2n + 1);
4645 }
4646 }
4647 List_iterator<partition_element> tab_it(tab_part_info->partitions);
4648 part_no = 0;
4649 do {
4650 partition_element *p_elem = tab_it++;
4651 if (all_parts || (part_no >= start_part && part_no <= end_part) ||
4652 (part_no >= start_sec_part && part_no <= end_sec_part)) {
4653 p_elem->part_state = PART_CHANGED;
4654 }
4655 } while (++part_no < num_orig_partitions);
4656 }
4657 /*
4658 Need to concatenate the lists here to make it possible to check the
4659 partition info for correctness using check_partition_info.
4660 For on-line add partition we set the state of this partition to
4661 PART_TO_BE_ADDED to ensure that it is known that it is not yet
4662 usable (becomes usable when partition is created and the switch of
4663 partition configuration is made.
4664 */
4665 {
4666 List_iterator<partition_element> alt_it(alt_part_info->partitions);
4667 uint part_count = 0;
4668 do {
4669 partition_element *part_elem = alt_it++;
4670 if (*new_part_info) part_elem->part_state = PART_TO_BE_ADDED;
4671 if (tab_part_info->partitions.push_back(part_elem)) {
4672 mem_alloc_error(1);
4673 goto err;
4674 }
4675 } while (++part_count < num_new_partitions);
4676 tab_part_info->num_parts += num_new_partitions;
4677 }
4678 /*
4679 If we specify partitions explicitly we don't use defaults anymore.
4680 Using ADD PARTITION also means that we don't have the default number
4681 of partitions anymore. We use this code also for Table reorganisations
4682 and here we don't set any default flags to false.
4683 */
4684 if (!(alter_info->flags & Alter_info::ALTER_TABLE_REORG)) {
4685 if (!alt_part_info->use_default_partitions) {
4686 DBUG_PRINT("info", ("part_info: %p", tab_part_info));
4687 tab_part_info->use_default_partitions = false;
4688 }
4689 tab_part_info->use_default_num_partitions = false;
4690 tab_part_info->is_auto_partitioned = false;
4691 }
4692 } else if (alter_info->flags & Alter_info::ALTER_DROP_PARTITION) {
4693 /*
4694 Drop a partition from a range partition and list partitioning is
4695 always safe and can be made more or less immediate. It is necessary
4696 however to ensure that the partition to be removed is safely removed
4697 and that REPAIR TABLE can remove the partition if for some reason the
4698 command to drop the partition failed in the middle.
4699 */
4700 uint part_count = 0;
4701 uint num_parts_dropped = alter_info->partition_names.elements;
4702 uint num_parts_found = 0;
4703 List_iterator<partition_element> part_it(tab_part_info->partitions);
4704
4705 tab_part_info->is_auto_partitioned = false;
4706 if (!(tab_part_info->part_type == partition_type::RANGE ||
4707 tab_part_info->part_type == partition_type::LIST)) {
4708 my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
4709 goto err;
4710 }
4711 if (num_parts_dropped >= tab_part_info->num_parts) {
4712 my_error(ER_DROP_LAST_PARTITION, MYF(0));
4713 goto err;
4714 }
4715 do {
4716 partition_element *part_elem = part_it++;
4717 if (is_name_in_list(part_elem->partition_name,
4718 alter_info->partition_names)) {
4719 /*
4720 Set state to indicate that the partition is to be dropped.
4721 */
4722 num_parts_found++;
4723 part_elem->part_state = PART_TO_BE_DROPPED;
4724 }
4725 } while (++part_count < tab_part_info->num_parts);
4726 if (num_parts_found != num_parts_dropped) {
4727 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP");
4728 goto err;
4729 }
4730 tab_part_info->num_parts -= num_parts_dropped;
4731 } else if (alter_info->flags & Alter_info::ALTER_REBUILD_PARTITION) {
4732 set_engine_all_partitions(tab_part_info,
4733 tab_part_info->default_engine_type);
4734 if (set_part_state(alter_info, tab_part_info, PART_CHANGED, false)) {
4735 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD");
4736 goto err;
4737 }
4738 if (!(*new_part_info)) {
4739 table->file->print_error(HA_ERR_WRONG_COMMAND, MYF(0));
4740 goto err;
4741 }
4742 } else if (alter_info->flags & Alter_info::ALTER_COALESCE_PARTITION) {
4743 uint num_parts_coalesced = alter_info->num_parts;
4744 uint num_parts_remain = tab_part_info->num_parts - num_parts_coalesced;
4745 List_iterator<partition_element> part_it(tab_part_info->partitions);
4746 if (tab_part_info->part_type != partition_type::HASH) {
4747 my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
4748 goto err;
4749 }
4750 if (num_parts_coalesced == 0) {
4751 my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
4752 goto err;
4753 }
4754 if (num_parts_coalesced >= tab_part_info->num_parts) {
4755 my_error(ER_DROP_LAST_PARTITION, MYF(0));
4756 goto err;
4757 }
4758 /*
4759 Online handling:
4760 COALESCE PARTITION:
4761 -------------------
4762 The figure below shows the manner in which partitions are handled when
4763 performing an on-line coalesce partition and which states they go through
4764 at start, after adding and copying partitions and finally after dropping
4765 the partitions to drop. The figure shows an example using four partitions
4766 to start with, using linear hash and coalescing one partition (always the
4767 last partition).
4768
4769 Using linear hash then all remaining partitions will have a new
4770 reorganised part.
4771
4772 Existing partitions Coalesced partition
4773 ------ ------ ------ | ------
4774 | | | | | | | | |
4775 | p0 | | p1 | | p2 | | | p3 |
4776 ------ ------ ------ | ------
4777 PART_NORMAL PART_CHANGED PART_NORMAL PART_REORGED_DROPPED
4778 PART_NORMAL PART_IS_CHANGED PART_NORMAL PART_TO_BE_DROPPED
4779 PART_NORMAL PART_NORMAL PART_NORMAL PART_IS_DROPPED
4780
4781 Reorganised existing partitions
4782 ------
4783 | |
4784 | p1'|
4785 ------
4786
4787 p0 - p3 is in the partitions list.
4788 The p1' partition will actually not be in any list it is deduced from the
4789 state of p1.
4790 */
4791 {
4792 uint part_count = 0, start_part = 1, start_sec_part = 1;
4793 uint end_part = 0, end_sec_part = 0;
4794 bool all_parts = true;
4795 if (*new_part_info && tab_part_info->linear_hash_ind) {
4796 uint upper_2n = tab_part_info->linear_hash_mask + 1;
4797 uint lower_2n = upper_2n >> 1;
4798 all_parts = false;
4799 if (num_parts_coalesced >= lower_2n) {
4800 all_parts = true;
4801 } else if (num_parts_remain >= lower_2n) {
4802 end_part = tab_part_info->num_parts - (lower_2n + 1);
4803 start_part = num_parts_remain - lower_2n;
4804 } else {
4805 start_part = 0;
4806 end_part = tab_part_info->num_parts - (lower_2n + 1);
4807 end_sec_part = (lower_2n >> 1) - 1;
4808 start_sec_part = end_sec_part - (lower_2n - (num_parts_remain + 1));
4809 }
4810 }
4811 do {
4812 partition_element *p_elem = part_it++;
4813 if (*new_part_info &&
4814 (all_parts ||
4815 (part_count >= start_part && part_count <= end_part) ||
4816 (part_count >= start_sec_part && part_count <= end_sec_part)))
4817 p_elem->part_state = PART_CHANGED;
4818 if (++part_count > num_parts_remain) {
4819 if (*new_part_info)
4820 p_elem->part_state = PART_REORGED_DROPPED;
4821 else
4822 part_it.remove();
4823 }
4824 } while (part_count < tab_part_info->num_parts);
4825 tab_part_info->num_parts = num_parts_remain;
4826 }
4827 if (!(alter_info->flags & Alter_info::ALTER_TABLE_REORG)) {
4828 tab_part_info->use_default_num_partitions = false;
4829 tab_part_info->is_auto_partitioned = false;
4830 }
4831 } else if (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION) {
4832 /*
4833 Reorganise partitions takes a number of partitions that are next
4834 to each other (at least for RANGE PARTITIONS) and then uses those
4835 to create a set of new partitions. So data is copied from those
4836 partitions into the new set of partitions. Those new partitions
4837 can have more values in the LIST value specifications or less both
4838 are allowed. The ranges can be different but since they are
4839 changing a set of consecutive partitions they must cover the same
4840 range as those changed from.
4841 This command can be used on RANGE and LIST partitions.
4842 */
4843 uint num_parts_reorged = alter_info->partition_names.elements;
4844 uint num_parts_new = thd->work_part_info->partitions.elements;
4845 uint check_total_partitions;
4846
4847 tab_part_info->is_auto_partitioned = false;
4848 if (num_parts_reorged > tab_part_info->num_parts) {
4849 my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
4850 goto err;
4851 }
4852 if (!(tab_part_info->part_type == partition_type::RANGE ||
4853 tab_part_info->part_type == partition_type::LIST) &&
4854 (num_parts_new != num_parts_reorged)) {
4855 my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0));
4856 goto err;
4857 }
4858 if (tab_part_info->is_sub_partitioned() && alt_part_info->num_subparts &&
4859 alt_part_info->num_subparts != tab_part_info->num_subparts) {
4860 my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0));
4861 goto err;
4862 }
4863 check_total_partitions = tab_part_info->num_parts + num_parts_new;
4864 check_total_partitions -= num_parts_reorged;
4865 if (check_total_partitions > MAX_PARTITIONS) {
4866 my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
4867 goto err;
4868 }
4869 alt_part_info->part_type = tab_part_info->part_type;
4870 alt_part_info->subpart_type = tab_part_info->subpart_type;
4871 alt_part_info->num_subparts = tab_part_info->num_subparts;
4872 DBUG_ASSERT(!alt_part_info->use_default_partitions);
4873 /* We specified partitions explicitly so don't use defaults anymore. */
4874 tab_part_info->use_default_partitions = false;
4875 if (alt_part_info->set_up_defaults_for_partitioning(part_handler, nullptr,
4876 0)) {
4877 goto err;
4878 }
4879 /*
4880 Online handling:
4881 REORGANIZE PARTITION:
4882 ---------------------
4883 The figure exemplifies the handling of partitions, their state changes and
4884 how they are organised. It exemplifies four partitions where two of the
4885 partitions are reorganised (p1 and p2) into two new partitions (p4 and
4886 p5). The reason of this change could be to change range limits, change
4887 list values or for hash partitions simply reorganise the partition which
4888 could also involve moving them to new disks or new node groups (MySQL
4889 Cluster).
4890
4891 Existing partitions
4892 ------ ------ ------ ------
4893 | | | | | | | |
4894 | p0 | | p1 | | p2 | | p3 |
4895 ------ ------ ------ ------
4896 PART_NORMAL PART_TO_BE_REORGED PART_NORMAL
4897 PART_NORMAL PART_TO_BE_DROPPED PART_NORMAL
4898 PART_NORMAL PART_IS_DROPPED PART_NORMAL
4899
4900 Reorganised new partitions (replacing p1 and p2)
4901 ------ ------
4902 | | | |
4903 | p4 | | p5 |
4904 ------ ------
4905 PART_TO_BE_ADDED
4906 PART_IS_ADDED
4907 PART_IS_ADDED
4908
4909 All unchanged partitions and the new partitions are in the partitions list
4910 in the order they will have when the change is completed. The reorganised
4911 partitions are placed in the temp_partitions list. PART_IS_ADDED is only a
4912 temporary state not written in the frm file. It is used to ensure we write
4913 the generated partition syntax in a correct manner.
4914 */
4915 {
4916 List_iterator<partition_element> tab_it(tab_part_info->partitions);
4917 uint part_count = 0;
4918 bool found_first = false;
4919 bool found_last = false;
4920 uint drop_count = 0;
4921 do {
4922 partition_element *part_elem = tab_it++;
4923 is_last_partition_reorged = false;
4924 if (is_name_in_list(part_elem->partition_name,
4925 alter_info->partition_names)) {
4926 is_last_partition_reorged = true;
4927 drop_count++;
4928 if (tab_part_info->column_list) {
4929 List_iterator<part_elem_value> p(part_elem->list_val_list);
4930 tab_max_elem_val = p++;
4931 } else
4932 tab_max_range = part_elem->range_value;
4933 if (*new_part_info &&
4934 tab_part_info->temp_partitions.push_back(part_elem)) {
4935 mem_alloc_error(1);
4936 goto err;
4937 }
4938 if (*new_part_info) part_elem->part_state = PART_TO_BE_REORGED;
4939 if (!found_first) {
4940 uint alt_part_count = 0;
4941 partition_element *alt_part_elem;
4942 List_iterator<partition_element> alt_it(
4943 alt_part_info->partitions);
4944 found_first = true;
4945 do {
4946 alt_part_elem = alt_it++;
4947 if (tab_part_info->column_list) {
4948 List_iterator<part_elem_value> p(
4949 alt_part_elem->list_val_list);
4950 alt_max_elem_val = p++;
4951 } else
4952 alt_max_range = alt_part_elem->range_value;
4953
4954 if (*new_part_info)
4955 alt_part_elem->part_state = PART_TO_BE_ADDED;
4956 if (alt_part_count == 0)
4957 tab_it.replace(alt_part_elem);
4958 else
4959 tab_it.after(alt_part_elem);
4960 } while (++alt_part_count < num_parts_new);
4961 } else if (found_last) {
4962 my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
4963 goto err;
4964 } else
4965 tab_it.remove();
4966 } else {
4967 if (found_first) found_last = true;
4968 }
4969 } while (++part_count < tab_part_info->num_parts);
4970 if (drop_count != num_parts_reorged) {
4971 my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE");
4972 goto err;
4973 }
4974 tab_part_info->num_parts = check_total_partitions;
4975 }
4976 } else {
4977 DBUG_ASSERT(false);
4978 }
4979 *partition_changed = true;
4980 thd->work_part_info = tab_part_info;
4981 if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION ||
4982 alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION) {
4983 if (tab_part_info->use_default_subpartitions &&
4984 !alt_part_info->use_default_subpartitions) {
4985 tab_part_info->use_default_subpartitions = false;
4986 tab_part_info->use_default_num_subpartitions = false;
4987 }
4988 if (tab_part_info->check_partition_info(thd, (handlerton **)nullptr,
4989 table->file, nullptr, true)) {
4990 goto err;
4991 }
4992 /*
4993 The check below needs to be performed after check_partition_info
4994 since this function "fixes" the item trees of the new partitions
4995 to reorganize into
4996 */
4997 if (alter_info->flags == Alter_info::ALTER_REORGANIZE_PARTITION &&
4998 tab_part_info->part_type == partition_type::RANGE) {
4999 bool is_error;
5000 if (is_last_partition_reorged) {
5001 if (tab_part_info->column_list) {
5002 is_error = tab_part_info->compare_column_values(
5003 alt_max_elem_val->col_val_array,
5004 tab_max_elem_val->col_val_array); // a < b.
5005 } else {
5006 is_error = alt_max_range < tab_max_range;
5007 }
5008 } else {
5009 if (tab_part_info->column_list) {
5010 is_error = tab_part_info->compare_column_values(
5011 alt_max_elem_val->col_val_array,
5012 tab_max_elem_val->col_val_array) ||
5013 tab_part_info->compare_column_values(
5014 tab_max_elem_val->col_val_array,
5015 alt_max_elem_val->col_val_array); // a != b.
5016 } else {
5017 is_error = alt_max_range != tab_max_range;
5018 }
5019 }
5020 if (is_error) {
5021 /*
5022 For range partitioning the total resulting range before and
5023 after the change must be the same except in one case. This is
5024 when the last partition is reorganised, in this case it is
5025 acceptable to increase the total range.
5026 The reason is that it is not allowed to have "holes" in the
5027 middle of the ranges and thus we should not allow to reorganise
5028 to create "holes".
5029 */
5030 my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
5031 goto err;
5032 }
5033 }
5034 }
5035 } else {
5036 /*
5037 When thd->lex->part_info has a reference to a partition_info the
5038 ALTER TABLE contained a definition of a partitioning.
5039
5040 Case I:
5041 If there was a partition before and there is a new one defined.
5042 We use the new partitioning. The new partitioning is already
5043 defined in the correct variable so no work is needed to
5044 accomplish this.
5045 We do however need to update partition_changed to ensure that not
5046 only the frm file is changed in the ALTER TABLE command.
5047
5048 Case IIa:
5049 There was a partitioning before and there is no new one defined.
5050 Also the user has not specified to remove partitioning explicitly.
5051
5052 We use the old partitioning also for the new table. We do this
5053 by assigning the partition_info from the table loaded in
5054 open_table to the partition_info struct used by mysql_create_table
5055 later in this method.
5056
5057 Case IIb:
5058 There was a partitioning before and there is no new one defined.
5059 The user has specified explicitly to remove partitioning
5060
5061 Since the user has specified explicitly to remove partitioning
5062 we override the old partitioning info and create a new table using
5063 the specified engine.
5064 In this case the partition also is changed.
5065
5066 Case III:
5067 There was no partitioning before altering the table, there is
5068 partitioning defined in the altered table. Use the new partitioning.
5069 No work needed since the partitioning info is already in the
5070 correct variable.
5071
5072 In this case we discover one case where the new partitioning is using
5073 the same partition function as the default (PARTITION BY KEY or
5074 PARTITION BY LINEAR KEY with the list of fields equal to the primary
5075 key fields OR PARTITION BY [LINEAR] KEY() for tables without primary
5076 key)
5077 Also here partition has changed and thus a new table must be
5078 created.
5079
5080 Case IV:
5081 There was no partitioning before and no partitioning defined.
5082 Obviously no work needed.
5083 */
5084 partition_info *tab_part_info = table->part_info;
5085
5086 if (tab_part_info) {
5087 /*
5088 The table must be reopened, this is necessary to avoid situations
5089 where a failing ALTER leaves behind a TABLE object which has its
5090 partitioning information updated by the SE, as InnoDB is doing in
5091 update_create_info().
5092 */
5093 table->m_needs_reopen = true;
5094 if (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING) {
5095 DBUG_PRINT("info", ("Remove partitioning"));
5096 if (!(create_info->used_fields & HA_CREATE_USED_ENGINE)) {
5097 DBUG_PRINT("info", ("No explicit engine used"));
5098 create_info->db_type = tab_part_info->default_engine_type;
5099 }
5100 DBUG_PRINT("info",
5101 ("New engine type: %s",
5102 ha_resolve_storage_engine_name(create_info->db_type)));
5103 thd->work_part_info = nullptr;
5104 *partition_changed = true;
5105 } else if (!thd->work_part_info) {
5106 /*
5107 Retain partitioning but possibly with a new storage engine
5108 beneath.
5109
5110 Create a copy of TABLE::part_info to be able to modify it freely.
5111 */
5112 if (!(tab_part_info = tab_part_info->get_clone(thd))) return true;
5113 thd->work_part_info = tab_part_info;
5114 if (create_info->used_fields & HA_CREATE_USED_ENGINE &&
5115 create_info->db_type != tab_part_info->default_engine_type) {
5116 /*
5117 Make sure change of engine happens to all partitions.
5118 */
5119 DBUG_PRINT("info", ("partition changed"));
5120 if (tab_part_info->is_auto_partitioned) {
5121 /*
5122 If the user originally didn't specify partitioning to be
5123 used we can remove it now.
5124 */
5125 thd->work_part_info = nullptr;
5126 } else {
5127 /*
5128 Ensure that all partitions have the proper engine set-up
5129 */
5130 set_engine_all_partitions(thd->work_part_info,
5131 create_info->db_type);
5132 }
5133 *partition_changed = true;
5134 }
5135 }
5136 }
5137 if (thd->work_part_info) {
5138 partition_info *part_info = thd->work_part_info;
5139 bool is_native_partitioned = false;
5140 /*
5141 Need to cater for engine types that can handle partition without
5142 using the partition handler.
5143 */
5144 if (part_info != tab_part_info) {
5145 if (part_info->fix_parser_data(thd)) {
5146 goto err;
5147 }
5148 /*
5149 Compare the old and new part_info. If only key_algorithm
5150 change is done, don't consider it as changed partitioning (to avoid
5151 rebuild). This is to handle KEY (numeric_cols) partitioned tables
5152 created in 5.1. For more info, see bug#14521864.
5153 */
5154 if (alter_info->flags != Alter_info::ALTER_PARTITION ||
5155 !table->part_info ||
5156 alter_info->requested_algorithm !=
5157 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE ||
5158 !table->part_info->has_same_partitioning(part_info)) {
5159 DBUG_PRINT("info", ("partition changed"));
5160 *partition_changed = true;
5161 }
5162 }
5163 /*
5164 Set up partition default_engine_type either from the create_info
5165 or from the previus table
5166 */
5167 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5168 part_info->default_engine_type = create_info->db_type;
5169 else {
5170 if (tab_part_info)
5171 part_info->default_engine_type = tab_part_info->default_engine_type;
5172 else
5173 part_info->default_engine_type = create_info->db_type;
5174 }
5175 if (check_native_partitioned(create_info, &is_native_partitioned,
5176 part_info, thd)) {
5177 goto err;
5178 }
5179 if (!is_native_partitioned) {
5180 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "native partitioning");
5181 goto err;
5182 }
5183 }
5184 }
5185 return false;
5186 err:
5187 *new_part_info = nullptr;
5188 return true;
5189 }
5190
5191 /*
5192 Prepare for calling val_int on partition function by setting fields to
5193 point to the record where the values of the PF-fields are stored.
5194
5195 SYNOPSIS
5196 set_field_ptr()
5197 ptr Array of fields to change ptr
5198 new_buf New record pointer
5199 old_buf Old record pointer
5200
5201 DESCRIPTION
5202 Set ptr in field objects of field array to refer to new_buf record
5203 instead of previously old_buf. Used before calling val_int and after
5204 it is used to restore pointers to table->record[0].
5205 This routine is placed outside of partition code since it can be useful
5206 also for other programs.
5207 */
5208
set_field_ptr(Field ** ptr,const uchar * new_buf,const uchar * old_buf)5209 static void set_field_ptr(Field **ptr, const uchar *new_buf,
5210 const uchar *old_buf) {
5211 ptrdiff_t diff = (new_buf - old_buf);
5212 DBUG_TRACE;
5213
5214 do {
5215 (*ptr)->move_field_offset(diff);
5216 } while (*(++ptr));
5217 }
5218
5219 /**
5220 Append all fields in read_set to string
5221
5222 @param[in,out] str String to append to.
5223 @param[in] row Row to append.
5224 @param[in] table Table containing read_set and fields for the row.
5225 */
append_row_to_str(String & str,const uchar * row,TABLE * table)5226 void append_row_to_str(String &str, const uchar *row, TABLE *table) {
5227 Field **fields, **field_ptr;
5228 const uchar *rec;
5229 uint num_fields = bitmap_bits_set(table->read_set);
5230 uint curr_field_index = 0;
5231 bool is_rec0 = !row || row == table->record[0];
5232 if (!row)
5233 rec = table->record[0];
5234 else
5235 rec = row;
5236
5237 /* Create a new array of all read fields. */
5238 fields = (Field **)my_malloc(key_memory_handler_errmsgs,
5239 sizeof(void *) * (num_fields + 1), MYF(0));
5240 if (!fields) return;
5241 fields[num_fields] = nullptr;
5242 for (field_ptr = table->field; *field_ptr; field_ptr++) {
5243 if (!bitmap_is_set(table->read_set, (*field_ptr)->field_index())) continue;
5244 fields[curr_field_index++] = *field_ptr;
5245 }
5246
5247 if (!is_rec0) set_field_ptr(fields, rec, table->record[0]);
5248
5249 for (field_ptr = fields; *field_ptr; field_ptr++) {
5250 Field *field = *field_ptr;
5251 str.append(" ");
5252 str.append(field->field_name);
5253 str.append(":");
5254 field_unpack(&str, field, 0, false);
5255 }
5256
5257 if (!is_rec0) set_field_ptr(fields, table->record[0], rec);
5258 my_free(fields);
5259 }
5260
5261 /*
5262 SYNOPSIS
5263 mem_alloc_error()
5264 size Size of memory attempted to allocate
5265 None
5266
5267 RETURN VALUES
5268 None
5269
5270 DESCRIPTION
5271 A routine to use for all the many places in the code where memory
5272 allocation error can happen, a tremendous amount of them, needs
5273 simple routine that signals this error.
5274 */
5275
mem_alloc_error(size_t size)5276 void mem_alloc_error(size_t size) {
5277 my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), static_cast<int>(size));
5278 }
5279
5280 /**
5281 Return comma-separated list of used partitions in the provided given string.
5282
5283 @param part_info Partitioning info
5284 @param[out] parts The resulting list of string to fill
5285
5286 Generate a list of used partitions (from bits in part_info->read_partitions
5287 bitmap), and store it into the provided String object.
5288
5289 @note
5290 The produced string must not be longer then MAX_PARTITIONS * (1 + FN_LEN).
5291 In case of UPDATE, only the partitions read is given, not the partitions
5292 that was written or locked.
5293 */
5294
make_used_partitions_str(partition_info * part_info,List<const char> * parts)5295 bool make_used_partitions_str(partition_info *part_info,
5296 List<const char> *parts) {
5297 parts->empty();
5298 partition_element *pe;
5299 uint partition_id = 0;
5300 List_iterator<partition_element> it(part_info->partitions);
5301 StringBuffer<FN_LEN> part_str(system_charset_info);
5302
5303 if (part_info->is_sub_partitioned()) {
5304 partition_element *head_pe;
5305 while ((head_pe = it++)) {
5306 List_iterator<partition_element> it2(head_pe->subpartitions);
5307 while ((pe = it2++)) {
5308 if (bitmap_is_set(&part_info->read_partitions, partition_id)) {
5309 part_str.length(0);
5310 if ((part_str.append(head_pe->partition_name,
5311 strlen(head_pe->partition_name),
5312 system_charset_info)) ||
5313 part_str.append('_') ||
5314 part_str.append(pe->partition_name, strlen(pe->partition_name),
5315 system_charset_info) ||
5316 parts->push_back(part_str.dup(current_thd->mem_root)))
5317 return true;
5318 }
5319 partition_id++;
5320 }
5321 }
5322 } else {
5323 while ((pe = it++)) {
5324 if (bitmap_is_set(&part_info->read_partitions, partition_id)) {
5325 part_str.length(0);
5326 if (part_str.append(pe->partition_name, strlen(pe->partition_name),
5327 system_charset_info) ||
5328 parts->push_back(part_str.dup(current_thd->mem_root)))
5329 return true;
5330 }
5331 partition_id++;
5332 }
5333 }
5334 return false;
5335 }
5336
5337 /****************************************************************************
5338 * Partition interval analysis support
5339 ***************************************************************************/
5340
5341 /*
5342 Setup partition_info::* members related to partitioning range analysis
5343
5344 SYNOPSIS
5345 set_up_partition_func_pointers()
5346 part_info Partitioning info structure
5347
5348 DESCRIPTION
5349 Assuming that passed partition_info structure already has correct values
5350 for members that specify [sub]partitioning type, table fields, and
5351 functions, set up partition_info::* members that are related to
5352 Partitioning Interval Analysis (see get_partitions_in_range_iter for its
5353 definition)
5354
5355 IMPLEMENTATION
5356 There are three available interval analyzer functions:
5357 (1) get_part_iter_for_interval_via_mapping
5358 (2) get_part_iter_for_interval_cols_via_map
5359 (3) get_part_iter_for_interval_via_walking
5360
5361 They all have limited applicability:
5362 (1) is applicable for "PARTITION BY <RANGE|LIST>(func(t.field))", where
5363 func is a monotonic function.
5364
5365 (2) is applicable for "PARTITION BY <RANGE|LIST> COLUMNS (field_list)
5366
5367 (3) is applicable for
5368 "[SUB]PARTITION BY <any-partitioning-type>(any_func(t.integer_field))"
5369
5370 If both (1) and (3) are applicable, (1) is preferred over (3).
5371
5372 This function sets part_info::get_part_iter_for_interval according to
5373 this criteria, and also sets some auxilary fields that the function
5374 uses.
5375 */
set_up_range_analysis_info(partition_info * part_info)5376 static void set_up_range_analysis_info(partition_info *part_info) {
5377 /* Set the catch-all default */
5378 part_info->get_part_iter_for_interval = nullptr;
5379 part_info->get_subpart_iter_for_interval = nullptr;
5380
5381 /*
5382 Check if get_part_iter_for_interval_via_mapping() can be used for
5383 partitioning
5384 */
5385 switch (part_info->part_type) {
5386 case partition_type::RANGE:
5387 case partition_type::LIST:
5388 if (!part_info->column_list) {
5389 if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) {
5390 part_info->get_part_iter_for_interval =
5391 get_part_iter_for_interval_via_mapping;
5392 goto setup_subparts;
5393 }
5394 } else {
5395 part_info->get_part_iter_for_interval =
5396 get_part_iter_for_interval_cols_via_map;
5397 goto setup_subparts;
5398 }
5399 default:;
5400 }
5401
5402 /*
5403 Check if get_part_iter_for_interval_via_walking() can be used for
5404 partitioning
5405 */
5406 if (part_info->num_part_fields == 1) {
5407 Field *field = part_info->part_field_array[0];
5408 switch (field->type()) {
5409 case MYSQL_TYPE_TINY:
5410 case MYSQL_TYPE_SHORT:
5411 case MYSQL_TYPE_INT24:
5412 case MYSQL_TYPE_LONG:
5413 case MYSQL_TYPE_LONGLONG:
5414 part_info->get_part_iter_for_interval =
5415 get_part_iter_for_interval_via_walking;
5416 break;
5417 default:;
5418 }
5419 }
5420
5421 setup_subparts:
5422 /*
5423 Check if get_part_iter_for_interval_via_walking() can be used for
5424 subpartitioning
5425 */
5426 if (part_info->num_subpart_fields == 1) {
5427 Field *field = part_info->subpart_field_array[0];
5428 switch (field->type()) {
5429 case MYSQL_TYPE_TINY:
5430 case MYSQL_TYPE_SHORT:
5431 case MYSQL_TYPE_LONG:
5432 case MYSQL_TYPE_LONGLONG:
5433 part_info->get_subpart_iter_for_interval =
5434 get_part_iter_for_interval_via_walking;
5435 break;
5436 default:;
5437 }
5438 }
5439 }
5440
5441 /*
5442 This function takes a memory of packed fields in opt-range format
5443 and stores it in record format. To avoid having to worry about how
5444 the length of fields are calculated in opt-range format we send
5445 an array of lengths used for each field in store_length_array.
5446
5447 SYNOPSIS
5448 store_tuple_to_record()
5449 pfield Field array
5450 store_length_array Array of field lengths
5451 value Memory where fields are stored
5452 value_end End of memory
5453
5454 RETURN VALUE
5455 nparts Number of fields assigned
5456 */
store_tuple_to_record(Field ** pfield,uint32 * store_length_array,uchar * value,uchar * value_end)5457 static uint32 store_tuple_to_record(Field **pfield, uint32 *store_length_array,
5458 uchar *value, uchar *value_end) {
5459 /* This function is inspired by store_key_image_rec. */
5460 uint32 nparts = 0;
5461 uchar *loc_value;
5462 while (value < value_end) {
5463 loc_value = value;
5464 if ((*pfield)->is_nullable()) {
5465 if (*loc_value)
5466 (*pfield)->set_null();
5467 else
5468 (*pfield)->set_notnull();
5469 loc_value++;
5470 }
5471 uint len = (*pfield)->pack_length();
5472 (*pfield)->set_key_image(loc_value, len);
5473 value += *store_length_array;
5474 store_length_array++;
5475 nparts++;
5476 pfield++;
5477 }
5478 return nparts;
5479 }
5480
5481 /**
5482 RANGE(columns) partitioning: compare partition value bound and probe tuple.
5483
5484 @param val Partition column values.
5485 @param nvals_in_rec Number of (prefix) fields to compare.
5486
5487 @return Less than/Equal to/Greater than 0 if the record is L/E/G than val.
5488
5489 @note The partition value bound is always a full tuple (but may include the
5490 MAXVALUE special value). The probe tuple may be a prefix of partitioning
5491 tuple.
5492 */
5493
cmp_rec_and_tuple(part_column_list_val * val,uint32 nvals_in_rec)5494 static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec) {
5495 partition_info *part_info = val->part_info;
5496 Field **field = part_info->part_field_array;
5497 Field **fields_end = field + nvals_in_rec;
5498 int res;
5499
5500 for (; field != fields_end; field++, val++) {
5501 if (val->max_value) return -1;
5502 if ((*field)->is_null()) {
5503 if (val->null_value) continue;
5504 return -1;
5505 }
5506 if (val->null_value) return +1;
5507 res = (*field)->cmp(val->column_value.field_image);
5508 if (res) return res;
5509 }
5510 return 0;
5511 }
5512
5513 /**
5514 Compare record and columns partition tuple including endpoint handling.
5515
5516 @param val Columns partition tuple
5517 @param n_vals_in_rec Number of columns to compare
5518 @param is_left_endpoint True if left endpoint (part_tuple < rec or
5519 part_tuple <= rec)
5520 @param include_endpoint If endpoint is included (part_tuple <= rec or
5521 rec <= part_tuple)
5522
5523 @return Less than/Equal to/Greater than 0 if the record is L/E/G than
5524 the partition tuple.
5525
5526 @see get_list_array_idx_for_endpoint() and
5527 get_partition_id_range_for_endpoint().
5528 */
5529
cmp_rec_and_tuple_prune(part_column_list_val * val,uint32 n_vals_in_rec,bool is_left_endpoint,bool include_endpoint)5530 static int cmp_rec_and_tuple_prune(part_column_list_val *val,
5531 uint32 n_vals_in_rec, bool is_left_endpoint,
5532 bool include_endpoint) {
5533 int cmp;
5534 Field **field;
5535 if ((cmp = cmp_rec_and_tuple(val, n_vals_in_rec))) return cmp;
5536 field = val->part_info->part_field_array + n_vals_in_rec;
5537 if (!(*field)) {
5538 /* Full match. Only equal if including endpoint. */
5539 if (include_endpoint) return 0;
5540
5541 if (is_left_endpoint)
5542 return +4; /* Start of range, part_tuple < rec, return higher. */
5543 return -4; /* End of range, rec < part_tupe, return lesser. */
5544 }
5545 /*
5546 The prefix is equal and there are more partition columns to compare.
5547
5548 If including left endpoint or not including right endpoint
5549 then the record is considered lesser compared to the partition.
5550
5551 i.e:
5552 part(10, x) <= rec(10, unknown) and rec(10, unknown) < part(10, x)
5553 part <= rec -> lesser (i.e. this or previous partitions)
5554 rec < part -> lesser (i.e. this or previous partitions)
5555 */
5556 if (is_left_endpoint == include_endpoint) return -2;
5557
5558 /*
5559 If right endpoint and the first additional partition value
5560 is MAXVALUE, then the record is lesser.
5561 */
5562 if (!is_left_endpoint && (val + n_vals_in_rec)->max_value) return -3;
5563
5564 /*
5565 Otherwise the record is considered greater.
5566
5567 rec <= part -> greater (i.e. does not match this partition, seek higher).
5568 part < rec -> greater (i.e. does not match this partition, seek higher).
5569 */
5570 return 2;
5571 }
5572
5573 typedef uint32 (*get_endpoint_func)(partition_info *, bool left_endpoint,
5574 bool include_endpoint);
5575
5576 typedef uint32 (*get_col_endpoint_func)(partition_info *, bool left_endpoint,
5577 bool include_endpoint,
5578 uint32 num_parts);
5579
5580 /**
5581 Get partition for RANGE COLUMNS endpoint.
5582
5583 @param part_info Partitioning metadata.
5584 @param is_left_endpoint True if left endpoint (const <=/< cols)
5585 @param include_endpoint True if range includes the endpoint (<=/>=)
5586 @param nparts Total number of partitions
5587
5588 @return Partition id of matching partition.
5589
5590 @see get_partition_id_cols_list_for_endpoint and
5591 get_partition_id_range_for_endpoint.
5592 */
5593
get_partition_id_cols_range_for_endpoint(partition_info * part_info,bool is_left_endpoint,bool include_endpoint,uint32 nparts)5594 static uint32 get_partition_id_cols_range_for_endpoint(
5595 partition_info *part_info, bool is_left_endpoint, bool include_endpoint,
5596 uint32 nparts) {
5597 uint min_part_id = 0, max_part_id = part_info->num_parts, loc_part_id;
5598 part_column_list_val *range_col_array = part_info->range_col_array;
5599 uint num_columns = part_info->part_field_list.elements;
5600 DBUG_TRACE;
5601
5602 /* Find the matching partition (including taking endpoint into account). */
5603 do {
5604 /* Midpoint, adjusted down, so it can never be > last partition. */
5605 loc_part_id = (max_part_id + min_part_id) >> 1;
5606 if (0 <=
5607 cmp_rec_and_tuple_prune(range_col_array + loc_part_id * num_columns,
5608 nparts, is_left_endpoint, include_endpoint))
5609 min_part_id = loc_part_id + 1;
5610 else
5611 max_part_id = loc_part_id;
5612 } while (max_part_id > min_part_id);
5613 loc_part_id = max_part_id;
5614
5615 /* Given value must be LESS THAN the found partition. */
5616 DBUG_ASSERT(loc_part_id == part_info->num_parts ||
5617 (0 > cmp_rec_and_tuple_prune(
5618 range_col_array + loc_part_id * num_columns, nparts,
5619 is_left_endpoint, include_endpoint)));
5620 /* Given value must be GREATER THAN or EQUAL to the previous partition. */
5621 DBUG_ASSERT(loc_part_id == 0 ||
5622 (0 <= cmp_rec_and_tuple_prune(
5623 range_col_array + (loc_part_id - 1) * num_columns,
5624 nparts, is_left_endpoint, include_endpoint)));
5625
5626 if (!is_left_endpoint) {
5627 /* Set the end after this partition if not already after the last. */
5628 if (loc_part_id < part_info->num_parts) loc_part_id++;
5629 }
5630 return loc_part_id;
5631 }
5632
get_part_iter_for_interval_cols_via_map(partition_info * part_info,bool,uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)5633 static int get_part_iter_for_interval_cols_via_map(
5634 partition_info *part_info, bool, uint32 *store_length_array,
5635 uchar *min_value, uchar *max_value, uint min_len, uint max_len, uint flags,
5636 PARTITION_ITERATOR *part_iter) {
5637 uint32 nparts;
5638 get_col_endpoint_func get_col_endpoint;
5639 DBUG_TRACE;
5640
5641 if (part_info->part_type == partition_type::RANGE) {
5642 get_col_endpoint = get_partition_id_cols_range_for_endpoint;
5643 part_iter->get_next = get_next_partition_id_range;
5644 } else if (part_info->part_type == partition_type::LIST) {
5645 get_col_endpoint = get_partition_id_cols_list_for_endpoint;
5646 part_iter->get_next = get_next_partition_id_list;
5647 part_iter->part_info = part_info;
5648 DBUG_ASSERT(part_info->num_list_values);
5649 } else {
5650 assert(0);
5651 get_col_endpoint = nullptr;
5652 }
5653
5654 if (flags & NO_MIN_RANGE)
5655 part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5656 else {
5657 // Copy from min_value to record
5658 nparts =
5659 store_tuple_to_record(part_info->part_field_array, store_length_array,
5660 min_value, min_value + min_len);
5661 part_iter->part_nums.start = part_iter->part_nums.cur =
5662 get_col_endpoint(part_info, true, !(flags & NEAR_MIN), nparts);
5663 }
5664 if (flags & NO_MAX_RANGE) {
5665 if (part_info->part_type == partition_type::RANGE)
5666 part_iter->part_nums.end = part_info->num_parts;
5667 else /* LIST_PARTITION */
5668 {
5669 DBUG_ASSERT(part_info->part_type == partition_type::LIST);
5670 part_iter->part_nums.end = part_info->num_list_values;
5671 }
5672 } else {
5673 // Copy from max_value to record
5674 nparts =
5675 store_tuple_to_record(part_info->part_field_array, store_length_array,
5676 max_value, max_value + max_len);
5677 part_iter->part_nums.end =
5678 get_col_endpoint(part_info, false, !(flags & NEAR_MAX), nparts);
5679 }
5680 if (part_iter->part_nums.start == part_iter->part_nums.end) return 0;
5681 return 1;
5682 }
5683
5684 /**
5685 Partitioning Interval Analysis: Initialize the iterator for "mapping" case
5686
5687 @param part_info Partition info
5688 @param is_subpart true - act for subpartitioning
5689 false - act for partitioning
5690 @param store_length_array Ignored.
5691 @param min_value minimum field value, in opt_range key format.
5692 @param max_value minimum field value, in opt_range key format.
5693 @param min_len Ignored.
5694 @param max_len Ignored.
5695 @param flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
5696 NO_MAX_RANGE.
5697 @param part_iter Iterator structure to be initialized
5698
5699 @details Initialize partition set iterator to walk over the interval in
5700 ordered-array-of-partitions (for RANGE partitioning) or
5701 ordered-array-of-list-constants (for LIST partitioning) space.
5702
5703 This function is used when partitioning is done by
5704 <RANGE|LIST>(ascending_func(t.field)), and we can map an interval in
5705 t.field space into a sub-array of partition_info::range_int_array or
5706 partition_info::list_array (see get_partition_id_range_for_endpoint,
5707 get_list_array_idx_for_endpoint for details).
5708
5709 The function performs this interval mapping, and sets the iterator to
5710 traverse the sub-array and return appropriate partitions.
5711
5712 @return Status of iterator
5713 @retval 0 No matching partitions (iterator not initialized)
5714 @retval 1 Ok, iterator intialized for traversal of matching partitions.
5715 @retval -1 All partitions would match (iterator not initialized)
5716 */
5717
get_part_iter_for_interval_via_mapping(partition_info * part_info,bool is_subpart MY_ATTRIBUTE ((unused)),uint32 * store_length_array,uchar * min_value,uchar * max_value,uint min_len,uint max_len,uint flags,PARTITION_ITERATOR * part_iter)5718 static int get_part_iter_for_interval_via_mapping(
5719 partition_info *part_info, bool is_subpart MY_ATTRIBUTE((unused)),
5720 uint32 *store_length_array, /* ignored */
5721 uchar *min_value, uchar *max_value, uint min_len,
5722 uint max_len, /* ignored */
5723 uint flags, PARTITION_ITERATOR *part_iter) {
5724 Field *field = part_info->part_field_array[0];
5725 uint32 max_endpoint_val = 0;
5726 get_endpoint_func get_endpoint = nullptr;
5727 bool can_match_multiple_values; /* is not '=' */
5728 uint field_len = field->pack_length_in_rec();
5729 MYSQL_TIME start_date;
5730 bool check_zero_dates = false;
5731 bool zero_in_start_date = true;
5732 DBUG_TRACE;
5733 DBUG_ASSERT(!is_subpart);
5734 (void)store_length_array;
5735 (void)min_len;
5736 (void)max_len;
5737 part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5738
5739 if (part_info->part_type == partition_type::RANGE) {
5740 if (part_info->part_charset_field_array)
5741 get_endpoint = get_partition_id_range_for_endpoint_charset;
5742 else
5743 get_endpoint = get_partition_id_range_for_endpoint;
5744 max_endpoint_val = part_info->num_parts;
5745 part_iter->get_next = get_next_partition_id_range;
5746 } else if (part_info->part_type == partition_type::LIST) {
5747 if (part_info->part_charset_field_array)
5748 get_endpoint = get_list_array_idx_for_endpoint_charset;
5749 else
5750 get_endpoint = get_list_array_idx_for_endpoint;
5751 max_endpoint_val = part_info->num_list_values;
5752 part_iter->get_next = get_next_partition_id_list;
5753 part_iter->part_info = part_info;
5754 if (max_endpoint_val == 0) {
5755 /*
5756 We handle this special case without optimisations since it is
5757 of little practical value but causes a great number of complex
5758 checks later in the code.
5759 */
5760 part_iter->part_nums.start = part_iter->part_nums.end = 0;
5761 part_iter->part_nums.cur = 0;
5762 part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5763 return -1;
5764 }
5765 } else
5766 MY_ASSERT_UNREACHABLE();
5767
5768 can_match_multiple_values = (flags || !min_value || !max_value ||
5769 memcmp(min_value, max_value, field_len));
5770 if (can_match_multiple_values &&
5771 (part_info->part_type == partition_type::RANGE ||
5772 part_info->has_null_value)) {
5773 /* Range scan on RANGE or LIST partitioned table */
5774 enum_monotonicity_info monotonic;
5775 monotonic = part_info->part_expr->get_monotonicity_info();
5776 if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
5777 monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL) {
5778 /* col is NOT NULL, but F(col) can return NULL, add NULL partition */
5779 part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5780 check_zero_dates = true;
5781 }
5782 }
5783
5784 /*
5785 Find minimum: Do special handling if the interval has left bound in form
5786 " NULL <= X ":
5787 */
5788 if (field->is_nullable() && part_info->has_null_value &&
5789 !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value) {
5790 part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5791 part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5792 if (!(flags & NO_MAX_RANGE) && *max_value) {
5793 /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
5794 part_iter->part_nums.end = 0;
5795 return 1;
5796 }
5797 } else {
5798 if (flags & NO_MIN_RANGE)
5799 part_iter->part_nums.start = part_iter->part_nums.cur = 0;
5800 else {
5801 /*
5802 Store the interval edge in the record buffer, and call the
5803 function that maps the edge in table-field space to an edge
5804 in ordered-set-of-partitions (for RANGE partitioning) or
5805 index-in-ordered-array-of-list-constants (for LIST) space.
5806 */
5807 store_key_image_to_rec(field, min_value, field_len);
5808 bool include_endp = !(flags & NEAR_MIN);
5809 part_iter->part_nums.start = get_endpoint(part_info, true, include_endp);
5810 if (!can_match_multiple_values && part_info->part_expr->null_value) {
5811 /* col = x and F(x) = NULL -> only search NULL partition */
5812 part_iter->part_nums.cur = part_iter->part_nums.start = 0;
5813 part_iter->part_nums.end = 0;
5814 part_iter->ret_null_part = part_iter->ret_null_part_orig = true;
5815 return 1;
5816 }
5817 part_iter->part_nums.cur = part_iter->part_nums.start;
5818 if (check_zero_dates && !part_info->part_expr->null_value) {
5819 if (!(flags & NO_MAX_RANGE) && (field->type() == MYSQL_TYPE_DATE ||
5820 field->type() == MYSQL_TYPE_DATETIME)) {
5821 /* Monotonic, but return NULL for dates with zeros in month/day. */
5822 zero_in_start_date = field->get_date(&start_date, 0);
5823 DBUG_PRINT("info",
5824 ("zero start %u %04d-%02d-%02d", zero_in_start_date,
5825 start_date.year, start_date.month, start_date.day));
5826 }
5827 }
5828 if (part_iter->part_nums.start == max_endpoint_val)
5829 return 0; /* No partitions */
5830 }
5831 }
5832
5833 /* Find maximum, do the same as above but for right interval bound */
5834 if (flags & NO_MAX_RANGE)
5835 part_iter->part_nums.end = max_endpoint_val;
5836 else {
5837 store_key_image_to_rec(field, max_value, field_len);
5838 bool include_endp = !(flags & NEAR_MAX);
5839 part_iter->part_nums.end = get_endpoint(part_info, false, include_endp);
5840 if (check_zero_dates && !zero_in_start_date &&
5841 !part_info->part_expr->null_value) {
5842 MYSQL_TIME end_date;
5843 bool zero_in_end_date = field->get_date(&end_date, 0);
5844 /*
5845 This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
5846 the NULL partition for ranges that cannot include a date with 0 as
5847 month/day.
5848 */
5849 DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d", zero_in_end_date,
5850 end_date.year, end_date.month, end_date.day));
5851 DBUG_ASSERT(!memcmp(((Item_func *)part_info->part_expr)->func_name(),
5852 "to_days", 7) ||
5853 !memcmp(((Item_func *)part_info->part_expr)->func_name(),
5854 "to_seconds", 10));
5855 if (!zero_in_end_date && start_date.month == end_date.month &&
5856 start_date.year == end_date.year)
5857 part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5858 }
5859 if (part_iter->part_nums.start >= part_iter->part_nums.end &&
5860 !part_iter->ret_null_part)
5861 return 0; /* No partitions */
5862 }
5863 return 1; /* Ok, iterator initialized */
5864 }
5865
5866 /* See get_part_iter_for_interval_via_walking for definition of what this is */
5867 #define MAX_RANGE_TO_WALK 32
5868
5869 /*
5870 Partitioning Interval Analysis: Initialize iterator to walk field interval
5871
5872 SYNOPSIS
5873 get_part_iter_for_interval_via_walking()
5874 part_info Partition info
5875 is_subpart true - act for subpartitioning
5876 false - act for partitioning
5877 min_value minimum field value, in opt_range key format.
5878 max_value minimum field value, in opt_range key format.
5879 flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
5880 NO_MAX_RANGE.
5881 part_iter Iterator structure to be initialized
5882
5883 DESCRIPTION
5884 Initialize partition set iterator to walk over interval in integer field
5885 space. That is, for "const1 <=? t.field <=? const2" interval, initialize
5886 the iterator to return a set of [sub]partitions obtained with the
5887 following procedure:
5888 get partition id for t.field = const1, return it
5889 get partition id for t.field = const1+1, return it
5890 ... t.field = const1+2, ...
5891 ... ... ...
5892 ... t.field = const2 ...
5893
5894 IMPLEMENTATION
5895 See get_partitions_in_range_iter for general description of interval
5896 analysis. We support walking over the following intervals:
5897 "t.field IS NULL"
5898 "c1 <=? t.field <=? c2", where c1 and c2 are finite.
5899 Intervals with +inf/-inf, and [NULL, c1] interval can be processed but
5900 that is more tricky and I don't have time to do it right now.
5901
5902 RETURN
5903 0 - No matching partitions, iterator not initialized
5904 1 - Some partitions would match, iterator intialized for traversing them
5905 -1 - All partitions would match, iterator not initialized
5906 */
5907
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)5908 static int get_part_iter_for_interval_via_walking(
5909 partition_info *part_info, bool is_subpart,
5910 uint32 *store_length_array, /* ignored */
5911 uchar *min_value, uchar *max_value, uint min_len,
5912 uint max_len, /* ignored */
5913 uint flags, PARTITION_ITERATOR *part_iter) {
5914 Field *field;
5915 uint total_parts;
5916 partition_iter_func get_next_func;
5917 DBUG_TRACE;
5918 (void)store_length_array;
5919 (void)min_len;
5920 (void)max_len;
5921
5922 part_iter->ret_null_part = part_iter->ret_null_part_orig = false;
5923 if (is_subpart) {
5924 field = part_info->subpart_field_array[0];
5925 total_parts = part_info->num_subparts;
5926 get_next_func = get_next_subpartition_via_walking;
5927 } else {
5928 field = part_info->part_field_array[0];
5929 total_parts = part_info->num_parts;
5930 get_next_func = get_next_partition_via_walking;
5931 }
5932
5933 /* Handle the "t.field IS NULL" interval, it is a special case */
5934 if (field->is_nullable() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
5935 *min_value && *max_value) {
5936 /*
5937 We don't have a part_iter->get_next() function that would find which
5938 partition "t.field IS NULL" belongs to, so find partition that contains
5939 NULL right here, and return an iterator over singleton set.
5940 */
5941 uint32 part_id;
5942 field->set_null();
5943 if (is_subpart) {
5944 if (!part_info->get_subpartition_id(part_info, &part_id)) {
5945 init_single_partition_iterator(part_id, part_iter);
5946 return 1; /* Ok, iterator initialized */
5947 }
5948 } else {
5949 longlong dummy;
5950 int res =
5951 part_info->is_sub_partitioned()
5952 ? part_info->get_part_partition_id(part_info, &part_id, &dummy)
5953 : part_info->get_partition_id(part_info, &part_id, &dummy);
5954 if (!res) {
5955 init_single_partition_iterator(part_id, part_iter);
5956 return 1; /* Ok, iterator initialized */
5957 }
5958 }
5959 return 0; /* No partitions match */
5960 }
5961
5962 if ((field->is_nullable() &&
5963 ((!(flags & NO_MIN_RANGE) && *min_value) || // NULL <? X
5964 (!(flags & NO_MAX_RANGE) && *max_value))) || // X <? NULL
5965 (flags & (NO_MIN_RANGE | NO_MAX_RANGE))) // -inf at any bound
5966 {
5967 return -1; /* Can't handle this interval, have to use all partitions */
5968 }
5969
5970 /* Get integers for left and right interval bound */
5971 ulonglong a, b;
5972 uint len = field->pack_length_in_rec();
5973 store_key_image_to_rec(field, min_value, len);
5974 a = field->val_int();
5975
5976 store_key_image_to_rec(field, max_value, len);
5977 b = field->val_int();
5978
5979 /*
5980 Handle a special case where the distance between interval bounds is
5981 exactly 4G-1. This interval is too big for range walking, and if it is an
5982 (x,y]-type interval then the following "b +=..." code will convert it to
5983 an empty interval by "wrapping around" a + 4G-1 + 1 = a.
5984 */
5985 if (b - a == ~0ULL) return -1;
5986
5987 if (flags & NEAR_MIN) ++a;
5988 if (!(flags & NEAR_MAX)) ++b;
5989 ulonglong n_values = b - a;
5990
5991 /*
5992 Will it pay off to enumerate all values in the [a..b] range and evaluate
5993 the partitioning function for every value? It depends on
5994 1. whether we'll be able to infer that some partitions are not used
5995 2. if time savings from not scanning these partitions will be greater
5996 than time spent in enumeration.
5997 We will assume that the cost of accessing one extra partition is greater
5998 than the cost of evaluating the partitioning function O(#partitions).
5999 This means we should jump at any chance to eliminate a partition, which
6000 gives us this logic:
6001
6002 Do the enumeration if
6003 - the number of values to enumerate is comparable to the number of
6004 partitions, or
6005 - there are not many values to enumerate.
6006 */
6007 if ((n_values > 2 * total_parts) && n_values > MAX_RANGE_TO_WALK) return -1;
6008
6009 part_iter->field_vals.start = part_iter->field_vals.cur = a;
6010 part_iter->field_vals.end = b;
6011 part_iter->part_info = part_info;
6012 part_iter->get_next = get_next_func;
6013 return 1;
6014 }
6015
6016 /*
6017 PARTITION_ITERATOR::get_next implementation: enumerate partitions in range
6018
6019 SYNOPSIS
6020 get_next_partition_id_range()
6021 part_iter Partition set iterator structure
6022
6023 DESCRIPTION
6024 This is implementation of PARTITION_ITERATOR::get_next() that returns
6025 [sub]partition ids in [min_partition_id, max_partition_id] range.
6026 The function conforms to partition_iter_func type.
6027
6028 RETURN
6029 partition id
6030 NOT_A_PARTITION_ID if there are no more partitions
6031 */
6032
get_next_partition_id_range(PARTITION_ITERATOR * part_iter)6033 uint32 get_next_partition_id_range(PARTITION_ITERATOR *part_iter) {
6034 if (part_iter->part_nums.cur >= part_iter->part_nums.end) {
6035 if (part_iter->ret_null_part) {
6036 part_iter->ret_null_part = false;
6037 return 0; /* NULL always in first range partition */
6038 }
6039 part_iter->part_nums.cur = part_iter->part_nums.start;
6040 part_iter->ret_null_part = part_iter->ret_null_part_orig;
6041 return NOT_A_PARTITION_ID;
6042 } else
6043 return part_iter->part_nums.cur++;
6044 }
6045
6046 /*
6047 PARTITION_ITERATOR::get_next implementation for LIST partitioning
6048
6049 SYNOPSIS
6050 get_next_partition_id_list()
6051 part_iter Partition set iterator structure
6052
6053 DESCRIPTION
6054 This implementation of PARTITION_ITERATOR::get_next() is special for
6055 LIST partitioning: it enumerates partition ids in
6056 part_info->list_array[i] (list_col_array[i*cols] for COLUMNS LIST
6057 partitioning) where i runs over [min_idx, max_idx] interval.
6058 The function conforms to partition_iter_func type.
6059
6060 RETURN
6061 partition id
6062 NOT_A_PARTITION_ID if there are no more partitions
6063 */
6064
get_next_partition_id_list(PARTITION_ITERATOR * part_iter)6065 static uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) {
6066 if (part_iter->part_nums.cur >= part_iter->part_nums.end) {
6067 if (part_iter->ret_null_part) {
6068 part_iter->ret_null_part = false;
6069 return part_iter->part_info->has_null_part_id;
6070 }
6071 part_iter->part_nums.cur = part_iter->part_nums.start;
6072 part_iter->ret_null_part = part_iter->ret_null_part_orig;
6073 return NOT_A_PARTITION_ID;
6074 } else {
6075 partition_info *part_info = part_iter->part_info;
6076 uint32 num_part = part_iter->part_nums.cur++;
6077 if (part_info->column_list) {
6078 uint num_columns = part_info->part_field_list.elements;
6079 return part_info->list_col_array[num_part * num_columns].partition_id;
6080 }
6081 return part_info->list_array[num_part].partition_id;
6082 }
6083 }
6084
6085 /*
6086 PARTITION_ITERATOR::get_next implementation: walk over field-space interval
6087
6088 SYNOPSIS
6089 get_next_partition_via_walking()
6090 part_iter Partitioning iterator
6091
6092 DESCRIPTION
6093 This implementation of PARTITION_ITERATOR::get_next() returns ids of
6094 partitions that contain records with partitioning field value within
6095 [start_val, end_val] interval.
6096 The function conforms to partition_iter_func type.
6097
6098 RETURN
6099 partition id
6100 NOT_A_PARTITION_ID if there are no more partitioning.
6101 */
6102
get_next_partition_via_walking(PARTITION_ITERATOR * part_iter)6103 static uint32 get_next_partition_via_walking(PARTITION_ITERATOR *part_iter) {
6104 uint32 part_id;
6105 Field *field = part_iter->part_info->part_field_array[0];
6106 while (part_iter->field_vals.cur != part_iter->field_vals.end) {
6107 longlong dummy;
6108 field->store(part_iter->field_vals.cur++,
6109 field->is_flag_set(UNSIGNED_FLAG));
6110 if ((part_iter->part_info->is_sub_partitioned() &&
6111 !part_iter->part_info->get_part_partition_id(part_iter->part_info,
6112 &part_id, &dummy)) ||
6113 !part_iter->part_info->get_partition_id(part_iter->part_info, &part_id,
6114 &dummy))
6115 return part_id;
6116 }
6117 part_iter->field_vals.cur = part_iter->field_vals.start;
6118 return NOT_A_PARTITION_ID;
6119 }
6120
6121 /* Same as get_next_partition_via_walking, but for subpartitions */
6122
get_next_subpartition_via_walking(PARTITION_ITERATOR * part_iter)6123 static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) {
6124 Field *field = part_iter->part_info->subpart_field_array[0];
6125 uint32 res;
6126 if (part_iter->field_vals.cur == part_iter->field_vals.end) {
6127 part_iter->field_vals.cur = part_iter->field_vals.start;
6128 return NOT_A_PARTITION_ID;
6129 }
6130 field->store(part_iter->field_vals.cur++, field->is_flag_set(UNSIGNED_FLAG));
6131 if (part_iter->part_info->get_subpartition_id(part_iter->part_info, &res))
6132 return NOT_A_PARTITION_ID;
6133 return res;
6134 }
6135
get_partition_field_store_length(Field * field)6136 uint get_partition_field_store_length(Field *field) {
6137 uint store_length;
6138
6139 store_length = field->key_length();
6140 if (field->is_nullable()) store_length += HA_KEY_NULL_LENGTH;
6141 if (field->real_type() == MYSQL_TYPE_VARCHAR)
6142 store_length += HA_KEY_BLOB_LENGTH;
6143 return store_length;
6144 }
6145