diff options
author | unknown <evgen@moonbone.local> | 2007-05-22 00:22:53 +0400 |
---|---|---|
committer | unknown <evgen@moonbone.local> | 2007-05-22 00:22:53 +0400 |
commit | f3b78f34e511305fec193f4cdbc8710f26baf993 (patch) | |
tree | 92d5f891dbb700d9b403af31359afaa1030d358b /sql/sql_table.cc | |
parent | bc31b650afb6981e50a7e947ac2a80727cf64d0a (diff) | |
download | mariadb-git-f3b78f34e511305fec193f4cdbc8710f26baf993.tar.gz |
Bug#27507: Wrong DATETIME value was allowed by ALTER TABLE in the NO_ZERO_DATE
mode.
When a new DATE/DATETIME field without default value is being added by the
ALTER TABLE the '0000-00-00' value is used as the default one. But it wasn't
checked whether such value was allowed by the set sql mode. Due to this
'0000-00-00' values was allowed for DATE/DATETIME fields even in the
NO_ZERO_DATE mode.
Now the mysql_alter_table() function checks whether the '0000-00-00' value
is allowed for DATE/DATETIME fields by the set sql mode.
The new error_if_not_empty flag is used in the mysql_alter_table() function
to indicate that it should abort if the table being altered isn't empty.
The new new_datetime_field field is used in the mysql_alter_table() function
for error throwing purposes.
The new error_if_not_empty parameter is added to the copy_data_between_tables()
function to indicate the it should return error if the source table isn't empty.
mysql-test/t/alter_table.test:
Added a test case for the bug#27507: Wrong DATETIME value was allowed by
ALTER TABLE in the NO_ZERO_DATE mode.
mysql-test/r/alter_table.result:
Added a test case for the bug#27507: Wrong DATETIME value was allowed by
ALTER TABLE in the NO_ZERO_DATE mode.
sql/sql_table.cc:
Bug#27507: Wrong DATETIME value was allowed by ALTER TABLE in the NO_ZERO_DATE
mode.
Now the mysql_alter_table() function checks whether the '0000-00-00' value
is allowed for DATE/DATETIME fields by the set sql mode.
The new error_if_not_empty flag is used in the mysql_alter_table() function
to indicate that it should abort if the table being altered isn't empty.
The new new_datetime_field field is used in the mysql_alter_table() function
for error throwing purposes.
The new error_if_not_empty parameter is added to the copy_data_between_tables()
function to indicate the it should return error if the source table isn't empty.
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 72 |
1 files changed, 69 insertions, 3 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 079cc0d6456..ed1c49d768a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -37,7 +37,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, bool ignore, uint order_num, ORDER *order, ha_rows *copied,ha_rows *deleted, - enum enum_enable_or_disable keys_onoff); + enum enum_enable_or_disable keys_onoff, + bool error_if_not_empty); static bool prepare_blob_field(THD *thd, create_field *sql_field); static bool check_engine(THD *thd, const char *table_name, @@ -3077,6 +3078,16 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, bool need_copy_table; bool no_table_reopen= FALSE, varchar= FALSE; frm_type_enum frm_type; + /* + Throw an error if the table to be altered isn't empty. + Used in DATE/DATETIME fields default value checking. + */ + bool error_if_not_empty= FALSE; + /* + A field used for error reporting in DATE/DATETIME fields default + value checking. + */ + create_field *new_datetime_field= 0; DBUG_ENTER("mysql_alter_table"); thd->proc_info="init"; @@ -3445,6 +3456,22 @@ view_err: my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name); DBUG_RETURN(TRUE); } + /* + Check that the DATE/DATETIME not null field we are going to add is + either has a default value or the '0000-00-00' is allowed by the + set sql mode. + If the '0000-00-00' value isn't allowed then raise the error_if_not_empty + flag to allow ALTER TABLE only if the table to be altered is empty. + */ + if ((def->sql_type == MYSQL_TYPE_DATE || + def->sql_type == MYSQL_TYPE_NEWDATE || + def->sql_type == MYSQL_TYPE_DATETIME) && !new_datetime_field && + !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) && + thd->variables.sql_mode & MODE_NO_ZERO_DATE) + { + new_datetime_field= def; + error_if_not_empty= TRUE; + } if (!def->after) new_info.create_list.push_back(def); else if (def->after == first_keyword) @@ -3765,7 +3792,8 @@ view_err: new_table->next_number_field=new_table->found_next_number_field; error= copy_data_between_tables(table, new_table, new_info.create_list, ignore, order_num, order, - &copied, &deleted, alter_info->keys_onoff); + &copied, &deleted, alter_info->keys_onoff, + error_if_not_empty); } else if (!new_table) { @@ -3999,6 +4027,37 @@ end_temporary: DBUG_RETURN(FALSE); err: + /* + No default value was provided for a DATE/DATETIME field, the + current sql_mode doesn't allow the '0000-00-00' value and + the table to be altered isn't empty. + Report error here. + */ + if (error_if_not_empty && thd->row_count) + { + const char *f_val; + enum enum_mysql_timestamp_type t_type; + switch (new_datetime_field->sql_type) + { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + f_val= "0000-00-00"; + t_type= MYSQL_TIMESTAMP_DATE; + break; + case MYSQL_TYPE_DATETIME: + f_val= "0000-00-00 00:00:00"; + t_type= MYSQL_TIMESTAMP_DATETIME; + break; + default: + /* Shouldn't get here. */ + DBUG_ASSERT(0); + } + bool save_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= TRUE; + make_truncated_value_warning(thd, f_val, strlength(f_val), t_type, + new_datetime_field->field_name); + thd->abort_on_warning= save_abort_on_warning; + } DBUG_RETURN(TRUE); } @@ -4010,7 +4069,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, uint order_num, ORDER *order, ha_rows *copied, ha_rows *deleted, - enum enum_enable_or_disable keys_onoff) + enum enum_enable_or_disable keys_onoff, + bool error_if_not_empty) { int error; Copy_field *copy,*copy_end; @@ -4125,6 +4185,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, break; } thd->row_count++; + /* Return error if source table isn't empty. */ + if (error_if_not_empty) + { + error= 1; + break; + } if (to->next_number_field) { if (auto_increment_field_copied) |