diff options
author | svoj@mysql.com/april.(none) <> | 2007-03-13 18:02:06 +0400 |
---|---|---|
committer | svoj@mysql.com/april.(none) <> | 2007-03-13 18:02:06 +0400 |
commit | cb132bea8fd94a17653a971e74636a36a74f14c5 (patch) | |
tree | cf2f53be0dbcd2f0f4414b5442205636de128294 | |
parent | 576db4f44c9caa09a16477dc5580e8938eb5b745 (diff) | |
download | mariadb-git-cb132bea8fd94a17653a971e74636a36a74f14c5.tar.gz |
BUG#26881 - Large MERGE tables report incorrect specification when no
differences in tables
Certain merge tables were wrongly reported as having incorrect definition:
- Some fields that are 1 byte long (e.g. TINYINT, CHAR(1)), might
be internally casted (in certain cases) to a different type on a
storage engine layer. (affects 4.1 and up)
- If tables in a merge (and a MERGE table itself) had short VARCHAR column (less
than 4 bytes) and at least one (but not all) tables were ALTER'ed (even to an
identical table: ALTER TABLE xxx ENGINE=yyy), table definitions went ouf of
sync. (affects 4.1 only)
This is fixed by relaxing a check for underlying conformance and setting
field type to FIELD_TYPE_STRING in case varchar is shorter than 4
when a table is created.
-rw-r--r-- | myisam/mi_create.c | 4 | ||||
-rw-r--r-- | mysql-test/r/merge.result | 13 | ||||
-rw-r--r-- | mysql-test/t/merge.test | 17 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 37 | ||||
-rw-r--r-- | sql/sql_parse.cc | 8 |
5 files changed, 77 insertions, 2 deletions
diff --git a/myisam/mi_create.c b/myisam/mi_create.c index da9e0887b00..5e363a4e670 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -158,6 +158,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, rec--; if (rec->type == (int) FIELD_SKIP_ZERO && rec->length == 1) { + /* + NOTE1: here we change a field type FIELD_SKIP_ZERO -> + FIELD_NORMAL + */ rec->type=(int) FIELD_NORMAL; packed--; min_pack_length++; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 33de735d714..00d8aa3d586 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -806,3 +806,16 @@ CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1); INSERT DELAYED INTO t2 VALUES(1); ERROR HY000: Table storage engine for 't2' doesn't have this option DROP TABLE t1, t2; +CREATE TABLE t1(c1 VARCHAR(1)); +CREATE TABLE m1 LIKE t1; +ALTER TABLE m1 ENGINE=MERGE UNION=(t1); +SELECT * FROM m1; +c1 +DROP TABLE t1, m1; +CREATE TABLE t1(c1 VARCHAR(4), c2 TINYINT, c3 TINYINT, c4 TINYINT, +c5 TINYINT, c6 TINYINT, c7 TINYINT, c8 TINYINT, c9 TINYINT); +CREATE TABLE m1 LIKE t1; +ALTER TABLE m1 ENGINE=MERGE UNION=(t1); +SELECT * FROM m1; +c1 c2 c3 c4 c5 c6 c7 c8 c9 +DROP TABLE t1, m1; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index f759d20dd80..032e80ecc93 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -437,4 +437,21 @@ CREATE TABLE t2(c1 INT) ENGINE=MERGE UNION=(t1); INSERT DELAYED INTO t2 VALUES(1); DROP TABLE t1, t2; +# +# BUG#26881 - Large MERGE tables report incorrect specification when no +# differences in tables +# +CREATE TABLE t1(c1 VARCHAR(1)); +CREATE TABLE m1 LIKE t1; +ALTER TABLE m1 ENGINE=MERGE UNION=(t1); +SELECT * FROM m1; +DROP TABLE t1, m1; + +CREATE TABLE t1(c1 VARCHAR(4), c2 TINYINT, c3 TINYINT, c4 TINYINT, + c5 TINYINT, c6 TINYINT, c7 TINYINT, c8 TINYINT, c9 TINYINT); +CREATE TABLE m1 LIKE t1; +ALTER TABLE m1 ENGINE=MERGE UNION=(t1); +SELECT * FROM m1; +DROP TABLE t1, m1; + # End of 4.1 tests diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2cec03a51db..c6802ffe53c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -304,6 +304,12 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, RETURN VALUE 0 - Equal definitions. 1 - Different definitions. + + TODO + - compare FULLTEXT keys; + - compare SPATIAL keys; + - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly + (should be corretly detected in table2myisam). */ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, @@ -329,6 +335,28 @@ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, { HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg; HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg; + if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT) + continue; + else if (t1_keyinfo[i].flag & HA_FULLTEXT || + t2_keyinfo[i].flag & HA_FULLTEXT) + { + DBUG_PRINT("error", ("Key %d has different definition", i)); + DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d", + test(t1_keyinfo[i].flag & HA_FULLTEXT), + test(t2_keyinfo[i].flag & HA_FULLTEXT))); + DBUG_RETURN(1); + } + if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL) + continue; + else if (t1_keyinfo[i].flag & HA_SPATIAL || + t2_keyinfo[i].flag & HA_SPATIAL) + { + DBUG_PRINT("error", ("Key %d has different definition", i)); + DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d", + test(t1_keyinfo[i].flag & HA_SPATIAL), + test(t2_keyinfo[i].flag & HA_SPATIAL))); + DBUG_RETURN(1); + } if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs || t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) { @@ -365,7 +393,14 @@ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo, { MI_COLUMNDEF *t1_rec= &t1_recinfo[i]; MI_COLUMNDEF *t2_rec= &t2_recinfo[i]; - if (t1_rec->type != t2_rec->type || + /* + FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create, + see NOTE1 in mi_create.c + */ + if ((t1_rec->type != t2_rec->type && + !(t1_rec->type == (int) FIELD_SKIP_ZERO && + t1_rec->length == 1 && + t2_rec->type == (int) FIELD_NORMAL)) || t1_rec->length != t2_rec->length || t1_rec->null_bit != t2_rec->null_bit) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d537da7080b..66b68cfc2f1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4653,8 +4653,14 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->length++; } break; - case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: + if (new_field->length < 4) + { + new_field->sql_type= FIELD_TYPE_STRING; + break; + } + /* fall through */ + case FIELD_TYPE_STRING: if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value) break; /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */ |