row0mysql.c, dict0dict.c, db0err.h, ha_innobase.cc:

  Heikki will merge to 4.0: Prevent listing the same column twice in an InnoDB index: that will cause index corruption when that col is UPDATEd
parent 7b58a93a
...@@ -1033,6 +1033,7 @@ dict_index_add_to_cache( ...@@ -1033,6 +1033,7 @@ dict_index_add_to_cache(
ulint n_ord; ulint n_ord;
ibool success; ibool success;
ulint i; ulint i;
ulint j;
ut_ad(index); ut_ad(index);
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
...@@ -1063,6 +1064,26 @@ dict_index_add_to_cache( ...@@ -1063,6 +1064,26 @@ dict_index_add_to_cache(
return(FALSE); return(FALSE);
} }
/* Check that the same column does not appear twice in the index.
InnoDB assumes this in its algorithms, e.g., update of an index
entry */
for (i = 0; i < dict_index_get_n_fields(index); i++) {
for (j = 0; j < i; j++) {
if (dict_index_get_nth_field(index, j)->col
== dict_index_get_nth_field(index, i)->col) {
fprintf(stderr,
"InnoDB: Error: column %s appears twice in index %s of table %s\n"
"InnoDB: This is not allowed in InnoDB.\n"
"InnoDB: UPDATE can cause such an index to become corrupt in InnoDB.\n",
dict_index_get_nth_field(index, i)->col->name,
index->name, table->name);
}
}
}
/* Build the cache internal representation of the index, /* Build the cache internal representation of the index,
containing also the added system fields */ containing also the added system fields */
......
...@@ -42,6 +42,8 @@ Created 5/24/1996 Heikki Tuuri ...@@ -42,6 +42,8 @@ Created 5/24/1996 Heikki Tuuri
#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint #define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
to a table failed */ to a table failed */
#define DB_COL_APPEARS_TWICE_IN_INDEX 40
/* The following are partial failure codes */ /* The following are partial failure codes */
#define DB_FAIL 1000 #define DB_FAIL 1000
#define DB_OVERFLOW 1001 #define DB_OVERFLOW 1001
......
...@@ -1393,7 +1393,7 @@ int ...@@ -1393,7 +1393,7 @@ int
row_create_index_for_mysql( row_create_index_for_mysql(
/*=======================*/ /*=======================*/
/* out: error number or DB_SUCCESS */ /* out: error number or DB_SUCCESS */
dict_index_t* index, /* in: index defintion */ dict_index_t* index, /* in: index definition */
trx_t* trx) /* in: transaction handle */ trx_t* trx) /* in: transaction handle */
{ {
ind_node_t* node; ind_node_t* node;
...@@ -1402,11 +1402,14 @@ row_create_index_for_mysql( ...@@ -1402,11 +1402,14 @@ row_create_index_for_mysql(
ulint namelen; ulint namelen;
ulint keywordlen; ulint keywordlen;
ulint err; ulint err;
ulint i;
ulint j;
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "creating index"; trx->op_info = (char *) "creating index";
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
...@@ -1422,6 +1425,29 @@ row_create_index_for_mysql( ...@@ -1422,6 +1425,29 @@ row_create_index_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/* Check that the same column does not appear twice in the index.
InnoDB assumes this in its algorithms, e.g., update of an index
entry */
for (i = 0; i < dict_index_get_n_fields(index); i++) {
for (j = 0; j < i; j++) {
if (0 == ut_strcmp(
dict_index_get_nth_field(index, j)->name,
dict_index_get_nth_field(index, i)->name)) {
fprintf(stderr,
"InnoDB: Error: column %s appears twice in index %s\n"
"InnoDB: This is not allowed in InnoDB.\n",
dict_index_get_nth_field(index, i)->name,
index->name);
err = DB_COL_APPEARS_TWICE_IN_INDEX;
goto error_handling;
}
}
}
heap = mem_heap_create(512); heap = mem_heap_create(512);
trx->dict_operation = TRUE; trx->dict_operation = TRUE;
...@@ -1434,11 +1460,13 @@ row_create_index_for_mysql( ...@@ -1434,11 +1460,13 @@ row_create_index_for_mysql(
SESS_COMM_EXECUTE, 0)); SESS_COMM_EXECUTE, 0));
que_run_threads(thr); que_run_threads(thr);
err = trx->error_state; err = trx->error_state;
que_graph_free((que_t*) que_node_get_parent(thr));
error_handling:
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
/* We have special error handling here */ /* We have special error handling here */
ut_a(err == DB_OUT_OF_FILE_SPACE);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
...@@ -1448,10 +1476,8 @@ row_create_index_for_mysql( ...@@ -1448,10 +1476,8 @@ row_create_index_for_mysql(
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
} }
que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = ""; trx->op_info = (char *) "";
return((int) err); return((int) err);
} }
......
...@@ -233,10 +233,14 @@ convert_error_code_to_mysql( ...@@ -233,10 +233,14 @@ convert_error_code_to_mysql(
return(HA_ERR_ROW_IS_REFERENCED); return(HA_ERR_ROW_IS_REFERENCED);
} else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) { } else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) {
return(HA_ERR_CANNOT_ADD_FOREIGN); return(HA_ERR_CANNOT_ADD_FOREIGN);
} else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
return(HA_ERR_WRONG_TABLE_DEF);
} else if (error == (int) DB_OUT_OF_FILE_SPACE) { } else if (error == (int) DB_OUT_OF_FILE_SPACE) {
return(HA_ERR_RECORD_FILE_FULL); return(HA_ERR_RECORD_FILE_FULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment