diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:24:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 12:24:36 +0000 |
commit | 06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch) | |
tree | e2c7b5777f728320e5b5542b6213fd3591ba51e2 /sql/partition_info.h | |
parent | Initial commit. (diff) | |
download | mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.tar.xz mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.zip |
Adding upstream version 1:10.11.6.upstream/1%10.11.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sql/partition_info.h')
-rw-r--r-- | sql/partition_info.h | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/sql/partition_info.h b/sql/partition_info.h new file mode 100644 index 00000000..3a8c3a37 --- /dev/null +++ b/sql/partition_info.h @@ -0,0 +1,572 @@ +#ifndef PARTITION_INFO_INCLUDED +#define PARTITION_INFO_INCLUDED + +/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#include "sql_class.h" +#include "partition_element.h" +#include "sql_partition.h" + +class partition_info; +struct TABLE_LIST; +/* Some function typedefs */ +typedef int (*get_part_id_func)(partition_info *part_info, uint32 *part_id, + longlong *func_value); +typedef int (*get_subpart_id_func)(partition_info *part_info, uint32 *part_id); +typedef bool (*check_constants_func)(THD *thd, partition_info *part_info); + +struct st_ddl_log_memory_entry; + +#define MAX_PART_NAME_SIZE 8 + +struct Vers_part_info : public Sql_alloc +{ + Vers_part_info() : + limit(0), + auto_hist(false), + now_part(NULL), + hist_part(NULL) + { + interval.type= INTERVAL_LAST; + } + Vers_part_info(const Vers_part_info &src) : + interval(src.interval), + limit(src.limit), + auto_hist(src.auto_hist), + now_part(NULL), + hist_part(NULL) + { + } + Vers_part_info& operator= (const Vers_part_info &src) + { + interval= src.interval; + limit= src.limit; + auto_hist= src.auto_hist; + now_part= src.now_part; + hist_part= src.hist_part; + return *this; + } + bool initialized() + { + if (now_part) + { + DBUG_ASSERT(now_part->id != UINT_MAX32); + DBUG_ASSERT(now_part->type == partition_element::CURRENT); + if (hist_part) + { + DBUG_ASSERT(hist_part->id != UINT_MAX32); + DBUG_ASSERT(hist_part->type == partition_element::HISTORY); + } + return true; + } + return false; + } + struct interval_t { + my_time_t start; + INTERVAL step; + enum interval_type type; + bool is_set() const { return type < INTERVAL_LAST; } + bool operator==(const interval_t &rhs) const + { + /* TODO: equivalent intervals like 1 hour and 60 mins should be considered equal */ + return start == rhs.start && type == rhs.type && !memcmp(&step, &rhs.step, sizeof(INTERVAL)); + } + } interval; + ulonglong limit; + bool auto_hist; + partition_element *now_part; + partition_element *hist_part; +}; + +/* + See generate_partition_syntax() for details of how the data is used + in partition expression. +*/ +class partition_info : public DDL_LOG_STATE, public Sql_alloc +{ +public: + /* + * Here comes a set of definitions needed for partitioned table handlers. + */ + List<partition_element> partitions; + List<partition_element> temp_partitions; + + /* + These are mutually exclusive with part_expr/subpart_expr depending on + what is specified in partitioning filter: expression or column list. + */ + List<const char> part_field_list; + List<const char> subpart_field_list; + + /* + If there is no subpartitioning, use only this func to get partition ids. + If there is subpartitioning, use the this func to get partition id when + you have both partition and subpartition fields. + */ + get_part_id_func get_partition_id; + + /* Get partition id when we don't have subpartition fields */ + get_part_id_func get_part_partition_id; + + /* + Get subpartition id when we have don't have partition fields by we do + have subpartition ids. + Mikael said that for given constant tuple + {subpart_field1, ..., subpart_fieldN} the subpartition id will be the + same in all subpartitions + */ + get_subpart_id_func get_subpartition_id; + + /* + When we have various string fields we might need some preparation + before and clean-up after calling the get_part_id_func's. We need + one such method for get_part_partition_id and one for + get_subpartition_id. + */ + get_part_id_func get_part_partition_id_charset; + get_subpart_id_func get_subpartition_id_charset; + + check_constants_func check_constants; + + /* NULL-terminated array of fields used in partitioned expression */ + Field **part_field_array; + Field **subpart_field_array; + Field **part_charset_field_array; + Field **subpart_charset_field_array; + /* + Array of all fields used in partition and subpartition expression, + without duplicates, NULL-terminated. + */ + Field **full_part_field_array; + /* + Set of all fields used in partition and subpartition expression. + Required for testing of partition fields in write_set when + updating. We need to set all bits in read_set because the row may + need to be inserted in a different [sub]partition. + */ + MY_BITMAP full_part_field_set; + + /* + When we have a field that requires transformation before calling the + partition functions we must allocate field buffers for the field of + the fields in the partition function. + */ + uchar **part_field_buffers; + uchar **subpart_field_buffers; + uchar **restore_part_field_ptrs; + uchar **restore_subpart_field_ptrs; + + Item *part_expr; + Item *subpart_expr; + + Item *item_free_list; + + /* + Bitmaps of partitions used by the current query. + * read_partitions - partitions to be used for reading. + * lock_partitions - partitions that must be locked (read or write). + Usually read_partitions is the same set as lock_partitions, but + in case of UPDATE the WHERE clause can limit the read_partitions set, + but not neccesarily the lock_partitions set. + Usage pattern: + * Initialized in ha_partition::open(). + * read+lock_partitions is set according to explicit PARTITION, + WL#5217, in open_and_lock_tables(). + * Bits in read_partitions can be cleared in prune_partitions() + in the optimizing step. + (WL#4443 is about allowing prune_partitions() to affect lock_partitions + and be done before locking too). + * When the partition enabled handler get an external_lock call it locks + all partitions in lock_partitions (and remembers which partitions it + locked, so that it can unlock them later). In case of LOCK TABLES it will + lock all partitions, and keep them locked while lock_partitions can + change for each statement under LOCK TABLES. + * Freed at the same time item_free_list is freed. + */ + MY_BITMAP read_partitions; + MY_BITMAP lock_partitions; + bool bitmaps_are_initialized; + + union { + longlong *range_int_array; + LIST_PART_ENTRY *list_array; + part_column_list_val *range_col_array; + part_column_list_val *list_col_array; + }; + + Vers_part_info *vers_info; + + /******************************************** + * INTERVAL ANALYSIS + ********************************************/ + /* + Partitioning interval analysis function for partitioning, or NULL if + interval analysis is not supported for this kind of partitioning. + */ + get_partitions_in_range_iter get_part_iter_for_interval; + /* + Partitioning interval analysis function for subpartitioning, or NULL if + interval analysis is not supported for this kind of partitioning. + */ + get_partitions_in_range_iter get_subpart_iter_for_interval; + + /******************************************** + * INTERVAL ANALYSIS ENDS + ********************************************/ + + longlong err_value; + char* part_info_string; + + partition_element *curr_part_elem; // part or sub part + partition_element *current_partition; // partition + part_elem_value *curr_list_val; + uint curr_list_object; + uint num_columns; + + TABLE *table; + /* + These key_map's are used for Partitioning to enable quick decisions + on whether we can derive more information about which partition to + scan just by looking at what index is used. + */ + key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF; + key_map some_fields_in_PF; + + handlerton *default_engine_type; + partition_type part_type; + partition_type subpart_type; + + uint part_info_len; + + uint num_parts; + uint num_subparts; + uint count_curr_subparts; // used during parsing + + uint num_list_values; + + uint num_part_fields; + uint num_subpart_fields; + uint num_full_part_fields; + + uint has_null_part_id; + uint32 default_partition_id; + /* + This variable is used to calculate the partition id when using + LINEAR KEY/HASH. This functionality is kept in the MySQL Server + but mainly of use to handlers supporting partitioning. + */ + uint16 linear_hash_mask; + /* + PARTITION BY KEY ALGORITHM=N + Which algorithm to use for hashing the fields. + N = 1 - Use 5.1 hashing (numeric fields are hashed as binary) + N = 2 - Use 5.5 hashing (numeric fields are hashed like latin1 bytes) + */ + enum enum_key_algorithm + { + KEY_ALGORITHM_NONE= 0, + KEY_ALGORITHM_51= 1, + KEY_ALGORITHM_55= 2 + }; + enum_key_algorithm key_algorithm; + + /* Only the number of partitions defined (uses default names and options). */ + bool use_default_partitions; + bool use_default_num_partitions; + /* Only the number of subpartitions defined (uses default names etc.). */ + bool use_default_subpartitions; + bool use_default_num_subpartitions; + bool default_partitions_setup; + bool defined_max_value; + inline bool has_default_partititon() + { + return (part_type == LIST_PARTITION && defined_max_value); + } + bool list_of_part_fields; // KEY or COLUMNS PARTITIONING + bool list_of_subpart_fields; // KEY SUBPARTITIONING + bool linear_hash_ind; // LINEAR HASH/KEY + bool fixed; + bool is_auto_partitioned; + bool has_null_value; + bool column_list; // COLUMNS PARTITIONING, 5.5+ + + partition_info() + : get_partition_id(NULL), get_part_partition_id(NULL), + get_subpartition_id(NULL), + part_field_array(NULL), subpart_field_array(NULL), + part_charset_field_array(NULL), + subpart_charset_field_array(NULL), + full_part_field_array(NULL), + part_field_buffers(NULL), subpart_field_buffers(NULL), + restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), + part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), + bitmaps_are_initialized(FALSE), + list_array(NULL), vers_info(NULL), err_value(0), + part_info_string(NULL), + curr_part_elem(NULL), current_partition(NULL), + curr_list_object(0), num_columns(0), table(NULL), + default_engine_type(NULL), + part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), + part_info_len(0), + num_parts(0), num_subparts(0), + count_curr_subparts(0), + num_list_values(0), num_part_fields(0), num_subpart_fields(0), + num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), + key_algorithm(KEY_ALGORITHM_NONE), + use_default_partitions(TRUE), use_default_num_partitions(TRUE), + use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE), + default_partitions_setup(FALSE), defined_max_value(FALSE), + list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), + linear_hash_ind(FALSE), fixed(FALSE), + is_auto_partitioned(FALSE), + has_null_value(FALSE), column_list(FALSE) + { + bzero((DDL_LOG_STATE *) this, sizeof(DDL_LOG_STATE)); + all_fields_in_PF.clear_all(); + all_fields_in_PPF.clear_all(); + all_fields_in_SPF.clear_all(); + some_fields_in_PF.clear_all(); + partitions.empty(); + temp_partitions.empty(); + part_field_list.empty(); + subpart_field_list.empty(); + } + ~partition_info() = default; + + partition_info *get_clone(THD *thd, bool empty_data_and_index_file= FALSE); + bool set_named_partition_bitmap(const char *part_name, size_t length); + bool set_partition_bitmaps(List<String> *partition_names); + /* Answers the question if subpartitioning is used for a certain table */ + bool is_sub_partitioned() + { + return (subpart_type == NOT_A_PARTITION ? FALSE : TRUE); + } + + /* Returns the total number of partitions on the leaf level */ + uint get_tot_partitions() + { + return num_parts * (is_sub_partitioned() ? num_subparts : 1); + } + + bool set_up_defaults_for_partitioning(THD *thd, handler *file, + HA_CREATE_INFO *info, + uint start_no); + const char *find_duplicate_field(); + char *find_duplicate_name(); + bool check_engine_mix(handlerton *engine_type, bool default_engine); + bool check_partition_info(THD *thd, handlerton **eng_type, + handler *file, HA_CREATE_INFO *info, + partition_info *add_or_reorg_part= NULL); + void print_no_partition_found(TABLE *table, myf errflag); + void print_debug(const char *str, uint*); + Item* get_column_item(Item *item, Field *field); + int fix_partition_values(THD *thd, + part_elem_value *val, + partition_element *part_elem); + bool fix_column_value_functions(THD *thd, + part_elem_value *val, + uint part_id); + bool fix_parser_data(THD *thd); + int add_max_value(THD *thd); + void init_col_val(part_column_list_val *col_val, Item *item); + int reorganize_into_single_field_col_val(THD *thd); + part_column_list_val *add_column_value(THD *thd); + bool set_part_expr(THD *thd, Item *item_ptr, bool is_subpart); + bool set_up_charset_field_preps(THD *thd); + bool check_partition_field_length(); + bool init_column_part(THD *thd); + bool add_column_list_value(THD *thd, Item *item); + partition_element *get_part_elem(const char *partition_name, char *file_name, + size_t file_name_size, uint32 *part_id); + void report_part_expr_error(bool use_subpart_expr); + bool has_same_partitioning(partition_info *new_part_info); + bool error_if_requires_values() const; +private: + bool set_up_default_partitions(THD *thd, handler *file, HA_CREATE_INFO *info, + uint start_no); + bool set_up_default_subpartitions(THD *thd, handler *file, + HA_CREATE_INFO *info); + char *create_default_partition_names(THD *thd, uint part_no, uint num_parts, + uint start_no); + char *create_default_subpartition_name(THD *thd, uint subpart_no, + const char *part_name); + bool prune_partition_bitmaps(List<String> *partition_names); // set_read_partitions() in 8.0 + bool add_named_partition(const char *part_name, size_t length); +public: + bool has_unique_name(partition_element *element); + bool field_in_partition_expr(Field *field) const; + + bool vers_init_info(THD *thd); + bool vers_set_interval(THD *thd, Item *interval, + interval_type int_type, Item *starts, + bool auto_part, const char *table_name); + bool vers_set_limit(ulonglong limit, bool auto_part, const char *table_name); + bool vers_set_hist_part(THD* thd, uint *create_count); + bool vers_require_hist_part(THD *thd) const + { + return part_type == VERSIONING_PARTITION && + thd->lex->vers_history_generating(); + } + void vers_check_limit(THD *thd); + bool vers_fix_field_list(THD *thd); + void vers_update_el_ids(); + partition_element *get_partition(uint part_id) + { + List_iterator<partition_element> it(partitions); + partition_element *el; + while ((el= it++)) + { + if (el->id == part_id) + return el; + } + return NULL; + } + uint next_part_no(uint new_parts) const; + + int gen_part_type(THD *thd, String *str) const; +}; + +void part_type_error(THD *thd, partition_info *work_part_info, + const char *part_type, partition_info *tab_part_info); + +uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); +bool check_partition_dirs(partition_info *part_info); +bool vers_create_partitions(THD* thd, TABLE_LIST* tl, uint num_parts); + +/* Initialize the iterator to return a single partition with given part_id */ + +static inline void init_single_partition_iterator(uint32 part_id, + PARTITION_ITERATOR *part_iter) +{ + part_iter->part_nums.start= part_iter->part_nums.cur= part_id; + part_iter->part_nums.end= part_id+1; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; + part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; + part_iter->get_next= get_next_partition_id_range; +} + +/* Initialize the iterator to enumerate all partitions */ +static inline +void init_all_partitions_iterator(partition_info *part_info, + PARTITION_ITERATOR *part_iter) +{ + part_iter->part_nums.start= part_iter->part_nums.cur= 0; + part_iter->part_nums.end= part_info->num_parts; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; + part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE; + part_iter->get_next= get_next_partition_id_range; +} + + +/** + @brief Update part_field_list by row_end field name + + @returns true on error; false on success +*/ +inline +bool partition_info::vers_fix_field_list(THD * thd) +{ + if (!table->versioned()) + { + // frm must be corrupted, normally CREATE/ALTER TABLE checks for that + my_error(ER_FILE_CORRUPT, MYF(0), table->s->path.str); + return true; + } + DBUG_ASSERT(part_type == VERSIONING_PARTITION); + DBUG_ASSERT(table->versioned(VERS_TIMESTAMP)); + + Field *row_end= table->vers_end_field(); + // needed in handle_list_of_fields() + row_end->flags|= GET_FIXED_FIELDS_FLAG; + Name_resolution_context *context= &thd->lex->current_select->context; + Item *row_end_item= new (thd->mem_root) Item_field(thd, context, row_end); + Item *row_end_ts= new (thd->mem_root) Item_func_unix_timestamp(thd, row_end_item); + set_part_expr(thd, row_end_ts, false); + + return false; +} + + +inline +void partition_info::vers_update_el_ids() +{ + DBUG_ASSERT(part_type == VERSIONING_PARTITION); + DBUG_ASSERT(table->versioned(VERS_TIMESTAMP)); + + List_iterator<partition_element> it(partitions); + partition_element *el; + for(uint32 id= 0; ((el= it++)); id++) + { + DBUG_ASSERT(el->type != partition_element::CONVENTIONAL); + /* Newly added element is inserted before AS_OF_NOW. */ + if (el->id == UINT_MAX32 || el->type == partition_element::CURRENT) + { + el->id= id; + if (el->type == partition_element::CURRENT) + break; + } + } +} + + +inline +bool make_partition_name(char *move_ptr, uint i) +{ + int res= snprintf(move_ptr, MAX_PART_NAME_SIZE + 1, "p%u", i); + return res < 0 || res > MAX_PART_NAME_SIZE; +} + + +#ifdef WITH_PARTITION_STORAGE_ENGINE +inline +uint partition_info::next_part_no(uint new_parts) const +{ + if (part_type != VERSIONING_PARTITION) + return num_parts; + DBUG_ASSERT(new_parts > 0); + /* Choose first non-occupied name suffix */ + uint32 suffix= num_parts - 1; + DBUG_ASSERT(suffix > 0); + char part_name[MAX_PART_NAME_SIZE + 1]; + List_iterator_fast<partition_element> it(table->part_info->partitions); + for (uint cur_part= 0; cur_part < new_parts; ++cur_part, ++suffix) + { + uint32 cur_suffix= suffix; + if (make_partition_name(part_name, suffix)) + return 0; + partition_element *el; + it.rewind(); + while ((el= it++)) + { + if (0 == my_strcasecmp(&my_charset_latin1, el->partition_name, part_name)) + { + if (make_partition_name(part_name, ++suffix)) + return 0; + it.rewind(); + } + } + if (cur_part > 0 && suffix > cur_suffix) + cur_part= 0; + } + return suffix - new_parts; +} +#endif + +#endif /* PARTITION_INFO_INCLUDED */ |