summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2021-02-20 23:18:51 +0300
committerAleksey Midenkov <midenok@gmail.com>2021-03-15 17:12:24 +0300
commit742280a28caea054cf5141907e97aa70f2a63f01 (patch)
tree0909c3e244b11daaaa54d67cdd2e18c966a18dd7
parent57075b34c89ac8c0e38c8500dffb38c1dcd11eb6 (diff)
downloadmariadb-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.result102
-rw-r--r--mysql-test/main/partition.test69
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item.cc29
-rw-r--r--sql/item.h30
-rw-r--r--sql/partition_info.cc18
-rw-r--r--sql/partition_info.h6
-rw-r--r--sql/sql_admin.cc2
-rw-r--r--sql/sql_base.cc7
-rw-r--r--sql/sql_lex.cc18
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_partition.cc127
-rw-r--r--sql/sql_partition.h7
-rw-r--r--sql/sql_show.cc4
-rw-r--r--sql/sql_table.cc44
-rw-r--r--sql/table.cc123
-rw-r--r--sql/table.h12
-rw-r--r--sql/temporary_tables.cc2
-rw-r--r--storage/connect/ha_connect.cc4
-rw-r--r--storage/innobase/handler/handler0alter.cc4
-rw-r--r--storage/spider/spd_table.cc2
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