Merge lp:~percona-dev/percona-server/bug744103 into lp:~percona-dev/percona-server/5.1.56
- bug744103
- Merge into 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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Fred Linhoss (community) | documentation | Approve | |
Percona developers | Pending | ||
Review via email: mp+55718@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Vadim Tkachenko (vadim-tk) wrote : | # |
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 | + |
Fix is good, but we need documentation.