diff options
author | Tatiana A. Nurnberg <azundris@mysql.com> | 2009-06-24 13:02:20 +0200 |
---|---|---|
committer | Tatiana A. Nurnberg <azundris@mysql.com> | 2009-06-24 13:02:20 +0200 |
commit | 74deaae946f060318900b93249e1d48f4d43c9af (patch) | |
tree | 91ef103df7056ffa6cd178a11a2301c411b885f3 /sql/field.cc | |
parent | e2ac8c07bdd2e58f5f7b4919a76a0d1881f3ed5e (diff) | |
download | mariadb-git-74deaae946f060318900b93249e1d48f4d43c9af.tar.gz |
Bug#43508: Renaming timestamp or date column triggers table copy
Altering a table to update a column with types DATE or TIMESTAMP
would incorrectly be seen as a significant change that necessitates
a slow copy+rename operation instead of a fast update.
There were two problems:
The character set is magically set for TIMESTAMP to be "binary",
but that was done too deep in field use code for ALTER TABLE to
know of it. Now, put that in the constructor for Field_timestamp.
Also, when we set the character set for the new replacement/
comparison field, also raise the "binary" field flag that tells us
we should compare it exactly. That is necessary to match the old
stored definition.
Next is the problem that the default length for TIMESTAMP and DATE
fields is different than the length read from the .frm . The
compressed size is written to the file, but the human-readable,
part-delimited length is used as default length. IIRC, for
timestamp it was 19!=14, and for date it was 8!=10. Length
mismatch causes a table copy.
Also, clean up a place where a comparison function alters one of its
parameters and replace it with an assertion of the condition it
mutates.
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 47 |
1 files changed, 19 insertions, 28 deletions
diff --git a/sql/field.cc b/sql/field.cc index ed085de1db3..ea80e809c4e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4723,6 +4723,7 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg, { /* For 4.0 MYD and 4.0 InnoDB compatibility */ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + field_charset= &my_charset_bin; if (!share->timestamp_field && unireg_check != NONE) { /* This timestamp has auto-update */ @@ -4743,6 +4744,7 @@ Field_timestamp::Field_timestamp(bool maybe_null_arg, { /* For 4.0 MYD and 4.0 InnoDB compatibility */ flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; + field_charset= &my_charset_bin; if (unireg_check != TIMESTAMP_DN_FIELD) flags|= ON_UPDATE_NOW_FLAG; } @@ -6504,20 +6506,9 @@ uint Field::is_equal(Create_field *new_field) } -/* If one of the fields is binary and the other one isn't return 1 else 0 */ - -bool Field_str::compare_str_field_flags(Create_field *new_field, uint32 flag_arg) -{ - return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - !(flag_arg & (BINCMP_FLAG | BINARY_FLAG))) || - (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - (flag_arg & (BINCMP_FLAG | BINARY_FLAG)))); -} - - uint Field_str::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == real_type()) && @@ -8283,7 +8274,7 @@ uint Field_blob::max_packed_col_length(uint max_length) uint Field_blob::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) @@ -9569,7 +9560,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } if (length == 0) - fld_length= 0; /* purecov: inspected */ + fld_length= NULL; /* purecov: inspected */ } sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; @@ -9721,8 +9712,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIMESTAMP: if (fld_length == NULL) { - /* Compressed date YYYYMMDDHHMMSS */ - length= MAX_DATETIME_COMPRESSED_WIDTH; + length= MAX_DATETIME_WIDTH; } else if (length != MAX_DATETIME_WIDTH) { @@ -9787,7 +9777,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, sql_type= MYSQL_TYPE_NEWDATE; /* fall trough */ case MYSQL_TYPE_NEWDATE: - length= 10; + length= MAX_DATE_WIDTH; break; case MYSQL_TYPE_TIME: length= 10; @@ -9868,6 +9858,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, DBUG_RETURN(TRUE); } + switch (fld_type) { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + charset= &my_charset_bin; + flags|= BINCMP_FLAG; + default: break; + } + DBUG_RETURN(FALSE); /* success */ } @@ -9976,16 +9977,6 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, null_bit= ((uchar) 1) << null_bit; } - switch (field_type) { - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_TIMESTAMP: - field_charset= &my_charset_bin; - default: break; - } - if (f_is_alpha(pack_flag)) { if (!f_is_packed(pack_flag)) |