Merge lp:~percona-dev/percona-server/bug744103 into lp:~percona-dev/percona-server/5.1.56

Proposed by Alexey Kopytov
Status: Merged
Merged at revision: 218
Proposed branch: lp:~percona-dev/percona-server/bug744103
Merge into: lp:~percona-dev/percona-server/5.1.56
Prerequisite: lp:~percona-dev/percona-server/fix-innodb_expand_import
Diff against target: 734 lines (+722/-0)
2 files modified
innodb_expand_fast_index_creation.patch (+720/-0)
series (+2/-0)
To merge this branch: bzr merge lp:~percona-dev/percona-server/bug744103
Reviewer Review Type Date Requested Status
Fred Linhoss (community) documentation Approve
Percona developers Pending
Review via email: mp+55718@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Fix is good, but we need documentation.

Revision history for this message
Fred Linhoss (fred-linhoss) wrote :

Documentation in progress; approving MP so as not to hold it up.

review: Approve (documentation)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'innodb_expand_fast_index_creation.patch'
2--- innodb_expand_fast_index_creation.patch 1970-01-01 00:00:00 +0000
3+++ innodb_expand_fast_index_creation.patch 2011-03-31 11:17:17 +0000
4@@ -0,0 +1,720 @@
5+# name : innodb_expand_fast_index_creation.patch
6+# maintainer : Alexey
7+#
8+# Expands the applicability of InnoDB fast index creation to mysqldump,
9+# ALTER TABLE and OPTIMIZE TABLE.
10+#
11+--- a/client/client_priv.h 2011-03-31 12:04:39.000000000 +0400
12++++ b/client/client_priv.h 2011-03-31 12:10:21.000000000 +0400
13+@@ -96,5 +96,6 @@
14+ OPT_FIRST_SLAVE,
15+ OPT_ALL,
16+ OPT_NO_REMOVE_EOL_CARRET,
17++ OPT_INNODB_OPTIMIZE_KEYS,
18+ OPT_MAX_CLIENT_OPTION
19+ };
20+--- a/client/mysqldump.c 2011-03-31 12:04:37.000000000 +0400
21++++ b/client/mysqldump.c 2011-03-31 12:05:39.000000000 +0400
22+@@ -45,6 +45,7 @@
23+ #include <m_ctype.h>
24+ #include <hash.h>
25+ #include <stdarg.h>
26++#include <my_list.h>
27+
28+ #include "client_priv.h"
29+ #include "mysql.h"
30+@@ -134,6 +135,8 @@
31+
32+ static my_bool server_supports_sql_no_fcache= FALSE;
33+
34++static my_bool opt_innodb_optimize_keys= FALSE;
35++
36+ /*
37+ Dynamic_string wrapper functions. In this file use these
38+ wrappers, they will terminate the process if there is
39+@@ -179,6 +182,8 @@
40+
41+ HASH ignore_table;
42+
43++LIST *skipped_keys_list;
44++
45+ static struct my_option my_long_options[] =
46+ {
47+ {"all", OPT_ALL, "Deprecated. Use --create-options instead.",
48+@@ -325,6 +330,11 @@
49+ "be specified with both database and table names, e.g., "
50+ "--ignore-table=database.table.",
51+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
52++ {"innodb-optimize-keys", OPT_INNODB_OPTIMIZE_KEYS,
53++ "Use InnoDB fast index creation by creating secondary indexes after "
54++ "dumping the data.",
55++ &opt_innodb_optimize_keys, &opt_innodb_optimize_keys, 0, GET_BOOL, NO_ARG,
56++ 0, 0, 0, 0, 0, 0},
57+ {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
58+ &opt_ignore, &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
59+ 0, 0},
60+@@ -2240,6 +2250,77 @@
61+ }
62+
63+ /*
64++ Remove secondary/foreign key definitions from a given SHOW CREATE TABLE string
65++ and store them into a temporary list to be used later.
66++
67++ SYNOPSIS
68++ skip_secondary_keys()
69++ create_str SHOW CREATE TABLE output
70++
71++
72++ DESCRIPTION
73++
74++ Stores all lines starting with "KEY" or "UNIQUE KEY" or "CONSTRAINT"
75++ into skipped_keys_list and removes them from the input string.
76++ Ignoring FOREIGN KEYS constraints when creating the table is ok, because
77++ mysqldump sets foreign_key_checks to 0 anyway.
78++*/
79++
80++static void skip_secondary_keys(char *create_str)
81++{
82++ char *ptr, *strend;
83++ char *last_comma = NULL;
84++
85++ strend= create_str + strlen(create_str);
86++
87++ ptr= create_str;
88++ while (*ptr)
89++ {
90++ char *tmp, *orig_ptr;
91++
92++ orig_ptr= ptr;
93++ /* Skip leading whitespace */
94++ while (*ptr && my_isspace(charset_info, *ptr))
95++ ptr++;
96++
97++ /* Read the next line */
98++ for (tmp= ptr; *tmp != '\n' && *tmp != '\0'; tmp++);
99++
100++ /* Is it a secondary index definition? */
101++ if (*tmp == '\n' &&
102++ (!strncmp(ptr, "UNIQUE KEY ", sizeof("UNIQUE KEY ") - 1) ||
103++ !strncmp(ptr, "KEY ", sizeof("KEY ") - 1) ||
104++ !strncmp(ptr, "CONSTRAINT ", sizeof("CONSTRAINT ") - 1)))
105++ {
106++ char *data, *end= tmp - 1;
107++
108++ /* Remove the trailing comma */
109++ if (*end == ',')
110++ end--;
111++ data= my_strndup(ptr, end - ptr + 1, MYF(MY_FAE));
112++ skipped_keys_list= list_cons(data, skipped_keys_list);
113++
114++ memmove(orig_ptr, tmp + 1, strend - tmp);
115++ ptr= orig_ptr;
116++ strend-= tmp + 1 - ptr;
117++
118++ /* Remove the comma on the previos line */
119++ if (last_comma != NULL)
120++ {
121++ *last_comma= ' ';
122++ last_comma = NULL;
123++ }
124++ }
125++ else
126++ {
127++ if (tmp[-1] == ',')
128++ last_comma= tmp - 1;
129++ ptr= (*tmp == '\0') ? tmp : tmp + 1;
130++ }
131++ }
132++}
133++
134++/*
135+ get_table_structure -- retrievs database structure, prints out corresponding
136+ CREATE statement and fills out insert_pat if the table is the type we will
137+ be dumping.
138+@@ -2480,6 +2561,9 @@
139+
140+ row= mysql_fetch_row(result);
141+
142++ if (opt_innodb_optimize_keys && !strcmp(table_type, "InnoDB"))
143++ skip_secondary_keys(row[1]);
144++
145+ fprintf(sql_file, (opt_compatible_mode & 3) ? "%s;\n" :
146+ "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"
147+ "/*!40101 SET character_set_client = utf8 */;\n"
148+@@ -3572,6 +3656,27 @@
149+ goto err;
150+ }
151+
152++ /* Perform delayed secondary index creation for --innodb-optimize-keys */
153++ if (skipped_keys_list)
154++ {
155++ uint keys;
156++ skipped_keys_list= list_reverse(skipped_keys_list);
157++ fprintf(md_result_file, "ALTER TABLE %s ", opt_quoted_table);
158++ for (keys= list_length(skipped_keys_list); keys > 0; keys--)
159++ {
160++ LIST *node= skipped_keys_list;
161++ char *def= node->data;
162++
163++ fprintf(md_result_file, "ADD %s%s", def, (keys > 1) ? ", " : ";\n");
164++
165++ skipped_keys_list= list_delete(skipped_keys_list, node);
166++ my_free(def, MYF(0));
167++ my_free(node, MYF(0));
168++ }
169++
170++ DBUG_ASSERT(skipped_keys_list == NULL);
171++ }
172++
173+ /* Moved enable keys to before unlock per bug 15977 */
174+ if (opt_disable_keys)
175+ {
176+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
177++++ b/mysql-test/r/percona_mysqldump_innodb_optimize_keys.result 2011-03-31 12:05:39.000000000 +0400
178+@@ -0,0 +1,109 @@
179++#
180++# Test the --innodb-optimize-keys option.
181++#
182++CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, KEY(b)) ENGINE=MyISAM;
183++######################################
184++
185++/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
186++/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
187++/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
188++/*!40101 SET NAMES utf8 */;
189++/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
190++/*!40103 SET TIME_ZONE='+00:00' */;
191++/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
192++/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
193++/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
194++/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
195++DROP TABLE IF EXISTS `t1`;
196++/*!40101 SET @saved_cs_client = @@character_set_client */;
197++/*!40101 SET character_set_client = utf8 */;
198++CREATE TABLE `t1` (
199++ `a` int(11) NOT NULL,
200++ `b` int(11) DEFAULT NULL,
201++ PRIMARY KEY (`a`),
202++ KEY `b` (`b`)
203++) ENGINE=MyISAM DEFAULT CHARSET=latin1;
204++/*!40101 SET character_set_client = @saved_cs_client */;
205++
206++LOCK TABLES `t1` WRITE;
207++/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
208++/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
209++UNLOCK TABLES;
210++/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
211++
212++/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
213++/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
214++/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
215++/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
216++/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
217++/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
218++/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
219++
220++######################################
221++DROP TABLE t1;
222++CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
223++INSERT INTO t2 VALUES (0), (1), (2);
224++CREATE TABLE t1 (
225++id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
226++a INT, b VARCHAR(255), c DECIMAL(10,3),
227++KEY (b),
228++UNIQUE KEY uniq(c,a),
229++FOREIGN KEY (a) REFERENCES t2(a) ON DELETE CASCADE
230++) ENGINE=InnoDB;
231++INSERT INTO t1(a,b,c) VALUES (0, "0", 0.0), (1, "1", 1.1), (2, "2", 2.2);
232++######################################
233++
234++/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
235++/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
236++/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
237++/*!40101 SET NAMES utf8 */;
238++/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
239++/*!40103 SET TIME_ZONE='+00:00' */;
240++/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
241++/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
242++/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
243++/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
244++DROP TABLE IF EXISTS `t1`;
245++/*!40101 SET @saved_cs_client = @@character_set_client */;
246++/*!40101 SET character_set_client = utf8 */;
247++CREATE TABLE `t1` (
248++ `id` int(11) NOT NULL AUTO_INCREMENT,
249++ `a` int(11) DEFAULT NULL,
250++ `b` varchar(255) DEFAULT NULL,
251++ `c` decimal(10,3) DEFAULT NULL,
252++ PRIMARY KEY (`id`)
253++) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
254++/*!40101 SET character_set_client = @saved_cs_client */;
255++
256++LOCK TABLES `t1` WRITE;
257++/*!40000 ALTER TABLE `t1` DISABLE KEYS */;
258++INSERT INTO `t1` VALUES (1,0,'0','0.000'),(2,1,'1','1.100'),(3,2,'2','2.200');
259++ALTER TABLE `t1` ADD UNIQUE KEY `uniq` (`c`,`a`), ADD KEY `b` (`b`), ADD KEY `a` (`a`), ADD CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t2` (`a`) ON DELETE CASCADE;
260++/*!40000 ALTER TABLE `t1` ENABLE KEYS */;
261++UNLOCK TABLES;
262++DROP TABLE IF EXISTS `t2`;
263++/*!40101 SET @saved_cs_client = @@character_set_client */;
264++/*!40101 SET character_set_client = utf8 */;
265++CREATE TABLE `t2` (
266++ `a` int(11) NOT NULL,
267++ PRIMARY KEY (`a`)
268++) ENGINE=InnoDB DEFAULT CHARSET=latin1;
269++/*!40101 SET character_set_client = @saved_cs_client */;
270++
271++LOCK TABLES `t2` WRITE;
272++/*!40000 ALTER TABLE `t2` DISABLE KEYS */;
273++INSERT INTO `t2` VALUES (0),(1),(2);
274++/*!40000 ALTER TABLE `t2` ENABLE KEYS */;
275++UNLOCK TABLES;
276++/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
277++
278++/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
279++/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
280++/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
281++/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
282++/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
283++/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
284++/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
285++
286++######################################
287++DROP TABLE t1, t2;
288+--- a/mysql-test/suite/innodb_plugin/r/innodb.result 2011-03-31 12:04:33.000000000 +0400
289++++ b/mysql-test/suite/innodb_plugin/r/innodb.result 2011-03-31 12:05:39.000000000 +0400
290+@@ -1679,7 +1679,7 @@
291+ 71
292+ SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted';
293+ variable_value - @innodb_rows_inserted_orig
294+-1067
295++1109
296+ SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated';
297+ variable_value - @innodb_rows_updated_orig
298+ 866
299+--- a/mysql-test/suite/innodb_plugin/t/innodb-index.test 2011-02-11 22:49:34.000000000 +0300
300++++ b/mysql-test/suite/innodb_plugin/t/innodb-index.test 2011-03-31 12:05:39.000000000 +0400
301+@@ -38,6 +38,11 @@
302+ show create table t1;
303+ --error ER_MULTIPLE_PRI_KEY
304+ alter table t1 add primary key (c);
305++# Suppress the error log messages occuring on duplicate key error
306++# during ALTER TABLE when using fast index creation
307++--disable_query_log
308++call mtr.add_suppression("Cannot find index PRIMARY in InnoDB index translation table.");
309++--enable_query_log
310+ --error ER_DUP_ENTRY
311+ alter table t1 drop primary key, add primary key (b);
312+ create unique index c on t1 (c);
313+--- a/mysql-test/suite/innodb_plugin/t/innodb.test 2011-02-11 22:49:35.000000000 +0300
314++++ b/mysql-test/suite/innodb_plugin/t/innodb.test 2011-03-31 12:05:39.000000000 +0400
315+@@ -15,6 +15,12 @@
316+
317+ -- source include/have_innodb_plugin.inc
318+
319++# Suppress the error log message occuring on duplicate key error
320++# during ALTER TABLE when using fast index creation
321++--disable_query_log
322++call mtr.add_suppression("Cannot find index v_2 in InnoDB index translation table.");
323++--enable_query_log
324++
325+ let $MYSQLD_DATADIR= `select @@datadir`;
326+
327+ # Save the original values of some variables in order to be able to
328+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
329++++ b/mysql-test/t/percona_mysqldump_innodb_optimize_keys.test 2011-03-31 12:05:39.000000000 +0400
330+@@ -0,0 +1,62 @@
331++# Embedded server doesn't support external clients
332++--source include/not_embedded.inc
333++
334++# Fast index creation is only available in InnoDB plugin
335++--source include/have_innodb_plugin.inc
336++
337++# Save the initial number of concurrent sessions
338++--source include/count_sessions.inc
339++
340++--echo #
341++--echo # Test the --innodb-optimize-keys option.
342++--echo #
343++
344++--let $file=$MYSQLTEST_VARDIR/tmp/t1.sql
345++
346++# First test that the option has no effect on non-InnoDB tables
347++
348++CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, KEY(b)) ENGINE=MyISAM;
349++
350++--exec $MYSQL_DUMP --skip-comments --innodb-optimize-keys test t1 >$file
351++
352++--echo ######################################
353++--cat_file $file
354++--echo ######################################
355++
356++--remove_file $file
357++
358++DROP TABLE t1;
359++
360++
361++# Check that for InnoDB tables secondary and foreign keys are created
362++# after the data is dumped
363++
364++CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=InnoDB;
365++INSERT INTO t2 VALUES (0), (1), (2);
366++
367++CREATE TABLE t1 (
368++ id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
369++ a INT, b VARCHAR(255), c DECIMAL(10,3),
370++ KEY (b),
371++ UNIQUE KEY uniq(c,a),
372++ FOREIGN KEY (a) REFERENCES t2(a) ON DELETE CASCADE
373++) ENGINE=InnoDB;
374++
375++INSERT INTO t1(a,b,c) VALUES (0, "0", 0.0), (1, "1", 1.1), (2, "2", 2.2);
376++
377++--exec $MYSQL_DUMP --skip-comments --innodb-optimize-keys test t1 t2 >$file
378++
379++--echo ######################################
380++--cat_file $file
381++--echo ######################################
382++
383++# Check that the resulting dump can be imported back
384++
385++--exec $MYSQL test < $file
386++
387++--remove_file $file
388++
389++DROP TABLE t1, t2;
390++
391++# Wait till we reached the initial number of concurrent sessions
392++--source include/wait_until_count_sessions.inc
393+--- a/sql/sql_lex.cc 2011-03-31 12:04:37.000000000 +0400
394++++ b/sql/sql_lex.cc 2011-03-31 12:13:39.000000000 +0400
395+@@ -1494,6 +1494,9 @@
396+ alter_list(rhs.alter_list, mem_root),
397+ key_list(rhs.key_list, mem_root),
398+ create_list(rhs.create_list, mem_root),
399++ delayed_key_list(rhs.delayed_key_list, mem_root),
400++ delayed_key_info(rhs.delayed_key_info),
401++ delayed_key_count(rhs.delayed_key_count),
402+ flags(rhs.flags),
403+ keys_onoff(rhs.keys_onoff),
404+ tablespace_op(rhs.tablespace_op),
405+@@ -1516,6 +1519,7 @@
406+ list_copy_and_replace_each_value(alter_list, mem_root);
407+ list_copy_and_replace_each_value(key_list, mem_root);
408+ list_copy_and_replace_each_value(create_list, mem_root);
409++ list_copy_and_replace_each_value(delayed_key_list, mem_root);
410+ /* partition_names are not deeply copied currently */
411+ }
412+
413+--- a/sql/sql_lex.h 2011-03-31 12:04:38.000000000 +0400
414++++ b/sql/sql_lex.h 2011-03-31 12:14:36.000000000 +0400
415+@@ -896,6 +896,9 @@
416+ List<Alter_column> alter_list;
417+ List<Key> key_list;
418+ List<Create_field> create_list;
419++ List<Key> delayed_key_list;
420++ KEY *delayed_key_info;
421++ uint delayed_key_count;
422+ uint flags;
423+ enum enum_enable_or_disable keys_onoff;
424+ enum tablespace_op_type tablespace_op;
425+@@ -907,6 +910,8 @@
426+
427+
428+ Alter_info() :
429++ delayed_key_info(NULL),
430++ delayed_key_count(0),
431+ flags(0),
432+ keys_onoff(LEAVE_AS_IS),
433+ tablespace_op(NO_TABLESPACE_OP),
434+@@ -922,6 +927,9 @@
435+ alter_list.empty();
436+ key_list.empty();
437+ create_list.empty();
438++ delayed_key_list.empty();
439++ delayed_key_info= NULL;
440++ delayed_key_count= 0;
441+ flags= 0;
442+ keys_onoff= LEAVE_AS_IS;
443+ tablespace_op= NO_TABLESPACE_OP;
444+--- a/sql/sql_table.cc 2011-03-31 12:04:35.000000000 +0400
445++++ b/sql/sql_table.cc 2011-03-31 12:05:39.000000000 +0400
446+@@ -2558,7 +2558,7 @@
447+ file The handler for the new table.
448+ key_info_buffer OUT An array of KEY structs for the indexes.
449+ key_count OUT The number of elements in the array.
450+- select_field_count The number of fields coming from a select table.
451++ select_field_count The number of fields coming from a select table.
452+
453+ DESCRIPTION
454+ Prepares the table and key structures for table creation.
455+@@ -2913,7 +2913,6 @@
456+ }
457+
458+ /* Create keys */
459+-
460+ List_iterator<Key> key_iterator(alter_info->key_list);
461+ List_iterator<Key> key_iterator2(alter_info->key_list);
462+ uint key_parts=0, fk_key_count=0;
463+@@ -3013,6 +3012,14 @@
464+ if (!*key_info_buffer || ! key_part_info)
465+ DBUG_RETURN(TRUE); // Out of memory
466+
467++ List_iterator<Key> delayed_key_iterator(alter_info->delayed_key_list);
468++ alter_info->delayed_key_count= 0;
469++ if (alter_info->delayed_key_list.elements > 0)
470++ {
471++ alter_info->delayed_key_info= (KEY *) sql_calloc(sizeof(KEY) *
472++ (*key_count));
473++ }
474++
475+ key_iterator.rewind();
476+ key_number=0;
477+ for (; (key=key_iterator++) ; key_number++)
478+@@ -3382,8 +3389,26 @@
479+ my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
480+ DBUG_RETURN(TRUE);
481+ }
482++
483++ if (alter_info->delayed_key_list.elements > 0)
484++ {
485++ Key *delayed_key;
486++
487++ delayed_key_iterator.rewind();
488++ while ((delayed_key= delayed_key_iterator++))
489++ {
490++ if (delayed_key == key)
491++ {
492++ alter_info->delayed_key_info[alter_info->delayed_key_count++]=
493++ *key_info;
494++ break;
495++ }
496++ }
497++ }
498++
499+ key_info++;
500+ }
501++
502+ if (!unique_key && !primary_key &&
503+ (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
504+ {
505+@@ -6081,6 +6106,10 @@
506+ List<Create_field> new_create_list;
507+ /* New key definitions are added here */
508+ List<Key> new_key_list;
509++ /* List with secondary keys which should be created after copying the data */
510++ List<Key> delayed_key_list;
511++ /* Foreign key list returned by handler::get_foreign_key_list() */
512++ List<FOREIGN_KEY_INFO> f_key_list;
513+ List_iterator<Alter_drop> drop_it(alter_info->drop_list);
514+ List_iterator<Create_field> def_it(alter_info->create_list);
515+ List_iterator<Alter_column> alter_it(alter_info->alter_list);
516+@@ -6093,6 +6122,7 @@
517+ uint used_fields= create_info->used_fields;
518+ KEY *key_info=table->key_info;
519+ bool rc= TRUE;
520++ bool skip_secondary;
521+
522+ DBUG_ENTER("mysql_prepare_alter_table");
523+
524+@@ -6120,6 +6150,7 @@
525+ char *tablespace= static_cast<char *>(thd->alloc(FN_LEN + 1));
526+ /*
527+ Regular alter table of disk stored table (no tablespace/storage change)
528++
529+ Copy tablespace name
530+ */
531+ if (tablespace &&
532+@@ -6270,7 +6301,23 @@
533+ /*
534+ Collect all keys which isn't in drop list. Add only those
535+ for which some fields exists.
536+- */
537++
538++ We also skip secondary keys for InnoDB tables and store them in
539++ delayed_key_list to create them later after copying the data to make use of
540++ the InnoDB fast index creation. The following conditions must be met:
541++
542++ - we are going to create an InnoDB table;
543++ - the key most be a non-UNIQUE one;
544++ - there are no foreign keys. This can be optimized later to exclude only
545++ those keys which are a part of foreign key constraints. Currently we
546++ simply disable this optimization for all keys if there are any foreign
547++ key constraints in the table.
548++ */
549++
550++ skip_secondary=
551++ !my_strcasecmp(system_charset_info, table->file->table_type(), "InnoDB") &&
552++ !table->file->get_foreign_key_list(thd, &f_key_list) &&
553++ f_key_list.elements == 0;
554+
555+ for (uint i=0 ; i < table->s->keys ; i++,key_info++)
556+ {
557+@@ -6373,6 +6420,8 @@
558+ test(key_info->flags & HA_GENERATED_KEY),
559+ key_parts);
560+ new_key_list.push_back(key);
561++ if (skip_secondary && key_type == Key::MULTIPLE)
562++ delayed_key_list.push_back(key);
563+ }
564+ }
565+ {
566+@@ -6380,7 +6429,21 @@
567+ while ((key=key_it++)) // Add new keys
568+ {
569+ if (key->type != Key::FOREIGN_KEY)
570+- new_key_list.push_back(key);
571++ {
572++ new_key_list.push_back(key);
573++ if (skip_secondary && key->type == Key::MULTIPLE)
574++ delayed_key_list.push_back(key);
575++ }
576++ else if (skip_secondary)
577++ {
578++ /*
579++ We are adding a foreign key so disable the secondary keys
580++ optimization.
581++ */
582++ skip_secondary= FALSE;
583++ delayed_key_list.empty();
584++ }
585++
586+ if (key->name &&
587+ !my_strcasecmp(system_charset_info,key->name,primary_key_name))
588+ {
589+@@ -6429,12 +6492,100 @@
590+ rc= FALSE;
591+ alter_info->create_list.swap(new_create_list);
592+ alter_info->key_list.swap(new_key_list);
593++ alter_info->delayed_key_list.swap(delayed_key_list);
594+ err:
595+ DBUG_RETURN(rc);
596+ }
597+
598+
599+ /*
600++ Temporarily remove secondary keys previously stored in
601++ alter_info->delayed_key_info.
602++*/
603++static int
604++remove_secondary_keys(THD *thd, TABLE *table, Alter_info *alter_info)
605++{
606++ uint *key_numbers;
607++ uint key_counter= 0;
608++ uint i;
609++ int error;
610++ DBUG_ENTER("remove_secondary_keys");
611++ DBUG_ASSERT(alter_info->delayed_key_count > 0);
612++
613++ key_numbers= (uint *) thd->alloc(sizeof(uint) *
614++ alter_info->delayed_key_count);
615++ for (i= 0; i < alter_info->delayed_key_count; i++)
616++ {
617++ KEY *key= alter_info->delayed_key_info + i;
618++ uint j;
619++
620++ for (j= 0; j < table->s->keys; j++)
621++ {
622++ if (!strcmp(table->key_info[j].name, key->name))
623++ {
624++ key_numbers[key_counter++]= j;
625++ break;
626++ }
627++ }
628++ }
629++
630++ DBUG_ASSERT(key_counter == alter_info->delayed_key_count);
631++
632++ if ((error= table->file->prepare_drop_index(table, key_numbers,
633++ key_counter)) ||
634++ (error= table->file->final_drop_index(table)))
635++ {
636++ table->file->print_error(error, MYF(0));
637++ }
638++
639++ DBUG_RETURN(error);
640++}
641++
642++/*
643++ Restore secondary keys previously removed in remove_secondary_keys.
644++*/
645++
646++static int
647++restore_secondary_keys(THD *thd, TABLE *table, Alter_info *alter_info)
648++{
649++ uint i;
650++ int error;
651++ DBUG_ENTER("restore_secondary_keys");
652++ DBUG_ASSERT(alter_info->delayed_key_count > 0);
653++
654++ thd_proc_info(thd, "restoring secondary keys");
655++
656++ /* Fix the key parts */
657++ for (i= 0; i < alter_info->delayed_key_count; i++)
658++ {
659++ KEY *key = alter_info->delayed_key_info + i;
660++ KEY_PART_INFO *key_part;
661++ KEY_PART_INFO *part_end;
662++
663++ part_end= key->key_part + key->key_parts;
664++ for (key_part= key->key_part; key_part < part_end; key_part++)
665++ key_part->field= table->field[key_part->fieldnr];
666++ }
667++
668++ if ((error= table->file->add_index(table, alter_info->delayed_key_info,
669++ alter_info->delayed_key_count)))
670++ {
671++ /*
672++ Exchange the key_info for the error message. If we exchange
673++ key number by key name in the message later, we need correct info.
674++ */
675++ KEY *save_key_info= table->key_info;
676++ table->key_info= alter_info->delayed_key_info;
677++ table->file->print_error(error, MYF(0));
678++ table->key_info= save_key_info;
679++
680++ DBUG_RETURN(error);
681++ }
682++
683++ DBUG_RETURN(0);
684++}
685++
686++/*
687+ Alter table
688+
689+ SYNOPSIS
690+@@ -7218,6 +7369,12 @@
691+ else
692+ create_info->data_file_name=create_info->index_file_name=0;
693+
694++ /*
695++ Postpone secondary index creation for InnoDB tables if the data has to be
696++ copied.
697++ TODO: is there a better way to check for InnoDB?
698++ */
699++
700+ DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
701+ /*
702+ Create a table with a temporary name.
703+@@ -7277,12 +7434,21 @@
704+ /* We don't want update TIMESTAMP fields during ALTER TABLE. */
705+ new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
706+ new_table->next_number_field=new_table->found_next_number_field;
707++
708++ if (alter_info->delayed_key_count > 0)
709++ {
710++ /* ignore the error */
711++ error= remove_secondary_keys(thd, new_table, alter_info);
712++ }
713++
714+ thd_proc_info(thd, "copy to tmp table");
715+ error= copy_data_between_tables(table, new_table,
716+ alter_info->create_list, ignore,
717+ order_num, order, &copied, &deleted,
718+ alter_info->keys_onoff,
719+ alter_info->error_if_not_empty);
720++ if (!error && alter_info->delayed_key_count > 0)
721++ error= restore_secondary_keys(thd, new_table, alter_info);
722+ }
723+ else
724+ {
725
726=== modified file 'series'
727--- series 2011-02-17 17:55:34 +0000
728+++ series 2011-03-31 11:17:17 +0000
729@@ -53,3 +53,5 @@
730 bug677407.patch
731 fix-bug671764.patch
732 mysql_remove_eol_carret.patch
733+innodb_expand_fast_index_creation.patch
734+

Subscribers

People subscribed via source and target branches