summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsvoj@mysql.com/april.(none) <>2007-03-13 18:02:06 +0400
committersvoj@mysql.com/april.(none) <>2007-03-13 18:02:06 +0400
commitcb132bea8fd94a17653a971e74636a36a74f14c5 (patch)
treecf2f53be0dbcd2f0f4414b5442205636de128294
parent576db4f44c9caa09a16477dc5580e8938eb5b745 (diff)
downloadmariadb-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.c4
-rw-r--r--mysql-test/r/merge.result13
-rw-r--r--mysql-test/t/merge.test17
-rw-r--r--sql/ha_myisam.cc37
-rw-r--r--sql/sql_parse.cc8
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 */