From 56c7d142174e9fa86c829340f6a513b116749677 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 29 Jul 2022 15:39:57 +0200 Subject: [PATCH] MDEV-29075 Changing explicit_defaults_for_timestamp within stored procedure works inconsistently --- .../inc/explicit_defaults_for_timestamp.inc | 48 ++++++++++++----- ...explicit_defaults_for_timestamp_off.result | 53 ++++++++++++++++++- .../explicit_defaults_for_timestamp_on.result | 46 ++++++++++++++++ sql/field.cc | 1 + sql/field.h | 4 +- sql/sql_table.cc | 8 ++- sql/sql_type.cc | 13 ----- sql/sql_type.h | 6 --- sql/sql_yacc.yy | 7 ++- 9 files changed, 147 insertions(+), 39 deletions(-) diff --git a/mysql-test/suite/sys_vars/inc/explicit_defaults_for_timestamp.inc b/mysql-test/suite/sys_vars/inc/explicit_defaults_for_timestamp.inc index 1fea4ca5bb9..0cd8aa2c568 100644 --- a/mysql-test/suite/sys_vars/inc/explicit_defaults_for_timestamp.inc +++ b/mysql-test/suite/sys_vars/inc/explicit_defaults_for_timestamp.inc @@ -5,19 +5,10 @@ CREATE TABLE t1 (a TIMESTAMP NULL); SHOW CREATE TABLE t1; DROP TABLE t1; - -if (`SELECT @@explicit_defaults_for_timestamp=0`) -{ - --error ER_INVALID_DEFAULT - CREATE TABLE t1 (a TIMESTAMP DEFAULT NULL); -} - -if (`SELECT @@explicit_defaults_for_timestamp=1`) -{ - CREATE TABLE t1 (a TIMESTAMP DEFAULT NULL); - SHOW CREATE TABLE t1; - DROP TABLE t1; -} +CREATE TABLE t1 (a TIMESTAMP DEFAULT NULL); +INSERT t1 () VALUES (); +SHOW CREATE TABLE t1; +DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP DEFAULT '0000-00-00 00:00:00'); SHOW CREATE TABLE t1; @@ -110,3 +101,34 @@ SELECT * FROM t1; DROP TABLE t1; SET sql_mode=DEFAULT; SET timestamp=DEFAULT; + +--echo # +--echo # MDEV-29075 Changing explicit_defaults_for_timestamp within stored procedure works inconsistently +--echo # +set statement explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp for create table t1 (ts timestamp); +show create table t1; +drop table t1; + +--delimiter $ +create procedure pr() +begin + set explicit_defaults_for_timestamp= 1-@@explicit_defaults_for_timestamp; + create table t1 (ts timestamp); +end $ +--delimiter ; + +call pr(); +show create table t1; +drop procedure pr; +drop table t1; + +prepare stmt from 'create or replace table t1 (a timestamp)'; +execute stmt; +show create table t1; +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +drop table t1; diff --git a/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_off.result b/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_off.result index ad3f4ad3b00..016b130285f 100644 --- a/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_off.result +++ b/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_off.result @@ -14,7 +14,13 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP DEFAULT NULL); -ERROR 42000: Invalid default value for 'a' +INSERT t1 () VALUES (); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP DEFAULT '0000-00-00 00:00:00'); SHOW CREATE TABLE t1; Table Create Table @@ -187,3 +193,48 @@ a DROP TABLE t1; SET sql_mode=DEFAULT; SET timestamp=DEFAULT; +# +# MDEV-29075 Changing explicit_defaults_for_timestamp within stored procedure works inconsistently +# +set statement explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp for create table t1 (ts timestamp); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create procedure pr() +begin +set explicit_defaults_for_timestamp= 1-@@explicit_defaults_for_timestamp; +create table t1 (ts timestamp); +end $ +call pr(); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop procedure pr; +drop table t1; +prepare stmt from 'create or replace table t1 (a timestamp)'; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_on.result b/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_on.result index e940cd5e541..e4aabdef93e 100644 --- a/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_on.result +++ b/mysql-test/suite/sys_vars/r/explicit_defaults_for_timestamp_on.result @@ -14,6 +14,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 (a TIMESTAMP DEFAULT NULL); +INSERT t1 () VALUES (); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -194,3 +195,48 @@ a DROP TABLE t1; SET sql_mode=DEFAULT; SET timestamp=DEFAULT; +# +# MDEV-29075 Changing explicit_defaults_for_timestamp within stored procedure works inconsistently +# +set statement explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp for create table t1 (ts timestamp); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create procedure pr() +begin +set explicit_defaults_for_timestamp= 1-@@explicit_defaults_for_timestamp; +create table t1 (ts timestamp); +end $ +call pr(); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop procedure pr; +drop table t1; +prepare stmt from 'create or replace table t1 (a timestamp)'; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +set explicit_defaults_for_timestamp=1-@@explicit_defaults_for_timestamp; +execute stmt; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index f3a89a653e4..3d6eaba6f73 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -10801,6 +10801,7 @@ Column_definition::Column_definition(THD *thd, Field *old_field, comment= old_field->comment; vcol_info= old_field->vcol_info; option_list= old_field->option_list; + explicitly_nullable= !(old_field->flags & NOT_NULL_FLAG); compression_method_ptr= 0; versioning= VERSIONING_NOT_SET; invisible= old_field->invisible; diff --git a/sql/field.h b/sql/field.h index 31a0256cc2f..8b7c6d6a554 100644 --- a/sql/field.h +++ b/sql/field.h @@ -5262,7 +5262,7 @@ public: uint flags, pack_length; List interval_list; engine_option_value *option_list; - + bool explicitly_nullable; /* This is additinal data provided for any computed(virtual) field. @@ -5284,7 +5284,7 @@ public: comment(null_clex_str), on_update(NULL), invisible(VISIBLE), char_length(0), flags(0), pack_length(0), - option_list(NULL), + option_list(NULL), explicitly_nullable(false), vcol_info(0), default_value(0), check_constraint(0), versioning(VERSIONING_NOT_SET), period(NULL) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0ba755f49b9..f6aae1af8e9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3133,13 +3133,17 @@ bool Column_definition::prepare_stage2(handler *file, void promote_first_timestamp_column(List *column_definitions) { + bool first= true; for (Create_field &column_definition : *column_definitions) { if (column_definition.is_timestamp_type() || // TIMESTAMP column_definition.unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy { + if (!column_definition.explicitly_nullable) + column_definition.flags|= NOT_NULL_FLAG; DBUG_PRINT("info", ("field-ptr:%p", column_definition.field)); - if ((column_definition.flags & NOT_NULL_FLAG) != 0 && // NOT NULL, + if (first && + (column_definition.flags & NOT_NULL_FLAG) != 0 && // NOT NULL, column_definition.default_value == NULL && // no constant default, column_definition.unireg_check == Field::NONE && // no function default column_definition.vcol_info == NULL && @@ -3153,7 +3157,7 @@ void promote_first_timestamp_column(List *column_definitions) )); column_definition.unireg_check= Field::TIMESTAMP_DNUN_FIELD; } - return; + first= false; } } } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 11a955627a6..d2939f5e6e9 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -4262,19 +4262,6 @@ void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const (void) item->get_date(thd, <ime, Datetime::Options(thd)); } -bool -Type_handler_timestamp_common:: -Column_definition_set_attributes(THD *thd, - Column_definition *def, - const Lex_field_type_st &attr, - CHARSET_INFO *cs, - column_definition_type_t type) const -{ - Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type); - if (!(thd->variables.option_bits & OPTION_EXPLICIT_DEF_TIMESTAMP)) - def->flags|= NOT_NULL_FLAG; - return false; -} void Type_handler_string_result::Item_update_null_value(Item *item) const { diff --git a/sql/sql_type.h b/sql/sql_type.h index a2e21d81894..c4e7765d0cb 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -6660,12 +6660,6 @@ public: bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *, date_mode_t fuzzydate) const override; - bool Column_definition_set_attributes(THD *thd, - Column_definition *def, - const Lex_field_type_st &attr, - CHARSET_INFO *cs, - column_definition_type_t type) - const override; }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 54db077aa2f..1baa395bf07 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6091,7 +6091,6 @@ field_def: | opt_generated_always AS virtual_column_func { Lex->last_field->vcol_info= $3; - Lex->last_field->flags&= ~NOT_NULL_FLAG; // undo automatic NOT NULL for timestamps } vcol_opt_specifier vcol_opt_attribute | opt_generated_always AS ROW_SYM START_SYM opt_asrow_attribute @@ -6566,7 +6565,11 @@ attribute_list: ; attribute: - NULL_SYM { Lex->last_field->flags&= ~ NOT_NULL_FLAG; } + NULL_SYM + { + Lex->last_field->flags&= ~NOT_NULL_FLAG; + Lex->last_field->explicitly_nullable= true; + } | DEFAULT column_default_expr { Lex->last_field->default_value= $2; } | ON UPDATE_SYM NOW_SYM opt_default_time_precision {