3894 Marko Mäkelä 2012-04-17
recv_recovery_from_checkpoint_start_func(): Remove a compiler warning.
modified:
storage/innobase/log/log0recv.cc
3893 Marko Mäkelä 2012-04-17
WL#5545 Allow multiple columns to be renamed to each other.
Fix clashes with FTS_DOC_ID.
merge_index_field_t: Replace field_name with col_no, so that
column renaming will not interfere with index creation.
dict_mem_table_col_rename(): Add the parameter nth_col, and remove the
return status.
innobase_create_key_defs(), prepare_inplace_alter_table_dict():
Add the parameter fts_doc_id_col.
innobase_fulltext_exist(): New predicated, for checking if a fulltext
index exists on a table.
ha_innobase::prepare_inplace_alter_table(): Prohibit renaming FTS_DOC_ID
when fulltext indexes exist on the table. Prohibit renaming columns to
internal column names defined in the InnoDB table object.
innobase_rename_column(): Add the parameter nth_col. Rename the columns
in the data dictionary based on old name and position.
ha_innobase::commit_inplace_alter_table(): If an operation fails, roll
back the data dictionary transaction.
dict_table_get_index_by_max_id(): Merge with row_merge_dict_table_get_index(),
and look up the columns by number, not by name.
modified:
mysql-test/suite/innodb/r/innodb-alter.result
mysql-test/suite/innodb/t/innodb-alter.test
storage/innobase/dict/dict0dict.cc
storage/innobase/dict/dict0mem.cc
storage/innobase/handler/handler0alter.cc
storage/innobase/include/dict0dict.h
storage/innobase/include/dict0mem.h
storage/innobase/include/row0merge.h
storage/innobase/row/row0merge.cc
3892 Marko Mäkelä 2012-04-17
Remove an extra initialization and add a debug assertion.
modified:
storage/innobase/include/row0upd.ic
3891 Marko Mäkelä 2012-04-17
Remove unused function innobase_create_fts_doc_id_idx().
modified:
storage/innobase/handler/handler0alter.cc
3890 Marko Mäkelä 2012-04-16
WL#5545: Test renaming to the reserved column names
DB_ROW_ID, DB_TRX_ID, DB_ROLL_PTR.
modified:
mysql-test/suite/innodb/r/innodb-alter.result
mysql-test/suite/innodb/t/innodb-alter.test
=== modified file 'mysql-test/suite/innodb/r/innodb-alter.result'
--- a/mysql-test/suite/innodb/r/innodb-alter.result revid:marko.makela@strippedx9
+++ b/mysql-test/suite/innodb/r/innodb-alter.result revid:marko.makela@stripped21
@@ -441,24 +441,93 @@ ALTER TABLE t1n CHANGE c1 Fts_DOC_ID INT
ERROR 42000: Incorrect column name 'FTS_DOC_ID'
ALTER TABLE t1n CHANGE c1 Fts_DOC_ID INT, ALGORITHM=COPY;
ERROR 42000: Incorrect column name 'Fts_DOC_ID'
+ALTER TABLE t1n CHANGE FTS_DOC_ID c11 INT, ALGORITHM=INPLACE;
+ERROR 42S22: Unknown column 'FTS_DOC_ID' in 't1n'
ALTER TABLE t1n CHANGE c1 FTS_DOC_ïD INT, ALGORITHM=INPLACE;
+ALTER TABLE t1n CHANGE FTS_DOC_ÏD c1 INT, ALGORITHM=INPLACE;
+ALTER TABLE t1n CHANGE c1 c2 INT, CHANGE c2 ct INT, CHANGE ct c1 TEXT,
+ALGORITHM=INPLACE;
+SHOW CREATE TABLE t1n;
+Table Create Table
+t1n CREATE TABLE `t1n` (
+ `c2` int(11) NOT NULL DEFAULT '0',
+ `ct` int(11) DEFAULT NULL,
+ `c1` text,
+ PRIMARY KEY (`c2`),
+ FULLTEXT KEY `ct` (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1n CHANGE c2 c1 INT, CHANGE ct c2 INT, CHANGE c1 ct TEXT,
+ALGORITHM=COPY;
+SHOW CREATE TABLE t1n;
+Table Create Table
+t1n CREATE TABLE `t1n` (
+ `c1` int(11) NOT NULL DEFAULT '0',
+ `c2` int(11) DEFAULT NULL,
+ `ct` text,
+ PRIMARY KEY (`c1`),
+ FULLTEXT KEY `ct` (`ct`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1n ADD INDEX(c2), CHANGE c2 c4 INT, ALGORITHM=INPLACE;
+ERROR 42000: Key column 'c2' doesn't exist in table
+ALTER TABLE t1n ADD INDEX(c2), CHANGE c2 c4 INT, ALGORITHM=COPY;
+ERROR 42000: Key column 'c2' doesn't exist in table
+ALTER TABLE t1n ADD INDEX(c4), CHANGE c2 c4 INT, ALGORITHM=INPLACE;
+SHOW CREATE TABLE t1n;
+Table Create Table
+t1n CREATE TABLE `t1n` (
+ `c1` int(11) NOT NULL DEFAULT '0',
+ `c4` int(11) DEFAULT NULL,
+ `ct` text,
+ PRIMARY KEY (`c1`),
+ KEY `c4` (`c4`),
+ FULLTEXT KEY `ct` (`ct`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1n DROP INDEX c4;
+ALTER TABLE t1n CHANGE c4 c1 INT, ADD INDEX(c1), ALGORITHM=INPLACE;
+ERROR 42S21: Duplicate column name 'c1'
+ALTER TABLE t1n CHANGE c4 c11 INT, ADD INDEX(c11), ALGORITHM=INPLACE;
+SHOW CREATE TABLE t1n;
+Table Create Table
+t1n CREATE TABLE `t1n` (
+ `c1` int(11) NOT NULL DEFAULT '0',
+ `c11` int(11) DEFAULT NULL,
+ `ct` text,
+ PRIMARY KEY (`c1`),
+ KEY `c11` (`c11`),
+ FULLTEXT KEY `ct` (`ct`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1n;
-ALTER TABLE t1o MODIFY c1 BIGINT NOT NULL;
-ALTER TABLE t1o ADD FULLTEXT INDEX(ct), CHANGE c1 FTS_DOC_ID BIGINT,
+ALTER TABLE t1o MODIFY c1 BIGINT UNSIGNED NOT NULL;
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct),
+CHANGE c1 FTS_DOC_ID BIGINT UNSIGNED NOT NULL,
ALGORITHM=INPLACE;
-ERROR HY000: Column 'FTS_DOC_ID' is of wrong type for an InnoDB FULLTEXT index
+ALTER TABLE t1o CHANGE FTS_DOC_ID foo_id BIGINT UNSIGNED NOT NULL;
+ERROR HY000: Column 'foo_id' is of wrong type for an InnoDB FULLTEXT index
SELECT sc.pos FROM information_schema.innodb_sys_columns sc
INNER JOIN information_schema.innodb_sys_tables st
ON sc.TABLE_ID=st.TABLE_ID
WHERE st.NAME='test/t1o' AND sc.NAME='FTS_DOC_ID';
pos
+0
+SHOW CREATE TABLE t1o;
+Table Create Table
+t1o CREATE TABLE `t1o` (
+ `FTS_DOC_ID` bigint(20) unsigned NOT NULL,
+ `c2` int(11) DEFAULT NULL,
+ `ct` text,
+ PRIMARY KEY (`FTS_DOC_ID`),
+ FULLTEXT KEY `ct` (`ct`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1o CHANGE FTS_DOC_ID foo_id BIGINT UNSIGNED NOT NULL,
+DROP INDEX ct, ALGORITHM=INPLACE;
+call mtr.add_suppression("InnoDB: Table test/t1o contains 2 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MySQL");
SHOW CREATE TABLE t1o;
Table Create Table
t1o CREATE TABLE `t1o` (
- `c1` bigint(20) NOT NULL,
+ `foo_id` bigint(20) unsigned NOT NULL,
`c2` int(11) DEFAULT NULL,
`ct` text,
- PRIMARY KEY (`c1`)
+ PRIMARY KEY (`foo_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1c, t1p, sys_tables, sys_indexes, sys_foreign;
CREATE TABLE sys_tables SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
@@ -471,14 +540,27 @@ SELECT i.NAME,i.POS,i.MTYPE,i.PRTYPE,i.L
FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS i
INNER JOIN sys_tables st ON i.TABLE_ID=st.TABLE_ID;
NAME POS MTYPE PRTYPE LEN
-c1 0 6 1288 8
+foo_id 0 6 1800 8
c2 1 6 1027 4
ct 2 5 524540 10
SELECT si.NAME,i.POS,i.NAME FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS i
INNER JOIN sys_indexes si ON i.INDEX_ID=si.INDEX_ID;
NAME POS NAME
-PRIMARY 0 c1
+PRIMARY 0 foo_id
+FTS_DOC_ID_INDEX 0 foo_id
SELECT i.* FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS i
INNER JOIN sys_foreign sf ON i.ID = sf.ID;
ID FOR_COL_NAME REF_COL_NAME POS
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct);
+ERROR HY000: Index 'FTS_DOC_ID_INDEX' is of wrong type for an InnoDB FULLTEXT index
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct),
+CHANGE foo_id FTS_DOC_ID BIGINT UNSIGNED NOT NULL;
+ERROR HY000: Index 'FTS_DOC_ID_INDEX' is of wrong type for an InnoDB FULLTEXT index
+ALTER TABLE t1o CHANGE foo_id FTS_DOC_ID BIGINT UNSIGNED NOT NULL;
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID);
+ERROR 42000: Incorrect index name 'FTS_DOC_ID_INDEX'
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID),
+ALGORITHM=COPY;
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID);
+ERROR 42000: Duplicate key name 'FTS_DOC_ID_INDEX'
DROP TABLE tt, t1o, sys_tables, sys_indexes, sys_foreign;
=== modified file 'mysql-test/suite/innodb/t/innodb-alter.test'
--- a/mysql-test/suite/innodb/t/innodb-alter.test revid:marko.makela@stripped
+++ b/mysql-test/suite/innodb/t/innodb-alter.test revid:marko.makela@oracle.com-20120417140601-q4xyu89kks7krh21
@@ -198,15 +198,41 @@ ALTER TABLE t1n ADD FULLTEXT INDEX(ct);
ALTER TABLE t1n CHANGE c1 Fts_DOC_ID INT, ALGORITHM=INPLACE;
--error ER_WRONG_COLUMN_NAME
ALTER TABLE t1n CHANGE c1 Fts_DOC_ID INT, ALGORITHM=COPY;
+--error ER_BAD_FIELD_ERROR
+ALTER TABLE t1n CHANGE FTS_DOC_ID c11 INT, ALGORITHM=INPLACE;
ALTER TABLE t1n CHANGE c1 FTS_DOC_ïD INT, ALGORITHM=INPLACE;
+
+ALTER TABLE t1n CHANGE FTS_DOC_ÏD c1 INT, ALGORITHM=INPLACE;
+ALTER TABLE t1n CHANGE c1 c2 INT, CHANGE c2 ct INT, CHANGE ct c1 TEXT,
+ALGORITHM=INPLACE;
+SHOW CREATE TABLE t1n;
+ALTER TABLE t1n CHANGE c2 c1 INT, CHANGE ct c2 INT, CHANGE c1 ct TEXT,
+ALGORITHM=COPY;
+SHOW CREATE TABLE t1n;
+
+--error ER_KEY_COLUMN_DOES_NOT_EXITS
+ALTER TABLE t1n ADD INDEX(c2), CHANGE c2 c4 INT, ALGORITHM=INPLACE;
+--error ER_KEY_COLUMN_DOES_NOT_EXITS
+ALTER TABLE t1n ADD INDEX(c2), CHANGE c2 c4 INT, ALGORITHM=COPY;
+ALTER TABLE t1n ADD INDEX(c4), CHANGE c2 c4 INT, ALGORITHM=INPLACE;
+SHOW CREATE TABLE t1n;
+ALTER TABLE t1n DROP INDEX c4;
+--error ER_DUP_FIELDNAME
+ALTER TABLE t1n CHANGE c4 c1 INT, ADD INDEX(c1), ALGORITHM=INPLACE;
+ALTER TABLE t1n CHANGE c4 c11 INT, ADD INDEX(c11), ALGORITHM=INPLACE;
+
+SHOW CREATE TABLE t1n;
DROP TABLE t1n;
-ALTER TABLE t1o MODIFY c1 BIGINT NOT NULL;
+ALTER TABLE t1o MODIFY c1 BIGINT UNSIGNED NOT NULL;
---error ER_INNODB_FT_WRONG_DOCID_COLUMN
-ALTER TABLE t1o ADD FULLTEXT INDEX(ct), CHANGE c1 FTS_DOC_ID BIGINT,
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct),
+CHANGE c1 FTS_DOC_ID BIGINT UNSIGNED NOT NULL,
ALGORITHM=INPLACE;
+--error ER_INNODB_FT_WRONG_DOCID_COLUMN
+ALTER TABLE t1o CHANGE FTS_DOC_ID foo_id BIGINT UNSIGNED NOT NULL;
+
# This should not show duplicates.
SELECT sc.pos FROM information_schema.innodb_sys_columns sc
INNER JOIN information_schema.innodb_sys_tables st
@@ -215,6 +241,13 @@ WHERE st.NAME='test/t1o' AND sc.NAME='FT
SHOW CREATE TABLE t1o;
+# This will leave an orphan FTS_DOC_ID_INDEX inside InnoDB.
+ALTER TABLE t1o CHANGE FTS_DOC_ID foo_id BIGINT UNSIGNED NOT NULL,
+DROP INDEX ct, ALGORITHM=INPLACE;
+call mtr.add_suppression("InnoDB: Table test/t1o contains 2 indexes inside InnoDB, which is different from the number of indexes 1 defined in the MySQL");
+
+SHOW CREATE TABLE t1o;
+
DROP TABLE t1c, t1p, sys_tables, sys_indexes, sys_foreign;
# Check the internal schemata of tt, t1o.
@@ -228,4 +261,30 @@ FROM INFORMATION_SCHEMA.INNODB_SYS_FOREI
-- source suite/innodb/include/innodb_dict.inc
+# Now, there exists a hidden FTS_DOC_ID_INDEX on foo_id, not FTS_DOC_ID.
+# We must rename the foo_id to FTS_DOC_ID first.
+
+-- error ER_INNODB_FT_WRONG_DOCID_INDEX
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct);
+
+# Ideally, the renaming should work in the same statement with
+# the ADD FULLTEXT INDEX. This is what we get by defining FTS_DOC_ID
+# as a half-hidden column.
+-- error ER_INNODB_FT_WRONG_DOCID_INDEX
+ALTER TABLE t1o ADD FULLTEXT INDEX(ct),
+CHANGE foo_id FTS_DOC_ID BIGINT UNSIGNED NOT NULL;
+
+ALTER TABLE t1o CHANGE foo_id FTS_DOC_ID BIGINT UNSIGNED NOT NULL;
+
+# InnoDB created FTS_DOC_ID_INDEX internally already.
+-- error ER_WRONG_NAME_FOR_INDEX
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID);
+
+# The ALGORITHM=COPY ignores the internally created index. */
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID),
+ALGORITHM=COPY;
+
+-- error ER_DUP_KEYNAME
+ALTER TABLE t1o ADD UNIQUE INDEX FTS_DOC_ID_INDEX(FTS_DOC_ID);
+
DROP TABLE tt, t1o, sys_tables, sys_indexes, sys_foreign;
=== modified file 'storage/innobase/dict/dict0dict.cc'
--- a/storage/innobase/dict/dict0dict.cc revid:marko.makela@stripped20120416182457-jw98vli3ujodcmx9
+++ b/storage/innobase/dict/dict0dict.cc revid:marko.makela@stripped601-q4xyu89kks7krh21
@@ -3150,65 +3150,6 @@ next_rec:
}
/**********************************************************************//**
-Returns an index object by matching on the name and column names and
-if more than one index matches return the index with the max id
-@return matching index, NULL if not found */
-UNIV_INTERN
-dict_index_t*
-dict_table_get_index_by_max_id(
-/*===========================*/
- dict_table_t* table, /*!< in: table */
- const char* name, /*!< in: the index name to find */
- const char** columns,/*!< in: array of column names */
- ulint n_cols) /*!< in: number of columns */
-{
- dict_index_t* index;
- dict_index_t* found;
-
- found = NULL;
- index = dict_table_get_first_index(table);
-
- while (index != NULL) {
- if (ut_strcmp(index->name, name) == 0
- && dict_index_get_n_ordering_defined_by_user(index)
- == n_cols) {
-
- ulint i;
-
- for (i = 0; i < n_cols; i++) {
- dict_field_t* field;
- const char* col_name;
-
- field = dict_index_get_nth_field(index, i);
-
- col_name = dict_table_get_col_name(
- table, dict_col_get_no(field->col));
-
- if (0 != innobase_strcasecmp(
- columns[i], col_name)) {
-
- break;
- }
- }
-
- if (i == n_cols) {
- /* We found a matching index, select
- the index with the higher id*/
-
- if (!found || index->id > found->id) {
-
- found = index;
- }
- }
- }
-
- index = dict_table_get_next_index(index);
- }
-
- return(found);
-}
-
-/**********************************************************************//**
Report an error in a foreign key definition. */
static
void
=== modified file 'storage/innobase/dict/dict0mem.cc'
--- a/storage/innobase/dict/dict0mem.cc revid:marko.makela@strippedujodcmx9
+++ b/storage/innobase/dict/dict0mem.cc revid:marko.makela@stripped
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@@ -250,10 +250,10 @@ void
dict_mem_table_col_rename_low(
/*==========================*/
dict_table_t* table, /*!< in/out: table */
+ unsigned i, /*!< in: column offset corresponding to s */
const char* from, /*!< in: old column name */
const char* to, /*!< in: new column name */
- const char* s, /*!< in: pointer to table->col_names */
- unsigned i) /*!< in: column offset corresponding to s */
+ const char* s) /*!< in: pointer to table->col_names */
{
size_t from_len = strlen(from), to_len = strlen(to);
@@ -357,33 +357,31 @@ dict_mem_table_col_rename_low(
}
/**********************************************************************//**
-Renames a column of a table in the data dictionary cache.
-@return whether the operation succeeded */
+Renames a column of a table in the data dictionary cache. */
UNIV_INTERN
-bool
+void
dict_mem_table_col_rename(
/*======================*/
dict_table_t* table, /*!< in/out: table */
+ unsigned nth_col,/*!< in: column index */
const char* from, /*!< in: old column name */
const char* to) /*!< in: new column name */
{
- unsigned i;
const char* s = table->col_names;
- if (!s) {
- return(false);
- }
+ ut_ad(nth_col < table->n_def);
- for (i = 0; i < table->n_def; i++) {
- if (!strcmp(from, s)) {
- dict_mem_table_col_rename_low(table, from, to, s, i);
- return(true);
- }
-
- s += strlen(s) + 1;
+ for (unsigned i = 0; i < nth_col; i++) {
+ size_t len = strlen(s);
+ ut_ad(len > 0);
+ s += len + 1;
}
- return(false);
+ /* This could fail if the data dictionaries are out of sync.
+ Proceed with the renaming anyway. */
+ ut_ad(!strcmp(from, s));
+
+ dict_mem_table_col_rename_low(table, nth_col, from, to, s);
}
/**********************************************************************//**
=== modified file 'storage/innobase/handler/handler0alter.cc'
--- a/storage/innobase/handler/handler0alter.cc revid:marko.makela@stripped-20120416182457-jw98vli3ujodcmx9
+++ b/storage/innobase/handler/handler0alter.cc revid:marko.makela@stripped20417140601-q4xyu89kks7krh21
@@ -626,6 +626,8 @@ innobase_create_index_field_def(
: key_part->field;
ut_a(field);
+ index_field->col_no = key_part->fieldnr;
+
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
if (DATA_BLOB == col_type
@@ -640,8 +642,6 @@ innobase_create_index_field_def(
index_field->prefix_len = 0;
}
- index_field->field_name = mem_heap_strdup(heap, field->field_name);
-
DBUG_VOID_RETURN;
}
@@ -935,6 +935,8 @@ innobase_create_key_defs(
/*!< in/out: number of indexes to be created */
bool got_default_clust,
/*!< in: whether the table lacks a primary key */
+ ulint fts_doc_id_col,
+ /*!< in: The column number for Doc ID */
bool add_fts_doc_id,
/*!< in: whether we need to add new DOC ID
column for FTS index */
@@ -1057,13 +1059,14 @@ created_clustered:
index->fields = static_cast<merge_index_field_t*>(
mem_heap_alloc(heap, sizeof *index->fields));
index->n_fields = 1;
+ index->fields->col_no = fts_doc_id_col;
index->fields->prefix_len = 0;
- index->fields->field_name = mem_heap_strdup(
- heap, FTS_DOC_ID_COL_NAME);
index->ind_type = DICT_UNIQUE;
+
if (new_primary || add_fts_doc_id) {
index->name = mem_heap_strdup(
heap, FTS_DOC_ID_INDEX_NAME);
+ ut_ad(fts_doc_id_col == altered_table->s->fields);
} else {
char* index_name;
index->name = index_name = static_cast<char*>(
@@ -1229,48 +1232,6 @@ no_match:
#endif
/********************************************************************//**
-This is to create FTS_DOC_ID_INDEX definition on the newly added Doc ID for
-the FTS indexes table
-@return dict_index_t for the FTS_DOC_ID_INDEX */
-dict_index_t*
-innobase_create_fts_doc_id_idx(
-/*===========================*/
- dict_table_t* indexed_table, /*!< in: Table where indexes are
- created */
- trx_t* trx, /*!< in: Transaction */
- bool new_clustered, /*!< in: true if creating a
- clustered index */
- mem_heap_t* heap) /*!< Heap for index definitions */
-{
- dict_index_t* index;
- merge_index_def_t fts_index_def;
- char* index_name;
-
- /* Create the temp index name for FTS_DOC_ID_INDEX */
- fts_index_def.name = index_name = static_cast<char*>(
- mem_heap_alloc(
- heap, FTS_DOC_ID_INDEX_NAME_LEN + 1 + !new_clustered));
- if (!new_clustered) {
- *index_name++ = TEMP_INDEX_PREFIX;
- }
- memcpy(index_name, FTS_DOC_ID_INDEX_NAME,
- FTS_DOC_ID_INDEX_NAME_LEN);
- index_name[FTS_DOC_ID_INDEX_NAME_LEN] = 0;
-
- /* Only the Doc ID will be indexed */
- fts_index_def.n_fields = 1;
- fts_index_def.ind_type = DICT_UNIQUE;
- fts_index_def.fields = static_cast<merge_index_field_t*>(
- mem_heap_alloc(heap, sizeof *fts_index_def.fields));
- fts_index_def.fields[0].prefix_len = 0;
- fts_index_def.fields[0].field_name = mem_heap_strdup(
- heap, FTS_DOC_ID_COL_NAME);
-
- index = row_merge_create_index(trx, indexed_table, &fts_index_def);
- return(index);
-}
-
-/********************************************************************//**
Drop any indexes that we were not able to free previously due to
open table handles. */
static
@@ -1371,6 +1332,7 @@ while preparing ALTER TABLE.
@param drop_foreign Foreign key constraints to be dropped, or NULL
@param n_drop_foreign Number of foreign key constraints to drop
@param num_fts_index Number of full-text indexes to create
+@param fts_doc_id_col The column number of FTS_DOC_ID
@param add_fts_doc_id Flag: add column FTS_DOC_ID?
@param add_fts_doc_id_idx Flag: add index (FTS_DOC_ID)?
@@ -1392,6 +1354,7 @@ prepare_inplace_alter_table_dict(
dict_foreign_t** drop_foreign,
ulint n_drop_foreign,
unsigned num_fts_index,
+ ulint fts_doc_id_col,
bool add_fts_doc_id,
bool add_fts_doc_id_idx)
{
@@ -1433,7 +1396,7 @@ prepare_inplace_alter_table_dict(
index_defs = innobase_create_key_defs(
heap, ha_alter_info, altered_table, n_add_index,
row_table_got_default_clust_index(indexed_table),
- add_fts_doc_id, add_fts_doc_id_idx);
+ fts_doc_id_col, add_fts_doc_id, add_fts_doc_id_idx);
new_clustered = DICT_CLUSTERED & index_defs[0].ind_type;
@@ -1608,7 +1571,8 @@ col_fail:
if (add_fts_doc_id) {
fts_add_doc_id_column(indexed_table, heap);
- indexed_table->fts->doc_col = altered_table->s->fields;
+ indexed_table->fts->doc_col = fts_doc_id_col;
+ ut_ad(fts_doc_id_col == altered_table->s->fields);
}
error = row_create_table_for_mysql(indexed_table, trx);
@@ -1875,6 +1839,24 @@ innobase_dropping_foreign(
return(false);
}
+/** Determine if fulltext indexes exist in a given table.
+@param table_share MySQL table
+@return whether fulltext indexes exist on the table */
+static
+bool
+innobase_fulltext_exist(
+/*====================*/
+ const TABLE_SHARE* table_share)
+{
+ for (uint i = 0; i < table_share->keys; i++) {
+ if (table_share->key_info[i].flags & HA_FULLTEXT) {
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
/** Allows InnoDB to update internal structures with concurrent
writes blocked. Invoked before inplace_alter_table().
@@ -1900,6 +1882,7 @@ ha_innobase::prepare_inplace_alter_table
mem_heap_t* heap;
int error;
ulint num_fts_index;
+ ulint fts_doc_col_no;
bool add_fts_doc_id = false;
bool add_fts_doc_id_idx = false;
@@ -1963,8 +1946,7 @@ err_exit_no_heap:
const char* name = 0;
- cf_it.init(ha_alter_info->alter_info
- ->create_list);
+ cf_it.init(ha_alter_info->alter_info->create_list);
while (Create_field* cf = cf_it++) {
if (cf->field == *fp) {
name = cf->field_name;
@@ -1974,9 +1956,28 @@ err_exit_no_heap:
ut_error;
check_if_ok_to_rename:
+ /* Prohibit renaming a column from FTS_DOC_ID
+ if full-text indexes exist. */
+ if (!my_strcasecmp(system_charset_info,
+ (*fp)->field_name,
+ FTS_DOC_ID_COL_NAME)
+ && innobase_fulltext_exist(altered_table->s)) {
+ my_error(ER_INNODB_FT_WRONG_DOCID_COLUMN,
+ MYF(0), name);
+ goto err_exit_no_heap;
+ }
+
+ /* Prohibit renaming a column to an internal column. */
const char* s = prebuilt->table->col_names;
+ unsigned j;
+ /* Skip user columns.
+ MySQL should have checked these already.
+ We want to allow renaming of c1 to c2, c2 to c1. */
+ for (j = 0; j < table->s->fields; j++) {
+ s += strlen(s) + 1;
+ }
- for (unsigned i = 0; i < prebuilt->table->n_def; i++) {
+ for (; j < prebuilt->table->n_def; j++) {
if (!my_strcasecmp(
system_charset_info, name, s)) {
my_error(ER_WRONG_COLUMN_NAME, MYF(0),
@@ -2226,10 +2227,10 @@ err_exit:
add a Doc ID hidden column and rebuild the primary index */
if (num_fts_index) {
ulint doc_col_no;
- ulint fts_doc_col_no;
if (!innobase_fts_check_doc_id_col(
prebuilt->table, altered_table, &fts_doc_col_no)) {
+ fts_doc_col_no = altered_table->s->fields;
add_fts_doc_id = true;
add_fts_doc_id_idx = true;
@@ -2270,6 +2271,7 @@ err_exit:
prebuilt->trx, table_share->table_name.str,
heap, drop_index, n_drop_index,
drop_fk, n_drop_fk, num_fts_index,
+ fts_doc_col_no,
add_fts_doc_id, add_fts_doc_id_idx));
}
@@ -2509,6 +2511,7 @@ innobase_drop_foreign(
/** Rename a column.
@param prebuilt the prebuilt struct
@param trx data dictionary transaction
+@param nth_col 0-based index of the column
@param from old column name
@param to new column name
@retval true Failure
@@ -2519,9 +2522,13 @@ innobase_rename_column(
/*===================*/
row_prebuilt_t* prebuilt,
trx_t* trx,
+ ulint nth_col,
const char* from,
const char* to)
{
+ pars_info_t* info;
+ dberr_t error;
+
DBUG_ENTER("innobase_rename_column");
DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX);
@@ -2531,94 +2538,156 @@ innobase_rename_column(
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- /* Rename the column in the data dictionary. */
- static const char sql[] =
- "PROCEDURE RENAME_COLUMN_PROC () IS\n"
- "fid CHAR;\n"
- "found INT;\n"
-
- "DECLARE CURSOR index_cur IS\n"
- " SELECT ID FROM SYS_INDEXES\n"
- " WHERE TABLE_ID=:tableid;\n"
-
- "DECLARE CURSOR for_cur IS\n"
- " SELECT ID FROM SYS_FOREIGN\n"
- " WHERE FOR_NAME=:table;\n"
-
- "DECLARE CURSOR ref_cur IS\n"
- " SELECT ID FROM SYS_FOREIGN\n"
- " WHERE REF_NAME=:table;\n"
-
- "BEGIN\n"
- "found := 1;\n"
- "OPEN index_cur;\n"
- "WHILE found = 1 LOOP\n"
- " FETCH index_cur INTO fid;\n"
- " IF (SQL % NOTFOUND) THEN\n"
- " found := 0;\n"
- " ELSE\n"
- " UPDATE SYS_FIELDS SET COL_NAME=:new\n"
- " WHERE INDEX_ID=fid AND COL_NAME=:old;\n"
- " END IF;\n"
- "END LOOP;\n"
- "CLOSE index_cur;\n"
-
- "UPDATE SYS_COLUMNS SET NAME=:new\n"
- "WHERE TABLE_ID=:tableid AND NAME=:old;\n"
-
- "found := 1;\n"
- "OPEN for_cur;\n"
- "WHILE found = 1 LOOP\n"
- " FETCH for_cur INTO fid;\n"
- " IF (SQL % NOTFOUND) THEN\n"
- " found := 0;\n"
- " ELSE\n"
- " UPDATE SYS_FOREIGN_COLS SET FOR_COL_NAME=:new\n"
- " WHERE ID=fid AND FOR_COL_NAME=:old;\n"
- " END IF;\n"
- "END LOOP;\n"
- "CLOSE for_cur;\n"
-
- "found := 1;\n"
- "OPEN ref_cur;\n"
- "WHILE found = 1 LOOP\n"
- " FETCH ref_cur INTO fid;\n"
- " IF (SQL % NOTFOUND) THEN\n"
- " found := 0;\n"
- " ELSE\n"
- " UPDATE SYS_FOREIGN_COLS SET REF_COL_NAME=:new\n"
- " WHERE ID=fid AND REF_COL_NAME=:old;\n"
- " END IF;\n"
- "END LOOP;\n"
- "CLOSE ref_cur;\n"
-
- "END;\n";
- pars_info_t* info = pars_info_create();
- dberr_t error;
+ info = pars_info_create();
pars_info_add_ull_literal(info, "tableid", prebuilt->table->id);
- pars_info_add_str_literal(info, "table", prebuilt->table->name);
+ pars_info_add_int4_literal(info, "nth", nth_col);
pars_info_add_str_literal(info, "old", from);
pars_info_add_str_literal(info, "new", to);
- trx->op_info = "renaming column";
+ trx->op_info = "renaming column in SYS_COLUMNS";
- error = que_eval_sql(info, sql, FALSE, trx);
- trx->op_info = "";
+ error = que_eval_sql(
+ info,
+ "PROCEDURE RENAME_SYS_COLUMNS_PROC () IS\n"
+ "BEGIN\n"
+ "UPDATE SYS_COLUMNS SET NAME=:new\n"
+ "WHERE TABLE_ID=:tableid AND NAME=:old\n"
+ "AND POS=:nth;\n"
+
+ /* Try again, in case there is a prefix_len
+ encoded in SYS_COLUMNS.POS */
+
+ "UPDATE SYS_COLUMNS SET NAME=:new\n"
+ "WHERE TABLE_ID=:tableid AND NAME=:old\n"
+ "AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
+
+ "END;\n",
+ FALSE, trx);
if (error != DB_SUCCESS) {
+err_exit:
my_error_innodb(error, prebuilt->table->name, 0);
trx->error_state = DB_SUCCESS;
+ trx->op_info = "";
DBUG_RETURN(true);
}
- /* Rename the column in the data dictionary cache. */
- if (!dict_mem_table_col_rename(prebuilt->table, from, to)) {
- DBUG_ASSERT(0);
- my_error(ER_NOT_KEYFILE, MYF(0), prebuilt->table->name);
- DBUG_RETURN(true);
+ trx->op_info = "renaming column in SYS_FIELDS";
+
+ for (dict_index_t* index = dict_table_get_first_index(prebuilt->table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+
+ for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
+ if (strcmp(dict_index_get_nth_field(index, i)->name,
+ from)) {
+ continue;
+ }
+
+ info = pars_info_create();
+
+ pars_info_add_ull_literal(info, "indexid", index->id);
+ pars_info_add_int4_literal(info, "nth", i);
+ pars_info_add_str_literal(info, "old", from);
+ pars_info_add_str_literal(info, "new", to);
+
+ error = que_eval_sql(
+ info,
+ "PROCEDURE RENAME_SYS_FIELDS_PROC () IS\n"
+ "BEGIN\n"
+
+ "UPDATE SYS_FIELDS SET COL_NAME=:new\n"
+ "WHERE INDEX_ID=:indexid AND COL_NAME=:old\n"
+ "AND POS=:nth;\n"
+
+ /* Try again, in case there is a prefix_len
+ encoded in SYS_FIELDS.POS */
+
+ "UPDATE SYS_FIELDS SET COL_NAME=:new\n"
+ "WHERE INDEX_ID=:indexid AND COL_NAME=:old\n"
+ "AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
+
+ "END;\n",
+ FALSE, trx);
+
+ if (error != DB_SUCCESS) {
+ goto err_exit;
+ }
+ }
}
+ trx->op_info = "renaming column in SYS_FOREIGN_COLS";
+
+ for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(
+ prebuilt->table->foreign_list);
+ foreign != NULL;
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
+ for (unsigned i = 0; i < foreign->n_fields; i++) {
+ if (strcmp(foreign->foreign_col_names[i], from)) {
+ continue;
+ }
+
+ info = pars_info_create();
+
+ pars_info_add_str_literal(info, "id", foreign->id);
+ pars_info_add_int4_literal(info, "nth", i);
+ pars_info_add_str_literal(info, "old", from);
+ pars_info_add_str_literal(info, "new", to);
+
+ error = que_eval_sql(
+ info,
+ "PROCEDURE RENAME_SYS_FOREIGN_F_PROC () IS\n"
+ "BEGIN\n"
+ "UPDATE SYS_FOREIGN_COLS\n"
+ "SET FOR_COL_NAME=:new\n"
+ "WHERE ID=:id AND POS=:nth\n"
+ "AND FOR_COL_NAME=:old;\n"
+ "END;\n",
+ FALSE, trx);
+
+ if (error != DB_SUCCESS) {
+ goto err_exit;
+ }
+ }
+ }
+
+ for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(
+ prebuilt->table->referenced_list);
+ foreign != NULL;
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
+ for (unsigned i = 0; i < foreign->n_fields; i++) {
+ if (strcmp(foreign->referenced_col_names[i], from)) {
+ continue;
+ }
+
+ info = pars_info_create();
+
+ pars_info_add_str_literal(info, "id", foreign->id);
+ pars_info_add_int4_literal(info, "nth", i);
+ pars_info_add_str_literal(info, "old", from);
+ pars_info_add_str_literal(info, "new", to);
+
+ error = que_eval_sql(
+ info,
+ "PROCEDURE RENAME_SYS_FOREIGN_R_PROC () IS\n"
+ "BEGIN\n"
+ "UPDATE SYS_FOREIGN_COLS\n"
+ "SET REF_COL_NAME=:new\n"
+ "WHERE ID=:id AND POS=:nth\n"
+ "AND REF_COL_NAME=:old;\n"
+ "END;\n",
+ FALSE, trx);
+
+ if (error != DB_SUCCESS) {
+ goto err_exit;
+ }
+ }
+ }
+
+ trx->op_info = "";
+ /* Rename the column in the data dictionary cache. */
+ dict_mem_table_col_rename(prebuilt->table, nth_col, from, to);
DBUG_RETURN(false);
}
@@ -2809,33 +2878,37 @@ ha_innobase::commit_inplace_alter_table(
&& (ha_alter_info->handler_flags
& Alter_inplace_info::ALTER_COLUMN_NAME)) {
List_iterator_fast<Create_field> cf_it;
+ uint i = 0;
+
+ for (Field** fp = table->field; *fp && err == 0; fp++, i++) {
+ if (!((*fp)->flags & FIELD_IS_RENAMED)) {
+ continue;
+ }
- for (Field** fp = table->field; err == 0 && *fp; fp++) {
- if ((*fp)->flags & FIELD_IS_RENAMED) {
- cf_it.init(ha_alter_info->alter_info
- ->create_list);
- while (Create_field* cf = cf_it++) {
- if (cf->field == *fp) {
- if (innobase_rename_column(
- prebuilt,
- trx,
- cf->field
- ->field_name,
- cf->field_name)) {
- err = -1;
- }
- goto processed_field;
+ cf_it.init(ha_alter_info->alter_info->create_list);
+ while (Create_field* cf = cf_it++) {
+ if (cf->field == *fp) {
+ if (innobase_rename_column(
+ prebuilt, trx, i,
+ cf->field->field_name,
+ cf->field_name)) {
+ err = -1;
}
+ goto processed_field;
}
-
- ut_error;
}
+
+ ut_error;
processed_field:
continue;
}
}
- trx_commit_for_mysql(trx);
+ if (err == 0) {
+ trx_commit_for_mysql(trx);
+ } else {
+ trx_rollback_for_mysql(trx);
+ }
if (err == 0 && ctx) {
/* The changes were successfully performed. */
=== modified file 'storage/innobase/include/dict0dict.h'
--- a/storage/innobase/include/dict0dict.h revid:marko.makela@strippedmx9
+++ b/storage/innobase/include/dict0dict.h revid:marko.makela@stripped
@@ -542,19 +542,6 @@ dict_foreign_find_index(
NOT NULL */
__attribute__((nonnull(1,2), warn_unused_result));
/**********************************************************************//**
-Returns an index object by matching on the name and column names and
-if more than one index matches return the index with the max id
-@return matching index, NULL if not found */
-UNIV_INTERN
-dict_index_t*
-dict_table_get_index_by_max_id(
-/*===========================*/
- dict_table_t* table, /*!< in: table */
- const char* name, /*!< in: the index name to find */
- const char** columns,/*!< in: array of column names */
- ulint n_cols) /*!< in: number of columns */
- __attribute__((nonnull, warn_unused_result));
-/**********************************************************************//**
Returns a column's name.
@return column name. NOTE: not guaranteed to stay valid if table is
modified in any way (columns added, etc.). */
=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h revid:marko.makela@strippedujodcmx9
+++ b/storage/innobase/include/dict0mem.h revid:marko.makela@stripped
@@ -253,13 +253,13 @@ dict_mem_table_add_col(
ulint len) /*!< in: precision */
__attribute__((nonnull(1)));
/**********************************************************************//**
-Renames a column of a table in the data dictionary cache.
-@return whether the operation succeeded */
+Renames a column of a table in the data dictionary cache. */
UNIV_INTERN
-bool
+void
dict_mem_table_col_rename(
/*======================*/
dict_table_t* table, /*!< in/out: table */
+ unsigned nth_col,/*!< in: column index */
const char* from, /*!< in: old column name */
const char* to) /*!< in: new column name */
__attribute__((nonnull));
=== modified file 'storage/innobase/include/row0merge.h'
--- a/storage/innobase/include/row0merge.h revid:marko.makela@strippedi3ujodcmx9
+++ b/storage/innobase/include/row0merge.h revid:marko.makela@stripped1
@@ -96,9 +96,9 @@ typedef struct merge_file_struct merge_f
/** Index field definition */
struct merge_index_field_struct {
+ ulint col_no; /*!< column offset */
ulint prefix_len; /*!< column prefix length, or 0
if indexing the whole column */
- const char* field_name; /*!< field name */
};
/** Index field definition */
=== modified file 'storage/innobase/include/row0upd.ic'
--- a/storage/innobase/include/row0upd.ic revid:marko.makela@stripped
+++ b/storage/innobase/include/row0upd.ic revid:marko.makela@oracle.com-20120417140601-q4xyu89kks7krh21
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
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 the Free Software
@@ -45,7 +45,6 @@ upd_create(
update = (upd_t*) mem_heap_zalloc(heap, sizeof(upd_t));
- update->info_bits = 0;
update->n_fields = n;
update->fields = (upd_field_t*)
mem_heap_zalloc(heap, sizeof(upd_field_t) * n);
@@ -110,6 +109,7 @@ upd_field_set_field_no(
fprintf(stderr, "\n"
"InnoDB: but index only has %lu fields\n",
(ulong) dict_index_get_n_fields(index));
+ ut_ad(0);
}
dict_col_copy_type(dict_index_get_nth_col(index, field_no),
=== modified file 'storage/innobase/log/log0recv.cc'
--- a/storage/innobase/log/log0recv.cc revid:marko.makela@stripped
+++ b/storage/innobase/log/log0recv.cc revid:marko.makela@strippedm-20120417140601-q4xyu89kks7krh21
@@ -2894,7 +2894,7 @@ recv_recovery_from_checkpoint_start_func
lsn_t checkpoint_lsn;
ib_uint64_t checkpoint_no;
lsn_t old_scanned_lsn;
- lsn_t group_scanned_lsn;
+ lsn_t group_scanned_lsn = 0;
lsn_t contiguous_lsn;
#ifdef UNIV_LOG_ARCHIVE
lsn_t archived_lsn;
=== modified file 'storage/innobase/row/row0merge.cc'
--- a/storage/innobase/row/row0merge.cc revid:marko.makela@strippedi3ujodcmx9
+++ b/storage/innobase/row/row0merge.cc revid:marko.makela@stripped
@@ -798,30 +798,47 @@ row_merge_heap_create(
Search an index object by name and column names. If several indexes match,
return the index with the max id.
@return matching index, NULL if not found */
-static
+static __attribute__((nonnull, warn_unused_result))
dict_index_t*
row_merge_dict_table_get_index(
/*===========================*/
dict_table_t* table, /*!< in: table */
const merge_index_def_t*index_def) /*!< in: index definition */
{
- ulint i;
- dict_index_t* index;
- const char** column_names;
+ dict_index_t* found = NULL;
- column_names = static_cast<const char**>(
- mem_alloc(index_def->n_fields * sizeof *column_names));
+ found = NULL;
+ for (dict_index_t* index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+
+ if (ut_strcmp(index->name, index_def->name) == 0
+ && dict_index_get_n_ordering_defined_by_user(index)
+ == index_def->n_fields) {
+
+ for (ulint i = 0; i < index_def->n_fields; i++) {
+ const dict_field_t* field
+ = dict_index_get_nth_field(index, i);
+
+ if (dict_col_get_no(field->col) !=
+ index_def->fields[i].col_no) {
+ goto next_index;
+ }
+ }
- for (i = 0; i < index_def->n_fields; ++i) {
- column_names[i] = index_def->fields[i].field_name;
- }
+ /* We found a matching index, select
+ the index with the higher id*/
- index = dict_table_get_index_by_max_id(
- table, index_def->name, column_names, index_def->n_fields);
+ if (!found || index->id > found->id) {
- mem_free((void*) column_names);
+ found = index;
+ }
+ }
+next_index:
+ continue;
+ }
- return(index);
+ return(found);
}
/********************************************************************//**
@@ -3095,8 +3112,9 @@ row_merge_create_index(
for (i = 0; i < n_fields; i++) {
merge_index_field_t* ifield = &index_def->fields[i];
- dict_mem_index_add_field(index, ifield->field_name,
- ifield->prefix_len);
+ dict_mem_index_add_field(
+ index, dict_table_get_col_name(table, ifield->col_no),
+ ifield->prefix_len);
}
/* Add the index to SYS_INDEXES, using the index prototype. */
No bundle (reason: useless for push emails).| Thread |
|---|
| • bzr push into mysql-trunk-wl5545 branch (marko.makela:3890 to 3894) | marko.makela | 20 Apr |