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.
This commit is contained in:
parent
bb708f49db
commit
90aa02715d
@ -884,3 +884,22 @@ id
|
|||||||
50
|
50
|
||||||
51
|
51
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
set @orig_sql_mode = @@sql_mode;
|
||||||
|
set sql_mode="no_zero_date";
|
||||||
|
create table t1(f1 int);
|
||||||
|
alter table t1 add column f2 datetime not null, add column f21 date not null;
|
||||||
|
insert into t1 values(1,'2000-01-01','2000-01-01');
|
||||||
|
alter table t1 add column f3 datetime not null;
|
||||||
|
ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'f3' at row 1
|
||||||
|
alter table t1 add column f3 date not null;
|
||||||
|
ERROR 22007: Incorrect date value: '0000-00-00' for column 'f3' at row 1
|
||||||
|
alter table t1 add column f4 datetime not null default '2002-02-02',
|
||||||
|
add column f41 date not null;
|
||||||
|
ERROR 22007: Incorrect date value: '0000-00-00' for column 'f41' at row 1
|
||||||
|
alter table t1 add column f4 datetime not null default '2002-02-02',
|
||||||
|
add column f41 date not null default '2002-02-02';
|
||||||
|
select * from t1;
|
||||||
|
f1 f2 f21 f4 f41
|
||||||
|
1 2000-01-01 00:00:00 2000-01-01 2002-02-02 00:00:00 2002-02-02
|
||||||
|
drop table t1;
|
||||||
|
set sql_mode= @orig_sql_mode;
|
||||||
|
@ -662,3 +662,25 @@ insert into t1 values (null);
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#27507: Wrong DATETIME value was allowed by ALTER TABLE in the
|
||||||
|
# NO_ZERO_DATE mode.
|
||||||
|
#
|
||||||
|
set @orig_sql_mode = @@sql_mode;
|
||||||
|
set sql_mode="no_zero_date";
|
||||||
|
create table t1(f1 int);
|
||||||
|
alter table t1 add column f2 datetime not null, add column f21 date not null;
|
||||||
|
insert into t1 values(1,'2000-01-01','2000-01-01');
|
||||||
|
--error 1292
|
||||||
|
alter table t1 add column f3 datetime not null;
|
||||||
|
--error 1292
|
||||||
|
alter table t1 add column f3 date not null;
|
||||||
|
--error 1292
|
||||||
|
alter table t1 add column f4 datetime not null default '2002-02-02',
|
||||||
|
add column f41 date not null;
|
||||||
|
alter table t1 add column f4 datetime not null default '2002-02-02',
|
||||||
|
add column f41 date not null default '2002-02-02';
|
||||||
|
select * from t1;
|
||||||
|
drop table t1;
|
||||||
|
set sql_mode= @orig_sql_mode;
|
||||||
|
@ -37,7 +37,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
List<create_field> &create, bool ignore,
|
List<create_field> &create, bool ignore,
|
||||||
uint order_num, ORDER *order,
|
uint order_num, ORDER *order,
|
||||||
ha_rows *copied,ha_rows *deleted,
|
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 prepare_blob_field(THD *thd, create_field *sql_field);
|
||||||
static bool check_engine(THD *thd, const char *table_name,
|
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 need_copy_table;
|
||||||
bool no_table_reopen= FALSE, varchar= FALSE;
|
bool no_table_reopen= FALSE, varchar= FALSE;
|
||||||
frm_type_enum frm_type;
|
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");
|
DBUG_ENTER("mysql_alter_table");
|
||||||
|
|
||||||
thd->proc_info="init";
|
thd->proc_info="init";
|
||||||
@ -3445,6 +3456,22 @@ view_err:
|
|||||||
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name);
|
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table_name);
|
||||||
DBUG_RETURN(TRUE);
|
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)
|
if (!def->after)
|
||||||
new_info.create_list.push_back(def);
|
new_info.create_list.push_back(def);
|
||||||
else if (def->after == first_keyword)
|
else if (def->after == first_keyword)
|
||||||
@ -3765,7 +3792,8 @@ view_err:
|
|||||||
new_table->next_number_field=new_table->found_next_number_field;
|
new_table->next_number_field=new_table->found_next_number_field;
|
||||||
error= copy_data_between_tables(table, new_table, new_info.create_list,
|
error= copy_data_between_tables(table, new_table, new_info.create_list,
|
||||||
ignore, order_num, order,
|
ignore, order_num, order,
|
||||||
&copied, &deleted, alter_info->keys_onoff);
|
&copied, &deleted, alter_info->keys_onoff,
|
||||||
|
error_if_not_empty);
|
||||||
}
|
}
|
||||||
else if (!new_table)
|
else if (!new_table)
|
||||||
{
|
{
|
||||||
@ -3999,6 +4027,37 @@ end_temporary:
|
|||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
|
|
||||||
err:
|
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);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4010,7 +4069,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
uint order_num, ORDER *order,
|
uint order_num, ORDER *order,
|
||||||
ha_rows *copied,
|
ha_rows *copied,
|
||||||
ha_rows *deleted,
|
ha_rows *deleted,
|
||||||
enum enum_enable_or_disable keys_onoff)
|
enum enum_enable_or_disable keys_onoff,
|
||||||
|
bool error_if_not_empty)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
Copy_field *copy,*copy_end;
|
Copy_field *copy,*copy_end;
|
||||||
@ -4125,6 +4185,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
thd->row_count++;
|
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 (to->next_number_field)
|
||||||
{
|
{
|
||||||
if (auto_increment_field_copied)
|
if (auto_increment_field_copied)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user