diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2021-02-20 23:18:51 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2021-03-15 17:12:24 +0300 |
commit | 742280a28caea054cf5141907e97aa70f2a63f01 (patch) | |
tree | 0909c3e244b11daaaa54d67cdd2e18c966a18dd7 | |
parent | 57075b34c89ac8c0e38c8500dffb38c1dcd11eb6 (diff) | |
download | mariadb-git-742280a28caea054cf5141907e97aa70f2a63f01.tar.gz |
MDEV-12483 Refactoring for part_info in TABLE_SHARE
part_info is unpacked at TABLE_SHARE::init_from_binary_frm_image()
- mysql_unpack_partition() is now TABLE_SHARE::unpack_partition()
- TABLE_SHARE::partition_info_str/_len is now TABLE_SHARE::part_sql
- init_lex_with_single_table() now can be inited with TABLE_SHARE
instead of TABLE. In this case it should be deinited by simple
end_lex() and restore thd->lex.
- check_table_name_processor() / update_table_name_processor() to
check and update table name in items.
- Removed is_create_table_ind. We now always fail table open if
partitioning expression is wrong (fix_fields_part_func()).
-rw-r--r-- | mysql-test/main/partition.result | 102 | ||||
-rw-r--r-- | mysql-test/main/partition.test | 69 | ||||
-rw-r--r-- | sql/handler.cc | 2 | ||||
-rw-r--r-- | sql/item.cc | 29 | ||||
-rw-r--r-- | sql/item.h | 30 | ||||
-rw-r--r-- | sql/partition_info.cc | 18 | ||||
-rw-r--r-- | sql/partition_info.h | 6 | ||||
-rw-r--r-- | sql/sql_admin.cc | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_lex.cc | 18 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_partition.cc | 127 | ||||
-rw-r--r-- | sql/sql_partition.h | 7 | ||||
-rw-r--r-- | sql/sql_show.cc | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 44 | ||||
-rw-r--r-- | sql/table.cc | 123 | ||||
-rw-r--r-- | sql/table.h | 12 | ||||
-rw-r--r-- | sql/temporary_tables.cc | 2 | ||||
-rw-r--r-- | storage/connect/ha_connect.cc | 4 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 4 | ||||
-rw-r--r-- | storage/spider/spd_table.cc | 2 |
21 files changed, 417 insertions, 197 deletions
diff --git a/mysql-test/main/partition.result b/mysql-test/main/partition.result index 373522ded40..d4f5ff888e7 100644 --- a/mysql-test/main/partition.result +++ b/mysql-test/main/partition.result @@ -2018,7 +2018,7 @@ PARTITION BY RANGE (t2.b) ( PARTITION p1 VALUES LESS THAN (10), PARTITION p2 VALUES LESS THAN (20) ) select * from t2; -ERROR 42S22: Unknown column 't2.b' in 'partition function' +ERROR 42S22: Unknown column '`t2`.`b`' in 'partition function' create table t1 (a int) PARTITION BY RANGE (b) ( PARTITION p1 VALUES LESS THAN (10), @@ -2820,3 +2820,103 @@ DROP TABLE t1,t2; # # End of 10.1 tests # +# +# MDEV-12483 Refactoring for part_info in TABLE_SHARE +# +create table t1 (x int, y int) +partition by range(x) +subpartition by hash(y) +subpartitions 10 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `x` int(11) DEFAULT NULL, + `y` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`x`) +SUBPARTITION BY HASH (`y`) +SUBPARTITIONS 10 +(PARTITION `p0` VALUES LESS THAN (10) ENGINE = MyISAM, + PARTITION `p1` VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +create table t2 like t1; +create database d; +use d; +create table t3 like test.t1; +use test; +create table t3 (x int, y int) +partition by range(t1.y) +subpartition by hash(x) +subpartitions 2 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +ERROR 42S22: Unknown column '`t1`.`y`' in 'partition function' +create table t3 (x int, y int) +partition by range(d.t3.y) +subpartition by hash(x) +subpartitions 2 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +ERROR 42S22: Unknown column '`d`.`t3`.`y`' in 'partition function' +create table t3 (x int, y int) +partition by range(y) +subpartition by hash(t1.x) +subpartitions 2 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +ERROR 42S22: Unknown column '`t1`.`x`' in 'subpartition function' +create table t3 (x int, y int) +partition by range(y) +subpartition by hash(d.t3.x) +subpartitions 2 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +ERROR 42S22: Unknown column '`d`.`t3`.`x`' in 'subpartition function' +create table t3 (x int, y int) +partition by range(t3.y) +subpartition by hash(t3.x) +subpartitions 2 ( +partition p0 values less than (10), +partition p1 values less than maxvalue +); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `x` int(11) DEFAULT NULL, + `y` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`x`) +SUBPARTITION BY HASH (`y`) +SUBPARTITIONS 10 +(PARTITION `p0` VALUES LESS THAN (10) ENGINE = MyISAM, + PARTITION `p1` VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `x` int(11) DEFAULT NULL, + `y` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`y`) +SUBPARTITION BY HASH (`x`) +SUBPARTITIONS 2 +(PARTITION `p0` VALUES LESS THAN (10) ENGINE = MyISAM, + PARTITION `p1` VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +show create table d.t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `x` int(11) DEFAULT NULL, + `y` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`x`) +SUBPARTITION BY HASH (`y`) +SUBPARTITIONS 10 +(PARTITION `p0` VALUES LESS THAN (10) ENGINE = MyISAM, + PARTITION `p1` VALUES LESS THAN MAXVALUE ENGINE = MyISAM) +drop database d; +drop tables t1, t2, t3; diff --git a/mysql-test/main/partition.test b/mysql-test/main/partition.test index 81752982959..451fdb6b204 100644 --- a/mysql-test/main/partition.test +++ b/mysql-test/main/partition.test @@ -3023,3 +3023,72 @@ DROP TABLE t1,t2; --echo # --echo # End of 10.1 tests --echo # + +--echo # +--echo # MDEV-12483 Refactoring for part_info in TABLE_SHARE +--echo # +create table t1 (x int, y int) +partition by range(x) +subpartition by hash(y) +subpartitions 10 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + +show create table t1; +create table t2 like t1; +create database d; +use d; +create table t3 like test.t1; +use test; + +--error ER_BAD_FIELD_ERROR +create table t3 (x int, y int) +partition by range(t1.y) +subpartition by hash(x) +subpartitions 2 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + +--error ER_BAD_FIELD_ERROR +create table t3 (x int, y int) +partition by range(d.t3.y) +subpartition by hash(x) +subpartitions 2 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + + +--error ER_BAD_FIELD_ERROR +create table t3 (x int, y int) +partition by range(y) +subpartition by hash(t1.x) +subpartitions 2 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + +--error ER_BAD_FIELD_ERROR +create table t3 (x int, y int) +partition by range(y) +subpartition by hash(d.t3.x) +subpartitions 2 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + +create table t3 (x int, y int) +partition by range(t3.y) +subpartition by hash(t3.x) +subpartitions 2 ( + partition p0 values less than (10), + partition p1 values less than maxvalue +); + +show create table t2; +show create table t3; +show create table d.t3; +drop database d; +drop tables t1, t2, t3; diff --git a/sql/handler.cc b/sql/handler.cc index f223def4aa9..c199d7da40f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5579,7 +5579,7 @@ int ha_create_table(THD *thd, const char *path, share.m_psi= PSI_CALL_get_table_share(temp_table, &share); if (open_table_from_share(thd, &share, &empty_clex_str, 0, READ_ALL, 0, - &table, true)) + &table)) { goto err; } diff --git a/sql/item.cc b/sql/item.cc index 731de380e07..b7e285f7096 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -728,6 +728,35 @@ bool Item_ident::collect_outer_ref_processor(void *param) } +bool Item_field::check_table_name_processor(void *arg) +{ + if (!table_name.length) + return false; + Check_table_name_prm &p= *(Check_table_name_prm *) arg; + Table_name a(p.db, p.table_name); + Table_name b(db_name.length ? db_name : p.db, table_name); + if (a.cmp(b)) + { + print(&p.field, (enum_query_type) (QT_ITEM_ORIGINAL_FUNC_NULLIF | + QT_NO_DATA_EXPANSION | + QT_TO_SYSTEM_CHARSET)); + return true; + } + return false; +} + + +bool Item_field::update_table_name_processor(void *arg) +{ + if (!table_name.length) + return false; + Check_table_name_prm &p= *(Check_table_name_prm *) arg; + db_name= p.db; + table_name= p.table_name; + return false; +} + + /** Store the pointer to this item field into a list if not already there. diff --git a/sql/item.h b/sql/item.h index 2b86736227f..50439a160fa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2125,6 +2125,24 @@ public: return 0; } + /** + Check db/table_name if they defined in item and match arg values + + @param arg Pointer to Check_table_name_prm structure + + @retval true Match failed + @retval false Match succeeded + */ + virtual bool check_table_name_processor(void *arg) { return false; } + /** + Update db/table_name if they are defined in item to arg values + + @param arg Pointer to Check_table_name_prm structure + + @return Always false + */ + virtual bool update_table_name_processor(void *arg) { return false; } + /* TRUE if the expression depends only on the table indicated by tab_map or can be converted to such an exression using equalities. @@ -2325,6 +2343,15 @@ public: bool collect; }; + struct Check_table_name_prm + { + LEX_CSTRING db; + LEX_CSTRING table_name; + String field; + Check_table_name_prm(LEX_CSTRING _db, LEX_CSTRING _table_name) : + db(_db), table_name(_table_name) {} + }; + /* For SP local variable returns pointer to Item representing its current value and pointer to current Item otherwise. @@ -3641,6 +3668,9 @@ public: } return 0; } + bool check_table_name_processor(void *arg) override; + bool update_table_name_processor(void *arg) override; + void cleanup() override; Item_equal *get_item_equal() override { return item_equal; } void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ce72a7af051..ddb5214c27b 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -40,9 +40,8 @@ #include "ha_partition.h" -partition_info *partition_info::get_clone(THD *thd) +partition_info *partition_info::get_clone(MEM_ROOT *mem_root) { - MEM_ROOT *mem_root= thd->mem_root; DBUG_ENTER("partition_info::get_clone"); List_iterator<partition_element> part_it(partitions); @@ -51,6 +50,8 @@ partition_info *partition_info::get_clone(THD *thd) if (unlikely(!clone)) DBUG_RETURN(NULL); + clone->item_free_list= NULL; + memset(&(clone->read_partitions), 0, sizeof(clone->read_partitions)); memset(&(clone->lock_partitions), 0, sizeof(clone->lock_partitions)); clone->bitmaps_are_initialized= FALSE; @@ -2635,6 +2636,13 @@ bool partition_info::vers_init_info(THD * thd) } +inline bool is_unpack_partition(const THD *thd) +{ + // TODO: find a better way of detecting we are under unpack_partition()? + return thd->lex->use_only_table_context; +} + + /** Assign INTERVAL and STARTS for SYSTEM_TIME partitions. @@ -2675,8 +2683,8 @@ bool partition_info::vers_set_interval(THD* thd, Item* interval, case INT_RESULT: case DECIMAL_RESULT: case REAL_RESULT: - /* When table member is defined, we are inside mysql_unpack_partition(). */ - if (!table || starts->val_int() > TIMESTAMP_MAX_VALUE) + /* When table member is defined, we are inside unpack_partition(). */ + if (!is_unpack_partition(thd) || starts->val_int() > TIMESTAMP_MAX_VALUE) goto interval_starts_error; vers_info->interval.start= (my_time_t) starts->val_int(); break; @@ -2694,7 +2702,7 @@ bool partition_info::vers_set_interval(THD* thd, Item* interval, default: goto interval_starts_error; } - if (!table) + if (!is_unpack_partition(thd)) { if (thd->query_start() < vers_info->interval.start) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, diff --git a/sql/partition_info.h b/sql/partition_info.h index 0656238ec07..3c1019c6367 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -330,7 +330,11 @@ public: } ~partition_info() {} - partition_info *get_clone(THD *thd); + partition_info *get_clone(MEM_ROOT *mem_root); + partition_info *get_clone(THD *thd) + { + return get_clone(thd->mem_root); + } bool set_named_partition_bitmap(const char *part_name, size_t length); bool set_partition_bitmaps(List<String> *partition_names); bool set_partition_bitmaps_from_table(TABLE_LIST *table_list); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 1454e1add55..1c4c77ff722 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -144,7 +144,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(0); // Can't open frm file if (open_table_from_share(thd, share, &empty_clex_str, 0, 0, 0, - &tmp_table, FALSE)) + &tmp_table)) { tdc_release_share(share); DBUG_RETURN(0); // Out of memory diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a9911c07710..8d2ada3659e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -607,8 +607,7 @@ bool flush_tables(THD *thd, flush_tables_type flag) if (!open_table_from_share(thd, share, &empty_clex_str, HA_OPEN_KEYFILE, 0, HA_OPEN_FOR_ALTER | HA_OPEN_FOR_FLUSH, - tmp_table, FALSE, - NULL)) + tmp_table)) { (void) tmp_table->file->extra(HA_EXTRA_FLUSH); /* @@ -2001,7 +2000,7 @@ retry_share: error= open_table_from_share(thd, share, &table_list->alias, HA_OPEN_KEYFILE | HA_TRY_READ_ONLY, EXTRA_RECORD, - thd->open_options, table, FALSE, + thd->open_options, table, IF_PARTITIONING(table_list->partition_names,0)); if (unlikely(error)) @@ -3040,7 +3039,7 @@ static bool auto_repair_table(THD *thd, TABLE_LIST *table_list) HA_OPEN_KEYFILE | HA_TRY_READ_ONLY, EXTRA_RECORD, ha_open_options | HA_OPEN_FOR_REPAIR, - &entry, FALSE) || ! entry.file || + &entry) || ! entry.file || (entry.file->is_crashed() && entry.file->ha_check_and_repair(thd))) { /* Give right error message */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index a787f371b4f..0517056dd23 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -708,10 +708,15 @@ void lex_free(void) */ int -init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) +init_lex_with_single_table(THD *thd, TABLE *table, TABLE_SHARE *s, LEX *lex) { TABLE_LIST *table_list; Table_ident *table_ident; + if (table) + { + DBUG_ASSERT(!s); + s= table->s; + } SELECT_LEX *select_lex= lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; /* @@ -726,8 +731,8 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) lex_start(thd); context->init(); if (unlikely((!(table_ident= new Table_ident(thd, - &table->s->db, - &table->s->table_name, + &s->db, + &s->table_name, TRUE)))) || (unlikely(!(table_list= select_lex->add_table_to_list(thd, table_ident, @@ -738,8 +743,11 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) lex->use_only_table_context= TRUE; lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VCOL_EXPR; select_lex->cur_pos_in_select_list= UNDEF_POS; - table->map= 1; //To ensure correct calculation of const item - table_list->table= table; + if (table) + { + table->map= 1; //To ensure correct calculation of const item + table_list->table= table; + } table_list->cacheable_table= false; lex->create_last_non_select_table= table_list; return FALSE; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76a81f256c8..5a0a38a4e0b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -5019,7 +5019,7 @@ extern void lex_end(LEX *lex); extern void lex_end_stage1(LEX *lex); extern void lex_end_stage2(LEX *lex); void end_lex_with_single_table(THD *thd, TABLE *table, LEX *old_lex); -int init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex); +int init_lex_with_single_table(THD *thd, TABLE *table, TABLE_SHARE *s, LEX *lex); extern int MYSQLlex(union YYSTYPE *yylval, THD *thd); extern int ORAlex(union YYSTYPE *yylval, THD *thd); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a85761da917..7e56d7062f8 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -191,7 +191,6 @@ static bool is_name_in_list(const char *name, List<const char> list_names) partition_default_handling() table Table object part_info Partition info to set up - is_create_table_ind Is this part of a table creation normalized_path Normalized path name of table and database RETURN VALUES @@ -200,32 +199,28 @@ static bool is_name_in_list(const char *name, List<const char> list_names) */ bool partition_default_handling(THD *thd, TABLE *table, partition_info *part_info, - bool is_create_table_ind, const char *normalized_path) { DBUG_ENTER("partition_default_handling"); - if (!is_create_table_ind) + if (part_info->use_default_num_partitions) { - if (part_info->use_default_num_partitions) + if (table->file->get_no_parts(normalized_path, &part_info->num_parts)) { - if (table->file->get_no_parts(normalized_path, &part_info->num_parts)) - { - DBUG_RETURN(TRUE); - } + DBUG_RETURN(TRUE); } - else if (part_info->is_sub_partitioned() && - part_info->use_default_num_subpartitions) + } + else if (part_info->is_sub_partitioned() && + part_info->use_default_num_subpartitions) + { + uint num_parts; + if (table->file->get_no_parts(normalized_path, &num_parts)) { - uint num_parts; - if (table->file->get_no_parts(normalized_path, &num_parts)) - { - DBUG_RETURN(TRUE); - } - DBUG_ASSERT(part_info->num_parts > 0); - DBUG_ASSERT((num_parts % part_info->num_parts) == 0); - part_info->num_subparts= num_parts / part_info->num_parts; + DBUG_RETURN(TRUE); } + DBUG_ASSERT(part_info->num_parts > 0); + DBUG_ASSERT((num_parts % part_info->num_parts) == 0); + part_info->num_subparts= num_parts / part_info->num_parts; } part_info->set_up_defaults_for_partitioning(thd, table->file, NULL, 0U); @@ -802,8 +797,6 @@ int check_signed_flag(partition_info *part_info) table The table object part_info Reference to partitioning data structure is_sub_part Is the table subpartitioned as well - is_create_table_ind Indicator of whether openfrm was called as part of - CREATE or ALTER TABLE RETURN VALUE TRUE An error occurred, something was wrong with the @@ -827,7 +820,7 @@ int check_signed_flag(partition_info *part_info) */ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, - bool is_sub_part, bool is_create_table_ind) + bool is_sub_part) { partition_info *part_info= table->part_info; bool result= TRUE; @@ -836,7 +829,7 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, LEX lex; DBUG_ENTER("fix_fields_part_func"); - if (init_lex_with_single_table(thd, table, &lex)) + if (init_lex_with_single_table(thd, table, NULL, &lex)) goto end; table->get_fields_in_item_tree= true; @@ -891,22 +884,12 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, /* We don't allow creating partitions with expressions with non matching - arguments as a (sub)partitioning function, - but we want to allow such expressions when opening existing tables for - easier maintenance. This exception should be deprecated at some point - in future so that we always throw an error. + arguments as a (sub)partitioning function. */ if (func_expr->walk(&Item::check_valid_arguments_processor, 0, NULL)) { - if (is_create_table_ind) - { - my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0)); - goto end; - } - else - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, - ER_THD(thd, ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR)); + my_error(ER_WRONG_EXPR_IN_PARTITION_FUNC_ERROR, MYF(0)); + goto end; } if (unlikely((!is_sub_part) && (error= check_signed_flag(part_info)))) @@ -1904,8 +1887,6 @@ bool check_part_func_fields(Field **ptr, bool ok_with_charsets) fix_partition_func() thd The thread object table TABLE object for which partition fields are set-up - is_create_table_ind Indicator of whether openfrm was called as part of - CREATE or ALTER TABLE RETURN VALUE TRUE Error @@ -1924,7 +1905,7 @@ NOTES of an error that is not discovered until here. */ -bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) +bool fix_partition_func(THD *thd, TABLE *table) { bool result= TRUE; partition_info *part_info= table->part_info; @@ -1938,15 +1919,10 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) thd->column_usage= COLUMNS_WRITE; DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage)); - if (!is_create_table_ind || - thd->lex->sql_command != SQLCOM_CREATE_TABLE) + if (partition_default_handling(thd, table, part_info, + table->s->normalized_path.str)) { - if (partition_default_handling(thd, table, part_info, - is_create_table_ind, - table->s->normalized_path.str)) - { - DBUG_RETURN(TRUE); - } + DBUG_RETURN(TRUE); } if (part_info->is_sub_partitioned()) { @@ -1966,7 +1942,7 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) else { if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr, - table, TRUE, is_create_table_ind))) + table, TRUE))) goto end; if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) { @@ -1994,7 +1970,7 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) else { if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, is_create_table_ind))) + table, FALSE))) goto end; if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) { @@ -2018,7 +1994,7 @@ bool fix_partition_func(THD *thd, TABLE *table, bool is_create_table_ind) part_info->vers_fix_field_list(thd)) goto end; if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, is_create_table_ind))) + table, FALSE))) goto end; } part_info->fixed= TRUE; @@ -2114,7 +2090,7 @@ static int add_part_field_list(THD *thd, String *str, List<const char> field_lis /* Must escape strings in partitioned tables frm-files, - parsing it later with mysql_unpack_partition will fail otherwise. + parsing it later with unpack_partition will fail otherwise. */ static int add_keyword_string(String *str, const char *keyword, @@ -4353,15 +4329,9 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, data structures of the partitioning. SYNOPSIS - mysql_unpack_partition() + TABLE_SHARE::unpack_partition() thd Thread object - part_buf Partition info from frm file - part_info_len Length of partition syntax - table Table object of partitioned table - create_table_ind Is it called from CREATE TABLE default_db_type What is the default engine of the table - work_part_info_used Flag is raised if we don't create new - part_info, but used thd->work_part_info RETURN VALUE TRUE Error @@ -4378,37 +4348,29 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, possible to retrace this given an item tree. */ -bool 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) +bool TABLE_SHARE::unpack_partition(THD *thd, handlerton *default_db_type) { bool result= TRUE; - partition_info *part_info; CHARSET_INFO *old_character_set_client= thd->variables.character_set_client; LEX *old_lex= thd->lex; LEX lex; PSI_statement_locker *parent_locker= thd->m_statement_psi; - DBUG_ENTER("mysql_unpack_partition"); + DBUG_ENTER("TABLE_SHARE::unpack_partition"); thd->variables.character_set_client= system_charset_info; Parser_state parser_state; - if (unlikely(parser_state.init(thd, part_buf, part_info_len))) + if (unlikely(parser_state.init(thd, LEX_STRING_WITH_LEN(part_sql)))) goto end; - if (unlikely(init_lex_with_single_table(thd, table, &lex))) + if (unlikely(init_lex_with_single_table(thd, NULL, this, &lex))) goto end; - *work_part_info_used= FALSE; - if (unlikely(!(lex.part_info= new partition_info()))) goto end; - lex.part_info->table= table; /* Indicates MYSQLparse from this place */ part_info= lex.part_info; - DBUG_PRINT("info", ("Parse: %s", part_buf)); + DBUG_PRINT("info", ("Parse: %s", part_sql.str)); thd->m_statement_psi= NULL; if (unlikely(parse_sql(thd, & parser_state, NULL)) || @@ -4438,28 +4400,6 @@ bool mysql_unpack_partition(THD *thd, DBUG_PRINT("info", ("default engine = %s, default_db_type = %s", ha_resolve_storage_engine_name(part_info->default_engine_type), ha_resolve_storage_engine_name(default_db_type))); - if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE) - { - /* - When we come here we are doing a create table. In this case we - have already done some preparatory work on the old part_info - object. We don't really need this new partition_info object. - Thus we go back to the old partition info object. - We need to free any memory objects allocated on item_free_list - by the parser since we are keeping the old info from the first - parser call in CREATE TABLE. - - This table object can not be used any more. However, since - this is CREATE TABLE, we know that it will be destroyed by the - caller, and rely on that. - */ - thd->free_items(); - part_info= thd->work_part_info; - *work_part_info_used= true; - } - table->part_info= part_info; - part_info->table= table; - table->file->set_part_info(part_info); if (!part_info->default_engine_type) part_info->default_engine_type= default_db_type; DBUG_ASSERT(part_info->default_engine_type == default_db_type); @@ -4467,7 +4407,8 @@ bool mysql_unpack_partition(THD *thd, DBUG_ASSERT(part_info->default_engine_type != partition_hton); result= FALSE; end: - end_lex_with_single_table(thd, table, old_lex); + lex_end(thd->lex); + thd->lex= old_lex; thd->variables.character_set_client= old_character_set_client; DBUG_RETURN(result); } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 58ba82dcd9f..5e7d52dfc20 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -93,7 +93,7 @@ void prune_partition_set(const TABLE *table, part_id_range *part_spec); bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); void set_linear_hash_mask(partition_info *part_info, uint num_parts); -bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); +bool fix_partition_func(THD *thd, TABLE *table); void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, part_id_range *part_spec); @@ -102,11 +102,6 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info, const key_range *key_spec, part_id_range *part_spec); -bool 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); void make_used_partitions_str(MEM_ROOT *mem_root, partition_info *part_info, String *parts_str, String_list &used_partitions_list); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4de99645eca..410bead9990 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5088,7 +5088,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE *table, if (!open_table_from_share(thd, share, table_name, 0, (EXTRA_RECORD | OPEN_FRM_FILE_ONLY), - thd->open_options, &tbl, FALSE)) + thd->open_options, &tbl)) { tbl.s= share; table_list.table= &tbl; @@ -5536,7 +5536,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, #ifdef WITH_PARTITION_STORAGE_ENGINE if (share->db_type() == partition_hton && - share->partition_info_str_len) + share->part_sql.length) { tmp_db_type= plugin_hton(share->default_part_plugin); is_partitioned= TRUE; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 59213190017..dd794447274 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -854,12 +854,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) error= 1; goto err; } - share->partition_info_str= tmp_part_syntax_str; + share->part_sql.str= tmp_part_syntax_str; } else - memcpy((char*) share->partition_info_str, part_syntax_buf, + memcpy((char*) share->part_sql.str, part_syntax_buf, syntax_len + 1); - share->partition_info_str_len= part_info->part_info_len= syntax_len; + share->part_sql.length= part_info->part_info_len= syntax_len; part_info->part_info_string= part_syntax_buf; } #endif @@ -4063,6 +4063,23 @@ handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db, goto err; } + Item::Check_table_name_prm p(db, table_name); + if (part_info->part_expr && + part_info->part_expr->walk(&Item::check_table_name_processor, false, + (void *) &p)) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), p.field.c_ptr(), "partition function"); + goto err; + } + + if (part_info->subpart_expr && + part_info->subpart_expr->walk(&Item::check_table_name_processor, false, + (void *) &p)) + { + my_error(ER_BAD_FIELD_ERROR, MYF(0), p.field.c_ptr(), "subpartition function"); + goto err; + } + /* We reverse the partitioning parser and generate a standard format for syntax stored in frm file. @@ -5152,7 +5169,23 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, #ifdef WITH_PARTITION_STORAGE_ENGINE /* Partition info is not handled by mysql_prepare_alter_table() call. */ if (src_table->table->part_info) - thd->work_part_info= src_table->table->part_info->get_clone(thd); + { + partition_info *part_info= src_table->table->part_info->get_clone(thd->mem_root); + part_info->table= NULL; + if (part_info->part_expr) + { + Item::Check_table_name_prm p(table->db, table->table_name); + (void) part_info->part_expr->walk(&Item::update_table_name_processor, false, + (void *) &p); + } + if (part_info->subpart_expr) + { + Item::Check_table_name_prm p(table->db, table->table_name); + (void) part_info->subpart_expr->walk(&Item::update_table_name_processor, false, + (void *) &p); + } + thd->work_part_info= part_info; + } #endif /* @@ -9207,8 +9240,7 @@ static int create_table_for_inplace_alter(THD *thd, alter_ctx.new_name.str, alter_ctx.get_tmp_path()); if (share->init_from_binary_frm_image(thd, true, frm->str, frm->length) || open_table_from_share(thd, share, &alter_ctx.new_name, 0, - EXTRA_RECORD, thd->open_options, - table, false)) + EXTRA_RECORD, thd->open_options, table)) { free_table_share(share); deletefrm(alter_ctx.get_tmp_path()); diff --git a/sql/table.cc b/sql/table.cc index a11e372c217..777a3e3d240 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -26,7 +26,7 @@ #include "sql_parse.h" // free_items #include "strfunc.h" // unhex_type2 #include "ha_partition.h" // PART_EXT - // mysql_unpack_partition, + // unpack_partition, // fix_partition_func, partition_info #include "sql_base.h" #include "create_options.h" @@ -511,6 +511,12 @@ void TABLE_SHARE::destroy() #ifdef WITH_PARTITION_STORAGE_ENGINE plugin_unlock(NULL, default_part_plugin); + if (part_info) + { + /* Allocated through table->mem_root, freed below */ + free_items(part_info->item_free_list); + part_info->item_free_list= 0; + } #endif /* WITH_PARTITION_STORAGE_ENGINE */ PSI_CALL_release_table_share(m_psi); @@ -1920,15 +1926,39 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, { uint32 partition_info_str_len = uint4korr(next_chunk); #ifdef WITH_PARTITION_STORAGE_ENGINE - if ((share->partition_info_buffer_size= - share->partition_info_str_len= partition_info_str_len)) + if ((share->partition_info_buffer_size= partition_info_str_len)) { - if (!(share->partition_info_str= (char*) + if (!(share->part_sql.str= (char*) memdup_root(&share->mem_root, next_chunk + 4, partition_info_str_len + 1))) { goto err; } + share->part_sql.length= partition_info_str_len; + /* + In this execution we must avoid calling thd->change_item_tree since + we might release memory before statement is completed. We do this + by changing to a new statement arena. As part of this arena we also + set the memory root to be the memory root of the table since we + call the parser and fix_fields which both can allocate memory for + item objects. We keep the arena to ensure that we can release the + free_list when closing the table object. + SEE Bug #21658 + */ + + Query_arena *backup_stmt_arena_ptr= thd->stmt_arena; + Query_arena backup_arena; + Query_arena part_func_arena(&mem_root, Query_arena::STMT_INITIALIZED); + thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); + thd->stmt_arena= &part_func_arena; + + bool error= + share->unpack_partition(thd, plugin_hton(share->default_part_plugin)); + thd->stmt_arena= backup_stmt_arena_ptr; + thd->restore_active_arena(&part_func_arena, &backup_arena); + share->part_info->item_free_list= part_func_arena.free_list; + if (error) + goto err; } #else if (partition_info_str_len) @@ -3381,12 +3411,11 @@ bool TABLE_SHARE::write_par_image(const uchar *par, size_t len) int TABLE_SHARE::read_frm_image(const uchar **frm, size_t *len) { - if (IF_PARTITIONING(partition_info_str, 0)) // cannot discover a partition + if (IF_PARTITIONING(part_info, 0)) // cannot discover a partition { DBUG_ASSERT(db_type()->discover_table == 0); return 1; } - if (frm_image) { *frm= frm_image->str; @@ -3602,7 +3631,7 @@ unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table, if (parser_state.init(thd, expr_str->c_ptr_safe(), expr_str->length())) goto end; - if (init_lex_with_single_table(thd, table, &lex)) + if (init_lex_with_single_table(thd, table, NULL, &lex)) goto end; lex.parse_vcol_expr= true; @@ -3812,7 +3841,7 @@ bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root) enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, const LEX_CSTRING *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, - bool is_create_table, List<String> *partitions_to_open) + List<String> *partitions_to_open) { enum open_frm_error error; uint records, i, bitmap_size, bitmap_count; @@ -4015,69 +4044,43 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, } #ifdef WITH_PARTITION_STORAGE_ENGINE - bool work_part_info_used; - if (share->partition_info_str_len && outparam->file) + bool err; + if (share->part_sql.length && outparam->file) { - /* - In this execution we must avoid calling thd->change_item_tree since - we might release memory before statement is completed. We do this - by changing to a new statement arena. As part of this arena we also - set the memory root to be the memory root of the table since we - call the parser and fix_fields which both can allocate memory for - item objects. We keep the arena to ensure that we can release the - free_list when closing the table object. - SEE Bug #21658 - */ + DBUG_ASSERT(share->part_info); + outparam->part_info= share->part_info->get_clone(&outparam->mem_root); + + if (!outparam->part_info) + { + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + error_reported= true; + goto err; + } + + outparam->part_info->table= outparam; + outparam->file->set_part_info(outparam->part_info); + outparam->part_info->is_auto_partitioned= share->auto_partitioned; + DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); Query_arena *backup_stmt_arena_ptr= thd->stmt_arena; Query_arena backup_arena; - Query_arena part_func_arena(&outparam->mem_root, - Query_arena::STMT_INITIALIZED); + Query_arena part_func_arena(&outparam->mem_root, Query_arena::STMT_INITIALIZED); thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); thd->stmt_arena= &part_func_arena; - bool tmp; - tmp= mysql_unpack_partition(thd, share->partition_info_str, - share->partition_info_str_len, - outparam, is_create_table, - plugin_hton(share->default_part_plugin), - &work_part_info_used); - if (tmp) - { - thd->stmt_arena= backup_stmt_arena_ptr; - thd->restore_active_arena(&part_func_arena, &backup_arena); - goto partititon_err; - } - outparam->part_info->is_auto_partitioned= share->auto_partitioned; - DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned)); - /* - We should perform the fix_partition_func in either local or - caller's arena depending on work_part_info_used value. - */ - if (!work_part_info_used) - tmp= fix_partition_func(thd, outparam, is_create_table); + if (share->part_info->part_expr) + outparam->part_info->part_expr= share->part_info->part_expr->build_clone(thd); + + if (share->part_info->subpart_expr) + outparam->part_info->subpart_expr= share->part_info->subpart_expr->build_clone(thd); + + err= fix_partition_func(thd, outparam); thd->stmt_arena= backup_stmt_arena_ptr; thd->restore_active_arena(&part_func_arena, &backup_arena); - if (!tmp) - { - if (work_part_info_used) - tmp= fix_partition_func(thd, outparam, is_create_table); - } outparam->part_info->item_free_list= part_func_arena.free_list; -partititon_err: - if (tmp) - { - if (is_create_table) - { - /* - During CREATE/ALTER TABLE it is ok to receive errors here. - It is not ok if it happens during the opening of an frm - file as part of a normal query. - */ - error_reported= TRUE; - } + + if (err) goto err; - } } #endif diff --git a/sql/table.h b/sql/table.h index b11ab3248ca..dea2e93f388 100644 --- a/sql/table.h +++ b/sql/table.h @@ -903,15 +903,18 @@ struct TABLE_SHARE #ifdef WITH_PARTITION_STORAGE_ENGINE /* filled in when reading from frm */ bool auto_partitioned; - char *partition_info_str; - uint partition_info_str_len; - uint partition_info_buffer_size; + /* NB: yyUnput() requires write access to sql buffer */ + LEX_STRING part_sql; + uint partition_info_buffer_size; plugin_ref default_part_plugin; + partition_info *part_info; + + bool unpack_partition(THD *thd, handlerton *default_db_type); #endif bool partitioned() const { - return IF_PARTITIONING(partition_info_str != NULL, false); + return IF_PARTITIONING(part_sql.str != NULL, false); } /** @@ -3215,7 +3218,6 @@ void init_mdl_requests(TABLE_LIST *table_list); enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, const LEX_CSTRING *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam, - bool is_create_table, List<String> *partitions_to_open= NULL); bool copy_keys_from_share(TABLE *outparam, MEM_ROOT *root); bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol); diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 1a8b5c471bd..4041b8ba5bd 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1117,7 +1117,7 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, EXTRA_RECORD, (ha_open_options | (open_options & HA_OPEN_FOR_CREATE)), - table, false)) + table)) { my_free(table); DBUG_RETURN(NULL); diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index f55692f34a5..bf679eaf297 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -1849,8 +1849,8 @@ bool ha_connect::CheckVirtualIndex(TABLE_SHARE *s) bool ha_connect::IsPartitioned(void) { #ifdef WITH_PARTITION_STORAGE_ENGINE - if (tshp) - return tshp->partition_info_str_len > 0; + if (tshp) + return tshp->part_info != NULL; else if (table && table->part_info) return true; else diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 975c7bf4da3..19887cbe952 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2427,8 +2427,8 @@ next_column: | ALTER_STORED_COLUMN_ORDER); } if (flags != 0 - || IF_PARTITIONING((altered_table->s->partition_info_str - && altered_table->s->partition_info_str_len), 0) + || IF_PARTITIONING((altered_table->s->part_sql.str + && altered_table->s->part_sql.length), 0) || (!check_v_col_in_order( this->table, altered_table, ha_alter_info))) { ha_alter_info->unsupported_reason = diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index a3ac359d1b9..80a62ea9152 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -2101,7 +2101,7 @@ int spider_parse_connect_info( DBUG_PRINT("info",("spider partition_info=%s", table_share->partition_info)); #else DBUG_PRINT("info",("spider partition_info=%s", - table_share->partition_info_str)); + table_share->part_sql.str)); #endif DBUG_PRINT("info",("spider part_info=%p", part_info)); #endif |