#At file:///home/svoj/devel/innodb-snapshots/mysql-5.1-bugteam/ based on revid:svoj@stripped
3526 Sergey Vojtovich 2010-04-01
Applying InnoDB snapshot, fixes BUG#51378.
Detailed revision comments:
r6789 | jyang | 2010-03-10 11:18:18 +0200 (Wed, 10 Mar 2010) | 10 lines
branches/zip: If a unique index is on a column prefix, such
unique index cannot be upgrade to primary index even if there
is no primary index already defined. Also fix possible corruption
when initialize "ref_length" value in case there is a mismatch
between MySQL and InnoDB primary key. Fix bug #51378: "Init
'ref_length' to correct value, in case an out of bound MySQL
primary_key".
rb://262 approved by Marko.
modified:
storage/innodb_plugin/handler/ha_innodb.cc
storage/innodb_plugin/handler/handler0alter.cc
=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc 2010-04-01 12:06:59 +0000
+++ b/storage/innodb_plugin/handler/ha_innodb.cc 2010-04-01 12:12:44 +0000
@@ -3304,6 +3304,9 @@ ha_innobase::innobase_initialize_autoinc
ulint err;
update_thd(ha_thd());
+
+ ut_a(prebuilt->trx == thd_to_trx(user_thd));
+
col_name = field->field_name;
index = innobase_get_index(table->s->next_number_index);
@@ -3494,31 +3497,86 @@ retry:
of length ref_length! */
if (!row_table_got_default_clust_index(ib_table)) {
- if (primary_key >= MAX_KEY) {
- sql_print_error("Table %s has a primary key in InnoDB data "
- "dictionary, but not in MySQL!", name);
- }
prebuilt->clust_index_was_generated = FALSE;
- /* MySQL allocates the buffer for ref. key_info->key_length
- includes space for all key columns + one byte for each column
- that may be NULL. ref_length must be as exact as possible to
- save space, because all row reference buffers are allocated
- based on ref_length. */
+ if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
+ sql_print_error("Table %s has a primary key in "
+ "InnoDB data dictionary, but not "
+ "in MySQL!", name);
+
+ /* This mismatch could cause further problems
+ if not attended, bring this to the user's attention
+ by printing a warning in addition to log a message
+ in the errorlog */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_SUCH_INDEX,
+ "InnoDB: Table %s has a "
+ "primary key in InnoDB data "
+ "dictionary, but not in "
+ "MySQL!", name);
+
+ /* If primary_key >= MAX_KEY, its (primary_key)
+ value could be out of bound if continue to index
+ into key_info[] array. Find InnoDB primary index,
+ and assign its key_length to ref_length.
+ In addition, since MySQL indexes are sorted starting
+ with primary index, unique index etc., initialize
+ ref_length to the first index key length in
+ case we fail to find InnoDB cluster index.
+
+ Please note, this will not resolve the primary
+ index mismatch problem, other side effects are
+ possible if users continue to use the table.
+ However, we allow this table to be opened so
+ that user can adopt necessary measures for the
+ mismatch while still being accessible to the table
+ date. */
+ ref_length = table->key_info[0].key_length;
+
+ /* Find correspoinding cluster index
+ key length in MySQL's key_info[] array */
+ for (ulint i = 0; i < table->s->keys; i++) {
+ dict_index_t* index;
+ index = innobase_get_index(i);
+ if (dict_index_is_clust(index)) {
+ ref_length =
+ table->key_info[i].key_length;
+ }
+ }
+ } else {
+ /* MySQL allocates the buffer for ref.
+ key_info->key_length includes space for all key
+ columns + one byte for each column that may be
+ NULL. ref_length must be as exact as possible to
+ save space, because all row reference buffers are
+ allocated based on ref_length. */
- ref_length = table->key_info[primary_key].key_length;
+ ref_length = table->key_info[primary_key].key_length;
+ }
} else {
if (primary_key != MAX_KEY) {
- sql_print_error("Table %s has no primary key in InnoDB data "
- "dictionary, but has one in MySQL! If you "
- "created the table with a MySQL version < "
- "3.23.54 and did not define a primary key, "
- "but defined a unique key with all non-NULL "
- "columns, then MySQL internally treats that "
- "key as the primary key. You can fix this "
- "error by dump + DROP + CREATE + reimport "
- "of the table.", name);
+ sql_print_error(
+ "Table %s has no primary key in InnoDB data "
+ "dictionary, but has one in MySQL! If you "
+ "created the table with a MySQL version < "
+ "3.23.54 and did not define a primary key, "
+ "but defined a unique key with all non-NULL "
+ "columns, then MySQL internally treats that "
+ "key as the primary key. You can fix this "
+ "error by dump + DROP + CREATE + reimport "
+ "of the table.", name);
+
+ /* This mismatch could cause further problems
+ if not attended, bring this to the user attention
+ by printing a warning in addition to log a message
+ in the errorlog */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_NO_SUCH_INDEX,
+ "InnoDB: Table %s has no "
+ "primary key in InnoDB data "
+ "dictionary, but has one in "
+ "MySQL!", name);
}
prebuilt->clust_index_was_generated = TRUE;
@@ -5402,9 +5460,6 @@ ha_innobase::innobase_get_index(
DBUG_ENTER("innobase_get_index");
ha_statistic_increment(&SSV::ha_read_key_count);
- ut_ad(user_thd == ha_thd());
- ut_a(prebuilt->trx == thd_to_trx(user_thd));
-
if (keynr != MAX_KEY && table->s->keys > 0) {
key = table->key_info + keynr;
=== modified file 'storage/innodb_plugin/handler/handler0alter.cc'
--- a/storage/innodb_plugin/handler/handler0alter.cc 2010-04-01 12:04:43 +0000
+++ b/storage/innodb_plugin/handler/handler0alter.cc 2010-04-01 12:12:44 +0000
@@ -528,12 +528,14 @@ innobase_create_key_def(
key_info->name, "PRIMARY");
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
- columns, MySQL will treat it as a PRIMARY KEY unless the
- table already has one. */
+ columns and if the index does not contain column prefix(es)
+ (only prefix/part of the column is indexed), MySQL will treat the
+ index as a PRIMARY KEY unless the table already has one. */
if (!new_primary && (key_info->flags & HA_NOSAME)
+ && (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
&& row_table_got_default_clust_index(table)) {
- uint key_part = key_info->key_parts;
+ uint key_part = key_info->key_parts;
new_primary = TRUE;
Attachment: [text/bzr-bundle] bzr/svoj@sun.com-20100401121244-binxhdawcn1fcaaz.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (svoj:3526) Bug#51378 | Sergey Vojtovich | 1 Apr |