diff --git a/mysql-test/main/plugin.result b/mysql-test/main/plugin.result index c3d974b8052..160e3f335c2 100644 --- a/mysql-test/main/plugin.result +++ b/mysql-test/main/plugin.result @@ -216,7 +216,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `VAROPT`=33 +) ENGINE=EXAMPLE DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci `varopt`=33 drop table t1; SET @@SQL_MODE=@OLD_SQL_MODE; select 1; diff --git a/mysql-test/suite/innodb/r/create_like.result b/mysql-test/suite/innodb/r/create_like.result new file mode 100644 index 00000000000..16d7c9f63bc --- /dev/null +++ b/mysql-test/suite/innodb/r/create_like.result @@ -0,0 +1,21 @@ +# +# MDEV-35144 CREATE TABLE ... LIKE uses current innodb_compression_default instead of the create value +# +set innodb_compression_default= off; +create table t1 (a int, b blob) engine=innodb; +set innodb_compression_default= on; +create table s_import like t1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` blob DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +show create table s_import; +Table Create Table +s_import CREATE TABLE `s_import` ( + `a` int(11) DEFAULT NULL, + `b` blob DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t1,s_import; +# End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/create_like.test b/mysql-test/suite/innodb/t/create_like.test new file mode 100644 index 00000000000..d348de7ebc8 --- /dev/null +++ b/mysql-test/suite/innodb/t/create_like.test @@ -0,0 +1,16 @@ +--source include/have_innodb.inc +--echo # +--echo # MDEV-35144 CREATE TABLE ... LIKE uses current innodb_compression_default instead of the create value +--echo # + +set innodb_compression_default= off; +create table t1 (a int, b blob) engine=innodb; +set innodb_compression_default= on; +create table s_import like t1; + +show create table t1; +show create table s_import; + +DROP TABLE t1,s_import; + +--echo # End of 10.5 tests diff --git a/mysql-test/suite/sql_sequence/alter.result b/mysql-test/suite/sql_sequence/alter.result index 10f106553e3..0508660e82b 100644 --- a/mysql-test/suite/sql_sequence/alter.result +++ b/mysql-test/suite/sql_sequence/alter.result @@ -340,5 +340,39 @@ next_not_cached_value minimum_value maximum_value start_value increment cache_si 1001 1 9223372036854775806 1 1 1000 0 0 drop sequence s1,s2; # -# End of 10.5 tests +# MDEV-35144 CREATE TABLE ... LIKE uses current innodb_compression_default instead of the create value # +set @@innodb_compression_default= off; +create or replace sequence s engine=innodb; +set @@innodb_compression_default= on; +create or replace table s_import like s; +show create table s; +Table Create Table +s CREATE TABLE `s` ( + `next_not_cached_value` bigint(21) NOT NULL, + `minimum_value` bigint(21) NOT NULL, + `maximum_value` bigint(21) NOT NULL, + `start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', + `increment` bigint(21) NOT NULL COMMENT 'increment value', + `cache_size` bigint(21) unsigned NOT NULL, + `cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + `cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=InnoDB SEQUENCE=1 +show create table s_import; +Table Create Table +s_import CREATE TABLE `s_import` ( + `next_not_cached_value` bigint(21) NOT NULL, + `minimum_value` bigint(21) NOT NULL, + `maximum_value` bigint(21) NOT NULL, + `start_value` bigint(21) NOT NULL COMMENT 'start value when sequences is created or value if RESTART is used', + `increment` bigint(21) NOT NULL COMMENT 'increment value', + `cache_size` bigint(21) unsigned NOT NULL, + `cycle_option` tinyint(1) unsigned NOT NULL COMMENT '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + `cycle_count` bigint(21) NOT NULL COMMENT 'How many cycles have been done' +) ENGINE=InnoDB SEQUENCE=1 +alter table s_import discard tablespace; +flush table s for export; +UNLOCK TABLES; +alter table s_import import tablespace; +drop table s,s_import; +# End of 10.5 tests diff --git a/mysql-test/suite/sql_sequence/alter.test b/mysql-test/suite/sql_sequence/alter.test index ffdb67186db..fce2cb45838 100644 --- a/mysql-test/suite/sql_sequence/alter.test +++ b/mysql-test/suite/sql_sequence/alter.test @@ -239,5 +239,23 @@ drop sequence s1,s2; --enable_ps_protocol --echo # ---echo # End of 10.5 tests +--echo # MDEV-35144 CREATE TABLE ... LIKE uses current innodb_compression_default instead of the create value --echo # + +set @@innodb_compression_default= off; +create or replace sequence s engine=innodb; +set @@innodb_compression_default= on; +create or replace table s_import like s; + +show create table s; +show create table s_import; + +alter table s_import discard tablespace; +flush table s for export; +--copy_file $MYSQLD_DATADIR/test/s.ibd $MYSQLD_DATADIR/test/s_import.ibd +--copy_file $MYSQLD_DATADIR/test/s.cfg $MYSQLD_DATADIR/test/s_import.cfg +UNLOCK TABLES; +alter table s_import import tablespace; +drop table s,s_import; + +--echo # End of 10.5 tests diff --git a/sql/create_options.cc b/sql/create_options.cc index 60e9b733efc..6e1217dcdfd 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -117,15 +117,13 @@ static bool report_unknown_option(THD *thd, engine_option_value *val, #define value_ptr(STRUCT,OPT) ((char*)(STRUCT) + (OPT)->offset) -static bool set_one_value(ha_create_table_option *opt, - THD *thd, const LEX_CSTRING *value, void *base, - bool suppress_warning, - MEM_ROOT *root) +static bool set_one_value(ha_create_table_option *opt, THD *thd, + const LEX_CSTRING *value, void *base, + bool suppress_warning, MEM_ROOT *root) { DBUG_ENTER("set_one_value"); DBUG_PRINT("enter", ("opt: %p type: %u name '%s' value: '%s'", - opt, - opt->type, opt->name, + opt, opt->type, opt->name, (value->str ? value->str : ""))); switch (opt->type) { @@ -141,10 +139,9 @@ static bool set_one_value(ha_create_table_option *opt, DBUG_RETURN(0); } - my_option optp= - { opt->name, 1, 0, (uchar **)val, 0, 0, GET_ULL, + my_option optp= { opt->name, 1, 0, (uchar **)val, 0, 0, GET_ULL, REQUIRED_ARG, (longlong)opt->def_value, (longlong)opt->min_value, - opt->max_value, 0, (long) opt->block_size, 0}; + opt->max_value, 0, (long) opt->block_size, 0 }; ulonglong orig_val= strtoull(value->str, NULL, 10); my_bool unused; @@ -236,6 +233,63 @@ static bool set_one_value(ha_create_table_option *opt, static const size_t ha_option_type_sizeof[]= { sizeof(ulonglong), sizeof(char *), sizeof(uint), sizeof(bool)}; +/** + Appends values of sysvar-based options if needed + + @param thd thread handler + @param option_list list of options given by user + @param rules list of option description by engine + @param root MEM_ROOT where allocate memory + + @retval TRUE Error + @retval FALSE OK +*/ + +bool extend_option_list(THD* thd, handlerton *hton, bool create, + engine_option_value **option_list, + ha_create_table_option *rules, MEM_ROOT *root) +{ + DBUG_ENTER("extend_option_list"); + + for (ha_create_table_option *opt= rules; rules && opt->name; opt++) + { + if (opt->var) + { + engine_option_value *found= NULL, *last; + for (engine_option_value *val= *option_list; val; val= val->next) + { + last= val; + if (!system_charset_info->strnncoll(opt->name, opt->name_length, + val->name.str, val->name.length)) + found= val; // find the last matching + } + if (found ? !found->value.str : create) + { + /* add the current value of the corresponding sysvar to the list */ + sys_var *sysvar= find_hton_sysvar(hton, opt->var); + DBUG_ASSERT(sysvar); + + if (!sysvar->session_is_default(thd)) + { + StringBuffer<256> sbuf(system_charset_info); + String *str= sysvar->val_str(&sbuf, thd, OPT_SESSION, &null_clex_str); + DBUG_ASSERT(str); + + LEX_CSTRING name= { opt->name, opt->name_length }; + LEX_CSTRING value= safe_lexcstrdup_root(root, str->to_lex_cstring()); + if (found) + found->value= value; + else + new (root) engine_option_value(name, value, + opt->type != HA_OPTION_TYPE_ULL, option_list, &last); + } + } + } + } + DBUG_RETURN(FALSE); +} + + /** Creates option structure and parses list of options in it @@ -250,7 +304,7 @@ static const size_t ha_option_type_sizeof[]= @retval FALSE OK */ -bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg, +bool parse_option_list(THD* thd, void *option_struct_arg, engine_option_value **option_list, ha_create_table_option *rules, bool suppress_warning, MEM_ROOT *root) @@ -296,58 +350,8 @@ bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg, break; } if (!seen || (opt->var && !last->value.str)) - { - LEX_CSTRING default_val= null_clex_str; - - /* - Okay, here's the logic for sysvar options: - 1. When we parse CREATE TABLE and sysvar option was not explicitly - mentioned we add it to the list as if it was specified with the - *current* value of the underlying sysvar. - 2. But only if the underlying sysvar value is different from the - sysvar's default. - 3. If it's ALTER TABLE or CREATE_SEQUENCE and the sysvar option was - not explicitly mentioned - do nothing, do not add it to the list. - 4. But if it was ALTER TABLE with sysvar option = DEFAULT, we - add it to the list (under the same condition #2). - 5. If we're here parsing the option list from the .frm file - for a normal open_table() and the sysvar option was not there - - do not add it to the list (makes no sense anyway) and - use the *default* value of the underlying sysvar. Because - sysvar value can change, but it should not affect existing tables. - This is how it's implemented: the current sysvar value is added - to the list if suppress_warning is FALSE (meaning a table is created, - that is CREATE TABLE or ALTER TABLE) and it's actually a CREATE TABLE - command or it's an ALTER TABLE and the option was seen (=DEFAULT). - - Note that if the option was set explicitly (not =DEFAULT) it wouldn't - have passes the if() condition above. - */ - if (!suppress_warning && opt->var && - (thd->lex->sql_command == SQLCOM_CREATE_TABLE || seen)) - { - // take a value from the variable and add it to the list - sys_var *sysvar= find_hton_sysvar(hton, opt->var); - DBUG_ASSERT(sysvar); - - if (!sysvar->session_is_default(thd)) - { - char buf[256]; - String sbuf(buf, sizeof(buf), system_charset_info), *str; - if ((str= sysvar->val_str(&sbuf, thd, OPT_SESSION, &null_clex_str))) - { - LEX_CSTRING name= { opt->name, opt->name_length }; - default_val.str= strmake_root(root, str->ptr(), str->length()); - default_val.length= str->length(); - val= new (root) engine_option_value(name, default_val, - opt->type != HA_OPTION_TYPE_ULL, option_list, &last); - val->parsed= true; - } - } - } - set_one_value(opt, thd, &default_val, *option_struct, + set_one_value(opt, thd, &null_clex_str, *option_struct, suppress_warning, root); - } } for (val= *option_list; val; val= val->next) @@ -474,13 +478,13 @@ bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share) MEM_ROOT *root= &share->mem_root; DBUG_ENTER("parse_engine_table_options"); - if (parse_option_list(thd, ht, &share->option_struct, & share->option_list, + if (parse_option_list(thd, &share->option_struct, & share->option_list, ht->table_options, TRUE, root)) DBUG_RETURN(TRUE); for (Field **field= share->field; *field; field++) { - if (parse_option_list(thd, ht, &(*field)->option_struct, + if (parse_option_list(thd, &(*field)->option_struct, & (*field)->option_list, ht->field_options, TRUE, root)) DBUG_RETURN(TRUE); @@ -488,7 +492,7 @@ bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share) for (uint index= 0; index < share->keys; index ++) { - if (parse_option_list(thd, ht, &share->key_info[index].option_struct, + if (parse_option_list(thd, &share->key_info[index].option_struct, & share->key_info[index].option_list, ht->index_options, TRUE, root)) DBUG_RETURN(TRUE); diff --git a/sql/create_options.h b/sql/create_options.h index ce64516794b..fc208d933a0 100644 --- a/sql/create_options.h +++ b/sql/create_options.h @@ -83,10 +83,14 @@ class Create_field; bool resolve_sysvar_table_options(handlerton *hton); void free_sysvar_table_options(handlerton *hton); bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share); -bool parse_option_list(THD* thd, handlerton *hton, void *option_struct, +bool parse_option_list(THD* thd, void *option_struct, engine_option_value **option_list, ha_create_table_option *rules, bool suppress_warning, MEM_ROOT *root); +bool extend_option_list(THD* thd, handlerton *hton, bool create, + engine_option_value **option_list, + ha_create_table_option *rules, MEM_ROOT *root); + bool engine_table_options_frm_read(const uchar *buff, size_t length, TABLE_SHARE *share); engine_option_value *merge_engine_table_options(engine_option_value *source, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c0f2502d61d..9daeb582938 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3767,7 +3767,11 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->offset= record_offset; if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) auto_increment++; - if (parse_option_list(thd, create_info->db_type, &sql_field->option_struct, + extend_option_list(thd, create_info->db_type, !sql_field->field, + &sql_field->option_list, + create_info->db_type->field_options, + thd->stmt_arena->mem_root); + if (parse_option_list(thd, &sql_field->option_struct, &sql_field->option_list, create_info->db_type->field_options, FALSE, thd->mem_root)) @@ -4034,7 +4038,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->usable_key_parts= key_number; key_info->algorithm= key->key_create_info.algorithm; key_info->option_list= key->option_list; - if (parse_option_list(thd, create_info->db_type, &key_info->option_struct, + extend_option_list(thd, create_info->db_type, !key->old, + &key_info->option_list, create_info->db_type->index_options, + thd->stmt_arena->mem_root); + if (parse_option_list(thd, &key_info->option_struct, &key_info->option_list, create_info->db_type->index_options, FALSE, thd->mem_root)) @@ -4624,10 +4631,13 @@ without_overlaps_err: push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_OPTION, ER_THD(thd, ER_UNKNOWN_OPTION), "transactional"); - if (parse_option_list(thd, file->partition_ht(), &create_info->option_struct, - &create_info->option_list, - file->partition_ht()->table_options, FALSE, - thd->mem_root)) + extend_option_list(thd, file->partition_ht(), + !thd->lex->create_like() && create_table_mode > C_ALTER_TABLE, + &create_info->option_list, file->partition_ht()->table_options, + thd->stmt_arena->mem_root); + if (parse_option_list(thd, &create_info->option_struct, + &create_info->option_list, + file->partition_ht()->table_options, FALSE, thd->mem_root)) DBUG_RETURN(TRUE); DBUG_EXECUTE_IF("key", diff --git a/sql/sql_table.h b/sql/sql_table.h index 8897493d8f4..f2be5654c66 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -190,9 +190,9 @@ bool add_keyword_to_query(THD *thd, String *result, const LEX_CSTRING *keyword, */ #define C_CREATE_SELECT(X) ((X) > 0 ? (X) : 0) #define C_ORDINARY_CREATE 0 -#define C_ALTER_TABLE -1 -#define C_ALTER_TABLE_FRM_ONLY -2 -#define C_ASSISTED_DISCOVERY -3 +#define C_ASSISTED_DISCOVERY -1 +#define C_ALTER_TABLE -2 +#define C_ALTER_TABLE_FRM_ONLY -3 int mysql_create_table_no_lock(THD *thd, Table_specification_st *create_info, Alter_info *alter_info, bool *is_trans,