1 /*
2 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /* drop and alter of tables */
26
27 #include "sql_priv.h"
28 #include "unireg.h"
29 #include "debug_sync.h"
30 #include "sql_table.h"
31 #include "sql_rename.h" // do_rename
32 #include "sql_parse.h" // test_if_data_home_dir
33 #include "sql_cache.h" // query_cache_*
34 #include "sql_base.h" // open_table_uncached, lock_table_names
35 #include "lock.h" // mysql_unlock_tables
36 #include "strfunc.h" // find_type2, find_set
37 #include "sql_view.h" // view_checksum
38 #include "sql_truncate.h" // regenerate_locked_table
39 #include "sql_partition.h" // mem_alloc_error,
40 // generate_partition_syntax,
41 // partition_info
42 // NOT_A_PARTITION_ID
43 #include "sql_db.h" // load_db_opt_by_name
44 #include "sql_time.h" // make_truncated_value_warning
45 #include "records.h" // init_read_record, end_read_record
46 #include "filesort.h" // filesort_free_buffers
47 #include "sql_select.h" // setup_order,
48 // make_unireg_sortorder
49 #include "sql_handler.h" // mysql_ha_rm_tables
50 #include "discover.h" // readfrm
51 #include "my_pthread.h" // pthread_mutex_t
52 #include "log_event.h" // Query_log_event
53 #include <hash.h>
54 #include <myisam.h>
55 #include <my_dir.h>
56 #include "sp_head.h"
57 #include "sp.h"
58 #include "sql_trigger.h"
59 #include "sql_parse.h"
60 #include "sql_show.h"
61 #include "transaction.h"
62 #include "datadict.h" // dd_frm_type()
63 #include "sql_resolver.h" // setup_order, fix_inner_refs
64 #include "table_cache.h"
65 #include <mysql/psi/mysql_table.h>
66
67 #ifdef __WIN__
68 #include <io.h>
69 #endif
70
71 #include <algorithm>
72 using std::max;
73 using std::min;
74
75 const char *primary_key_name="PRIMARY";
76
77 #ifdef USE_SYMDIR
78 bool symdir_warning_emitted= false;
79 #endif
80
81 static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
82 static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
83 static int copy_data_between_tables(TABLE *from,TABLE *to,
84 List<Create_field> &create, bool ignore,
85 uint order_num, ORDER *order,
86 ha_rows *copied,ha_rows *deleted,
87 Alter_info::enum_enable_or_disable keys_onoff,
88 Alter_table_ctx *alter_ctx);
89
90 static bool prepare_blob_field(THD *thd, Create_field *sql_field);
91 static void sp_prepare_create_field(THD *thd, Create_field *sql_field);
92 static bool check_engine(THD *thd, const char *db_name,
93 const char *table_name,
94 HA_CREATE_INFO *create_info);
95
96 static int
97 mysql_prepare_create_table(THD *thd, const char *error_schema_name,
98 const char *error_table_name,
99 HA_CREATE_INFO *create_info,
100 Alter_info *alter_info,
101 bool tmp_table,
102 uint *db_options,
103 handler *file, KEY **key_info_buffer,
104 uint *key_count, int select_field_count);
105
106
107 /**
108 @brief Helper function for explain_filename
109 @param thd Thread handle
110 @param to_p Explained name in system_charset_info
111 @param end_p End of the to_p buffer
112 @param name Name to be converted
113 @param name_len Length of the name, in bytes
114 */
add_identifier(THD * thd,char * to_p,const char * end_p,const char * name,uint name_len)115 static char* add_identifier(THD* thd, char *to_p, const char * end_p,
116 const char* name, uint name_len)
117 {
118 uint res;
119 uint errors;
120 const char *conv_name;
121 char tmp_name[FN_REFLEN];
122 char conv_string[FN_REFLEN];
123 int quote;
124
125 DBUG_ENTER("add_identifier");
126 if (!name[name_len])
127 conv_name= name;
128 else
129 {
130 strnmov(tmp_name, name, name_len);
131 tmp_name[name_len]= 0;
132 conv_name= tmp_name;
133 }
134 res= strconvert(&my_charset_filename, conv_name, system_charset_info,
135 conv_string, FN_REFLEN, &errors);
136 if (!res || errors)
137 {
138 DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors));
139 conv_name= name;
140 }
141 else
142 {
143 DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
144 conv_name= conv_string;
145 }
146
147 quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"';
148
149 if (quote != EOF && (end_p - to_p > 2))
150 {
151 *(to_p++)= (char) quote;
152 while (*conv_name && (end_p - to_p - 1) > 0)
153 {
154 uint length= my_mbcharlen(system_charset_info, *conv_name);
155 if (!length)
156 length= 1;
157 if (length == 1 && *conv_name == (char) quote)
158 {
159 if ((end_p - to_p) < 3)
160 break;
161 *(to_p++)= (char) quote;
162 *(to_p++)= *(conv_name++);
163 }
164 else if (((long) length) < (end_p - to_p))
165 {
166 to_p= strnmov(to_p, conv_name, length);
167 conv_name+= length;
168 }
169 else
170 break; /* string already filled */
171 }
172 if (end_p > to_p) {
173 *(to_p++)= (char) quote;
174 if (end_p > to_p)
175 *to_p= 0; /* terminate by NUL, but do not include it in the count */
176 }
177 }
178 else
179 to_p= strnmov(to_p, conv_name, end_p - to_p);
180 DBUG_RETURN(to_p);
181 }
182
183
184 /**
185 @brief Explain a path name by split it to database, table etc.
186
187 @details Break down the path name to its logic parts
188 (database, table, partition, subpartition).
189 filename_to_tablename cannot be used on partitions, due to the #P# part.
190 There can be up to 6 '#', #P# for partition, #SP# for subpartition
191 and #TMP# or #REN# for temporary or renamed partitions.
192 This should be used when something should be presented to a user in a
193 diagnostic, error etc. when it would be useful to know what a particular
194 file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc.
195
196 @param thd Thread handle
197 @param from Path name in my_charset_filename
198 Null terminated in my_charset_filename, normalized
199 to use '/' as directory separation character.
200 @param to Explained name in system_charset_info
201 @param to_length Size of to buffer
202 @param explain_mode Requested output format.
203 EXPLAIN_ALL_VERBOSE ->
204 [Database `db`, ]Table `tbl`[,[ Temporary| Renamed]
205 Partition `p` [, Subpartition `sp`]]
206 EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl`
207 [[ Temporary| Renamed] Partition `p`
208 [, Subpartition `sp`]]
209 EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |*
210 [,[ Temporary| Renamed] Partition `p`
211 [, Subpartition `sp`]] *|
212 (| is really a /, and it is all in one line)
213
214 @retval Length of returned string
215 */
216
explain_filename(THD * thd,const char * from,char * to,uint to_length,enum_explain_filename_mode explain_mode)217 uint explain_filename(THD* thd,
218 const char *from,
219 char *to,
220 uint to_length,
221 enum_explain_filename_mode explain_mode)
222 {
223 char *to_p= to;
224 char *end_p= to_p + to_length;
225 const char *db_name= NULL;
226 int db_name_len= 0;
227 const char *table_name;
228 int table_name_len= 0;
229 const char *part_name= NULL;
230 int part_name_len= 0;
231 const char *subpart_name= NULL;
232 int subpart_name_len= 0;
233 enum enum_part_name_type {NORMAL, TEMP, RENAMED} part_type= NORMAL;
234
235 const char *tmp_p;
236 DBUG_ENTER("explain_filename");
237 DBUG_PRINT("enter", ("from '%s'", from));
238 tmp_p= from;
239 table_name= from;
240 /*
241 If '/' then take last directory part as database.
242 '/' is the directory separator, not FN_LIB_CHAR
243 */
244 while ((tmp_p= strchr(tmp_p, '/')))
245 {
246 db_name= table_name;
247 /* calculate the length */
248 db_name_len= tmp_p - db_name;
249 tmp_p++;
250 table_name= tmp_p;
251 }
252 tmp_p= table_name;
253 /* Look if there are partition tokens in the table name. */
254 while ((tmp_p= strchr(tmp_p, '#')))
255 {
256 tmp_p++;
257 switch (tmp_p[0]) {
258 case 'P':
259 case 'p':
260 if (tmp_p[1] == '#')
261 {
262 part_name= tmp_p + 2;
263 tmp_p+= 2;
264 }
265 break;
266 case 'S':
267 case 's':
268 if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#')
269 {
270 part_name_len= tmp_p - part_name - 1;
271 subpart_name= tmp_p + 3;
272 tmp_p+= 3;
273 }
274 break;
275 case 'T':
276 case 't':
277 if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
278 (tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
279 tmp_p[3] == '#' && !tmp_p[4])
280 {
281 part_type= TEMP;
282 tmp_p+= 4;
283 }
284 break;
285 case 'R':
286 case 'r':
287 if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
288 (tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
289 tmp_p[3] == '#' && !tmp_p[4])
290 {
291 part_type= RENAMED;
292 tmp_p+= 4;
293 }
294 break;
295 default:
296 /* Not partition name part. */
297 ;
298 }
299 }
300 if (part_name)
301 {
302 table_name_len= part_name - table_name - 3;
303 if (subpart_name)
304 subpart_name_len= strlen(subpart_name);
305 else
306 part_name_len= strlen(part_name);
307 if (part_type != NORMAL)
308 {
309 if (subpart_name)
310 subpart_name_len-= 5;
311 else
312 part_name_len-= 5;
313 }
314 }
315 else
316 table_name_len= strlen(table_name);
317 if (db_name)
318 {
319 if (explain_mode == EXPLAIN_ALL_VERBOSE)
320 {
321 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME),
322 end_p - to_p);
323 *(to_p++)= ' ';
324 to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
325 to_p= strnmov(to_p, ", ", end_p - to_p);
326 }
327 else
328 {
329 to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
330 to_p= strnmov(to_p, ".", end_p - to_p);
331 }
332 }
333 if (explain_mode == EXPLAIN_ALL_VERBOSE)
334 {
335 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p);
336 *(to_p++)= ' ';
337 to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
338 }
339 else
340 to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
341 if (part_name)
342 {
343 if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
344 to_p= strnmov(to_p, " /* ", end_p - to_p);
345 else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE)
346 to_p= strnmov(to_p, " ", end_p - to_p);
347 else
348 to_p= strnmov(to_p, ", ", end_p - to_p);
349 if (part_type != NORMAL)
350 {
351 if (part_type == TEMP)
352 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
353 end_p - to_p);
354 else
355 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME),
356 end_p - to_p);
357 to_p= strnmov(to_p, " ", end_p - to_p);
358 }
359 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME),
360 end_p - to_p);
361 *(to_p++)= ' ';
362 to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len);
363 if (subpart_name)
364 {
365 to_p= strnmov(to_p, ", ", end_p - to_p);
366 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME),
367 end_p - to_p);
368 *(to_p++)= ' ';
369 to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len);
370 }
371 if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
372 to_p= strnmov(to_p, " */", end_p - to_p);
373 }
374 DBUG_PRINT("exit", ("to '%s'", to));
375 DBUG_RETURN(to_p - to);
376 }
377
378
379 /*
380 Translate a file name to a table name (WL #1324).
381
382 SYNOPSIS
383 filename_to_tablename()
384 from The file name in my_charset_filename.
385 to OUT The table name in system_charset_info.
386 to_length The size of the table name buffer.
387
388 RETURN
389 Table name length.
390 */
391
filename_to_tablename(const char * from,char * to,uint to_length,bool stay_quiet)392 uint filename_to_tablename(const char *from, char *to, uint to_length
393 #ifndef DBUG_OFF
394 , bool stay_quiet
395 #endif /* DBUG_OFF */
396 )
397 {
398 uint errors;
399 size_t res;
400 DBUG_ENTER("filename_to_tablename");
401 DBUG_PRINT("enter", ("from '%s'", from));
402
403 if (strlen(from) >= tmp_file_prefix_length &&
404 !memcmp(from, tmp_file_prefix, tmp_file_prefix_length))
405 {
406 /* Temporary table name. */
407 res= (strnmov(to, from, to_length) - to);
408 }
409 else
410 {
411 res= strconvert(&my_charset_filename, from,
412 system_charset_info, to, to_length, &errors);
413 if (errors) // Old 5.0 name
414 {
415 res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
416 to);
417 #ifndef DBUG_OFF
418 if (!stay_quiet) {
419 #endif /* DBUG_OFF */
420 sql_print_error("Invalid (old?) table or database name '%s'", from);
421 #ifndef DBUG_OFF
422 }
423 #endif /* DBUG_OFF */
424 /*
425 TODO: add a stored procedure for fix table and database names,
426 and mention its name in error log.
427 */
428 }
429 }
430
431 DBUG_PRINT("exit", ("to '%s'", to));
432 DBUG_RETURN(res);
433 }
434
435
436 /**
437 Check if given string begins with "#mysql50#" prefix
438
439 @param name string to check cut
440
441 @retval
442 FALSE no prefix found
443 @retval
444 TRUE prefix found
445 */
446
check_mysql50_prefix(const char * name)447 bool check_mysql50_prefix(const char *name)
448 {
449 return (name[0] == '#' &&
450 !strncmp(name, MYSQL50_TABLE_NAME_PREFIX,
451 MYSQL50_TABLE_NAME_PREFIX_LENGTH));
452 }
453
454
455 /**
456 Check if given string begins with "#mysql50#" prefix, cut it if so.
457
458 @param from string to check and cut
459 @param to[out] buffer for result string
460 @param to_length its size
461
462 @retval
463 0 no prefix found
464 @retval
465 non-0 result string length
466 */
467
check_n_cut_mysql50_prefix(const char * from,char * to,uint to_length)468 uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length)
469 {
470 if (check_mysql50_prefix(from))
471 return (uint) (strmake(to, from + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
472 to_length - 1) - to);
473 return 0;
474 }
475
476
477 /*
478 Translate a table name to a file name (WL #1324).
479
480 SYNOPSIS
481 tablename_to_filename()
482 from The table name in system_charset_info.
483 to OUT The file name in my_charset_filename.
484 to_length The size of the file name buffer.
485
486 RETURN
487 File name length.
488 */
489
tablename_to_filename(const char * from,char * to,uint to_length)490 uint tablename_to_filename(const char *from, char *to, uint to_length)
491 {
492 uint errors, length;
493 DBUG_ENTER("tablename_to_filename");
494 DBUG_PRINT("enter", ("from '%s'", from));
495
496 if ((length= check_n_cut_mysql50_prefix(from, to, to_length)))
497 {
498 /*
499 Check if the name supplied is a valid mysql 5.0 name and
500 make the name a zero length string if it's not.
501 Note that just returning zero length is not enough :
502 a lot of places don't check the return value and expect
503 a zero terminated string.
504 */
505 if (check_table_name(to, length, TRUE) != IDENT_NAME_OK)
506 {
507 to[0]= 0;
508 length= 0;
509 }
510 DBUG_RETURN(length);
511 }
512 length= strconvert(system_charset_info, from,
513 &my_charset_filename, to, to_length, &errors);
514 if (check_if_legal_tablename(to) &&
515 length + 4 < to_length)
516 {
517 memcpy(to + length, "@@@", 4);
518 length+= 3;
519 }
520 DBUG_PRINT("exit", ("to '%s'", to));
521 DBUG_RETURN(length);
522 }
523
524
525 /*
526 @brief Creates path to a file: mysql_data_dir/db/table.ext
527
528 @param buff Where to write result in my_charset_filename.
529 This may be the same as table_name.
530 @param bufflen buff size
531 @param db Database name in system_charset_info.
532 @param table_name Table name in system_charset_info.
533 @param ext File extension.
534 @param flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
535 table_name is temporary, do not change.
536 @param was_truncated points to location that will be
537 set to true if path was truncated,
538 to false otherwise.
539
540 @note
541 Uses database and table name, and extension to create
542 a file name in mysql_data_dir. Database and table
543 names are converted from system_charset_info into "fscs".
544 Unless flags indicate a temporary table name.
545 'db' is always converted.
546 'ext' is not converted.
547
548 The conversion suppression is required for ALTER TABLE. This
549 statement creates intermediate tables. These are regular
550 (non-temporary) tables with a temporary name. Their path names must
551 be derivable from the table name. So we cannot use
552 build_tmptable_filename() for them.
553
554 @return
555 path length
556 */
557
build_table_filename(char * buff,size_t bufflen,const char * db,const char * table_name,const char * ext,uint flags,bool * was_truncated)558 uint build_table_filename(char *buff, size_t bufflen, const char *db,
559 const char *table_name, const char *ext,
560 uint flags, bool *was_truncated)
561 {
562 char tbbuff[FN_REFLEN], dbbuff[FN_REFLEN];
563 uint tab_len, db_len;
564 DBUG_ENTER("build_table_filename");
565 DBUG_PRINT("enter", ("db: '%s' table_name: '%s' ext: '%s' flags: %x",
566 db, table_name, ext, flags));
567
568 if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
569 tab_len= strnmov(tbbuff, table_name, sizeof(tbbuff)) - tbbuff;
570 else
571 tab_len= tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
572
573 db_len= tablename_to_filename(db, dbbuff, sizeof(dbbuff));
574
575 char *end = buff + bufflen;
576 /* Don't add FN_ROOTDIR if mysql_data_home already includes it */
577 char *pos = strnmov(buff, mysql_data_home, bufflen);
578 size_t rootdir_len= strlen(FN_ROOTDIR);
579 if (pos - rootdir_len >= buff &&
580 memcmp(pos - rootdir_len, FN_ROOTDIR, rootdir_len) != 0)
581 pos= strnmov(pos, FN_ROOTDIR, end - pos);
582 else
583 rootdir_len= 0;
584 pos= strxnmov(pos, end - pos, dbbuff, FN_ROOTDIR, NullS);
585 #ifdef USE_SYMDIR
586 if (!(flags & SKIP_SYMDIR_ACCESS))
587 {
588 my_bool is_symdir;
589
590 unpack_dirname(buff, buff, &is_symdir);
591 /*
592 Lack of synchronization for access to symdir_warning_emitted is OK
593 as in the worst case it might result in a few extra warnings
594 printed to error log.
595 */
596 if (is_symdir && !symdir_warning_emitted)
597 {
598 symdir_warning_emitted= true;
599 sql_print_warning("Symbolic links based on .sym files are deprecated. "
600 "Please use native Windows symbolic links instead "
601 "(see MKLINK command).");
602 }
603 pos= strend(buff);
604 }
605 #endif
606 pos= strxnmov(pos, end - pos, tbbuff, ext, NullS);
607
608 /**
609 Mark OUT param if path gets truncated.
610 Most of functions which invoke this function are sure that the
611 path will not be truncated. In case some functions are not sure,
612 we can use 'was_truncated' OUTPARAM
613 */
614 *was_truncated= false;
615 if (pos == end &&
616 (bufflen < mysql_data_home_len + rootdir_len + db_len +
617 strlen(FN_ROOTDIR) + tab_len + strlen(ext)))
618 *was_truncated= true;
619
620 DBUG_PRINT("exit", ("buff: '%s'", buff));
621 DBUG_RETURN(pos - buff);
622 }
623
624
625 /**
626 Create path to a temporary table mysql_tmpdir/#sql1234_12_1
627 (i.e. to its .FRM file but without an extension).
628
629 @param thd The thread handle.
630 @param buff Where to write result in my_charset_filename.
631 @param bufflen buff size
632
633 @note
634 Uses current_pid, thread_id, and tmp_table counter to create
635 a file name in mysql_tmpdir.
636
637 @return Path length.
638 */
639
build_tmptable_filename(THD * thd,char * buff,size_t bufflen)640 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
641 {
642 DBUG_ENTER("build_tmptable_filename");
643
644 char *p= strnmov(buff, mysql_tmpdir, bufflen);
645 my_snprintf(p, bufflen - (p - buff), "/%s%lx_%lx_%x",
646 tmp_file_prefix, current_pid,
647 thd->thread_id, thd->tmp_table++);
648
649 if (lower_case_table_names)
650 {
651 /* Convert all except tmpdir to lower case */
652 my_casedn_str(files_charset_info, p);
653 }
654
655 size_t length= unpack_filename(buff, buff);
656 DBUG_PRINT("exit", ("buff: '%s'", buff));
657 DBUG_RETURN(length);
658 }
659
660 /*
661 --------------------------------------------------------------------------
662
663 MODULE: DDL log
664 -----------------
665
666 This module is used to ensure that we can recover from crashes that occur
667 in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2;
668 We need to ensure that both t1 and t2 are dropped and not only t1 and
669 also that each table drop is entirely done and not "half-baked".
670
671 To support this we create log entries for each meta-data statement in the
672 ddl log while we are executing. These entries are dropped when the
673 operation is completed.
674
675 At recovery those entries that were not completed will be executed.
676
677 There is only one ddl log in the system and it is protected by a mutex
678 and there is a global struct that contains information about its current
679 state.
680
681 History:
682 First version written in 2006 by Mikael Ronstrom
683 --------------------------------------------------------------------------
684 */
685
686 struct st_global_ddl_log
687 {
688 /*
689 We need to adjust buffer size to be able to handle downgrades/upgrades
690 where IO_SIZE has changed. We'll set the buffer size such that we can
691 handle that the buffer size was upto 4 times bigger in the version
692 that wrote the DDL log.
693 */
694 char file_entry_buf[4*IO_SIZE];
695 char file_name_str[FN_REFLEN];
696 char *file_name;
697 DDL_LOG_MEMORY_ENTRY *first_free;
698 DDL_LOG_MEMORY_ENTRY *first_used;
699 uint num_entries;
700 File file_id;
701 uint name_len;
702 uint io_size;
703 bool inited;
704 bool do_release;
705 bool recovery_phase;
st_global_ddl_logst_global_ddl_log706 st_global_ddl_log() : inited(false), do_release(false) {}
707 };
708
709 st_global_ddl_log global_ddl_log;
710
711 mysql_mutex_t LOCK_gdl;
712
713 #define DDL_LOG_ENTRY_TYPE_POS 0
714 #define DDL_LOG_ACTION_TYPE_POS 1
715 #define DDL_LOG_PHASE_POS 2
716 #define DDL_LOG_NEXT_ENTRY_POS 4
717 #define DDL_LOG_NAME_POS 8
718
719 #define DDL_LOG_NUM_ENTRY_POS 0
720 #define DDL_LOG_NAME_LEN_POS 4
721 #define DDL_LOG_IO_SIZE_POS 8
722
723 /**
724 Read one entry from ddl log file.
725
726 @param entry_no Entry number to read
727
728 @return Operation status
729 @retval true Error
730 @retval false Success
731 */
732
read_ddl_log_file_entry(uint entry_no)733 static bool read_ddl_log_file_entry(uint entry_no)
734 {
735 bool error= FALSE;
736 File file_id= global_ddl_log.file_id;
737 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
738 uint io_size= global_ddl_log.io_size;
739 DBUG_ENTER("read_ddl_log_file_entry");
740
741 mysql_mutex_assert_owner(&LOCK_gdl);
742 if (mysql_file_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
743 MYF(MY_WME)) != io_size)
744 error= TRUE;
745 DBUG_RETURN(error);
746 }
747
748
749 /**
750 Write one entry to ddl log file.
751
752 @param entry_no Entry number to write
753
754 @return Operation status
755 @retval true Error
756 @retval false Success
757 */
758
write_ddl_log_file_entry(uint entry_no)759 static bool write_ddl_log_file_entry(uint entry_no)
760 {
761 bool error= FALSE;
762 File file_id= global_ddl_log.file_id;
763 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
764 DBUG_ENTER("write_ddl_log_file_entry");
765
766 mysql_mutex_assert_owner(&LOCK_gdl);
767 if (mysql_file_pwrite(file_id, file_entry_buf,
768 IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
769 error= TRUE;
770 DBUG_RETURN(error);
771 }
772
773
774 /**
775 Sync the ddl log file.
776
777 @return Operation status
778 @retval FALSE Success
779 @retval TRUE Error
780 */
781
sync_ddl_log_file()782 static bool sync_ddl_log_file()
783 {
784 DBUG_ENTER("sync_ddl_log_file");
785 DBUG_RETURN(mysql_file_sync(global_ddl_log.file_id, MYF(MY_WME)));
786 }
787
788
789 /**
790 Write ddl log header.
791
792 @return Operation status
793 @retval TRUE Error
794 @retval FALSE Success
795 */
796
write_ddl_log_header()797 static bool write_ddl_log_header()
798 {
799 uint16 const_var;
800 DBUG_ENTER("write_ddl_log_header");
801
802 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
803 global_ddl_log.num_entries);
804 const_var= FN_REFLEN;
805 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
806 (ulong) const_var);
807 const_var= IO_SIZE;
808 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
809 (ulong) const_var);
810 if (write_ddl_log_file_entry(0UL))
811 {
812 sql_print_error("Error writing ddl log header");
813 DBUG_RETURN(TRUE);
814 }
815 DBUG_RETURN(sync_ddl_log_file());
816 }
817
818
819 /**
820 Create ddl log file name.
821 @param file_name Filename setup
822 */
823
create_ddl_log_file_name(char * file_name)824 static inline void create_ddl_log_file_name(char *file_name)
825 {
826 strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS);
827 }
828
829
830 /**
831 Read header of ddl log file.
832
833 When we read the ddl log header we get information about maximum sizes
834 of names in the ddl log and we also get information about the number
835 of entries in the ddl log.
836
837 @return Last entry in ddl log (0 if no entries)
838 */
839
read_ddl_log_header()840 static uint read_ddl_log_header()
841 {
842 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
843 char file_name[FN_REFLEN];
844 uint entry_no;
845 bool successful_open= FALSE;
846 DBUG_ENTER("read_ddl_log_header");
847
848 mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_SLOW);
849 mysql_mutex_lock(&LOCK_gdl);
850 create_ddl_log_file_name(file_name);
851 if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
852 file_name,
853 O_RDWR | O_BINARY, MYF(0))) >= 0)
854 {
855 if (read_ddl_log_file_entry(0UL))
856 {
857 /* Write message into error log */
858 sql_print_error("Failed to read ddl log file in recovery");
859 }
860 else
861 successful_open= TRUE;
862 }
863 if (successful_open)
864 {
865 entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
866 global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
867 global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
868 DBUG_ASSERT(global_ddl_log.io_size <=
869 sizeof(global_ddl_log.file_entry_buf));
870 }
871 else
872 {
873 entry_no= 0;
874 }
875 global_ddl_log.first_free= NULL;
876 global_ddl_log.first_used= NULL;
877 global_ddl_log.num_entries= 0;
878 global_ddl_log.do_release= true;
879 mysql_mutex_unlock(&LOCK_gdl);
880 DBUG_RETURN(entry_no);
881 }
882
883
884 /**
885 Convert from ddl_log_entry struct to file_entry_buf binary blob.
886
887 @param ddl_log_entry filled in ddl_log_entry struct.
888 */
889
set_global_from_ddl_log_entry(const DDL_LOG_ENTRY * ddl_log_entry)890 static void set_global_from_ddl_log_entry(const DDL_LOG_ENTRY *ddl_log_entry)
891 {
892 mysql_mutex_assert_owner(&LOCK_gdl);
893 global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]=
894 (char)DDL_LOG_ENTRY_CODE;
895 global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]=
896 (char)ddl_log_entry->action_type;
897 global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0;
898 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS],
899 ddl_log_entry->next_entry);
900 DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_REFLEN);
901 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
902 ddl_log_entry->name, FN_REFLEN - 1);
903 if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION ||
904 ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION ||
905 ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
906 {
907 DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_REFLEN);
908 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN],
909 ddl_log_entry->from_name, FN_REFLEN - 1);
910 }
911 else
912 global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN]= 0;
913 DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_REFLEN);
914 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_REFLEN)],
915 ddl_log_entry->handler_name, FN_REFLEN - 1);
916 if (ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
917 {
918 DBUG_ASSERT(strlen(ddl_log_entry->tmp_name) < FN_REFLEN);
919 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (3*FN_REFLEN)],
920 ddl_log_entry->tmp_name, FN_REFLEN - 1);
921 }
922 else
923 global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (3*FN_REFLEN)]= 0;
924 }
925
926
927 /**
928 Convert from file_entry_buf binary blob to ddl_log_entry struct.
929
930 @param[out] ddl_log_entry struct to fill in.
931
932 @note Strings (names) are pointing to the global_ddl_log structure,
933 so LOCK_gdl needs to be hold until they are read or copied.
934 */
935
set_ddl_log_entry_from_global(DDL_LOG_ENTRY * ddl_log_entry,const uint read_entry)936 static void set_ddl_log_entry_from_global(DDL_LOG_ENTRY *ddl_log_entry,
937 const uint read_entry)
938 {
939 char *file_entry_buf= (char*) global_ddl_log.file_entry_buf;
940 uint inx;
941 uchar single_char;
942
943 mysql_mutex_assert_owner(&LOCK_gdl);
944 ddl_log_entry->entry_pos= read_entry;
945 single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS];
946 ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char;
947 single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS];
948 ddl_log_entry->action_type= (enum ddl_log_action_code)single_char;
949 ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS];
950 ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]);
951 ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS];
952 inx= DDL_LOG_NAME_POS + global_ddl_log.name_len;
953 ddl_log_entry->from_name= &file_entry_buf[inx];
954 inx+= global_ddl_log.name_len;
955 ddl_log_entry->handler_name= &file_entry_buf[inx];
956 if (ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
957 {
958 inx+= global_ddl_log.name_len;
959 ddl_log_entry->tmp_name= &file_entry_buf[inx];
960 }
961 else
962 ddl_log_entry->tmp_name= NULL;
963 }
964
965
966 /**
967 Read a ddl log entry.
968
969 Read a specified entry in the ddl log.
970
971 @param read_entry Number of entry to read
972 @param[out] entry_info Information from entry
973
974 @return Operation status
975 @retval TRUE Error
976 @retval FALSE Success
977 */
978
read_ddl_log_entry(uint read_entry,DDL_LOG_ENTRY * ddl_log_entry)979 static bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
980 {
981 DBUG_ENTER("read_ddl_log_entry");
982
983 if (read_ddl_log_file_entry(read_entry))
984 {
985 DBUG_RETURN(TRUE);
986 }
987 set_ddl_log_entry_from_global(ddl_log_entry, read_entry);
988 DBUG_RETURN(FALSE);
989 }
990
991
992 /**
993 Initialise ddl log.
994
995 Write the header of the ddl log file and length of names. Also set
996 number of entries to zero.
997
998 @return Operation status
999 @retval TRUE Error
1000 @retval FALSE Success
1001 */
1002
init_ddl_log()1003 static bool init_ddl_log()
1004 {
1005 char file_name[FN_REFLEN];
1006 DBUG_ENTER("init_ddl_log");
1007
1008 if (global_ddl_log.inited)
1009 goto end;
1010
1011 global_ddl_log.io_size= IO_SIZE;
1012 global_ddl_log.name_len= FN_REFLEN;
1013 create_ddl_log_file_name(file_name);
1014 if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log,
1015 file_name, CREATE_MODE,
1016 O_RDWR | O_TRUNC | O_BINARY,
1017 MYF(MY_WME))) < 0)
1018 {
1019 /* Couldn't create ddl log file, this is serious error */
1020 sql_print_error("Failed to open ddl log file");
1021 DBUG_RETURN(TRUE);
1022 }
1023 global_ddl_log.inited= TRUE;
1024 if (write_ddl_log_header())
1025 {
1026 (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
1027 global_ddl_log.inited= FALSE;
1028 DBUG_RETURN(TRUE);
1029 }
1030
1031 end:
1032 DBUG_RETURN(FALSE);
1033 }
1034
1035
1036 /**
1037 Sync ddl log file.
1038
1039 @return Operation status
1040 @retval TRUE Error
1041 @retval FALSE Success
1042 */
1043
sync_ddl_log_no_lock()1044 static bool sync_ddl_log_no_lock()
1045 {
1046 DBUG_ENTER("sync_ddl_log_no_lock");
1047
1048 mysql_mutex_assert_owner(&LOCK_gdl);
1049 if ((!global_ddl_log.recovery_phase) &&
1050 init_ddl_log())
1051 {
1052 DBUG_RETURN(TRUE);
1053 }
1054 DBUG_RETURN(sync_ddl_log_file());
1055 }
1056
1057
1058 /**
1059 @brief Deactivate an individual entry.
1060
1061 @details For complex rename operations we need to deactivate individual
1062 entries.
1063
1064 During replace operations where we start with an existing table called
1065 t1 and a replacement table called t1#temp or something else and where
1066 we want to delete t1 and rename t1#temp to t1 this is not possible to
1067 do in a safe manner unless the ddl log is informed of the phases in
1068 the change.
1069
1070 Delete actions are 1-phase actions that can be ignored immediately after
1071 being executed.
1072 Rename actions from x to y is also a 1-phase action since there is no
1073 interaction with any other handlers named x and y.
1074 Replace action where drop y and x -> y happens needs to be a two-phase
1075 action. Thus the first phase will drop y and the second phase will
1076 rename x -> y.
1077
1078 @param entry_no Entry position of record to change
1079
1080 @return Operation status
1081 @retval TRUE Error
1082 @retval FALSE Success
1083 */
1084
deactivate_ddl_log_entry_no_lock(uint entry_no)1085 static bool deactivate_ddl_log_entry_no_lock(uint entry_no)
1086 {
1087 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
1088 DBUG_ENTER("deactivate_ddl_log_entry_no_lock");
1089
1090 mysql_mutex_assert_owner(&LOCK_gdl);
1091 if (!read_ddl_log_file_entry(entry_no))
1092 {
1093 if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
1094 {
1095 /*
1096 Log entry, if complete mark it done (IGNORE).
1097 Otherwise increase the phase by one.
1098 */
1099 if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
1100 file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
1101 (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
1102 file_entry_buf[DDL_LOG_PHASE_POS] == 1) ||
1103 (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION &&
1104 file_entry_buf[DDL_LOG_PHASE_POS] >= EXCH_PHASE_TEMP_TO_FROM))
1105 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
1106 else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
1107 {
1108 DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0);
1109 file_entry_buf[DDL_LOG_PHASE_POS]= 1;
1110 }
1111 else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION)
1112 {
1113 DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] <=
1114 EXCH_PHASE_FROM_TO_NAME);
1115 file_entry_buf[DDL_LOG_PHASE_POS]++;
1116 }
1117 else
1118 {
1119 DBUG_ASSERT(0);
1120 }
1121 if (write_ddl_log_file_entry(entry_no))
1122 {
1123 sql_print_error("Error in deactivating log entry. Position = %u",
1124 entry_no);
1125 DBUG_RETURN(TRUE);
1126 }
1127 }
1128 }
1129 else
1130 {
1131 sql_print_error("Failed in reading entry before deactivating it");
1132 DBUG_RETURN(TRUE);
1133 }
1134 DBUG_RETURN(FALSE);
1135 }
1136
1137
1138 /**
1139 Execute one action in a ddl log entry
1140
1141 @param ddl_log_entry Information in action entry to execute
1142
1143 @return Operation status
1144 @retval TRUE Error
1145 @retval FALSE Success
1146 */
1147
execute_ddl_log_action(THD * thd,DDL_LOG_ENTRY * ddl_log_entry)1148 static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
1149 {
1150 bool frm_action= FALSE;
1151 LEX_STRING handler_name;
1152 handler *file= NULL;
1153 MEM_ROOT mem_root;
1154 int error= TRUE;
1155 char to_path[FN_REFLEN];
1156 char from_path[FN_REFLEN];
1157 #ifdef WITH_PARTITION_STORAGE_ENGINE
1158 char *par_ext= (char*)".par";
1159 #endif
1160 handlerton *hton;
1161 DBUG_ENTER("execute_ddl_log_action");
1162
1163 mysql_mutex_assert_owner(&LOCK_gdl);
1164 if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE)
1165 {
1166 DBUG_RETURN(FALSE);
1167 }
1168 DBUG_PRINT("ddl_log",
1169 ("execute type %c next %u name '%s' from_name '%s' handler '%s'"
1170 " tmp_name '%s'",
1171 ddl_log_entry->action_type,
1172 ddl_log_entry->next_entry,
1173 ddl_log_entry->name,
1174 ddl_log_entry->from_name,
1175 ddl_log_entry->handler_name,
1176 ddl_log_entry->tmp_name));
1177 handler_name.str= (char*)ddl_log_entry->handler_name;
1178 handler_name.length= strlen(ddl_log_entry->handler_name);
1179 init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
1180 if (!strcmp(ddl_log_entry->handler_name, reg_ext))
1181 frm_action= TRUE;
1182 else
1183 {
1184 plugin_ref plugin= ha_resolve_by_name(thd, &handler_name, FALSE);
1185 if (!plugin)
1186 {
1187 my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name);
1188 goto error;
1189 }
1190 hton= plugin_data(plugin, handlerton*);
1191 file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
1192 if (!file)
1193 {
1194 mem_alloc_error(sizeof(handler));
1195 goto error;
1196 }
1197 }
1198 switch (ddl_log_entry->action_type)
1199 {
1200 case DDL_LOG_REPLACE_ACTION:
1201 case DDL_LOG_DELETE_ACTION:
1202 {
1203 if (ddl_log_entry->phase == 0)
1204 {
1205 if (frm_action)
1206 {
1207 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
1208 if ((error= mysql_file_delete(key_file_frm, to_path, MYF(MY_WME))))
1209 {
1210 if (my_errno != ENOENT)
1211 break;
1212 }
1213 #ifdef WITH_PARTITION_STORAGE_ENGINE
1214 strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
1215 (void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME));
1216 #endif
1217 }
1218 else
1219 {
1220 if ((error= file->ha_delete_table(ddl_log_entry->name)))
1221 {
1222 if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE)
1223 break;
1224 }
1225 }
1226 if ((deactivate_ddl_log_entry_no_lock(ddl_log_entry->entry_pos)))
1227 break;
1228 (void) sync_ddl_log_no_lock();
1229 error= FALSE;
1230 if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
1231 break;
1232 }
1233 DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
1234 /*
1235 Fall through and perform the rename action of the replace
1236 action. We have already indicated the success of the delete
1237 action in the log entry by stepping up the phase.
1238 */
1239 }
1240 case DDL_LOG_RENAME_ACTION:
1241 {
1242 error= TRUE;
1243 if (frm_action)
1244 {
1245 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
1246 strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
1247 if (mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME)))
1248 break;
1249 #ifdef WITH_PARTITION_STORAGE_ENGINE
1250 strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
1251 strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS);
1252 (void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME));
1253 #endif
1254 }
1255 else
1256 {
1257 if (file->ha_rename_table(ddl_log_entry->from_name,
1258 ddl_log_entry->name))
1259 break;
1260 }
1261 if ((deactivate_ddl_log_entry_no_lock(ddl_log_entry->entry_pos)))
1262 break;
1263 (void) sync_ddl_log_no_lock();
1264 error= FALSE;
1265 break;
1266 }
1267 case DDL_LOG_EXCHANGE_ACTION:
1268 {
1269 /* We hold LOCK_gdl, so we can alter global_ddl_log.file_entry_buf */
1270 char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf;
1271 /* not yet implemented for frm */
1272 DBUG_ASSERT(!frm_action);
1273 /*
1274 Using a case-switch here to revert all currently done phases,
1275 since it will fall through until the first phase is undone.
1276 */
1277 switch (ddl_log_entry->phase) {
1278 case EXCH_PHASE_TEMP_TO_FROM:
1279 /* tmp_name -> from_name possibly done */
1280 (void) file->ha_rename_table(ddl_log_entry->from_name,
1281 ddl_log_entry->tmp_name);
1282 /* decrease the phase and sync */
1283 file_entry_buf[DDL_LOG_PHASE_POS]--;
1284 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1285 break;
1286 if (sync_ddl_log_no_lock())
1287 break;
1288 /* fall through */
1289 case EXCH_PHASE_FROM_TO_NAME:
1290 /* from_name -> name possibly done */
1291 (void) file->ha_rename_table(ddl_log_entry->name,
1292 ddl_log_entry->from_name);
1293 /* decrease the phase and sync */
1294 file_entry_buf[DDL_LOG_PHASE_POS]--;
1295 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1296 break;
1297 if (sync_ddl_log_no_lock())
1298 break;
1299 /* fall through */
1300 case EXCH_PHASE_NAME_TO_TEMP:
1301 /* name -> tmp_name possibly done */
1302 (void) file->ha_rename_table(ddl_log_entry->tmp_name,
1303 ddl_log_entry->name);
1304 /* disable the entry and sync */
1305 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
1306 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1307 break;
1308 if (sync_ddl_log_no_lock())
1309 break;
1310 error= FALSE;
1311 break;
1312 default:
1313 DBUG_ASSERT(0);
1314 break;
1315 }
1316
1317 break;
1318 }
1319 default:
1320 DBUG_ASSERT(0);
1321 break;
1322 }
1323 delete file;
1324 error:
1325 free_root(&mem_root, MYF(0));
1326 DBUG_RETURN(error);
1327 }
1328
1329
1330 /**
1331 Get a free entry in the ddl log
1332
1333 @param[out] active_entry A ddl log memory entry returned
1334
1335 @return Operation status
1336 @retval TRUE Error
1337 @retval FALSE Success
1338 */
1339
get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY ** active_entry,bool * write_header)1340 static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
1341 bool *write_header)
1342 {
1343 DDL_LOG_MEMORY_ENTRY *used_entry;
1344 DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used;
1345 DBUG_ENTER("get_free_ddl_log_entry");
1346
1347 if (global_ddl_log.first_free == NULL)
1348 {
1349 if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(
1350 sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
1351 {
1352 sql_print_error("Failed to allocate memory for ddl log free list");
1353 DBUG_RETURN(TRUE);
1354 }
1355 global_ddl_log.num_entries++;
1356 used_entry->entry_pos= global_ddl_log.num_entries;
1357 *write_header= TRUE;
1358 }
1359 else
1360 {
1361 used_entry= global_ddl_log.first_free;
1362 global_ddl_log.first_free= used_entry->next_log_entry;
1363 *write_header= FALSE;
1364 }
1365 /*
1366 Move from free list to used list
1367 */
1368 used_entry->next_log_entry= first_used;
1369 used_entry->prev_log_entry= NULL;
1370 used_entry->next_active_log_entry= NULL;
1371 global_ddl_log.first_used= used_entry;
1372 if (first_used)
1373 first_used->prev_log_entry= used_entry;
1374
1375 *active_entry= used_entry;
1376 DBUG_RETURN(FALSE);
1377 }
1378
1379
1380 /**
1381 Execute one entry in the ddl log.
1382
1383 Executing an entry means executing a linked list of actions.
1384
1385 @param first_entry Reference to first action in entry
1386
1387 @return Operation status
1388 @retval TRUE Error
1389 @retval FALSE Success
1390 */
1391
execute_ddl_log_entry_no_lock(THD * thd,uint first_entry)1392 static bool execute_ddl_log_entry_no_lock(THD *thd, uint first_entry)
1393 {
1394 DDL_LOG_ENTRY ddl_log_entry;
1395 uint read_entry= first_entry;
1396 DBUG_ENTER("execute_ddl_log_entry_no_lock");
1397
1398 mysql_mutex_assert_owner(&LOCK_gdl);
1399 do
1400 {
1401 if (read_ddl_log_entry(read_entry, &ddl_log_entry))
1402 {
1403 /* Write to error log and continue with next log entry */
1404 sql_print_error("Failed to read entry = %u from ddl log",
1405 read_entry);
1406 break;
1407 }
1408 DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE ||
1409 ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE);
1410
1411 if (execute_ddl_log_action(thd, &ddl_log_entry))
1412 {
1413 /* Write to error log and continue with next log entry */
1414 sql_print_error("Failed to execute action for entry = %u from ddl log",
1415 read_entry);
1416 break;
1417 }
1418 read_entry= ddl_log_entry.next_entry;
1419 } while (read_entry);
1420 DBUG_RETURN(FALSE);
1421 }
1422
1423
1424 /*
1425 External interface methods for the DDL log Module
1426 ---------------------------------------------------
1427 */
1428
1429 /**
1430 Write a ddl log entry.
1431
1432 A careful write of the ddl log is performed to ensure that we can
1433 handle crashes occurring during CREATE and ALTER TABLE processing.
1434
1435 @param ddl_log_entry Information about log entry
1436 @param[out] entry_written Entry information written into
1437
1438 @return Operation status
1439 @retval TRUE Error
1440 @retval FALSE Success
1441 */
1442
write_ddl_log_entry(DDL_LOG_ENTRY * ddl_log_entry,DDL_LOG_MEMORY_ENTRY ** active_entry)1443 bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
1444 DDL_LOG_MEMORY_ENTRY **active_entry)
1445 {
1446 bool error, write_header;
1447 DBUG_ENTER("write_ddl_log_entry");
1448
1449 mysql_mutex_assert_owner(&LOCK_gdl);
1450 if (init_ddl_log())
1451 {
1452 DBUG_RETURN(TRUE);
1453 }
1454 set_global_from_ddl_log_entry(ddl_log_entry);
1455 if (get_free_ddl_log_entry(active_entry, &write_header))
1456 {
1457 DBUG_RETURN(TRUE);
1458 }
1459 error= FALSE;
1460 DBUG_PRINT("ddl_log",
1461 ("write type %c next %u name '%s' from_name '%s' handler '%s'"
1462 " tmp_name '%s'",
1463 (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS],
1464 ddl_log_entry->next_entry,
1465 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
1466 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1467 + FN_REFLEN],
1468 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1469 + (2*FN_REFLEN)],
1470 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1471 + (3*FN_REFLEN)]));
1472 if (write_ddl_log_file_entry((*active_entry)->entry_pos))
1473 {
1474 error= TRUE;
1475 sql_print_error("Failed to write entry_no = %u",
1476 (*active_entry)->entry_pos);
1477 }
1478 if (write_header && !error)
1479 {
1480 (void) sync_ddl_log_no_lock();
1481 if (write_ddl_log_header())
1482 error= TRUE;
1483 }
1484 if (error)
1485 release_ddl_log_memory_entry(*active_entry);
1486 DBUG_RETURN(error);
1487 }
1488
1489
1490 /**
1491 @brief Write final entry in the ddl log.
1492
1493 @details This is the last write in the ddl log. The previous log entries
1494 have already been written but not yet synched to disk.
1495 We write a couple of log entries that describes action to perform.
1496 This entries are set-up in a linked list, however only when a first
1497 execute entry is put as the first entry these will be executed.
1498 This routine writes this first.
1499
1500 @param first_entry First entry in linked list of entries
1501 to execute, if 0 = NULL it means that
1502 the entry is removed and the entries
1503 are put into the free list.
1504 @param complete Flag indicating we are simply writing
1505 info about that entry has been completed
1506 @param[in,out] active_entry Entry to execute, 0 = NULL if the entry
1507 is written first time and needs to be
1508 returned. In this case the entry written
1509 is returned in this parameter
1510
1511 @return Operation status
1512 @retval TRUE Error
1513 @retval FALSE Success
1514 */
1515
write_execute_ddl_log_entry(uint first_entry,bool complete,DDL_LOG_MEMORY_ENTRY ** active_entry)1516 bool write_execute_ddl_log_entry(uint first_entry,
1517 bool complete,
1518 DDL_LOG_MEMORY_ENTRY **active_entry)
1519 {
1520 bool write_header= FALSE;
1521 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
1522 DBUG_ENTER("write_execute_ddl_log_entry");
1523
1524 mysql_mutex_assert_owner(&LOCK_gdl);
1525 if (init_ddl_log())
1526 {
1527 DBUG_RETURN(TRUE);
1528 }
1529 if (!complete)
1530 {
1531 /*
1532 We haven't synched the log entries yet, we synch them now before
1533 writing the execute entry. If complete is true we haven't written
1534 any log entries before, we are only here to write the execute
1535 entry to indicate it is done.
1536 */
1537 (void) sync_ddl_log_no_lock();
1538 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
1539 }
1540 else
1541 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE;
1542 file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */
1543 file_entry_buf[DDL_LOG_PHASE_POS]= 0;
1544 int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry);
1545 file_entry_buf[DDL_LOG_NAME_POS]= 0;
1546 file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN]= 0;
1547 file_entry_buf[DDL_LOG_NAME_POS + 2*FN_REFLEN]= 0;
1548 if (!(*active_entry))
1549 {
1550 if (get_free_ddl_log_entry(active_entry, &write_header))
1551 {
1552 DBUG_RETURN(TRUE);
1553 }
1554 write_header= TRUE;
1555 }
1556 if (write_ddl_log_file_entry((*active_entry)->entry_pos))
1557 {
1558 sql_print_error("Error writing execute entry in ddl log");
1559 release_ddl_log_memory_entry(*active_entry);
1560 DBUG_RETURN(TRUE);
1561 }
1562 (void) sync_ddl_log_no_lock();
1563 if (write_header)
1564 {
1565 if (write_ddl_log_header())
1566 {
1567 release_ddl_log_memory_entry(*active_entry);
1568 DBUG_RETURN(TRUE);
1569 }
1570 }
1571 DBUG_RETURN(FALSE);
1572 }
1573
1574
1575 /**
1576 Deactivate an individual entry.
1577
1578 @details see deactivate_ddl_log_entry_no_lock.
1579
1580 @param entry_no Entry position of record to change
1581
1582 @return Operation status
1583 @retval TRUE Error
1584 @retval FALSE Success
1585 */
1586
deactivate_ddl_log_entry(uint entry_no)1587 bool deactivate_ddl_log_entry(uint entry_no)
1588 {
1589 bool error;
1590 DBUG_ENTER("deactivate_ddl_log_entry");
1591
1592 mysql_mutex_lock(&LOCK_gdl);
1593 error= deactivate_ddl_log_entry_no_lock(entry_no);
1594 mysql_mutex_unlock(&LOCK_gdl);
1595 DBUG_RETURN(error);
1596 }
1597
1598
1599 /**
1600 Sync ddl log file.
1601
1602 @return Operation status
1603 @retval TRUE Error
1604 @retval FALSE Success
1605 */
1606
sync_ddl_log()1607 bool sync_ddl_log()
1608 {
1609 bool error;
1610 DBUG_ENTER("sync_ddl_log");
1611
1612 mysql_mutex_lock(&LOCK_gdl);
1613 error= sync_ddl_log_no_lock();
1614 mysql_mutex_unlock(&LOCK_gdl);
1615
1616 DBUG_RETURN(error);
1617 }
1618
1619
1620 /**
1621 Release a log memory entry.
1622 @param log_memory_entry Log memory entry to release
1623 */
1624
release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY * log_entry)1625 void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry)
1626 {
1627 DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free;
1628 DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry;
1629 DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry;
1630 DBUG_ENTER("release_ddl_log_memory_entry");
1631
1632 mysql_mutex_assert_owner(&LOCK_gdl);
1633 global_ddl_log.first_free= log_entry;
1634 log_entry->next_log_entry= first_free;
1635
1636 if (prev_log_entry)
1637 prev_log_entry->next_log_entry= next_log_entry;
1638 else
1639 global_ddl_log.first_used= next_log_entry;
1640 if (next_log_entry)
1641 next_log_entry->prev_log_entry= prev_log_entry;
1642 DBUG_VOID_RETURN;
1643 }
1644
1645
1646 /**
1647 Execute one entry in the ddl log.
1648
1649 Executing an entry means executing a linked list of actions.
1650
1651 @param first_entry Reference to first action in entry
1652
1653 @return Operation status
1654 @retval TRUE Error
1655 @retval FALSE Success
1656 */
1657
execute_ddl_log_entry(THD * thd,uint first_entry)1658 bool execute_ddl_log_entry(THD *thd, uint first_entry)
1659 {
1660 bool error;
1661 DBUG_ENTER("execute_ddl_log_entry");
1662
1663 mysql_mutex_lock(&LOCK_gdl);
1664 error= execute_ddl_log_entry_no_lock(thd, first_entry);
1665 mysql_mutex_unlock(&LOCK_gdl);
1666 DBUG_RETURN(error);
1667 }
1668
1669
1670 /**
1671 Close the ddl log.
1672 */
1673
close_ddl_log()1674 static void close_ddl_log()
1675 {
1676 DBUG_ENTER("close_ddl_log");
1677 if (global_ddl_log.file_id >= 0)
1678 {
1679 (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
1680 global_ddl_log.file_id= (File) -1;
1681 }
1682 DBUG_VOID_RETURN;
1683 }
1684
1685
1686 /**
1687 Execute the ddl log at recovery of MySQL Server.
1688 */
1689
execute_ddl_log_recovery()1690 void execute_ddl_log_recovery()
1691 {
1692 uint num_entries, i;
1693 THD *thd;
1694 DDL_LOG_ENTRY ddl_log_entry;
1695 char file_name[FN_REFLEN];
1696 static char recover_query_string[]= "INTERNAL DDL LOG RECOVER IN PROGRESS";
1697 DBUG_ENTER("execute_ddl_log_recovery");
1698
1699 /*
1700 Initialise global_ddl_log struct
1701 */
1702 memset(global_ddl_log.file_entry_buf, 0, sizeof(global_ddl_log.file_entry_buf));
1703 global_ddl_log.inited= FALSE;
1704 global_ddl_log.recovery_phase= TRUE;
1705 global_ddl_log.io_size= IO_SIZE;
1706 global_ddl_log.file_id= (File) -1;
1707
1708 /*
1709 To be able to run this from boot, we allocate a temporary THD
1710 */
1711 if (!(thd=new THD))
1712 DBUG_VOID_RETURN;
1713 thd->thread_stack= (char*) &thd;
1714 thd->store_globals();
1715
1716 thd->set_query(recover_query_string, strlen(recover_query_string));
1717
1718 /* this also initialize LOCK_gdl */
1719 num_entries= read_ddl_log_header();
1720 mysql_mutex_lock(&LOCK_gdl);
1721 for (i= 1; i < num_entries + 1; i++)
1722 {
1723 if (read_ddl_log_entry(i, &ddl_log_entry))
1724 {
1725 sql_print_error("Failed to read entry no = %u from ddl log", i);
1726 continue;
1727 }
1728 if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE)
1729 {
1730 if (execute_ddl_log_entry_no_lock(thd, ddl_log_entry.next_entry))
1731 {
1732 /* Real unpleasant scenario but we continue anyways. */
1733 continue;
1734 }
1735 }
1736 }
1737 close_ddl_log();
1738 create_ddl_log_file_name(file_name);
1739 (void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0));
1740 global_ddl_log.recovery_phase= FALSE;
1741 mysql_mutex_unlock(&LOCK_gdl);
1742 thd->reset_query();
1743 delete thd;
1744 /* Remember that we don't have a THD */
1745 my_pthread_setspecific_ptr(THR_THD, 0);
1746 DBUG_VOID_RETURN;
1747 }
1748
1749
1750 /**
1751 Release all memory allocated to the ddl log.
1752 */
1753
release_ddl_log()1754 void release_ddl_log()
1755 {
1756 DDL_LOG_MEMORY_ENTRY *free_list;
1757 DDL_LOG_MEMORY_ENTRY *used_list;
1758 DBUG_ENTER("release_ddl_log");
1759
1760 if (!global_ddl_log.do_release)
1761 DBUG_VOID_RETURN;
1762
1763 mysql_mutex_lock(&LOCK_gdl);
1764 free_list= global_ddl_log.first_free;
1765 used_list= global_ddl_log.first_used;
1766 while (used_list)
1767 {
1768 DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
1769 my_free(used_list);
1770 used_list= tmp;
1771 }
1772 while (free_list)
1773 {
1774 DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
1775 my_free(free_list);
1776 free_list= tmp;
1777 }
1778 close_ddl_log();
1779 global_ddl_log.inited= 0;
1780 mysql_mutex_unlock(&LOCK_gdl);
1781 mysql_mutex_destroy(&LOCK_gdl);
1782 global_ddl_log.do_release= false;
1783 DBUG_VOID_RETURN;
1784 }
1785
1786
1787 /*
1788 ---------------------------------------------------------------------------
1789
1790 END MODULE DDL log
1791 --------------------
1792
1793 ---------------------------------------------------------------------------
1794 */
1795
1796
1797 /**
1798 @brief construct a temporary shadow file name.
1799
1800 @details Make a shadow file name used by ALTER TABLE to construct the
1801 modified table (with keeping the original). The modified table is then
1802 moved back as original table. The name must start with the temp file
1803 prefix so it gets filtered out by table files listing routines.
1804
1805 @param[out] buff buffer to receive the constructed name
1806 @param bufflen size of buff
1807 @param lpt alter table data structure
1808
1809 @retval path length
1810 */
1811
build_table_shadow_filename(char * buff,size_t bufflen,ALTER_PARTITION_PARAM_TYPE * lpt)1812 uint build_table_shadow_filename(char *buff, size_t bufflen,
1813 ALTER_PARTITION_PARAM_TYPE *lpt)
1814 {
1815 char tmp_name[FN_REFLEN];
1816 my_snprintf (tmp_name, sizeof (tmp_name), "%s-%s", tmp_file_prefix,
1817 lpt->table_name);
1818 return build_table_filename(buff, bufflen, lpt->db, tmp_name, "", FN_IS_TMP);
1819 }
1820
1821
1822 /*
1823 SYNOPSIS
1824 mysql_write_frm()
1825 lpt Struct carrying many parameters needed for this
1826 method
1827 flags Flags as defined below
1828 WFRM_INITIAL_WRITE If set we need to prepare table before
1829 creating the frm file
1830 WFRM_INSTALL_SHADOW If set we should install the new frm
1831 WFRM_KEEP_SHARE If set we know that the share is to be
1832 retained and thus we should ensure share
1833 object is correct, if not set we don't
1834 set the new partition syntax string since
1835 we know the share object is destroyed.
1836 WFRM_PACK_FRM If set we should pack the frm file and delete
1837 the frm file
1838
1839 RETURN VALUES
1840 TRUE Error
1841 FALSE Success
1842
1843 DESCRIPTION
1844 A support method that creates a new frm file and in this process it
1845 regenerates the partition data. It works fine also for non-partitioned
1846 tables since it only handles partitioned data if it exists.
1847 */
1848
mysql_write_frm(ALTER_PARTITION_PARAM_TYPE * lpt,uint flags)1849 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
1850 {
1851 /*
1852 Prepare table to prepare for writing a new frm file where the
1853 partitions in add/drop state have temporarily changed their state
1854 We set tmp_table to avoid get errors on naming of primary key index.
1855 */
1856 int error= 0;
1857 char path[FN_REFLEN+1];
1858 char shadow_path[FN_REFLEN+1];
1859 char shadow_frm_name[FN_REFLEN+1];
1860 char frm_name[FN_REFLEN+1];
1861 #ifdef WITH_PARTITION_STORAGE_ENGINE
1862 char *part_syntax_buf;
1863 uint syntax_len;
1864 partition_info *old_part_info= lpt->table->part_info;
1865 #endif
1866 DBUG_ENTER("mysql_write_frm");
1867
1868 /*
1869 Build shadow frm file name
1870 */
1871 build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
1872 strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
1873 if (flags & WFRM_WRITE_SHADOW)
1874 {
1875 if (mysql_prepare_create_table(lpt->thd, lpt->db,
1876 lpt->table_name,
1877 lpt->create_info,
1878 lpt->alter_info,
1879 /*tmp_table*/ 1,
1880 &lpt->db_options,
1881 lpt->table->file,
1882 &lpt->key_info_buffer,
1883 &lpt->key_count,
1884 /*select_field_count*/ 0))
1885 {
1886 DBUG_RETURN(TRUE);
1887 }
1888 #ifdef WITH_PARTITION_STORAGE_ENGINE
1889 {
1890 partition_info *part_info= lpt->part_info;
1891 if (part_info)
1892 {
1893 if (!(part_syntax_buf= generate_partition_syntax(part_info,
1894 &syntax_len,
1895 TRUE, TRUE,
1896 lpt->create_info,
1897 lpt->alter_info,
1898 NULL)))
1899 {
1900 DBUG_RETURN(TRUE);
1901 }
1902 part_info->part_info_string= part_syntax_buf;
1903 part_info->part_info_len= syntax_len;
1904 lpt->table->file->set_part_info(part_info, false);
1905 }
1906 }
1907 #endif
1908 /* Write shadow frm file */
1909 lpt->create_info->table_options= lpt->db_options;
1910 if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
1911 lpt->table_name, lpt->create_info,
1912 lpt->alter_info->create_list, lpt->key_count,
1913 lpt->key_info_buffer, lpt->table->file)) ||
1914 lpt->table->file->ha_create_handler_files(shadow_path, NULL,
1915 CHF_CREATE_FLAG,
1916 lpt->create_info))
1917 {
1918 mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
1919 error= 1;
1920 goto end;
1921 }
1922 }
1923 if (flags & WFRM_PACK_FRM)
1924 {
1925 /*
1926 We need to pack the frm file and after packing it we delete the
1927 frm file to ensure it doesn't get used. This is only used for
1928 handlers that have the main version of the frm file stored in the
1929 handler.
1930 */
1931 uchar *data;
1932 size_t length;
1933 if (readfrm(shadow_path, &data, &length) ||
1934 packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
1935 {
1936 my_free(data);
1937 my_free(lpt->pack_frm_data);
1938 mem_alloc_error(length);
1939 error= 1;
1940 goto end;
1941 }
1942 error= mysql_file_delete(key_file_frm, shadow_frm_name, MYF(MY_WME));
1943 }
1944 if (flags & WFRM_INSTALL_SHADOW)
1945 {
1946 #ifdef WITH_PARTITION_STORAGE_ENGINE
1947 partition_info *part_info= lpt->part_info;
1948 if (part_info)
1949 {
1950 lpt->table->file->set_part_info(part_info, false);
1951 }
1952 #endif
1953 /*
1954 Build frm file name
1955 */
1956 build_table_filename(path, sizeof(path) - 1, lpt->db,
1957 lpt->table_name, "", 0);
1958 strxmov(frm_name, path, reg_ext, NullS);
1959 /*
1960 When we are changing to use new frm file we need to ensure that we
1961 don't collide with another thread in process to open the frm file.
1962 We start by deleting the .frm file and possible .par file. Then we
1963 write to the DDL log that we have completed the delete phase by
1964 increasing the phase of the log entry. Next step is to rename the
1965 new .frm file and the new .par file to the real name. After
1966 completing this we write a new phase to the log entry that will
1967 deactivate it.
1968 */
1969 if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
1970 #ifdef WITH_PARTITION_STORAGE_ENGINE
1971 lpt->table->file->ha_create_handler_files(path, shadow_path,
1972 CHF_DELETE_FLAG, NULL) ||
1973 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
1974 (sync_ddl_log(), FALSE) ||
1975 mysql_file_rename(key_file_frm,
1976 shadow_frm_name, frm_name, MYF(MY_WME)) ||
1977 lpt->table->file->ha_create_handler_files(path, shadow_path,
1978 CHF_RENAME_FLAG, NULL))
1979 #else
1980 mysql_file_rename(key_file_frm,
1981 shadow_frm_name, frm_name, MYF(MY_WME)))
1982 #endif
1983 {
1984 error= 1;
1985 goto err;
1986 }
1987 #ifdef WITH_PARTITION_STORAGE_ENGINE
1988 if (part_info && (flags & WFRM_KEEP_SHARE))
1989 {
1990 TABLE_SHARE *share= lpt->table->s;
1991 char *tmp_part_syntax_str;
1992 if (!(part_syntax_buf= generate_partition_syntax(part_info,
1993 &syntax_len,
1994 TRUE, TRUE,
1995 lpt->create_info,
1996 lpt->alter_info,
1997 NULL)))
1998 {
1999 error= 1;
2000 goto err;
2001 }
2002 if (share->partition_info_buffer_size < syntax_len + 1)
2003 {
2004 share->partition_info_buffer_size= syntax_len+1;
2005 if (!(tmp_part_syntax_str= (char*) strmake_root(&share->mem_root,
2006 part_syntax_buf,
2007 syntax_len)))
2008 {
2009 error= 1;
2010 goto err;
2011 }
2012 share->partition_info_str= tmp_part_syntax_str;
2013 }
2014 else
2015 memcpy((char*) share->partition_info_str, part_syntax_buf,
2016 syntax_len + 1);
2017 share->partition_info_str_len= part_info->part_info_len= syntax_len;
2018 part_info->part_info_string= part_syntax_buf;
2019 }
2020 #endif
2021
2022 err:
2023 #ifdef WITH_PARTITION_STORAGE_ENGINE
2024 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
2025 part_info->frm_log_entry= NULL;
2026 (void) sync_ddl_log();
2027 #endif
2028 ;
2029 }
2030
2031 end:
2032 if (old_part_info)
2033 {
2034 lpt->table->file->set_part_info(old_part_info, false);
2035 }
2036 DBUG_RETURN(error);
2037 }
2038
2039
2040 /*
2041 SYNOPSIS
2042 write_bin_log()
2043 thd Thread object
2044 clear_error is clear_error to be called
2045 query Query to log
2046 query_length Length of query
2047 is_trans if the event changes either
2048 a trans or non-trans engine.
2049
2050 RETURN VALUES
2051 NONE
2052
2053 DESCRIPTION
2054 Write the binlog if open, routine used in multiple places in this
2055 file
2056 */
2057
write_bin_log(THD * thd,bool clear_error,char const * query,ulong query_length,bool is_trans)2058 int write_bin_log(THD *thd, bool clear_error,
2059 char const *query, ulong query_length, bool is_trans)
2060 {
2061 int error= 0;
2062 if (mysql_bin_log.is_open())
2063 {
2064 int errcode= 0;
2065 if (clear_error)
2066 thd->clear_error();
2067 else
2068 errcode= query_error_code(thd, TRUE);
2069 error= thd->binlog_query(THD::STMT_QUERY_TYPE,
2070 query, query_length, is_trans, FALSE, FALSE,
2071 errcode);
2072 }
2073 return error;
2074 }
2075
2076
2077 /*
2078 delete (drop) tables.
2079
2080 SYNOPSIS
2081 mysql_rm_table()
2082 thd Thread handle
2083 tables List of tables to delete
2084 if_exists If 1, don't give error if one table doesn't exists
2085
2086 NOTES
2087 Will delete all tables that can be deleted and give a compact error
2088 messages for tables that could not be deleted.
2089 If a table is in use, we will wait for all users to free the table
2090 before dropping it
2091
2092 Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but
2093 not if under LOCK TABLES.
2094
2095 RETURN
2096 FALSE OK. In this case ok packet is sent to user
2097 TRUE Error
2098
2099 */
2100
mysql_rm_table(THD * thd,TABLE_LIST * tables,my_bool if_exists,my_bool drop_temporary)2101 bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
2102 my_bool drop_temporary)
2103 {
2104 bool error;
2105 Drop_table_error_handler err_handler;
2106 TABLE_LIST *table;
2107 /*
2108 The following flags will be used to check if this statement will be split
2109 */
2110 uint have_non_tmp_table= 0;
2111 uint have_trans_tmp_table= 0;
2112 uint have_non_trans_tmp_table= 0;
2113
2114 DBUG_ENTER("mysql_rm_table");
2115
2116 /* Disable drop of enabled log tables, must be done before name locking */
2117 for (table= tables; table; table= table->next_local)
2118 {
2119 if (check_if_log_table(table->db_length, table->db,
2120 table->table_name_length, table->table_name, true))
2121 {
2122 my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
2123 DBUG_RETURN(true);
2124 }
2125 /*
2126 Here we are sure that the tmp table exists and will set the flag based on
2127 table transactional type.
2128 */
2129 if (is_temporary_table(table))
2130 {
2131 if (table->table->s->tmp_table == TRANSACTIONAL_TMP_TABLE)
2132 have_trans_tmp_table= 1;
2133 else if (table->table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
2134 have_non_trans_tmp_table= 1;
2135 }
2136 }
2137
2138 if (!drop_temporary)
2139 {
2140 if (!thd->locked_tables_mode)
2141 {
2142 if (lock_table_names(thd, tables, NULL,
2143 thd->variables.lock_wait_timeout, 0))
2144 DBUG_RETURN(true);
2145 for (table= tables; table; table= table->next_local)
2146 {
2147 if (is_temporary_table(table))
2148 continue;
2149
2150 tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
2151 false);
2152 /* Here we are sure that a non-tmp table exists */
2153 have_non_tmp_table= 1;
2154 }
2155 }
2156 else
2157 {
2158 for (table= tables; table; table= table->next_local)
2159 if (is_temporary_table(table))
2160 {
2161 /*
2162 A temporary table.
2163
2164 Don't try to find a corresponding MDL lock or assign it
2165 to table->mdl_request.ticket. There can't be metadata
2166 locks for temporary tables: they are local to the session.
2167
2168 Later in this function we release the MDL lock only if
2169 table->mdl_requeset.ticket is not NULL. Thus here we
2170 ensure that we won't release the metadata lock on the base
2171 table locked with LOCK TABLES as a side effect of temporary
2172 table drop.
2173 */
2174 DBUG_ASSERT(table->mdl_request.ticket == NULL);
2175 }
2176 else
2177 {
2178 /*
2179 Not a temporary table.
2180
2181 Since 'tables' list can't contain duplicates (this is ensured
2182 by parser) it is safe to cache pointer to the TABLE instances
2183 in its elements.
2184 */
2185 table->table= find_table_for_mdl_upgrade(thd, table->db,
2186 table->table_name, false);
2187 if (!table->table)
2188 DBUG_RETURN(true);
2189 table->mdl_request.ticket= table->table->mdl_ticket;
2190 /* Here we are sure that a non-tmp table exists */
2191 have_non_tmp_table= 1;
2192 }
2193 }
2194 }
2195
2196 /*
2197 DROP TABLE statements mixing non-temporary and temporary tables or
2198 transactional and non-transactional temporary tables are unsafe to execute
2199 if GTID_NEXT is set to GTID_GROUP because these statements will be split to
2200 be sent to binlog and there is only one GTID is available to log multiple
2201 statements.
2202 See comments in the beginning of mysql_rm_table_no_locks() for more info.
2203 */
2204 if (thd->variables.gtid_next.type == GTID_GROUP &&
2205 (have_non_tmp_table + have_trans_tmp_table +
2206 have_non_trans_tmp_table > 1))
2207 {
2208 DBUG_PRINT("err",("have_non_tmp_table: %d, have_trans_tmp_table: %d, "
2209 "have_non_trans_tmp_table: %d", have_non_tmp_table,
2210 have_trans_tmp_table, have_non_trans_tmp_table));
2211 my_error(ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_GTID_GROUP, MYF(0));
2212 DBUG_RETURN(true);
2213 }
2214
2215 /* mark for close and remove all cached entries */
2216 thd->push_internal_handler(&err_handler);
2217 error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
2218 false, false);
2219 thd->pop_internal_handler();
2220
2221 if (error)
2222 DBUG_RETURN(TRUE);
2223 my_ok(thd);
2224 DBUG_RETURN(FALSE);
2225
2226 }
2227
2228 /**
2229 Execute the drop of a normal or temporary table.
2230
2231 @param thd Thread handler
2232 @param tables Tables to drop
2233 @param if_exists If set, don't give an error if table doesn't exists.
2234 In this case we give an warning of level 'NOTE'
2235 @param drop_temporary Only drop temporary tables
2236 @param drop_view Allow to delete VIEW .frm
2237 @param dont_log_query Don't write query to log files. This will also not
2238 generate warnings if the handler files doesn't exists
2239
2240 @retval 0 ok
2241 @retval 1 Error
2242 @retval -1 Thread was killed
2243
2244 @note This function assumes that metadata locks have already been taken.
2245 It is also assumed that the tables have been removed from TDC.
2246
2247 @note This function assumes that temporary tables to be dropped have
2248 been pre-opened using corresponding table list elements.
2249
2250 @todo When logging to the binary log, we should log
2251 tmp_tables and transactional tables as separate statements if we
2252 are in a transaction; This is needed to get these tables into the
2253 cached binary log that is only written on COMMIT.
2254 The current code only writes DROP statements that only uses temporary
2255 tables to the cache binary log. This should be ok on most cases, but
2256 not all.
2257 */
2258
mysql_rm_table_no_locks(THD * thd,TABLE_LIST * tables,bool if_exists,bool drop_temporary,bool drop_view,bool dont_log_query)2259 int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
2260 bool drop_temporary, bool drop_view,
2261 bool dont_log_query)
2262 {
2263 TABLE_LIST *table;
2264 char path[FN_REFLEN + 1], *alias= NULL;
2265 uint path_length= 0;
2266 String wrong_tables;
2267 int error= 0;
2268 int non_temp_tables_count= 0;
2269 bool foreign_key_error=0;
2270 bool non_tmp_error= 0;
2271 bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
2272 bool non_tmp_table_deleted= 0;
2273 bool have_nonexistent_tmp_table= 0;
2274 bool is_drop_tmp_if_exists_with_no_defaultdb= 0;
2275 String built_query;
2276 String built_trans_tmp_query, built_non_trans_tmp_query;
2277 String nonexistent_tmp_tables;
2278 DBUG_ENTER("mysql_rm_table_no_locks");
2279
2280 /*
2281 Prepares the drop statements that will be written into the binary
2282 log as follows:
2283
2284 1 - If we are not processing a "DROP TEMPORARY" it prepares a
2285 "DROP".
2286
2287 2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
2288 not true.
2289
2290 3 - If the current format is row, the IF EXISTS token needs to be
2291 appended because one does not know if CREATE TEMPORARY was previously
2292 written to the binary log.
2293
2294 4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
2295
2296 5 - For temporary tables, there is a need to differentiate tables
2297 in transactional and non-transactional storage engines. For that,
2298 reason, two types of drop statements are prepared.
2299
2300 The need to different the type of tables when dropping a temporary
2301 table stems from the fact that such drop does not commit an ongoing
2302 transaction and changes to non-transactional tables must be written
2303 ahead of the transaction in some circumstances.
2304
2305 6 - At the time of writing 'DROP TEMPORARY TABLE IF EXISTS'
2306 statements into the binary log if the default database specified in
2307 thd->db is present then they are binlogged as
2308 'USE `default_db`; DROP TEMPORARY TABLE IF EXISTS `t1`;'
2309 otherwise they will be binlogged with the actual database name to
2310 which the table belongs to.
2311 'DROP TEMPORARY TABLE IF EXISTS `actual_db`.`t1`
2312 */
2313 if (!dont_log_query)
2314 {
2315 if (!drop_temporary)
2316 {
2317 built_query.set_charset(system_charset_info);
2318 if (if_exists)
2319 built_query.append("DROP TABLE IF EXISTS ");
2320 else
2321 built_query.append("DROP TABLE ");
2322 }
2323
2324 if (thd->is_current_stmt_binlog_format_row() || if_exists)
2325 {
2326 /*
2327 If default database doesnot exist in those cases set
2328 'is_drop_tmp_if_exists_with_no_defaultdb flag to 'true' so that the
2329 'DROP TEMPORARY TABLE IF EXISTS' command is logged with a qualified
2330 table name.
2331 */
2332 if (thd->db != NULL && check_db_dir_existence(thd->db))
2333 is_drop_tmp_if_exists_with_no_defaultdb= true;
2334 built_trans_tmp_query.set_charset(system_charset_info);
2335 built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
2336 built_non_trans_tmp_query.set_charset(system_charset_info);
2337 built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
2338 }
2339 else
2340 {
2341 built_trans_tmp_query.set_charset(system_charset_info);
2342 built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
2343 built_non_trans_tmp_query.set_charset(system_charset_info);
2344 built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
2345 }
2346 nonexistent_tmp_tables.set_charset(system_charset_info);
2347 }
2348
2349 for (table= tables; table; table= table->next_local)
2350 {
2351 bool is_trans;
2352 char *db=table->db;
2353 int db_len= table->db_length;
2354 handlerton *table_type;
2355 enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
2356
2357 DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx",
2358 table->db, table->table_name, (long) table->table,
2359 table->table ? (long) table->table->s : (long) -1));
2360
2361 /*
2362 If we are in locked tables mode and are dropping a temporary table,
2363 the ticket should be NULL to ensure that we don't release a lock
2364 on a base table later.
2365 */
2366 DBUG_ASSERT(!(thd->locked_tables_mode &&
2367 table->open_type != OT_BASE_ONLY &&
2368 find_temporary_table(thd, table) &&
2369 table->mdl_request.ticket != NULL));
2370
2371 thd->add_to_binlog_accessed_dbs(table->db);
2372
2373 /*
2374 drop_temporary_table may return one of the following error codes:
2375 . 0 - a temporary table was successfully dropped.
2376 . 1 - a temporary table was not found.
2377 . -1 - a temporary table is used by an outer statement.
2378 */
2379 if (table->open_type == OT_BASE_ONLY)
2380 error= 1;
2381 else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
2382 {
2383 DBUG_ASSERT(thd->in_sub_stmt);
2384 goto err;
2385 }
2386
2387 if ((drop_temporary && if_exists) || !error)
2388 {
2389 /*
2390 This handles the case of temporary tables. We have the following cases:
2391
2392 . "DROP TEMPORARY" was executed and a temporary table was affected
2393 (i.e. drop_temporary && !error) or the if_exists was specified (i.e.
2394 drop_temporary && if_exists).
2395
2396 . "DROP" was executed but a temporary table was affected (.i.e
2397 !error).
2398 */
2399 if (!dont_log_query)
2400 {
2401 /*
2402 If there is an error, we don't know the type of the engine
2403 at this point. So, we keep it in the nonexistent_tmp_table list.
2404 */
2405 if (error == 1)
2406 have_nonexistent_tmp_table= true;
2407 else if (is_trans)
2408 trans_tmp_table_deleted= TRUE;
2409 else
2410 non_trans_tmp_table_deleted= TRUE;
2411
2412 String *built_ptr_query=
2413 (error == 1 ? &nonexistent_tmp_tables :
2414 (is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query));
2415 /*
2416 Write the database name if it is not the current one or if
2417 thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY'
2418 query.
2419 */
2420 if (thd->db == NULL || strcmp(db,thd->db) != 0
2421 || is_drop_tmp_if_exists_with_no_defaultdb )
2422 {
2423 append_identifier(thd, built_ptr_query, db, db_len,
2424 system_charset_info, thd->charset());
2425 built_ptr_query->append(".");
2426 }
2427 append_identifier(thd, built_ptr_query, table->table_name,
2428 strlen(table->table_name), system_charset_info,
2429 thd->charset());
2430 built_ptr_query->append(",");
2431 }
2432 /*
2433 This means that a temporary table was droped and as such there
2434 is no need to proceed with the code that tries to drop a regular
2435 table.
2436 */
2437 if (!error) continue;
2438 }
2439 else if (!drop_temporary)
2440 {
2441 non_temp_tables_count++;
2442
2443 if (thd->locked_tables_mode)
2444 {
2445 if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
2446 {
2447 error= -1;
2448 goto err;
2449 }
2450 close_all_tables_for_name(thd, table->table->s, true, NULL);
2451 table->table= 0;
2452 }
2453
2454 /* Check that we have an exclusive lock on the table to be dropped. */
2455 DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
2456 table->table_name,
2457 MDL_EXCLUSIVE));
2458 if (thd->killed)
2459 {
2460 error= -1;
2461 goto err;
2462 }
2463 alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
2464 /* remove .frm file and engine files */
2465 path_length= build_table_filename(path, sizeof(path) - 1, db, alias,
2466 reg_ext,
2467 table->internal_tmp_table ?
2468 FN_IS_TMP : 0);
2469
2470 /*
2471 This handles the case where a "DROP" was executed and a regular
2472 table "may be" dropped as drop_temporary is FALSE and error is
2473 TRUE. If the error was FALSE a temporary table was dropped and
2474 regardless of the status of drop_tempoary a "DROP TEMPORARY"
2475 must be used.
2476 */
2477 if (!dont_log_query)
2478 {
2479 /*
2480 Note that unless if_exists is TRUE or a temporary table was deleted,
2481 there is no means to know if the statement should be written to the
2482 binary log. See further information on this variable in what follows.
2483 */
2484 non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted);
2485 /*
2486 Don't write the database name if it is the current one (or if
2487 thd->db is NULL).
2488 */
2489 if (thd->db == NULL || strcmp(db,thd->db) != 0)
2490 {
2491 append_identifier(thd, &built_query, db, db_len,
2492 system_charset_info, thd->charset());
2493 built_query.append(".");
2494 }
2495
2496 append_identifier(thd, &built_query, table->table_name,
2497 strlen(table->table_name), system_charset_info,
2498 thd->charset());
2499 built_query.append(",");
2500 }
2501 }
2502 DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
2503 DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table",
2504 my_sleep(100000););
2505 error= 0;
2506 if (drop_temporary ||
2507 ((access(path, F_OK) &&
2508 ha_create_table_from_engine(thd, db, alias)) ||
2509 (!drop_view &&
2510 dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
2511 {
2512 /*
2513 One of the following cases happened:
2514 . "DROP TEMPORARY" but a temporary table was not found.
2515 . "DROP" but table was not found on disk and table can't be
2516 created from engine.
2517 . ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
2518 */
2519 if (if_exists)
2520 {
2521 String tbl_name;
2522 tbl_name.append(String(db,system_charset_info));
2523 tbl_name.append('.');
2524 tbl_name.append(String(table->table_name,system_charset_info));
2525
2526 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
2527 ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
2528 tbl_name.c_ptr());
2529 }
2530 else
2531 {
2532 non_tmp_error = (drop_temporary ? non_tmp_error : TRUE);
2533 error= 1;
2534 }
2535 }
2536 else
2537 {
2538 char *end;
2539 if (frm_db_type == DB_TYPE_UNKNOWN)
2540 {
2541 dd_frm_type(thd, path, &frm_db_type);
2542 DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
2543 }
2544 table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
2545 // Remove extension for delete
2546 *(end= path + path_length - reg_ext_length)= '\0';
2547 DBUG_PRINT("info", ("deleting table of type %d",
2548 (table_type ? table_type->db_type : 0)));
2549 error= ha_delete_table(thd, table_type, path, db, table->table_name,
2550 !dont_log_query);
2551
2552 /* No error if non existent table and 'IF EXIST' clause or view */
2553 if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
2554 (if_exists || table_type == NULL))
2555 {
2556 error= 0;
2557 thd->clear_error();
2558 }
2559 if (error == HA_ERR_ROW_IS_REFERENCED)
2560 {
2561 /* the table is referenced by a foreign key constraint */
2562 foreign_key_error= 1;
2563 }
2564 if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
2565 {
2566 int new_error;
2567 /* Delete the table definition file */
2568 strmov(end,reg_ext);
2569 if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
2570 {
2571 non_tmp_table_deleted= TRUE;
2572 new_error= Table_triggers_list::drop_all_triggers(thd, db,
2573 table->table_name);
2574 }
2575 error|= new_error;
2576 }
2577 non_tmp_error= error ? TRUE : non_tmp_error;
2578 }
2579 if (error)
2580 {
2581 if (error == HA_ERR_TOO_MANY_CONCURRENT_TRXS)
2582 {
2583 my_error(HA_ERR_TOO_MANY_CONCURRENT_TRXS, MYF(0));
2584 wrong_tables.free();
2585 error= 1;
2586 goto err;
2587 }
2588
2589 if (wrong_tables.length())
2590 wrong_tables.append(',');
2591
2592 wrong_tables.append(String(db,system_charset_info));
2593 wrong_tables.append('.');
2594 wrong_tables.append(String(table->table_name,system_charset_info));
2595 }
2596 DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
2597 table->table ? (long) table->table->s : (long) -1));
2598
2599 DBUG_EXECUTE_IF("bug43138",
2600 my_printf_error(ER_BAD_TABLE_ERROR,
2601 ER(ER_BAD_TABLE_ERROR), MYF(0),
2602 table->table_name););
2603 #ifdef HAVE_PSI_TABLE_INTERFACE
2604 if (drop_temporary && likely(error == 0))
2605 PSI_TABLE_CALL(drop_table_share)
2606 (true, table->db, table->db_length, table->table_name, table->table_name_length);
2607 #endif
2608 }
2609 DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
2610 thd->thread_specific_used= TRUE;
2611 error= 0;
2612 err:
2613 if (wrong_tables.length())
2614 {
2615 if (!foreign_key_error)
2616 my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
2617 wrong_tables.c_ptr());
2618 else
2619 my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
2620 error= 1;
2621 }
2622
2623 if (have_nonexistent_tmp_table || non_trans_tmp_table_deleted ||
2624 trans_tmp_table_deleted || non_tmp_table_deleted)
2625 {
2626 query_cache_invalidate3(thd, tables, 0);
2627
2628 if (have_nonexistent_tmp_table || non_trans_tmp_table_deleted ||
2629 trans_tmp_table_deleted)
2630 thd->transaction.stmt.mark_dropped_temp_table();
2631
2632 /*
2633 The statement may contain up to three types of temporary tables:
2634 transactional, non-transactional, and non-existent tables.
2635
2636 The statement is logged using up to two statements: non-transactional
2637 and transactional tables are logged in different statements.
2638
2639 The non-existing tables are logged together with transactional ones, if
2640 any transactional tables exist or if there is only non-existing tables;
2641 otherwise are logged together with non-transactional ones.
2642
2643 This logic ensures that:
2644 - On master, transactional and non-transactional tables are written to
2645 different statements.
2646 - Therefore, slave will never see statements containing both transactional
2647 and non-transactional tables.
2648 - Since non-existing temporary tables are logged together with whatever
2649 type of temporary tables that exist, the slave thus writes any statement
2650 as just one statement. I.e., the slave never splits a statement into two.
2651 This is crucial when GTIDs are enabled, since otherwise the statement,
2652 which already has a GTID, would need two different GTIDs.
2653 */
2654 if (!dont_log_query && mysql_bin_log.is_open())
2655 {
2656 if (non_trans_tmp_table_deleted)
2657 {
2658 /*
2659 Add the list of nonexistent tmp tables here only if there is no
2660 trans tmp table deleted.
2661 */
2662 if (!trans_tmp_table_deleted && have_nonexistent_tmp_table)
2663 built_non_trans_tmp_query.append(nonexistent_tmp_tables);
2664 /* Chop of the last comma */
2665 built_non_trans_tmp_query.chop();
2666 built_non_trans_tmp_query.append(" /* generated by server */");
2667 #ifdef WITH_WSREP
2668 thd->wsrep_skip_wsrep_GTID = true;
2669 #endif /* WITH_WSREP */
2670 error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2671 built_non_trans_tmp_query.ptr(),
2672 built_non_trans_tmp_query.length(),
2673 FALSE, FALSE,
2674 is_drop_tmp_if_exists_with_no_defaultdb,
2675 0);
2676 /*
2677 When temporary and regular tables or temporary tables with
2678 different storage engines are dropped on a single
2679 statement, the original statement is split in two or more.
2680 These statements are logged in distinct events to binary
2681 logs, when gtid_mode is ON each DDL event must have its own
2682 GTID. Since drop temporary table does not implicitly
2683 commit, in these cases we must force a commit.
2684 */
2685 if (gtid_mode > 0 && (trans_tmp_table_deleted || non_tmp_table_deleted))
2686 error |= mysql_bin_log.commit(thd, true);
2687 }
2688 if (trans_tmp_table_deleted ||
2689 (have_nonexistent_tmp_table && !non_trans_tmp_table_deleted))
2690 {
2691 if (have_nonexistent_tmp_table)
2692 built_trans_tmp_query.append(nonexistent_tmp_tables);
2693 /* Chop of the last comma */
2694 built_trans_tmp_query.chop();
2695 built_trans_tmp_query.append(" /* generated by server */");
2696 #ifdef WITH_WSREP
2697 thd->wsrep_skip_wsrep_GTID = true;
2698 #endif /* WITH_WSREP */
2699 error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2700 built_trans_tmp_query.ptr(),
2701 built_trans_tmp_query.length(),
2702 TRUE, FALSE,
2703 is_drop_tmp_if_exists_with_no_defaultdb,
2704 0);
2705 /*
2706 When temporary and regular tables are dropped on a single
2707 statement, the original statement is split in two or more.
2708 These statements are logged in distinct events to binary
2709 logs, when gtid_mode is ON each DDL event must have its own
2710 GTID. Since drop temporary table does not implicitly
2711 commit, in these cases we must force a commit.
2712 */
2713 if (gtid_mode > 0 && non_tmp_table_deleted)
2714 error |= mysql_bin_log.commit(thd, true);
2715 }
2716 /*
2717 when the DROP TABLE command is used to DROP a single table and if that
2718 command fails then the query cannot generate 'partial results'. In
2719 that case the query will not be written to the binary log.
2720 */
2721 if (non_tmp_table_deleted &&
2722 (thd->lex->select_lex.table_list.elements > 1 || !error))
2723 {
2724 /* Chop of the last comma */
2725 built_query.chop();
2726 built_query.append(" /* generated by server */");
2727 int error_code = (non_tmp_error ?
2728 (foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
2729 #ifdef WITH_WSREP
2730 thd->wsrep_skip_wsrep_GTID = false;
2731 #endif /* WITH_WSREP */
2732 error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2733 built_query.ptr(),
2734 built_query.length(),
2735 TRUE, FALSE, FALSE,
2736 error_code);
2737 }
2738 }
2739 }
2740
2741 if (!drop_temporary)
2742 {
2743 /*
2744 Under LOCK TABLES we should release meta-data locks on the tables
2745 which were dropped.
2746
2747 Leave LOCK TABLES mode if we managed to drop all tables which were
2748 locked. Additional check for 'non_temp_tables_count' is to avoid
2749 leaving LOCK TABLES mode if we have dropped only temporary tables.
2750 */
2751 if (thd->locked_tables_mode)
2752 {
2753 if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
2754 {
2755 thd->locked_tables_list.unlock_locked_tables(thd);
2756 goto end;
2757 }
2758 for (table= tables; table; table= table->next_local)
2759 {
2760 /* Drop locks for all successfully dropped tables. */
2761 if (table->table == NULL && table->mdl_request.ticket)
2762 {
2763 /*
2764 Under LOCK TABLES we may have several instances of table open
2765 and locked and therefore have to remove several metadata lock
2766 requests associated with them.
2767 */
2768 thd->mdl_context.release_all_locks_for_name(table->mdl_request.ticket);
2769 }
2770 }
2771 }
2772 /*
2773 Rely on the caller to implicitly commit the transaction
2774 and release metadata locks.
2775 */
2776 }
2777
2778 end:
2779 #ifdef WITH_WSREP
2780 thd->wsrep_skip_wsrep_GTID = false;
2781 #endif /* WITH_WSREP */
2782 DBUG_RETURN(error);
2783 }
2784
2785
2786 /**
2787 Quickly remove a table.
2788
2789 @param thd Thread context.
2790 @param base The handlerton handle.
2791 @param db The database name.
2792 @param table_name The table name.
2793 @param flags Flags for build_table_filename() as well as describing
2794 if handler files / .FRM should be deleted as well.
2795
2796 @return False in case of success, True otherwise.
2797 */
2798
quick_rm_table(THD * thd,handlerton * base,const char * db,const char * table_name,uint flags)2799 bool quick_rm_table(THD *thd, handlerton *base, const char *db,
2800 const char *table_name, uint flags)
2801 {
2802 char path[FN_REFLEN + 1];
2803 bool error= 0;
2804 DBUG_ENTER("quick_rm_table");
2805
2806 uint path_length= build_table_filename(path, sizeof(path) - 1,
2807 db, table_name, reg_ext, flags);
2808 if (mysql_file_delete(key_file_frm, path, MYF(0)))
2809 error= 1; /* purecov: inspected */
2810 path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
2811 if (flags & NO_HA_TABLE)
2812 {
2813 handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
2814 if (!file)
2815 DBUG_RETURN(true);
2816 (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, NULL);
2817 delete file;
2818 }
2819 if (!(flags & (FRM_ONLY|NO_HA_TABLE)))
2820 error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
2821 DBUG_RETURN(error);
2822 }
2823
2824 /*
2825 Sort keys in the following order:
2826 - PRIMARY KEY
2827 - UNIQUE keys where all column are NOT NULL
2828 - UNIQUE keys that don't contain partial segments
2829 - Other UNIQUE keys
2830 - Normal keys
2831 - Fulltext keys
2832
2833 This will make checking for duplicated keys faster and ensure that
2834 PRIMARY keys are prioritized.
2835 */
2836
sort_keys(KEY * a,KEY * b)2837 static int sort_keys(KEY *a, KEY *b)
2838 {
2839 ulong a_flags= a->flags, b_flags= b->flags;
2840
2841 if (a_flags & HA_NOSAME)
2842 {
2843 if (!(b_flags & HA_NOSAME))
2844 return -1;
2845 if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
2846 {
2847 /* Sort NOT NULL keys before other keys */
2848 return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
2849 }
2850 if (a->name == primary_key_name)
2851 return -1;
2852 if (b->name == primary_key_name)
2853 return 1;
2854 /* Sort keys don't containing partial segments before others */
2855 if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
2856 return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
2857 }
2858 else if (b_flags & HA_NOSAME)
2859 return 1; // Prefer b
2860
2861 if ((a_flags ^ b_flags) & HA_FULLTEXT)
2862 {
2863 return (a_flags & HA_FULLTEXT) ? 1 : -1;
2864 }
2865 /*
2866 Prefer original key order. usable_key_parts contains here
2867 the original key position.
2868 */
2869 return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
2870 (a->usable_key_parts > b->usable_key_parts) ? 1 :
2871 0);
2872 }
2873
2874 /*
2875 Check TYPELIB (set or enum) for duplicates
2876
2877 SYNOPSIS
2878 check_duplicates_in_interval()
2879 set_or_name "SET" or "ENUM" string for warning message
2880 name name of the checked column
2881 typelib list of values for the column
2882 dup_val_count returns count of duplicate elements
2883
2884 DESCRIPTION
2885 This function prints an warning for each value in list
2886 which has some duplicates on its right
2887
2888 RETURN VALUES
2889 0 ok
2890 1 Error
2891 */
2892
check_duplicates_in_interval(const char * set_or_name,const char * name,TYPELIB * typelib,const CHARSET_INFO * cs,uint * dup_val_count)2893 bool check_duplicates_in_interval(const char *set_or_name,
2894 const char *name, TYPELIB *typelib,
2895 const CHARSET_INFO *cs, uint *dup_val_count)
2896 {
2897 TYPELIB tmp= *typelib;
2898 const char **cur_value= typelib->type_names;
2899 unsigned int *cur_length= typelib->type_lengths;
2900 *dup_val_count= 0;
2901
2902 for ( ; tmp.count > 1; cur_value++, cur_length++)
2903 {
2904 tmp.type_names++;
2905 tmp.type_lengths++;
2906 tmp.count--;
2907 if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
2908 {
2909 THD *thd= current_thd;
2910 ErrConvString err(*cur_value, *cur_length, cs);
2911 if (current_thd->is_strict_mode())
2912 {
2913 my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
2914 name, err.ptr(), set_or_name);
2915 return 1;
2916 }
2917 push_warning_printf(thd,Sql_condition::WARN_LEVEL_NOTE,
2918 ER_DUPLICATED_VALUE_IN_TYPE,
2919 ER(ER_DUPLICATED_VALUE_IN_TYPE),
2920 name, err.ptr(), set_or_name);
2921 (*dup_val_count)++;
2922 }
2923 }
2924 return 0;
2925 }
2926
2927
2928 /*
2929 Check TYPELIB (set or enum) max and total lengths
2930
2931 SYNOPSIS
2932 calculate_interval_lengths()
2933 cs charset+collation pair of the interval
2934 typelib list of values for the column
2935 max_length length of the longest item
2936 tot_length sum of the item lengths
2937
2938 DESCRIPTION
2939 After this function call:
2940 - ENUM uses max_length
2941 - SET uses tot_length.
2942
2943 RETURN VALUES
2944 void
2945 */
calculate_interval_lengths(const CHARSET_INFO * cs,TYPELIB * interval,uint32 * max_length,uint32 * tot_length)2946 static void calculate_interval_lengths(const CHARSET_INFO *cs,
2947 TYPELIB *interval,
2948 uint32 *max_length,
2949 uint32 *tot_length)
2950 {
2951 const char **pos;
2952 uint *len;
2953 *max_length= *tot_length= 0;
2954 for (pos= interval->type_names, len= interval->type_lengths;
2955 *pos ; pos++, len++)
2956 {
2957 size_t length= cs->cset->numchars(cs, *pos, *pos + *len);
2958 *tot_length+= length;
2959 set_if_bigger(*max_length, (uint32)length);
2960 }
2961 }
2962
2963
2964 /*
2965 Prepare a create_table instance for packing
2966
2967 SYNOPSIS
2968 prepare_create_field()
2969 sql_field field to prepare for packing
2970 blob_columns count for BLOBs
2971 table_flags table flags
2972
2973 DESCRIPTION
2974 This function prepares a Create_field instance.
2975 Fields such as pack_flag are valid after this call.
2976
2977 RETURN VALUES
2978 0 ok
2979 1 Error
2980 */
2981
prepare_create_field(Create_field * sql_field,uint * blob_columns,longlong table_flags)2982 int prepare_create_field(Create_field *sql_field,
2983 uint *blob_columns,
2984 longlong table_flags)
2985 {
2986 unsigned int dup_val_count;
2987 DBUG_ENTER("prepare_field");
2988
2989 /*
2990 This code came from mysql_prepare_create_table.
2991 Indent preserved to make patching easier
2992 */
2993 DBUG_ASSERT(sql_field->charset);
2994
2995 switch (sql_field->sql_type) {
2996 case MYSQL_TYPE_BLOB:
2997 case MYSQL_TYPE_MEDIUM_BLOB:
2998 case MYSQL_TYPE_TINY_BLOB:
2999 case MYSQL_TYPE_LONG_BLOB:
3000 sql_field->pack_flag=FIELDFLAG_BLOB |
3001 pack_length_to_packflag(sql_field->pack_length -
3002 portable_sizeof_char_ptr);
3003 if (sql_field->charset->state & MY_CS_BINSORT)
3004 sql_field->pack_flag|=FIELDFLAG_BINARY;
3005 sql_field->length=8; // Unireg field length
3006 sql_field->unireg_check=Field::BLOB_FIELD;
3007 (*blob_columns)++;
3008 break;
3009 case MYSQL_TYPE_GEOMETRY:
3010 #ifdef HAVE_SPATIAL
3011 if (!(table_flags & HA_CAN_GEOMETRY))
3012 {
3013 my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
3014 MYF(0), "GEOMETRY");
3015 DBUG_RETURN(1);
3016 }
3017 sql_field->pack_flag=FIELDFLAG_GEOM |
3018 pack_length_to_packflag(sql_field->pack_length -
3019 portable_sizeof_char_ptr);
3020 if (sql_field->charset->state & MY_CS_BINSORT)
3021 sql_field->pack_flag|=FIELDFLAG_BINARY;
3022 sql_field->length=8; // Unireg field length
3023 sql_field->unireg_check=Field::BLOB_FIELD;
3024 (*blob_columns)++;
3025 break;
3026 #else
3027 my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
3028 sym_group_geom.name, sym_group_geom.needed_define);
3029 DBUG_RETURN(1);
3030 #endif /*HAVE_SPATIAL*/
3031 case MYSQL_TYPE_VARCHAR:
3032 #ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
3033 if (table_flags & HA_NO_VARCHAR)
3034 {
3035 /* convert VARCHAR to CHAR because handler is not yet up to date */
3036 sql_field->sql_type= MYSQL_TYPE_VAR_STRING;
3037 sql_field->pack_length= calc_pack_length(sql_field->sql_type,
3038 (uint) sql_field->length);
3039 if ((sql_field->length / sql_field->charset->mbmaxlen) >
3040 MAX_FIELD_CHARLENGTH)
3041 {
3042 my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
3043 MYF(0), sql_field->field_name,
3044 static_cast<ulong>(MAX_FIELD_CHARLENGTH));
3045 DBUG_RETURN(1);
3046 }
3047 }
3048 #endif
3049 /* fall through */
3050 case MYSQL_TYPE_STRING:
3051 sql_field->pack_flag=0;
3052 if (sql_field->charset->state & MY_CS_BINSORT)
3053 sql_field->pack_flag|=FIELDFLAG_BINARY;
3054 break;
3055 case MYSQL_TYPE_ENUM:
3056 sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
3057 FIELDFLAG_INTERVAL;
3058 if (sql_field->charset->state & MY_CS_BINSORT)
3059 sql_field->pack_flag|=FIELDFLAG_BINARY;
3060 sql_field->unireg_check=Field::INTERVAL_FIELD;
3061 if (check_duplicates_in_interval("ENUM",sql_field->field_name,
3062 sql_field->interval,
3063 sql_field->charset, &dup_val_count))
3064 DBUG_RETURN(1);
3065 break;
3066 case MYSQL_TYPE_SET:
3067 sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
3068 FIELDFLAG_BITFIELD;
3069 if (sql_field->charset->state & MY_CS_BINSORT)
3070 sql_field->pack_flag|=FIELDFLAG_BINARY;
3071 sql_field->unireg_check=Field::BIT_FIELD;
3072 if (check_duplicates_in_interval("SET",sql_field->field_name,
3073 sql_field->interval,
3074 sql_field->charset, &dup_val_count))
3075 DBUG_RETURN(1);
3076 /* Check that count of unique members is not more then 64 */
3077 if (sql_field->interval->count - dup_val_count > sizeof(longlong)*8)
3078 {
3079 my_error(ER_TOO_BIG_SET, MYF(0), sql_field->field_name);
3080 DBUG_RETURN(1);
3081 }
3082 break;
3083 case MYSQL_TYPE_DATE: // Rest of string types
3084 case MYSQL_TYPE_NEWDATE:
3085 case MYSQL_TYPE_TIME:
3086 case MYSQL_TYPE_DATETIME:
3087 case MYSQL_TYPE_TIME2:
3088 case MYSQL_TYPE_DATETIME2:
3089 case MYSQL_TYPE_NULL:
3090 sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
3091 break;
3092 case MYSQL_TYPE_BIT:
3093 /*
3094 We have sql_field->pack_flag already set here, see
3095 mysql_prepare_create_table().
3096 */
3097 break;
3098 case MYSQL_TYPE_NEWDECIMAL:
3099 sql_field->pack_flag=(FIELDFLAG_NUMBER |
3100 (sql_field->flags & UNSIGNED_FLAG ? 0 :
3101 FIELDFLAG_DECIMAL) |
3102 (sql_field->flags & ZEROFILL_FLAG ?
3103 FIELDFLAG_ZEROFILL : 0) |
3104 (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
3105 break;
3106 case MYSQL_TYPE_TIMESTAMP:
3107 case MYSQL_TYPE_TIMESTAMP2:
3108 /* fall-through */
3109 default:
3110 sql_field->pack_flag=(FIELDFLAG_NUMBER |
3111 (sql_field->flags & UNSIGNED_FLAG ? 0 :
3112 FIELDFLAG_DECIMAL) |
3113 (sql_field->flags & ZEROFILL_FLAG ?
3114 FIELDFLAG_ZEROFILL : 0) |
3115 f_settype((uint) sql_field->sql_type) |
3116 (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
3117 break;
3118 }
3119 if (!(sql_field->flags & NOT_NULL_FLAG))
3120 sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
3121 if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
3122 sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
3123 DBUG_RETURN(0);
3124 }
3125
3126
create_typelib(MEM_ROOT * mem_root,Create_field * field_def,List<String> * src)3127 static TYPELIB *create_typelib(MEM_ROOT *mem_root,
3128 Create_field *field_def,
3129 List<String> *src)
3130 {
3131 const CHARSET_INFO *cs= field_def->charset;
3132
3133 if (!src->elements)
3134 return NULL;
3135
3136 TYPELIB *result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
3137 result->count= src->elements;
3138 result->name= "";
3139 if (!(result->type_names=(const char **)
3140 alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1))))
3141 return NULL;
3142 result->type_lengths= (uint*)(result->type_names + result->count+1);
3143 List_iterator<String> it(*src);
3144 String conv;
3145 for (uint i=0; i < result->count; i++)
3146 {
3147 uint32 dummy;
3148 uint length;
3149 String *tmp= it++;
3150
3151 if (String::needs_conversion(tmp->length(), tmp->charset(),
3152 cs, &dummy))
3153 {
3154 uint cnv_errs;
3155 conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
3156
3157 length= conv.length();
3158 result->type_names[i]= (char*) strmake_root(mem_root, conv.ptr(),
3159 length);
3160 }
3161 else
3162 {
3163 length= tmp->length();
3164 result->type_names[i]= strmake_root(mem_root, tmp->ptr(), length);
3165 }
3166
3167 // Strip trailing spaces.
3168 length= cs->cset->lengthsp(cs, result->type_names[i], length);
3169 result->type_lengths[i]= length;
3170 ((uchar *)result->type_names[i])[length]= '\0';
3171 }
3172 result->type_names[result->count]= 0;
3173 result->type_lengths[result->count]= 0;
3174
3175 return result;
3176 }
3177
3178
3179 /**
3180 Prepare an instance of Create_field for field creation
3181 (fill all necessary attributes).
3182
3183 @param[in] thd Thread handle
3184 @param[in] sp The current SP
3185 @param[in] field_type Field type
3186 @param[out] field_def An instance of create_field to be filled
3187
3188 @return Error status.
3189 */
3190
fill_field_definition(THD * thd,sp_head * sp,enum enum_field_types field_type,Create_field * field_def)3191 bool fill_field_definition(THD *thd,
3192 sp_head *sp,
3193 enum enum_field_types field_type,
3194 Create_field *field_def)
3195 {
3196 LEX *lex= thd->lex;
3197 LEX_STRING cmt = { 0, 0 };
3198 uint unused1= 0;
3199
3200 if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
3201 lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
3202 &lex->interval_list,
3203 lex->charset ? lex->charset :
3204 thd->variables.collation_database,
3205 lex->uint_geom_type))
3206 {
3207 return true;
3208 }
3209
3210 if (field_def->interval_list.elements)
3211 {
3212 field_def->interval= create_typelib(sp->get_current_mem_root(),
3213 field_def,
3214 &field_def->interval_list);
3215 }
3216
3217 sp_prepare_create_field(thd, field_def);
3218
3219 return prepare_create_field(field_def, &unused1, HA_CAN_GEOMETRY);
3220 }
3221
3222 /*
3223 Get character set from field object generated by parser using
3224 default values when not set.
3225
3226 SYNOPSIS
3227 get_sql_field_charset()
3228 sql_field The sql_field object
3229 create_info Info generated by parser
3230
3231 RETURN VALUES
3232 cs Character set
3233 */
3234
get_sql_field_charset(Create_field * sql_field,HA_CREATE_INFO * create_info)3235 const CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
3236 HA_CREATE_INFO *create_info)
3237 {
3238 const CHARSET_INFO *cs= sql_field->charset;
3239
3240 if (!cs)
3241 cs= create_info->default_table_charset;
3242 /*
3243 table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname
3244 if we want change character set for all varchar/char columns.
3245 But the table charset must not affect the BLOB fields, so don't
3246 allow to change my_charset_bin to somethig else.
3247 */
3248 if (create_info->table_charset && cs != &my_charset_bin)
3249 cs= create_info->table_charset;
3250 return cs;
3251 }
3252
3253
3254 /**
3255 Modifies the first column definition whose SQL type is TIMESTAMP
3256 by adding the features DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
3257
3258 @param column_definitions The list of column definitions, in the physical
3259 order in which they appear in the table.
3260 */
promote_first_timestamp_column(List<Create_field> * column_definitions)3261 void promote_first_timestamp_column(List<Create_field> *column_definitions)
3262 {
3263 List_iterator<Create_field> it(*column_definitions);
3264 Create_field *column_definition;
3265
3266 while ((column_definition= it++) != NULL)
3267 {
3268 if (column_definition->sql_type == MYSQL_TYPE_TIMESTAMP || // TIMESTAMP
3269 column_definition->sql_type == MYSQL_TYPE_TIMESTAMP2 || // ms TIMESTAMP
3270 column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
3271 {
3272 if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
3273 column_definition->def == NULL && // no constant default,
3274 column_definition->unireg_check == Field::NONE) // no function default
3275 {
3276 DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to "
3277 "DEFAULT CURRENT_TIMESTAMP ON UPDATE "
3278 "CURRENT_TIMESTAMP",
3279 column_definition->field_name
3280 ));
3281 column_definition->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
3282 }
3283 return;
3284 }
3285 }
3286 }
3287
3288
3289 /**
3290 Check if there is a duplicate key. Report a warning for every duplicate key.
3291
3292 @param thd Thread context.
3293 @param error_schema_name Schema name of the table used for error reporting.
3294 @param error_table_name Table name used for error reporting.
3295 @param key Key to be checked.
3296 @param key_info Key meta-data info.
3297 @param alter_info List of columns and indexes to create.
3298 */
check_duplicate_key(THD * thd,const char * error_schema_name,const char * error_table_name,Key * key,KEY * key_info,Alter_info * alter_info)3299 static void check_duplicate_key(THD *thd, const char *error_schema_name,
3300 const char *error_table_name,
3301 Key *key, KEY *key_info,
3302 Alter_info *alter_info)
3303 {
3304 /*
3305 We only check for duplicate indexes if it is requested and the
3306 key is not auto-generated.
3307
3308 Check is requested if the key was explicitly created or altered
3309 (Index is altered/column associated with it is dropped) by the user
3310 (unless it's a foreign key).
3311 */
3312 if (!key->key_create_info.check_for_duplicate_indexes || key->generated)
3313 return;
3314
3315 List_iterator<Key> key_list_iterator(alter_info->key_list);
3316 List_iterator<Key_part_spec> key_column_iterator(key->columns);
3317 Key *k;
3318
3319 while ((k= key_list_iterator++))
3320 {
3321 // Looking for a similar key...
3322
3323 if (k == key)
3324 {
3325 /*
3326 Since the duplicate index might exist before or after
3327 the modified key in the list, we continue the
3328 comparison with rest of the keys in case of DROP COLUMN
3329 operation.
3330 */
3331 if (alter_info->flags & Alter_info::ALTER_DROP_COLUMN)
3332 continue;
3333 else
3334 break;
3335 }
3336
3337 if (k->generated ||
3338 (key->type != k->type) ||
3339 (key->key_create_info.algorithm != k->key_create_info.algorithm) ||
3340 (key->columns.elements != k->columns.elements))
3341 {
3342 // Keys are different.
3343 continue;
3344 }
3345
3346 /*
3347 Keys 'key' and 'k' might be identical.
3348 Check that the keys have identical columns in the same order.
3349 */
3350
3351 List_iterator<Key_part_spec> k_column_iterator(k->columns);
3352
3353 bool all_columns_are_identical= true;
3354
3355 key_column_iterator.rewind();
3356
3357 for (uint i= 0; i < key->columns.elements; ++i)
3358 {
3359 Key_part_spec *c1= key_column_iterator++;
3360 Key_part_spec *c2= k_column_iterator++;
3361
3362 DBUG_ASSERT(c1 && c2);
3363
3364 if (my_strcasecmp(system_charset_info,
3365 c1->field_name.str, c2->field_name.str) ||
3366 (c1->length != c2->length))
3367 {
3368 all_columns_are_identical= false;
3369 break;
3370 }
3371 }
3372
3373 // Report a warning if we have two identical keys.
3374
3375 if (all_columns_are_identical)
3376 {
3377 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
3378 ER_DUP_INDEX, ER(ER_DUP_INDEX),
3379 key_info->name,
3380 error_schema_name,
3381 error_table_name);
3382 break;
3383 }
3384 }
3385 }
3386
3387
3388 /*
3389 Preparation for table creation
3390
3391 SYNOPSIS
3392 mysql_prepare_create_table()
3393 thd Thread object.
3394 error_schema_name Schema name of the table to create/alter,only
3395 used for error reporting.
3396 error_table_name Name of table to create/alter, only used for
3397 error reporting.
3398 create_info Create information (like MAX_ROWS).
3399 alter_info List of columns and indexes to create
3400 tmp_table If a temporary table is to be created.
3401 db_options INOUT Table options (like HA_OPTION_PACK_RECORD).
3402 file The handler for the new table.
3403 key_info_buffer OUT An array of KEY structs for the indexes.
3404 key_count OUT The number of elements in the array.
3405 select_field_count The number of fields coming from a select table.
3406
3407 DESCRIPTION
3408 Prepares the table and key structures for table creation.
3409
3410 NOTES
3411 sets create_info->varchar if the table has a varchar
3412
3413 RETURN VALUES
3414 FALSE OK
3415 TRUE error
3416 */
3417
3418 static int
mysql_prepare_create_table(THD * thd,const char * error_schema_name,const char * error_table_name,HA_CREATE_INFO * create_info,Alter_info * alter_info,bool tmp_table,uint * db_options,handler * file,KEY ** key_info_buffer,uint * key_count,int select_field_count)3419 mysql_prepare_create_table(THD *thd, const char *error_schema_name,
3420 const char *error_table_name,
3421 HA_CREATE_INFO *create_info,
3422 Alter_info *alter_info,
3423 bool tmp_table,
3424 uint *db_options,
3425 handler *file, KEY **key_info_buffer,
3426 uint *key_count, int select_field_count)
3427 {
3428 const char *key_name;
3429 Create_field *sql_field,*dup_field;
3430 uint field,null_fields,blob_columns,max_key_length;
3431 ulong record_offset= 0;
3432 KEY *key_info;
3433 KEY_PART_INFO *key_part_info;
3434 int field_no,dup_no;
3435 int select_field_pos,auto_increment=0;
3436 List_iterator<Create_field> it(alter_info->create_list);
3437 List_iterator<Create_field> it2(alter_info->create_list);
3438 uint total_uneven_bit_length= 0;
3439 DBUG_ENTER("mysql_prepare_create_table");
3440
3441 LEX_STRING* connect_string = &create_info->connect_string;
3442 if (connect_string->length != 0 &&
3443 connect_string->length > CONNECT_STRING_MAXLEN &&
3444 (system_charset_info->cset->charpos(system_charset_info,
3445 connect_string->str,
3446 (connect_string->str +
3447 connect_string->length),
3448 CONNECT_STRING_MAXLEN)
3449 < connect_string->length))
3450 {
3451 my_error(ER_WRONG_STRING_LENGTH, MYF(0),
3452 connect_string->str, "CONNECTION", CONNECT_STRING_MAXLEN);
3453 DBUG_RETURN(TRUE);
3454 }
3455
3456 select_field_pos= alter_info->create_list.elements - select_field_count;
3457 null_fields=blob_columns=0;
3458 create_info->varchar= 0;
3459 max_key_length= file->max_key_length();
3460
3461 for (field_no=0; (sql_field=it++) ; field_no++)
3462 {
3463 const CHARSET_INFO *save_cs;
3464
3465 /*
3466 Initialize length from its original value (number of characters),
3467 which was set in the parser. This is necessary if we're
3468 executing a prepared statement for the second time.
3469 */
3470 sql_field->length= sql_field->char_length;
3471 /* Set field charset. */
3472 save_cs= sql_field->charset= get_sql_field_charset(sql_field,
3473 create_info);
3474 if (sql_field->flags & BINCMP_FLAG)
3475 {
3476 // e.g. CREATE TABLE t1 (a CHAR(1) BINARY);
3477 if (!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
3478 MY_CS_BINSORT,MYF(0))))
3479 {
3480 char tmp[65];
3481 strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
3482 STRING_WITH_LEN("_bin"));
3483 my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
3484 DBUG_RETURN(TRUE);
3485 }
3486 /*
3487 Now that we have sql_field->charset set properly,
3488 we don't need the BINCMP_FLAG any longer.
3489 */
3490 sql_field->flags&= ~BINCMP_FLAG;
3491 }
3492
3493 /*
3494 Convert the default value from client character
3495 set into the column character set if necessary.
3496 */
3497 if (sql_field->def &&
3498 save_cs != sql_field->def->collation.collation &&
3499 (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
3500 sql_field->sql_type == MYSQL_TYPE_STRING ||
3501 sql_field->sql_type == MYSQL_TYPE_SET ||
3502 sql_field->sql_type == MYSQL_TYPE_ENUM))
3503 {
3504 /*
3505 Starting from 5.1 we work here with a copy of Create_field
3506 created by the caller, not with the instance that was
3507 originally created during parsing. It's OK to create
3508 a temporary item and initialize with it a member of the
3509 copy -- this item will be thrown away along with the copy
3510 at the end of execution, and thus not introduce a dangling
3511 pointer in the parsed tree of a prepared statement or a
3512 stored procedure statement.
3513 */
3514 sql_field->def= sql_field->def->safe_charset_converter(save_cs);
3515
3516 if (sql_field->def == NULL)
3517 {
3518 /* Could not convert */
3519 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3520 DBUG_RETURN(TRUE);
3521 }
3522 }
3523
3524 if (sql_field->sql_type == MYSQL_TYPE_SET ||
3525 sql_field->sql_type == MYSQL_TYPE_ENUM)
3526 {
3527 uint32 dummy;
3528 const CHARSET_INFO *cs= sql_field->charset;
3529 TYPELIB *interval= sql_field->interval;
3530
3531 /*
3532 Create typelib from interval_list, and if necessary
3533 convert strings from client character set to the
3534 column character set.
3535 */
3536 if (!interval)
3537 {
3538 /*
3539 Create the typelib in runtime memory - we will free the
3540 occupied memory at the same time when we free this
3541 sql_field -- at the end of execution.
3542 */
3543 interval= sql_field->interval= typelib(thd->mem_root,
3544 sql_field->interval_list);
3545 List_iterator<String> int_it(sql_field->interval_list);
3546 String conv, *tmp;
3547 char comma_buf[4]; /* 4 bytes for utf32 */
3548 int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
3549 (uchar*) comma_buf +
3550 sizeof(comma_buf));
3551 DBUG_ASSERT(comma_length > 0);
3552 for (uint i= 0; (tmp= int_it++); i++)
3553 {
3554 size_t lengthsp;
3555 if (String::needs_conversion(tmp->length(), tmp->charset(),
3556 cs, &dummy))
3557 {
3558 uint cnv_errs;
3559 conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
3560 interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
3561 conv.length());
3562 interval->type_lengths[i]= conv.length();
3563 }
3564
3565 // Strip trailing spaces.
3566 lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
3567 interval->type_lengths[i]);
3568 interval->type_lengths[i]= lengthsp;
3569 ((uchar *)interval->type_names[i])[lengthsp]= '\0';
3570 if (sql_field->sql_type == MYSQL_TYPE_SET)
3571 {
3572 if (cs->coll->instr(cs, interval->type_names[i],
3573 interval->type_lengths[i],
3574 comma_buf, comma_length, NULL, 0))
3575 {
3576 ErrConvString err(tmp->ptr(), tmp->length(), cs);
3577 my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
3578 DBUG_RETURN(TRUE);
3579 }
3580 }
3581 }
3582 sql_field->interval_list.empty(); // Don't need interval_list anymore
3583 }
3584
3585 if (sql_field->sql_type == MYSQL_TYPE_SET)
3586 {
3587 uint32 field_length;
3588 if (sql_field->def != NULL)
3589 {
3590 char *not_used;
3591 uint not_used2;
3592 bool not_found= 0;
3593 String str, *def= sql_field->def->val_str(&str);
3594 if (def == NULL) /* SQL "NULL" maps to NULL */
3595 {
3596 if ((sql_field->flags & NOT_NULL_FLAG) != 0)
3597 {
3598 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3599 DBUG_RETURN(TRUE);
3600 }
3601
3602 /* else, NULL is an allowed value */
3603 (void) find_set(interval, NULL, 0,
3604 cs, ¬_used, ¬_used2, ¬_found);
3605 }
3606 else /* not NULL */
3607 {
3608 (void) find_set(interval, def->ptr(), def->length(),
3609 cs, ¬_used, ¬_used2, ¬_found);
3610 }
3611
3612 if (not_found)
3613 {
3614 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3615 DBUG_RETURN(TRUE);
3616 }
3617 }
3618 calculate_interval_lengths(cs, interval, &dummy, &field_length);
3619 sql_field->length= field_length + (interval->count - 1);
3620 }
3621 else /* MYSQL_TYPE_ENUM */
3622 {
3623 uint32 field_length;
3624 DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
3625 if (sql_field->def != NULL)
3626 {
3627 String str, *def= sql_field->def->val_str(&str);
3628 if (def == NULL) /* SQL "NULL" maps to NULL */
3629 {
3630 if ((sql_field->flags & NOT_NULL_FLAG) != 0)
3631 {
3632 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3633 DBUG_RETURN(TRUE);
3634 }
3635
3636 /* else, the defaults yield the correct length for NULLs. */
3637 }
3638 else /* not NULL */
3639 {
3640 def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
3641 if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
3642 {
3643 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3644 DBUG_RETURN(TRUE);
3645 }
3646 }
3647 }
3648 calculate_interval_lengths(cs, interval, &field_length, &dummy);
3649 sql_field->length= field_length;
3650 }
3651 set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
3652 }
3653
3654 if (sql_field->sql_type == MYSQL_TYPE_BIT)
3655 {
3656 sql_field->pack_flag= FIELDFLAG_NUMBER;
3657 if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
3658 total_uneven_bit_length+= sql_field->length & 7;
3659 else
3660 sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
3661 }
3662
3663 sql_field->create_length_to_internal_length();
3664 if (prepare_blob_field(thd, sql_field))
3665 DBUG_RETURN(TRUE);
3666
3667 if (!(sql_field->flags & NOT_NULL_FLAG))
3668 null_fields++;
3669
3670 if (check_column_name(sql_field->field_name))
3671 {
3672 my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
3673 DBUG_RETURN(TRUE);
3674 }
3675
3676 /* Check if we have used the same field name before */
3677 for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
3678 {
3679 if (my_strcasecmp(system_charset_info,
3680 sql_field->field_name,
3681 dup_field->field_name) == 0)
3682 {
3683 /*
3684 If this was a CREATE ... SELECT statement, accept a field
3685 redefinition if we are changing a field in the SELECT part
3686 */
3687 if (field_no < select_field_pos || dup_no >= select_field_pos)
3688 {
3689 my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
3690 DBUG_RETURN(TRUE);
3691 }
3692 else
3693 {
3694 /* Field redefined */
3695
3696 /*
3697 If we are replacing a BIT field, revert the increment
3698 of total_uneven_bit_length that was done above.
3699 */
3700 if (sql_field->sql_type == MYSQL_TYPE_BIT &&
3701 file->ha_table_flags() & HA_CAN_BIT_FIELD)
3702 total_uneven_bit_length-= sql_field->length & 7;
3703
3704 sql_field->def= dup_field->def;
3705 sql_field->sql_type= dup_field->sql_type;
3706
3707 /*
3708 If we are replacing a field with a BIT field, we need
3709 to initialize pack_flag. Note that we do not need to
3710 increment total_uneven_bit_length here as this dup_field
3711 has already been processed.
3712 */
3713 if (sql_field->sql_type == MYSQL_TYPE_BIT)
3714 {
3715 sql_field->pack_flag= FIELDFLAG_NUMBER;
3716 if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD))
3717 sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
3718 }
3719
3720 sql_field->charset= (dup_field->charset ?
3721 dup_field->charset :
3722 create_info->default_table_charset);
3723 sql_field->length= dup_field->char_length;
3724 sql_field->pack_length= dup_field->pack_length;
3725 sql_field->key_length= dup_field->key_length;
3726 sql_field->decimals= dup_field->decimals;
3727 sql_field->create_length_to_internal_length();
3728 sql_field->unireg_check= dup_field->unireg_check;
3729 /*
3730 We're making one field from two, the result field will have
3731 dup_field->flags as flags. If we've incremented null_fields
3732 because of sql_field->flags, decrement it back.
3733 */
3734 if (!(sql_field->flags & NOT_NULL_FLAG))
3735 null_fields--;
3736 sql_field->flags= dup_field->flags;
3737 sql_field->interval= dup_field->interval;
3738 it2.remove(); // Remove first (create) definition
3739 select_field_pos--;
3740 break;
3741 }
3742 }
3743 }
3744 /* Don't pack rows in old tables if the user has requested this */
3745 if ((sql_field->flags & BLOB_FLAG) ||
3746 (sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
3747 create_info->row_type != ROW_TYPE_FIXED))
3748 (*db_options)|= HA_OPTION_PACK_RECORD;
3749 it2.rewind();
3750 }
3751
3752 /* record_offset will be increased with 'length-of-null-bits' later */
3753 record_offset= 0;
3754 null_fields+= total_uneven_bit_length;
3755
3756 it.rewind();
3757 while ((sql_field=it++))
3758 {
3759 DBUG_ASSERT(sql_field->charset != 0);
3760
3761 if (prepare_create_field(sql_field, &blob_columns,
3762 file->ha_table_flags()))
3763 DBUG_RETURN(TRUE);
3764 if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
3765 create_info->varchar= TRUE;
3766 sql_field->offset= record_offset;
3767 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
3768 auto_increment++;
3769 record_offset+= sql_field->pack_length;
3770 }
3771 if (auto_increment > 1)
3772 {
3773 my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
3774 DBUG_RETURN(TRUE);
3775 }
3776 if (auto_increment &&
3777 (file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
3778 {
3779 my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
3780 ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
3781 DBUG_RETURN(TRUE);
3782 }
3783
3784 if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
3785 {
3786 my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
3787 MYF(0));
3788 DBUG_RETURN(TRUE);
3789 }
3790
3791 /*
3792 CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows
3793 inserted in the created table depends on the order of the rows fetched
3794 from the select tables. This order may differ on master and slave. We
3795 therefore mark it as unsafe.
3796 */
3797 if (select_field_count > 0 && auto_increment)
3798 thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
3799
3800 /* Create keys */
3801
3802 List_iterator<Key> key_iterator(alter_info->key_list);
3803 List_iterator<Key> key_iterator2(alter_info->key_list);
3804 uint key_parts=0, fk_key_count=0;
3805 bool primary_key=0,unique_key=0;
3806 Key *key, *key2;
3807 uint tmp, key_number;
3808 /* special marker for keys to be ignored */
3809 static char ignore_key[1];
3810
3811 /* Calculate number of key segements */
3812 *key_count= 0;
3813
3814 while ((key=key_iterator++))
3815 {
3816 DBUG_PRINT("info", ("key name: '%s' type: %d", key->name.str ? key->name.str :
3817 "(none)" , key->type));
3818 if (key->type == Key::FOREIGN_KEY)
3819 {
3820 fk_key_count++;
3821 Foreign_key *fk_key= (Foreign_key*) key;
3822 if (fk_key->ref_columns.elements &&
3823 fk_key->ref_columns.elements != fk_key->columns.elements)
3824 {
3825 my_error(ER_WRONG_FK_DEF, MYF(0),
3826 (fk_key->name.str ? fk_key->name.str :
3827 "foreign key without name"),
3828 ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
3829 DBUG_RETURN(TRUE);
3830 }
3831 continue;
3832 }
3833 (*key_count)++;
3834 tmp=file->max_key_parts();
3835 if (key->columns.elements > tmp)
3836 {
3837 my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
3838 DBUG_RETURN(TRUE);
3839 }
3840 if (check_string_char_length(&key->name, "", NAME_CHAR_LEN,
3841 system_charset_info, 1))
3842 {
3843 my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
3844 DBUG_RETURN(TRUE);
3845 }
3846 key_iterator2.rewind ();
3847 if (key->type != Key::FOREIGN_KEY)
3848 {
3849 while ((key2 = key_iterator2++) != key)
3850 {
3851 /*
3852 foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
3853 'generated', and a generated key is a prefix of the other key.
3854 Then we do not need the generated shorter key.
3855 */
3856 if ((key2->type != Key::FOREIGN_KEY &&
3857 key2->name.str != ignore_key &&
3858 !foreign_key_prefix(key, key2)))
3859 {
3860 /* TODO: issue warning message */
3861 /* mark that the generated key should be ignored */
3862 if (!key2->generated ||
3863 (key->generated && key->columns.elements <
3864 key2->columns.elements))
3865 key->name.str= ignore_key;
3866 else
3867 {
3868 key2->name.str= ignore_key;
3869 key_parts-= key2->columns.elements;
3870 (*key_count)--;
3871 }
3872 break;
3873 }
3874 }
3875 }
3876 if (key->name.str != ignore_key)
3877 key_parts+=key->columns.elements;
3878 else
3879 (*key_count)--;
3880 if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
3881 !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
3882 {
3883 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
3884 DBUG_RETURN(TRUE);
3885 }
3886 }
3887 tmp=file->max_keys();
3888 if (*key_count > tmp)
3889 {
3890 my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
3891 DBUG_RETURN(TRUE);
3892 }
3893
3894 (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
3895 key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
3896 if (!*key_info_buffer || ! key_part_info)
3897 DBUG_RETURN(TRUE); // Out of memory
3898
3899 key_iterator.rewind();
3900 key_number=0;
3901 for (; (key=key_iterator++) ; key_number++)
3902 {
3903 uint key_length=0;
3904 Key_part_spec *column;
3905
3906 if (key->name.str == ignore_key)
3907 {
3908 /* ignore redundant keys */
3909 do
3910 key=key_iterator++;
3911 while (key && key->name.str == ignore_key);
3912 if (!key)
3913 break;
3914 }
3915
3916 switch (key->type) {
3917 case Key::MULTIPLE:
3918 key_info->flags= 0;
3919 break;
3920 case Key::FULLTEXT:
3921 key_info->flags= HA_FULLTEXT;
3922 if ((key_info->parser_name= &key->key_create_info.parser_name)->str)
3923 key_info->flags|= HA_USES_PARSER;
3924 else
3925 key_info->parser_name= 0;
3926 break;
3927 case Key::SPATIAL:
3928 #ifdef HAVE_SPATIAL
3929 key_info->flags= HA_SPATIAL;
3930 break;
3931 #else
3932 my_error(ER_FEATURE_DISABLED, MYF(0),
3933 sym_group_geom.name, sym_group_geom.needed_define);
3934 DBUG_RETURN(TRUE);
3935 #endif
3936 case Key::FOREIGN_KEY:
3937 key_number--; // Skip this key
3938 continue;
3939 default:
3940 key_info->flags = HA_NOSAME;
3941 break;
3942 }
3943 if (key->generated)
3944 key_info->flags|= HA_GENERATED_KEY;
3945
3946 key_info->user_defined_key_parts=(uint8) key->columns.elements;
3947 key_info->actual_key_parts= key_info->user_defined_key_parts;
3948 key_info->key_part=key_part_info;
3949 key_info->usable_key_parts= key_number;
3950 key_info->algorithm= key->key_create_info.algorithm;
3951
3952 if (key->type == Key::FULLTEXT)
3953 {
3954 if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
3955 {
3956 #ifdef WITH_PARTITION_STORAGE_ENGINE
3957 if (file->ht == partition_hton)
3958 {
3959 my_message(ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING,
3960 ER(ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING),
3961 MYF(0));
3962 DBUG_RETURN(TRUE);
3963 }
3964 #endif
3965 my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
3966 MYF(0));
3967 DBUG_RETURN(TRUE);
3968 }
3969 }
3970 /*
3971 Make SPATIAL to be RTREE by default
3972 SPATIAL only on BLOB or at least BINARY, this
3973 actually should be replaced by special GEOM type
3974 in near future when new frm file is ready
3975 checking for proper key parts number:
3976 */
3977
3978 /* TODO: Add proper checks if handler supports key_type and algorithm */
3979 if (key_info->flags & HA_SPATIAL)
3980 {
3981 if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
3982 {
3983 my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
3984 MYF(0));
3985 DBUG_RETURN(TRUE);
3986 }
3987 if (key_info->user_defined_key_parts != 1)
3988 {
3989 my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
3990 DBUG_RETURN(TRUE);
3991 }
3992 }
3993 else if (key_info->algorithm == HA_KEY_ALG_RTREE)
3994 {
3995 #ifdef HAVE_RTREE_KEYS
3996 if ((key_info->user_defined_key_parts & 1) == 1)
3997 {
3998 my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
3999 DBUG_RETURN(TRUE);
4000 }
4001 /* TODO: To be deleted */
4002 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
4003 DBUG_RETURN(TRUE);
4004 #else
4005 my_error(ER_FEATURE_DISABLED, MYF(0),
4006 sym_group_rtree.name, sym_group_rtree.needed_define);
4007 DBUG_RETURN(TRUE);
4008 #endif
4009 }
4010
4011 /* Take block size from key part or table part */
4012 /*
4013 TODO: Add warning if block size changes. We can't do it here, as
4014 this may depend on the size of the key
4015 */
4016 key_info->block_size= (key->key_create_info.block_size ?
4017 key->key_create_info.block_size :
4018 create_info->key_block_size);
4019
4020 if (key_info->block_size)
4021 key_info->flags|= HA_USES_BLOCK_SIZE;
4022
4023 List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
4024 const CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
4025 for (uint column_nr=0 ; (column=cols++) ; column_nr++)
4026 {
4027 Key_part_spec *dup_column;
4028
4029 it.rewind();
4030 field=0;
4031 while ((sql_field=it++) &&
4032 my_strcasecmp(system_charset_info,
4033 column->field_name.str,
4034 sql_field->field_name))
4035 field++;
4036 if (!sql_field)
4037 {
4038 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
4039 DBUG_RETURN(TRUE);
4040 }
4041 while ((dup_column= cols2++) != column)
4042 {
4043 if (!my_strcasecmp(system_charset_info,
4044 column->field_name.str, dup_column->field_name.str))
4045 {
4046 my_printf_error(ER_DUP_FIELDNAME,
4047 ER(ER_DUP_FIELDNAME),MYF(0),
4048 column->field_name.str);
4049 DBUG_RETURN(TRUE);
4050 }
4051 }
4052 cols2.rewind();
4053 if (key->type == Key::FULLTEXT)
4054 {
4055 if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
4056 sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
4057 !f_is_blob(sql_field->pack_flag)) ||
4058 sql_field->charset == &my_charset_bin ||
4059 sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
4060 (ft_key_charset && sql_field->charset != ft_key_charset))
4061 {
4062 my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
4063 DBUG_RETURN(-1);
4064 }
4065 ft_key_charset=sql_field->charset;
4066 /*
4067 for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
4068 code anyway, and 0 (set to column width later) for char's. it has
4069 to be correct col width for char's, as char data are not prefixed
4070 with length (unlike blobs, where ft code takes data length from a
4071 data prefix, ignoring column->length).
4072 */
4073 column->length= MY_TEST(f_is_blob(sql_field->pack_flag));
4074 }
4075 else
4076 {
4077 column->length*= sql_field->charset->mbmaxlen;
4078
4079 if (key->type == Key::SPATIAL)
4080 {
4081 if (column->length)
4082 {
4083 my_error(ER_WRONG_SUB_KEY, MYF(0));
4084 DBUG_RETURN(TRUE);
4085 }
4086 if (!f_is_geom(sql_field->pack_flag))
4087 {
4088 my_error(ER_SPATIAL_MUST_HAVE_GEOM_COL, MYF(0));
4089 DBUG_RETURN(TRUE);
4090 }
4091 }
4092
4093 if (f_is_blob(sql_field->pack_flag) ||
4094 (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
4095 {
4096 if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
4097 {
4098 my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
4099 DBUG_RETURN(TRUE);
4100 }
4101 if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
4102 Field::GEOM_POINT)
4103 column->length= MAX_LEN_GEOM_POINT_FIELD;
4104 if (!column->length)
4105 {
4106 my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
4107 DBUG_RETURN(TRUE);
4108 }
4109 }
4110 #ifdef HAVE_SPATIAL
4111 if (key->type == Key::SPATIAL)
4112 {
4113 if (!column->length)
4114 {
4115 /*
4116 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
4117 Lately we'll extend this code to support more dimensions
4118 */
4119 column->length= 4*sizeof(double);
4120 }
4121 }
4122 #endif
4123 if (!(sql_field->flags & NOT_NULL_FLAG))
4124 {
4125 if (key->type == Key::PRIMARY)
4126 {
4127 /* Implicitly set primary key fields to NOT NULL for ISO conf. */
4128 sql_field->flags|= NOT_NULL_FLAG;
4129 sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
4130 null_fields--;
4131 }
4132 else
4133 {
4134 key_info->flags|= HA_NULL_PART_KEY;
4135 if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
4136 {
4137 my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
4138 DBUG_RETURN(TRUE);
4139 }
4140 if (key->type == Key::SPATIAL)
4141 {
4142 my_message(ER_SPATIAL_CANT_HAVE_NULL,
4143 ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
4144 DBUG_RETURN(TRUE);
4145 }
4146 }
4147 }
4148 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
4149 {
4150 if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
4151 auto_increment--; // Field is used
4152 }
4153 }
4154
4155 key_part_info->fieldnr= field;
4156 key_part_info->offset= (uint16) sql_field->offset;
4157 key_part_info->key_type=sql_field->pack_flag;
4158 uint key_part_length= sql_field->key_length;
4159
4160 if (column->length)
4161 {
4162 if (f_is_blob(sql_field->pack_flag))
4163 {
4164 key_part_length= column->length;
4165 /*
4166 There is a possibility that the given prefix length is less
4167 than the engine max key part length, but still greater
4168 than the BLOB field max size. We handle this case
4169 using the max_field_size variable below.
4170 */
4171 uint max_field_size= sql_field->key_length * sql_field->charset->mbmaxlen;
4172 if ((max_field_size && key_part_length > max_field_size) ||
4173 key_part_length > max_key_length ||
4174 key_part_length > file->max_key_part_length())
4175 {
4176 // Given prefix length is too large, adjust it.
4177 key_part_length= min(max_key_length, file->max_key_part_length());
4178 if (max_field_size)
4179 key_part_length= min(key_part_length, max_field_size);
4180 if (key->type == Key::MULTIPLE)
4181 {
4182 /* not a critical problem */
4183 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4184 ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
4185 key_part_length);
4186 /* Align key length to multibyte char boundary */
4187 key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
4188 /*
4189 If SQL_MODE is STRICT, then report error, else report warning
4190 and continue execution.
4191 */
4192 if (thd->is_error())
4193 DBUG_RETURN(true);
4194 }
4195 else
4196 {
4197 my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
4198 DBUG_RETURN(TRUE);
4199 }
4200 }
4201 }
4202 // Catch invalid use of partial keys
4203 else if (!f_is_geom(sql_field->pack_flag) &&
4204 // is the key partial?
4205 column->length != key_part_length &&
4206 // is prefix length bigger than field length?
4207 (column->length > key_part_length ||
4208 // can the field have a partial key?
4209 !Field::type_can_have_key_part (sql_field->sql_type) ||
4210 // a packed field can't be used in a partial key
4211 f_is_packed(sql_field->pack_flag) ||
4212 // does the storage engine allow prefixed search?
4213 ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
4214 // and is this a 'unique' key?
4215 (key_info->flags & HA_NOSAME))))
4216 {
4217 my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
4218 DBUG_RETURN(TRUE);
4219 }
4220 else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
4221 key_part_length= column->length;
4222 }
4223 else if (key_part_length == 0)
4224 {
4225 my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
4226 DBUG_RETURN(TRUE);
4227 }
4228 if (key_part_length > file->max_key_part_length() &&
4229 key->type != Key::FULLTEXT)
4230 {
4231 key_part_length= file->max_key_part_length();
4232 if (key->type == Key::MULTIPLE)
4233 {
4234 /* not a critical problem */
4235 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4236 ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
4237 key_part_length);
4238 /* Align key length to multibyte char boundary */
4239 key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
4240 /*
4241 If SQL_MODE is STRICT, then report error, else report warning
4242 and continue execution.
4243 */
4244 if (thd->is_error())
4245 DBUG_RETURN(true);
4246 }
4247 else
4248 {
4249 my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
4250 DBUG_RETURN(TRUE);
4251 }
4252 }
4253 key_part_info->length= (uint16) key_part_length;
4254 /* Use packed keys for long strings on the first column */
4255 if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
4256 !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
4257 (key_part_length >= KEY_DEFAULT_PACK_LENGTH &&
4258 (sql_field->sql_type == MYSQL_TYPE_STRING ||
4259 sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
4260 sql_field->pack_flag & FIELDFLAG_BLOB)))
4261 {
4262 if ((column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB)) ||
4263 sql_field->sql_type == MYSQL_TYPE_VARCHAR)
4264 key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
4265 else
4266 key_info->flags|= HA_PACK_KEY;
4267 }
4268 /*
4269 Check if the key segment is partial, set the key flag
4270 accordingly. The key segment for a POINT column is NOT considered
4271 partial if key_length==MAX_LEN_GEOM_POINT_FIELD.
4272 */
4273 if (key_part_length != sql_field->key_length &&
4274 !(sql_field->sql_type == MYSQL_TYPE_GEOMETRY &&
4275 sql_field->geom_type == Field::GEOM_POINT &&
4276 key_part_length == MAX_LEN_GEOM_POINT_FIELD))
4277 {
4278 key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
4279 }
4280
4281 key_length+= key_part_length;
4282 key_part_info++;
4283
4284 /* Create the key name based on the first column (if not given) */
4285 if (column_nr == 0)
4286 {
4287 if (key->type == Key::PRIMARY)
4288 {
4289 if (primary_key)
4290 {
4291 my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
4292 MYF(0));
4293 DBUG_RETURN(TRUE);
4294 }
4295 key_name=primary_key_name;
4296 primary_key=1;
4297 }
4298 else if (!(key_name= key->name.str))
4299 key_name=make_unique_key_name(sql_field->field_name,
4300 *key_info_buffer, key_info);
4301 if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
4302 {
4303 my_error(ER_DUP_KEYNAME, MYF(0), key_name);
4304 DBUG_RETURN(TRUE);
4305 }
4306 key_info->name=(char*) key_name;
4307 }
4308 }
4309 key_info->actual_flags= key_info->flags;
4310 if (!key_info->name || check_column_name(key_info->name))
4311 {
4312 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
4313 DBUG_RETURN(TRUE);
4314 }
4315 if (!(key_info->flags & HA_NULL_PART_KEY))
4316 unique_key=1;
4317 key_info->key_length=(uint16) key_length;
4318 if (key_length > max_key_length && key->type != Key::FULLTEXT)
4319 {
4320 my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
4321 DBUG_RETURN(TRUE);
4322 }
4323 if (validate_comment_length(thd, key->key_create_info.comment.str,
4324 &key->key_create_info.comment.length,
4325 INDEX_COMMENT_MAXLEN,
4326 ER_TOO_LONG_INDEX_COMMENT,
4327 key_info->name))
4328 DBUG_RETURN(true);
4329 key_info->comment.length= key->key_create_info.comment.length;
4330 if (key_info->comment.length > 0)
4331 {
4332 key_info->flags|= HA_USES_COMMENT;
4333 key_info->comment.str= key->key_create_info.comment.str;
4334 }
4335
4336 // Check if a duplicate index is defined.
4337 check_duplicate_key(thd, error_schema_name, error_table_name,
4338 key, key_info, alter_info);
4339
4340 key_info++;
4341 }
4342
4343 if (!unique_key && !primary_key &&
4344 (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
4345 {
4346 my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
4347 DBUG_RETURN(TRUE);
4348 }
4349 if (auto_increment > 0)
4350 {
4351 my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
4352 DBUG_RETURN(TRUE);
4353 }
4354 /* Sort keys in optimized order */
4355 my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
4356 (qsort_cmp) sort_keys);
4357 create_info->null_bits= null_fields;
4358
4359 /* Check fields. */
4360 it.rewind();
4361 while ((sql_field=it++))
4362 {
4363 Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
4364
4365 if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
4366 !sql_field->def &&
4367 is_timestamp_type(sql_field->sql_type) &&
4368 (sql_field->flags & NOT_NULL_FLAG) &&
4369 (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
4370 {
4371 /*
4372 An error should be reported if:
4373 - NO_ZERO_DATE SQL mode is active;
4374 - there is no explicit DEFAULT clause (default column value);
4375 - this is a TIMESTAMP column;
4376 - the column is not NULL;
4377 - this is not the DEFAULT CURRENT_TIMESTAMP column.
4378
4379 In other words, an error should be reported if
4380 - NO_ZERO_DATE SQL mode is active;
4381 - the column definition is equivalent to
4382 'column_name TIMESTAMP DEFAULT 0'.
4383 */
4384
4385 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
4386 DBUG_RETURN(TRUE);
4387 }
4388 }
4389
4390 DBUG_RETURN(FALSE);
4391 }
4392
4393 /**
4394 @brief check comment length of table, column, index and partition
4395
4396 @details If comment length is more than the standard length
4397 truncate it and store the comment length upto the standard
4398 comment length size
4399
4400 @param thd Thread handle
4401 @param comment_str Comment string
4402 @param[in,out] comment_len Comment length
4403 @param max_len Maximum allowed comment length
4404 @param err_code Error message
4405 @param comment_name Type of comment
4406
4407 @return Operation status
4408 @retval true Error found
4409 @retval false On success
4410 */
4411
validate_comment_length(THD * thd,const char * comment_str,size_t * comment_len,uint max_len,uint err_code,const char * comment_name)4412 bool validate_comment_length(THD *thd, const char *comment_str,
4413 size_t *comment_len, uint max_len,
4414 uint err_code, const char *comment_name)
4415 {
4416 int length= 0;
4417 DBUG_ENTER("validate_comment_length");
4418 uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
4419 comment_str,
4420 comment_str +
4421 *comment_len,
4422 max_len);
4423 if (tmp_len < *comment_len)
4424 {
4425 if (thd->is_strict_mode())
4426 {
4427 my_error(err_code, MYF(0),
4428 comment_name, static_cast<ulong>(max_len));
4429 DBUG_RETURN(true);
4430 }
4431 char warn_buff[MYSQL_ERRMSG_SIZE];
4432 length= my_snprintf(warn_buff, sizeof(warn_buff), ER(err_code),
4433 comment_name, static_cast<ulong>(max_len));
4434 /* do not push duplicate warnings */
4435 if (!thd->get_stmt_da()->has_sql_condition(warn_buff, length))
4436 push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
4437 err_code, warn_buff);
4438 *comment_len= tmp_len;
4439 }
4440 DBUG_RETURN(false);
4441 }
4442
4443
4444 /*
4445 Set table default charset, if not set
4446
4447 SYNOPSIS
4448 set_table_default_charset()
4449 create_info Table create information
4450
4451 DESCRIPTION
4452 If the table character set was not given explicitely,
4453 let's fetch the database default character set and
4454 apply it to the table.
4455 */
4456
set_table_default_charset(THD * thd,HA_CREATE_INFO * create_info,char * db)4457 static void set_table_default_charset(THD *thd,
4458 HA_CREATE_INFO *create_info, char *db)
4459 {
4460 /*
4461 If the table character set was not given explicitly,
4462 let's fetch the database default character set and
4463 apply it to the table.
4464 */
4465 if (!create_info->default_table_charset)
4466 {
4467 HA_CREATE_INFO db_info;
4468
4469 load_db_opt_by_name(thd, db, &db_info);
4470
4471 create_info->default_table_charset= db_info.default_table_charset;
4472 }
4473 }
4474
4475
4476 /*
4477 Extend long VARCHAR fields to blob & prepare field if it's a blob
4478
4479 SYNOPSIS
4480 prepare_blob_field()
4481 sql_field Field to check
4482
4483 RETURN
4484 0 ok
4485 1 Error (sql_field can't be converted to blob)
4486 In this case the error is given
4487 */
4488
prepare_blob_field(THD * thd,Create_field * sql_field)4489 static bool prepare_blob_field(THD *thd, Create_field *sql_field)
4490 {
4491 DBUG_ENTER("prepare_blob_field");
4492
4493 if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
4494 !(sql_field->flags & BLOB_FLAG))
4495 {
4496 /* Convert long VARCHAR columns to TEXT or BLOB */
4497 char warn_buff[MYSQL_ERRMSG_SIZE];
4498
4499 if (sql_field->def || thd->is_strict_mode())
4500 {
4501 my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
4502 static_cast<ulong>(MAX_FIELD_VARCHARLENGTH /
4503 sql_field->charset->mbmaxlen));
4504 DBUG_RETURN(1);
4505 }
4506 sql_field->sql_type= MYSQL_TYPE_BLOB;
4507 sql_field->flags|= BLOB_FLAG;
4508 my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_AUTO_CONVERT), sql_field->field_name,
4509 (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
4510 (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
4511 push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
4512 warn_buff);
4513 }
4514
4515 if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
4516 {
4517 if (sql_field->sql_type == FIELD_TYPE_BLOB ||
4518 sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
4519 sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB)
4520 {
4521 /* The user has given a length to the blob column */
4522 sql_field->sql_type= get_blob_type_from_length(sql_field->length);
4523 sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
4524 }
4525 sql_field->length= 0;
4526 }
4527 DBUG_RETURN(0);
4528 }
4529
4530
4531 /*
4532 Preparation of Create_field for SP function return values.
4533 Based on code used in the inner loop of mysql_prepare_create_table()
4534 above.
4535
4536 SYNOPSIS
4537 sp_prepare_create_field()
4538 thd Thread object
4539 sql_field Field to prepare
4540
4541 DESCRIPTION
4542 Prepares the field structures for field creation.
4543
4544 */
4545
sp_prepare_create_field(THD * thd,Create_field * sql_field)4546 static void sp_prepare_create_field(THD *thd, Create_field *sql_field)
4547 {
4548 if (sql_field->sql_type == MYSQL_TYPE_SET ||
4549 sql_field->sql_type == MYSQL_TYPE_ENUM)
4550 {
4551 uint32 field_length, dummy;
4552 if (sql_field->sql_type == MYSQL_TYPE_SET)
4553 {
4554 calculate_interval_lengths(sql_field->charset,
4555 sql_field->interval, &dummy,
4556 &field_length);
4557 sql_field->length= field_length +
4558 (sql_field->interval->count - 1);
4559 }
4560 else /* MYSQL_TYPE_ENUM */
4561 {
4562 calculate_interval_lengths(sql_field->charset,
4563 sql_field->interval,
4564 &field_length, &dummy);
4565 sql_field->length= field_length;
4566 }
4567 set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
4568 }
4569
4570 if (sql_field->sql_type == MYSQL_TYPE_BIT)
4571 {
4572 sql_field->pack_flag= FIELDFLAG_NUMBER |
4573 FIELDFLAG_TREAT_BIT_AS_CHAR;
4574 }
4575 sql_field->create_length_to_internal_length();
4576 DBUG_ASSERT(sql_field->def == 0);
4577 /* Can't go wrong as sql_field->def is not defined */
4578 (void) prepare_blob_field(thd, sql_field);
4579 }
4580
4581
4582 /**
4583 Create a table
4584
4585 @param thd Thread object
4586 @param db Database
4587 @param table_name Table name
4588 @param error_table_name The real table name in case table_name is a temporary
4589 table (ALTER). Only used for error messages.
4590 @param path Path to table (i.e. to its .FRM file without
4591 the extension).
4592 @param create_info Create information (like MAX_ROWS)
4593 @param alter_info Description of fields and keys for new table
4594 @param internal_tmp_table Set to true if this is an internal temporary table
4595 (From ALTER TABLE)
4596 @param select_field_count Number of fields coming from SELECT part of
4597 CREATE TABLE ... SELECT statement. Must be zero
4598 for standard create of table.
4599 @param no_ha_table Indicates that only .FRM file (and PAR file if table
4600 is partitioned) needs to be created and not a table
4601 in the storage engine.
4602 @param[out] is_trans Identifies the type of engine where the table
4603 was created: either trans or non-trans.
4604 @param[out] key_info Array of KEY objects describing keys in table
4605 which was created.
4606 @param[out] key_count Number of keys in table which was created.
4607
4608 If one creates a temporary table, this is automatically opened
4609
4610 Note that this function assumes that caller already have taken
4611 exclusive metadata lock on table being created or used some other
4612 way to ensure that concurrent operations won't intervene.
4613 mysql_create_table() is a wrapper that can be used for this.
4614
4615 @retval false OK
4616 @retval true error
4617 */
4618
4619 static
create_table_impl(THD * thd,const char * db,const char * table_name,const char * error_table_name,const char * path,HA_CREATE_INFO * create_info,Alter_info * alter_info,bool internal_tmp_table,uint select_field_count,bool no_ha_table,bool * is_trans,KEY ** key_info,uint * key_count)4620 bool create_table_impl(THD *thd,
4621 const char *db, const char *table_name,
4622 const char *error_table_name,
4623 const char *path,
4624 HA_CREATE_INFO *create_info,
4625 Alter_info *alter_info,
4626 bool internal_tmp_table,
4627 uint select_field_count,
4628 bool no_ha_table,
4629 bool *is_trans,
4630 KEY **key_info,
4631 uint *key_count)
4632 {
4633 const char *alias;
4634 uint db_options;
4635 handler *file;
4636 bool error= TRUE;
4637 DBUG_ENTER("create_table_impl");
4638 DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
4639 db, table_name, internal_tmp_table));
4640
4641
4642 /* Check for duplicate fields and check type of table to create */
4643 if (!alter_info->create_list.elements)
4644 {
4645 my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
4646 MYF(0));
4647 DBUG_RETURN(TRUE);
4648 }
4649 if (check_engine(thd, db, table_name, create_info))
4650 DBUG_RETURN(TRUE);
4651
4652 set_table_default_charset(thd, create_info, (char*) db);
4653
4654 db_options= create_info->table_options;
4655 if (create_info->row_type == ROW_TYPE_DYNAMIC)
4656 db_options|=HA_OPTION_PACK_RECORD;
4657 alias= table_case_name(create_info, table_name);
4658 if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
4659 create_info->db_type)))
4660 {
4661 mem_alloc_error(sizeof(handler));
4662 DBUG_RETURN(TRUE);
4663 }
4664 #ifdef WITH_PARTITION_STORAGE_ENGINE
4665 partition_info *part_info= thd->work_part_info;
4666
4667 if (!part_info && create_info->db_type->partition_flags &&
4668 (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION))
4669 {
4670 /*
4671 Table is not defined as a partitioned table but the engine handles
4672 all tables as partitioned. The handler will set up the partition info
4673 object with the default settings.
4674 */
4675 thd->work_part_info= part_info= new partition_info();
4676 if (!part_info)
4677 {
4678 mem_alloc_error(sizeof(partition_info));
4679 DBUG_RETURN(TRUE);
4680 }
4681 file->set_auto_partitions(part_info);
4682 part_info->default_engine_type= create_info->db_type;
4683 part_info->is_auto_partitioned= TRUE;
4684 }
4685 if (part_info)
4686 {
4687 /*
4688 The table has been specified as a partitioned table.
4689 If this is part of an ALTER TABLE the handler will be the partition
4690 handler but we need to specify the default handler to use for
4691 partitions also in the call to check_partition_info. We transport
4692 this information in the default_db_type variable, it is either
4693 DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command.
4694 */
4695 Key *key;
4696 handlerton *part_engine_type= create_info->db_type;
4697 char *part_syntax_buf;
4698 uint syntax_len;
4699 handlerton *engine_type;
4700 List_iterator<partition_element> part_it(part_info->partitions);
4701 partition_element *part_elem;
4702
4703 while ((part_elem= part_it++))
4704 {
4705 if (part_elem->part_comment)
4706 {
4707 size_t comment_len= strlen(part_elem->part_comment);
4708 if (validate_comment_length(thd, part_elem->part_comment,
4709 &comment_len,
4710 TABLE_PARTITION_COMMENT_MAXLEN,
4711 ER_TOO_LONG_TABLE_PARTITION_COMMENT,
4712 part_elem->partition_name))
4713 DBUG_RETURN(true);
4714 part_elem->part_comment[comment_len]= '\0';
4715 }
4716 if (part_elem->subpartitions.elements)
4717 {
4718 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4719 partition_element *subpart_elem;
4720 while ((subpart_elem= sub_it++))
4721 {
4722 if (subpart_elem->part_comment)
4723 {
4724 size_t comment_len= strlen(subpart_elem->part_comment);
4725 if (validate_comment_length(thd, subpart_elem->part_comment,
4726 &comment_len,
4727 TABLE_PARTITION_COMMENT_MAXLEN,
4728 ER_TOO_LONG_TABLE_PARTITION_COMMENT,
4729 subpart_elem->partition_name))
4730 DBUG_RETURN(true);
4731 subpart_elem->part_comment[comment_len]= '\0';
4732 }
4733 }
4734 }
4735 }
4736 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4737 {
4738 my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
4739 goto err;
4740 }
4741 if ((part_engine_type == partition_hton) &&
4742 part_info->default_engine_type)
4743 {
4744 /*
4745 This only happens at ALTER TABLE.
4746 default_engine_type was assigned from the engine set in the ALTER
4747 TABLE command.
4748 */
4749 ;
4750 }
4751 else
4752 {
4753 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
4754 {
4755 part_info->default_engine_type= create_info->db_type;
4756 }
4757 else
4758 {
4759 if (part_info->default_engine_type == NULL)
4760 {
4761 part_info->default_engine_type= ha_checktype(thd,
4762 DB_TYPE_DEFAULT, 0, 0);
4763 }
4764 }
4765 }
4766 DBUG_PRINT("info", ("db_type = %s create_info->db_type = %s",
4767 ha_resolve_storage_engine_name(part_info->default_engine_type),
4768 ha_resolve_storage_engine_name(create_info->db_type)));
4769 if (part_info->check_partition_info(thd, &engine_type, file,
4770 create_info, FALSE))
4771 goto err;
4772 part_info->default_engine_type= engine_type;
4773
4774 /*
4775 We reverse the partitioning parser and generate a standard format
4776 for syntax stored in frm file.
4777 */
4778 if (!(part_syntax_buf= generate_partition_syntax(part_info,
4779 &syntax_len,
4780 TRUE, TRUE,
4781 create_info,
4782 alter_info,
4783 NULL)))
4784 goto err;
4785 part_info->part_info_string= part_syntax_buf;
4786 part_info->part_info_len= syntax_len;
4787 if ((!(engine_type->partition_flags &&
4788 engine_type->partition_flags() & HA_CAN_PARTITION)) ||
4789 create_info->db_type == partition_hton)
4790 {
4791 /*
4792 The handler assigned to the table cannot handle partitioning.
4793 Assign the partition handler as the handler of the table.
4794 */
4795 DBUG_PRINT("info", ("db_type: %s",
4796 ha_resolve_storage_engine_name(create_info->db_type)));
4797 delete file;
4798 create_info->db_type= partition_hton;
4799 if (!(file= get_ha_partition(part_info)))
4800 {
4801 DBUG_RETURN(TRUE);
4802 }
4803 /*
4804 If we have default number of partitions or subpartitions we
4805 might require to set-up the part_info object such that it
4806 creates a proper .par file. The current part_info object is
4807 only used to create the frm-file and .par-file.
4808 */
4809 if (part_info->use_default_num_partitions &&
4810 part_info->num_parts &&
4811 (int)part_info->num_parts !=
4812 file->get_default_no_partitions(create_info))
4813 {
4814 uint i;
4815 List_iterator<partition_element> part_it(part_info->partitions);
4816 part_it++;
4817 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
4818 for (i= 1; i < part_info->partitions.elements; i++)
4819 (part_it++)->part_state= PART_TO_BE_DROPPED;
4820 }
4821 else if (part_info->is_sub_partitioned() &&
4822 part_info->use_default_num_subpartitions &&
4823 part_info->num_subparts &&
4824 (int)part_info->num_subparts !=
4825 file->get_default_no_partitions(create_info))
4826 {
4827 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
4828 part_info->num_subparts= file->get_default_no_partitions(create_info);
4829 }
4830 }
4831 else if (create_info->db_type != engine_type)
4832 {
4833 /*
4834 We come here when we don't use a partitioned handler.
4835 Since we use a partitioned table it must be "native partitioned".
4836 We have switched engine from defaults, most likely only specified
4837 engines in partition clauses.
4838 */
4839 delete file;
4840 if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
4841 engine_type)))
4842 {
4843 mem_alloc_error(sizeof(handler));
4844 DBUG_RETURN(TRUE);
4845 }
4846 }
4847 /*
4848 Unless table's storage engine supports partitioning natively
4849 don't allow foreign keys on partitioned tables (they won't
4850 work work even with InnoDB beneath of partitioning engine).
4851 If storage engine handles partitioning natively (like NDB)
4852 foreign keys support is possible, so we let the engine decide.
4853 */
4854 if (create_info->db_type == partition_hton)
4855 {
4856 List_iterator_fast<Key> key_iterator(alter_info->key_list);
4857 while ((key= key_iterator++))
4858 {
4859 if (key->type == Key::FOREIGN_KEY)
4860 {
4861 my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
4862 goto err;
4863 }
4864 }
4865 }
4866 }
4867 #endif
4868
4869 if (mysql_prepare_create_table(thd, db, error_table_name,
4870 create_info, alter_info,
4871 internal_tmp_table,
4872 &db_options, file,
4873 key_info, key_count,
4874 select_field_count))
4875 goto err;
4876
4877 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4878 create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
4879
4880 /* Check if table already exists */
4881 if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
4882 find_temporary_table(thd, db, table_name))
4883 {
4884 if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
4885 {
4886 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
4887 ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
4888 alias);
4889 error= 0;
4890 goto err;
4891 }
4892 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
4893 goto err;
4894 }
4895
4896 if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
4897 {
4898 char frm_name[FN_REFLEN+1];
4899 strxnmov(frm_name, sizeof(frm_name) - 1, path, reg_ext, NullS);
4900
4901 if (!access(frm_name, F_OK))
4902 {
4903 if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
4904 goto warn;
4905 my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
4906 goto err;
4907 }
4908 /*
4909 We don't assert here, but check the result, because the table could be
4910 in the table definition cache and in the same time the .frm could be
4911 missing from the disk, in case of manual intervention which deletes
4912 the .frm file. The user has to use FLUSH TABLES; to clear the cache.
4913 Then she could create the table. This case is pretty obscure and
4914 therefore we don't introduce a new error message only for it.
4915 */
4916 mysql_mutex_lock(&LOCK_open);
4917 if (get_cached_table_share(db, table_name))
4918 {
4919 mysql_mutex_unlock(&LOCK_open);
4920 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
4921 goto err;
4922 }
4923 mysql_mutex_unlock(&LOCK_open);
4924 }
4925
4926 /*
4927 Check that table with given name does not already
4928 exist in any storage engine. In such a case it should
4929 be discovered and the error ER_TABLE_EXISTS_ERROR be returned
4930 unless user specified CREATE TABLE IF EXISTS
4931 An exclusive metadata lock ensures that no
4932 one else is attempting to discover the table. Since
4933 it's not on disk as a frm file, no one could be using it!
4934 */
4935 if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
4936 {
4937 bool create_if_not_exists =
4938 create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
4939 int retcode = ha_table_exists_in_engine(thd, db, table_name);
4940 DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
4941 switch (retcode)
4942 {
4943 case HA_ERR_NO_SUCH_TABLE:
4944 /* Normal case, no table exists. we can go and create it */
4945 break;
4946 case HA_ERR_TABLE_EXIST:
4947 DBUG_PRINT("info", ("Table existed in handler"));
4948
4949 if (create_if_not_exists)
4950 goto warn;
4951 my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
4952 goto err;
4953 break;
4954 default:
4955 DBUG_PRINT("info", ("error: %u from storage engine", retcode));
4956 my_error(retcode, MYF(0),table_name);
4957 goto err;
4958 }
4959 }
4960
4961 THD_STAGE_INFO(thd, stage_creating_table);
4962
4963 {
4964 size_t dirlen;
4965 char dirpath[FN_REFLEN];
4966
4967 /*
4968 data_file_name and index_file_name include the table name without
4969 extension. Mostly this does not refer to an existing file. When
4970 comparing data_file_name or index_file_name against the data
4971 directory, we try to resolve all symbolic links. On some systems,
4972 we use realpath(3) for the resolution. This returns ENOENT if the
4973 resolved path does not refer to an existing file. my_realpath()
4974 does then copy the requested path verbatim, without symlink
4975 resolution. Thereafter the comparison can fail even if the
4976 requested path is within the data directory. E.g. if symlinks to
4977 another file system are used. To make realpath(3) return the
4978 resolved path, we strip the table name and compare the directory
4979 path only. If the directory doesn't exist either, table creation
4980 will fail anyway.
4981 */
4982 if (create_info->data_file_name)
4983 {
4984 dirname_part(dirpath, create_info->data_file_name, &dirlen);
4985 if (test_if_data_home_dir(dirpath))
4986 {
4987 my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
4988 goto err;
4989 }
4990 }
4991 if (create_info->index_file_name)
4992 {
4993 dirname_part(dirpath, create_info->index_file_name, &dirlen);
4994 if (test_if_data_home_dir(dirpath))
4995 {
4996 my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
4997 goto err;
4998 }
4999 }
5000 }
5001
5002 #ifdef WITH_PARTITION_STORAGE_ENGINE
5003 if (check_partition_dirs(thd->lex->part_info))
5004 {
5005 goto err;
5006 }
5007 #endif /* WITH_PARTITION_STORAGE_ENGINE */
5008
5009 if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
5010 {
5011 if (create_info->data_file_name)
5012 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5013 WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
5014 "DATA DIRECTORY");
5015 if (create_info->index_file_name)
5016 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5017 WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
5018 "INDEX DIRECTORY");
5019 create_info->data_file_name= create_info->index_file_name= 0;
5020 }
5021 create_info->table_options=db_options;
5022
5023 /*
5024 Create .FRM (and .PAR file for partitioned table).
5025 If "no_ha_table" is false also create table in storage engine.
5026 */
5027 if (rea_create_table(thd, path, db, table_name,
5028 create_info, alter_info->create_list,
5029 *key_count, *key_info, file, no_ha_table))
5030 goto err;
5031
5032 if (!no_ha_table && create_info->options & HA_LEX_CREATE_TMP_TABLE)
5033 {
5034 /*
5035 Open a table (skipping table cache) and add it into
5036 THD::temporary_tables list.
5037 */
5038
5039 TABLE *table= open_table_uncached(thd, path, db, table_name, true, true);
5040
5041 if (!table)
5042 {
5043 (void) rm_temporary_table(create_info->db_type, path);
5044 goto err;
5045 }
5046
5047 if (is_trans != NULL)
5048 *is_trans= table->file->has_transactions();
5049
5050 thd->thread_specific_used= TRUE;
5051 }
5052 #ifdef WITH_PARTITION_STORAGE_ENGINE
5053 else if (part_info && no_ha_table)
5054 {
5055 /*
5056 For partitioned tables we can't find some problems with table
5057 until table is opened. Therefore in order to disallow creation
5058 of corrupted tables we have to try to open table as the part
5059 of its creation process.
5060 In cases when both .FRM and SE part of table are created table
5061 is implicitly open in ha_create_table() call.
5062 In cases when we create .FRM without SE part we have to open
5063 table explicitly.
5064 */
5065 TABLE table;
5066 TABLE_SHARE share;
5067
5068 init_tmp_table_share(thd, &share, db, 0, table_name, path);
5069
5070 bool result= (open_table_def(thd, &share, 0) ||
5071 open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
5072 0, &table, true));
5073 /*
5074 Assert that the change list is empty as no partition function currently
5075 needs to modify item tree. May need call THD::rollback_item_tree_changes
5076 later before calling closefrm if the change list is not empty.
5077 */
5078 DBUG_ASSERT(thd->change_list.is_empty());
5079 if (!result)
5080 (void) closefrm(&table, 0);
5081
5082 free_table_share(&share);
5083
5084 if (result)
5085 {
5086 char frm_name[FN_REFLEN + 1];
5087 strxnmov(frm_name, sizeof(frm_name) - 1, path, reg_ext, NullS);
5088 (void) mysql_file_delete(key_file_frm, frm_name, MYF(0));
5089 (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG,
5090 create_info);
5091 goto err;
5092 }
5093 }
5094 #endif
5095
5096 error= FALSE;
5097 err:
5098 THD_STAGE_INFO(thd, stage_after_create);
5099 delete file;
5100 DBUG_RETURN(error);
5101
5102 warn:
5103 error= FALSE;
5104 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
5105 ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
5106 alias);
5107 goto err;
5108 }
5109
5110
5111 /**
5112 Simple wrapper around create_table_impl() to be used
5113 in various version of CREATE TABLE statement.
5114 */
mysql_create_table_no_lock(THD * thd,const char * db,const char * table_name,HA_CREATE_INFO * create_info,Alter_info * alter_info,uint select_field_count,bool * is_trans)5115 bool mysql_create_table_no_lock(THD *thd,
5116 const char *db, const char *table_name,
5117 HA_CREATE_INFO *create_info,
5118 Alter_info *alter_info,
5119 uint select_field_count,
5120 bool *is_trans)
5121 {
5122 KEY *not_used_1;
5123 uint not_used_2;
5124 char path[FN_REFLEN + 1];
5125
5126 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
5127 build_tmptable_filename(thd, path, sizeof(path));
5128 else
5129 {
5130 bool was_truncated;
5131 int length;
5132 const char *alias= table_case_name(create_info, table_name);
5133 length= build_table_filename(path, sizeof(path) - 1, db, alias,
5134 "", 0, &was_truncated);
5135 // Check if we hit FN_REFLEN bytes along with file extension.
5136 if (was_truncated || length+reg_ext_length > FN_REFLEN)
5137 {
5138 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), sizeof(path)-1, path);
5139 return true;
5140 }
5141 }
5142
5143 return create_table_impl(thd, db, table_name, table_name, path, create_info,
5144 alter_info, false, select_field_count, false,
5145 is_trans, ¬_used_1, ¬_used_2);
5146 }
5147
5148
5149 /**
5150 Implementation of SQLCOM_CREATE_TABLE.
5151
5152 Take the metadata locks (including a shared lock on the affected
5153 schema) and create the table. Is written to be called from
5154 mysql_execute_command(), to which it delegates the common parts
5155 with other commands (i.e. implicit commit before and after,
5156 close of thread tables.
5157 */
5158
mysql_create_table(THD * thd,TABLE_LIST * create_table,HA_CREATE_INFO * create_info,Alter_info * alter_info)5159 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
5160 HA_CREATE_INFO *create_info,
5161 Alter_info *alter_info)
5162 {
5163 bool result;
5164 bool is_trans= FALSE;
5165 uint not_used;
5166 DBUG_ENTER("mysql_create_table");
5167
5168 /*
5169 Open or obtain "X" MDL lock on the table being created.
5170 To check the existence of table, lock of type "S" is obtained on the table
5171 and then it is upgraded to "X" if table does not exists.
5172 */
5173 if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0))
5174 {
5175 result= TRUE;
5176 goto end;
5177 }
5178
5179 /* Got lock. */
5180 DEBUG_SYNC(thd, "locked_table_name");
5181
5182 /* We can abort create table for any table type */
5183 thd->abort_on_warning= thd->is_strict_mode();
5184
5185 /*
5186 Promote first timestamp column, when explicit_defaults_for_timestamp
5187 is not set
5188 */
5189 if (!thd->variables.explicit_defaults_for_timestamp)
5190 promote_first_timestamp_column(&alter_info->create_list);
5191
5192 result= mysql_create_table_no_lock(thd, create_table->db,
5193 create_table->table_name, create_info,
5194 alter_info, 0, &is_trans);
5195 /*
5196 Don't write statement if:
5197 - Table creation has failed
5198 - Row-based logging is used and we are creating a temporary table
5199 Otherwise, the statement shall be binlogged.
5200 */
5201 if (!result)
5202 {
5203 /*
5204 CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling
5205 stmt.mark_created_temp_table() guarantees the transaction can be binlogged
5206 correctly.
5207 */
5208 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
5209 thd->transaction.stmt.mark_created_temp_table();
5210
5211 if (!thd->is_current_stmt_binlog_format_row() ||
5212 (thd->is_current_stmt_binlog_format_row() &&
5213 !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))
5214 {
5215 thd->add_to_binlog_accessed_dbs(create_table->db);
5216 result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
5217 }
5218 }
5219
5220 thd->abort_on_warning= false;
5221 end:
5222 DBUG_RETURN(result);
5223 }
5224
5225
5226 /*
5227 ** Give the key name after the first field with an optional '_#' after
5228 **/
5229
5230 static bool
check_if_keyname_exists(const char * name,KEY * start,KEY * end)5231 check_if_keyname_exists(const char *name, KEY *start, KEY *end)
5232 {
5233 for (KEY *key=start ; key != end ; key++)
5234 if (!my_strcasecmp(system_charset_info,name,key->name))
5235 return 1;
5236 return 0;
5237 }
5238
5239
5240 static char *
make_unique_key_name(const char * field_name,KEY * start,KEY * end)5241 make_unique_key_name(const char *field_name,KEY *start,KEY *end)
5242 {
5243 char buff[MAX_FIELD_NAME],*buff_end;
5244
5245 if (!check_if_keyname_exists(field_name,start,end) &&
5246 my_strcasecmp(system_charset_info,field_name,primary_key_name))
5247 return (char*) field_name; // Use fieldname
5248 buff_end=strmake(buff,field_name, sizeof(buff)-4);
5249
5250 /*
5251 Only 3 chars + '\0' left, so need to limit to 2 digit
5252 This is ok as we can't have more than 100 keys anyway
5253 */
5254 for (uint i=2 ; i< 100; i++)
5255 {
5256 *buff_end= '_';
5257 int10_to_str(i, buff_end+1, 10);
5258 if (!check_if_keyname_exists(buff,start,end))
5259 return sql_strdup(buff);
5260 }
5261 return (char*) "not_specified"; // Should never happen
5262 }
5263
5264
5265 /****************************************************************************
5266 ** Alter a table definition
5267 ****************************************************************************/
5268
5269
5270 /**
5271 Rename a table.
5272
5273 @param base The handlerton handle.
5274 @param old_db The old database name.
5275 @param old_name The old table name.
5276 @param new_db The new database name.
5277 @param new_name The new table name.
5278 @param flags flags
5279 FN_FROM_IS_TMP old_name is temporary.
5280 FN_TO_IS_TMP new_name is temporary.
5281 NO_FRM_RENAME Don't rename the FRM file
5282 but only the table in the storage engine.
5283 NO_HA_TABLE Don't rename table in engine.
5284 NO_FK_CHECKS Don't check FK constraints during rename.
5285
5286 @return false OK
5287 @return true Error
5288 */
5289
5290 bool
mysql_rename_table(handlerton * base,const char * old_db,const char * old_name,const char * new_db,const char * new_name,uint flags)5291 mysql_rename_table(handlerton *base, const char *old_db,
5292 const char *old_name, const char *new_db,
5293 const char *new_name, uint flags)
5294 {
5295 THD *thd= current_thd;
5296 char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
5297 lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
5298 char *from_base= from, *to_base= to;
5299 char tmp_name[NAME_LEN+1];
5300 handler *file;
5301 int error=0;
5302 ulonglong save_bits= thd->variables.option_bits;
5303 int length;
5304 bool was_truncated;
5305 DBUG_ENTER("mysql_rename_table");
5306 DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
5307 old_db, old_name, new_db, new_name));
5308
5309 // Temporarily disable foreign key checks
5310 if (flags & NO_FK_CHECKS)
5311 thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
5312
5313 file= (base == NULL ? 0 :
5314 get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
5315
5316 build_table_filename(from, sizeof(from) - 1, old_db, old_name, "",
5317 flags & FN_FROM_IS_TMP);
5318 length= build_table_filename(to, sizeof(to) - 1, new_db, new_name, "",
5319 flags & FN_TO_IS_TMP, &was_truncated);
5320 // Check if we hit FN_REFLEN bytes along with file extension.
5321 if (was_truncated || length+reg_ext_length > FN_REFLEN)
5322 {
5323 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), sizeof(to)-1, to);
5324 DBUG_RETURN(TRUE);
5325 }
5326
5327 /*
5328 If lower_case_table_names == 2 (case-preserving but case-insensitive
5329 file system) and the storage is not HA_FILE_BASED, we need to provide
5330 a lowercase file name, but we leave the .frm in mixed case.
5331 */
5332 if (lower_case_table_names == 2 && file &&
5333 !(file->ha_table_flags() & HA_FILE_BASED))
5334 {
5335 strmov(tmp_name, old_name);
5336 my_casedn_str(files_charset_info, tmp_name);
5337 build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "",
5338 flags & FN_FROM_IS_TMP);
5339 from_base= lc_from;
5340
5341 strmov(tmp_name, new_name);
5342 my_casedn_str(files_charset_info, tmp_name);
5343 build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "",
5344 flags & FN_TO_IS_TMP);
5345 to_base= lc_to;
5346 }
5347
5348 if (flags & NO_HA_TABLE)
5349 {
5350 if (rename_file_ext(from,to,reg_ext))
5351 error= my_errno;
5352 (void) file->ha_create_handler_files(to, from, CHF_RENAME_FLAG, NULL);
5353 }
5354 else if (!file || !(error=file->ha_rename_table(from_base, to_base)))
5355 {
5356 if (!(flags & NO_FRM_RENAME) && rename_file_ext(from,to,reg_ext))
5357 {
5358 error=my_errno;
5359 /* Restore old file name */
5360 if (file)
5361 file->ha_rename_table(to_base, from_base);
5362 }
5363 }
5364 delete file;
5365 if (error == HA_ERR_WRONG_COMMAND)
5366 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
5367 else if (error)
5368 {
5369 char errbuf[MYSYS_STRERROR_SIZE];
5370 my_error(ER_ERROR_ON_RENAME, MYF(0), from, to,
5371 error, my_strerror(errbuf, sizeof(errbuf), error));
5372 }
5373
5374 #ifdef HAVE_PSI_TABLE_INTERFACE
5375 /*
5376 Remove the old table share from the pfs table share array. The new table
5377 share will be created when the renamed table is first accessed.
5378 */
5379 if (likely(error == 0))
5380 {
5381 my_bool temp_table= (my_bool)is_prefix(old_name, tmp_file_prefix);
5382 PSI_TABLE_CALL(drop_table_share)
5383 (temp_table, old_db, strlen(old_db), old_name, strlen(old_name));
5384 }
5385 #endif
5386
5387 // Restore options bits to the original value
5388 thd->variables.option_bits= save_bits;
5389
5390 DBUG_RETURN(error != 0);
5391 }
5392
5393
5394 /*
5395 Create a table identical to the specified table
5396
5397 SYNOPSIS
5398 mysql_create_like_table()
5399 thd Thread object
5400 table Table list element for target table
5401 src_table Table list element for source table
5402 create_info Create info
5403
5404 RETURN VALUES
5405 FALSE OK
5406 TRUE error
5407 */
5408
mysql_create_like_table(THD * thd,TABLE_LIST * table,TABLE_LIST * src_table,HA_CREATE_INFO * create_info)5409 bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
5410 HA_CREATE_INFO *create_info)
5411 {
5412 HA_CREATE_INFO local_create_info;
5413 Alter_info local_alter_info;
5414 Alter_table_ctx local_alter_ctx; // Not used
5415 bool res= TRUE;
5416 bool is_trans= FALSE;
5417 uint not_used;
5418 DBUG_ENTER("mysql_create_like_table");
5419
5420 #ifdef WITH_WSREP
5421 if (WSREP(thd) && !thd->wsrep_applier)
5422 {
5423 TABLE *tmp_table;
5424 bool is_tmp_table= FALSE;
5425
5426 for (tmp_table= thd->temporary_tables; tmp_table; tmp_table=tmp_table->next)
5427 {
5428 if (!strcmp(src_table->db, tmp_table->s->db.str) &&
5429 !strcmp(src_table->table_name, tmp_table->s->table_name.str))
5430 {
5431 is_tmp_table= TRUE;
5432 break;
5433 }
5434 }
5435 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
5436 {
5437 /* CREATE TEMPORARY TABLE LIKE must be skipped from replication */
5438 WSREP_DEBUG("CREATE TEMPORARY TABLE LIKE... skipped replication\n %s",
5439 WSREP_QUERY(thd));
5440 }
5441 else if (!is_tmp_table)
5442 {
5443 /* this is straight CREATE TABLE LIKE... eith no tmp tables */
5444 WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
5445 }
5446 else
5447 {
5448 /* here we have CREATE TABLE LIKE <temporary table>
5449 the temporary table definition will be needed in slaves to
5450 enable the create to succeed
5451 */
5452 TABLE_LIST tbl;
5453 memset(&tbl, 0, sizeof(tbl));
5454 tbl.db= src_table->db;
5455 tbl.table_name= tbl.alias= src_table->table_name;
5456 tbl.table= tmp_table;
5457 char buf[2048];
5458 String query(buf, sizeof(buf), system_charset_info);
5459 query.length(0); // Have to zero it since constructor doesn't
5460
5461 (void) store_create_info(thd, &tbl, &query, NULL, TRUE);
5462 WSREP_DEBUG("TMP TABLE: %s", query.ptr());
5463
5464 thd->wsrep_TOI_pre_query= query.ptr();
5465 thd->wsrep_TOI_pre_query_len= query.length();
5466
5467 WSREP_TO_ISOLATION_BEGIN(table->db, table->table_name, NULL);
5468
5469 thd->wsrep_TOI_pre_query= NULL;
5470 thd->wsrep_TOI_pre_query_len= 0;
5471 }
5472 }
5473 #endif
5474
5475 /*
5476 We the open source table to get its description in HA_CREATE_INFO
5477 and Alter_info objects. This also acquires a shared metadata lock
5478 on this table which ensures that no concurrent DDL operation will
5479 mess with it.
5480 Also in case when we create non-temporary table open_tables()
5481 call obtains an exclusive metadata lock on target table ensuring
5482 that we can safely perform table creation.
5483 Thus by holding both these locks we ensure that our statement is
5484 properly isolated from all concurrent operations which matter.
5485 */
5486 if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0))
5487 goto err;
5488 src_table->table->use_all_columns();
5489
5490 DEBUG_SYNC(thd, "create_table_like_after_open");
5491
5492 /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
5493 memset(&local_create_info, 0, sizeof(local_create_info));
5494 local_create_info.db_type= src_table->table->s->db_type();
5495 local_create_info.row_type= src_table->table->s->row_type;
5496 if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
5497 &local_alter_info, &local_alter_ctx))
5498 goto err;
5499 #ifdef WITH_PARTITION_STORAGE_ENGINE
5500 /* Partition info is not handled by mysql_prepare_alter_table() call. */
5501 if (src_table->table->part_info)
5502 thd->work_part_info= src_table->table->part_info->get_clone();
5503 #endif
5504
5505 /*
5506 Adjust description of source table before using it for creation of
5507 target table.
5508
5509 Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
5510 temporary table which represents I_S table.
5511 */
5512 if (src_table->schema_table)
5513 local_create_info.max_rows= 0;
5514 /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
5515 local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
5516 /* Replace type of source table with one specified in the statement. */
5517 local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
5518 local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
5519 /* Reset auto-increment counter for the new table. */
5520 local_create_info.auto_increment_value= 0;
5521 /*
5522 Do not inherit values of DATA and INDEX DIRECTORY options from
5523 the original table. This is documented behavior.
5524 */
5525 local_create_info.data_file_name= local_create_info.index_file_name= NULL;
5526 local_create_info.alias= create_info->alias;
5527
5528 if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
5529 &local_create_info, &local_alter_info,
5530 0, &is_trans)))
5531 goto err;
5532
5533 /*
5534 Ensure that table or view does not exist and we have an exclusive lock on
5535 target table if we are creating non-temporary table. In LOCK TABLES mode
5536 the only way the table is locked, is if it already exists (since you cannot
5537 LOCK TABLE a non-existing table). And the only way we then can end up here
5538 is if IF EXISTS was used.
5539 */
5540 DBUG_ASSERT(table->table || table->view ||
5541 (create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
5542 (thd->locked_tables_mode != LTM_LOCK_TABLES &&
5543 thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
5544 table->table_name,
5545 MDL_EXCLUSIVE)) ||
5546 (thd->locked_tables_mode == LTM_LOCK_TABLES &&
5547 (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) &&
5548 thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
5549 table->table_name,
5550 MDL_SHARED_NO_WRITE)));
5551
5552 DEBUG_SYNC(thd, "create_table_like_before_binlog");
5553
5554 /*
5555 CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling
5556 stmt.mark_created_temp_table() guarantees the transaction can be binlogged
5557 correctly.
5558 */
5559 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
5560 thd->transaction.stmt.mark_created_temp_table();
5561
5562 /*
5563 We have to write the query before we unlock the tables.
5564 */
5565 if (!thd->is_current_stmt_binlog_disabled() &&
5566 thd->is_current_stmt_binlog_format_row())
5567 {
5568 /*
5569 Since temporary tables are not replicated under row-based
5570 replication, CREATE TABLE ... LIKE ... needs special
5571 treatement. We have four cases to consider, according to the
5572 following decision table:
5573
5574 ==== ========= ========= ==============================
5575 Case Target Source Write to binary log
5576 ==== ========= ========= ==============================
5577 1 normal normal Original statement
5578 2 normal temporary Generated statement
5579 3 temporary normal Nothing
5580 4 temporary temporary Nothing
5581 ==== ========= ========= ==============================
5582 */
5583 if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
5584 {
5585 if (src_table->table->s->tmp_table) // Case 2
5586 {
5587 char buf[2048];
5588 String query(buf, sizeof(buf), system_charset_info);
5589 query.length(0); // Have to zero it since constructor doesn't
5590 Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
5591 bool new_table= FALSE; // Whether newly created table is open.
5592
5593 /*
5594 The condition avoids a crash as described in BUG#48506. Other
5595 binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
5596 when the existing object is a view will be solved by BUG 47442.
5597 */
5598 if (!table->view)
5599 {
5600 if (!table->table)
5601 {
5602 /*
5603 In order for store_create_info() to work we need to open
5604 destination table if it is not already open (i.e. if it
5605 has not existed before). We don't need acquire metadata
5606 lock in order to do this as we already hold exclusive
5607 lock on this table. The table will be closed by
5608 close_thread_table() at the end of this branch.
5609 */
5610 if (open_table(thd, table, &ot_ctx))
5611 goto err;
5612 new_table= TRUE;
5613 }
5614
5615 /*
5616 After opening a MERGE table add the children to the query list of
5617 tables, so that children tables info can be used on "CREATE TABLE"
5618 statement generation by the binary log.
5619 Note that placeholders don't have the handler open.
5620 */
5621 if (table->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
5622 goto err;
5623
5624 /*
5625 As the reference table is temporary and may not exist on slave, we must
5626 force the ENGINE to be present into CREATE TABLE.
5627 */
5628 create_info->used_fields|= HA_CREATE_USED_ENGINE;
5629
5630 int result MY_ATTRIBUTE((unused))=
5631 store_create_info(thd, table, &query,
5632 create_info, TRUE /* show_database */);
5633
5634 DBUG_ASSERT(result == 0); // store_create_info() always return 0
5635 if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
5636 goto err;
5637
5638 if (new_table)
5639 {
5640 DBUG_ASSERT(thd->open_tables == table->table);
5641 /*
5642 When opening the table, we ignored the locked tables
5643 (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table
5644 without risking to close some locked table.
5645 */
5646 close_thread_table(thd, &thd->open_tables);
5647 }
5648 }
5649 }
5650 else // Case 1
5651 if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
5652 goto err;
5653 }
5654 /*
5655 Case 3 and 4 does nothing under RBR
5656 */
5657 }
5658 else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
5659 goto err;
5660
5661 err:
5662 DBUG_RETURN(res);
5663 #ifdef WITH_WSREP
5664 error:
5665 thd->wsrep_TOI_pre_query= NULL;
5666 DBUG_RETURN(TRUE);
5667 #endif /* WITH_WSREP */
5668 }
5669
5670
5671 /* table_list should contain just one table */
mysql_discard_or_import_tablespace(THD * thd,TABLE_LIST * table_list,bool discard)5672 int mysql_discard_or_import_tablespace(THD *thd,
5673 TABLE_LIST *table_list,
5674 bool discard)
5675 {
5676 Alter_table_prelocking_strategy alter_prelocking_strategy;
5677 int error;
5678 DBUG_ENTER("mysql_discard_or_import_tablespace");
5679
5680 /*
5681 Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
5682 ALTER TABLE
5683 */
5684
5685 THD_STAGE_INFO(thd, stage_discard_or_import_tablespace);
5686
5687 /*
5688 We set this flag so that ha_innobase::open and ::external_lock() do
5689 not complain when we lock the table
5690 */
5691 thd->tablespace_op= TRUE;
5692 /*
5693 Adjust values of table-level and metadata which was set in parser
5694 for the case general ALTER TABLE.
5695 */
5696 table_list->mdl_request.set_type(MDL_EXCLUSIVE);
5697 table_list->lock_type= TL_WRITE;
5698 /* Do not open views. */
5699 table_list->required_type= FRMTYPE_TABLE;
5700
5701 if (open_and_lock_tables(thd, table_list, FALSE, 0,
5702 &alter_prelocking_strategy))
5703 {
5704 thd->tablespace_op=FALSE;
5705 DBUG_RETURN(-1);
5706 }
5707
5708 error= table_list->table->file->ha_discard_or_import_tablespace(discard);
5709
5710 THD_STAGE_INFO(thd, stage_end);
5711
5712 if (error)
5713 goto err;
5714
5715 /*
5716 The 0 in the call below means 'not in a transaction', which means
5717 immediate invalidation; that is probably what we wish here
5718 */
5719 query_cache_invalidate3(thd, table_list, 0);
5720
5721 /* The ALTER TABLE is always in its own transaction */
5722 error= trans_commit_stmt(thd);
5723 if (trans_commit_implicit(thd))
5724 error=1;
5725 if (error)
5726 goto err;
5727 error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
5728
5729 err:
5730 thd->tablespace_op=FALSE;
5731
5732 if (error == 0)
5733 {
5734 my_ok(thd);
5735 DBUG_RETURN(0);
5736 }
5737
5738 table_list->table->file->print_error(error, MYF(0));
5739
5740 DBUG_RETURN(-1);
5741 }
5742
5743
5744 /**
5745 Check if key is a candidate key, i.e. a unique index with no index
5746 fields partial or nullable.
5747 */
5748
is_candidate_key(KEY * key)5749 static bool is_candidate_key(KEY *key)
5750 {
5751 KEY_PART_INFO *key_part;
5752 KEY_PART_INFO *key_part_end= key->key_part + key->user_defined_key_parts;
5753
5754 if (!(key->flags & HA_NOSAME) || (key->flags & HA_NULL_PART_KEY))
5755 return false;
5756
5757 for (key_part= key->key_part; key_part < key_part_end; key_part++)
5758 {
5759 if (key_part->key_part_flag & HA_PART_KEY_SEG)
5760 return false;
5761 }
5762
5763 return true;
5764 }
5765
5766
5767 /**
5768 Get Create_field object for newly created table by field index.
5769
5770 @param alter_info Alter_info describing newly created table.
5771 @param idx Field index.
5772 */
5773
get_field_by_index(Alter_info * alter_info,uint idx)5774 static Create_field *get_field_by_index(Alter_info *alter_info, uint idx)
5775 {
5776 List_iterator_fast<Create_field> field_it(alter_info->create_list);
5777 uint field_idx= 0;
5778 Create_field *field;
5779
5780 while ((field= field_it++) && field_idx < idx)
5781 { field_idx++; }
5782
5783 return field;
5784 }
5785
5786
compare_uint(const uint * s,const uint * t)5787 static int compare_uint(const uint *s, const uint *t)
5788 {
5789 return (*s < *t) ? -1 : ((*s > *t) ? 1 : 0);
5790 }
5791
5792
5793 /**
5794 Compare original and new versions of a table and fill Alter_inplace_info
5795 describing differences between those versions.
5796
5797 @param thd Thread
5798 @param table The original table.
5799 @param varchar Indicates that new definition has new
5800 VARCHAR column.
5801 @param[in/out] ha_alter_info Data structure which already contains
5802 basic information about create options,
5803 field and keys for the new version of
5804 table and which should be completed with
5805 more detailed information needed for
5806 in-place ALTER.
5807
5808 First argument 'table' contains information of the original
5809 table, which includes all corresponding parts that the new
5810 table has in arguments create_list, key_list and create_info.
5811
5812 Compare the changes between the original and new table definitions.
5813 The result of this comparison is then passed to SE which determines
5814 whether it can carry out these changes in-place.
5815
5816 Mark any changes detected in the ha_alter_flags.
5817 We generally try to specify handler flags only if there are real
5818 changes. But in cases when it is cumbersome to determine if some
5819 attribute has really changed we might choose to set flag
5820 pessimistically, for example, relying on parser output only.
5821
5822 If there are no data changes, but index changes, 'index_drop_buffer'
5823 and/or 'index_add_buffer' are populated with offsets into
5824 table->key_info or key_info_buffer respectively for the indexes
5825 that need to be dropped and/or (re-)created.
5826
5827 Note that this function assumes that it is OK to change Alter_info
5828 and HA_CREATE_INFO which it gets. It is caller who is responsible
5829 for creating copies for this structures if he needs them unchanged.
5830
5831 @retval true error
5832 @retval false success
5833 */
5834
fill_alter_inplace_info(THD * thd,TABLE * table,bool varchar,Alter_inplace_info * ha_alter_info)5835 static bool fill_alter_inplace_info(THD *thd,
5836 TABLE *table,
5837 bool varchar,
5838 Alter_inplace_info *ha_alter_info)
5839 {
5840 Field **f_ptr, *field;
5841 List_iterator_fast<Create_field> new_field_it;
5842 Create_field *new_field;
5843 KEY_PART_INFO *key_part, *new_part;
5844 KEY_PART_INFO *end;
5845 uint candidate_key_count= 0;
5846 Alter_info *alter_info= ha_alter_info->alter_info;
5847 DBUG_ENTER("fill_alter_inplace_info");
5848
5849 /* Allocate result buffers. */
5850 if (! (ha_alter_info->index_drop_buffer=
5851 (KEY**) thd->alloc(sizeof(KEY*) * table->s->keys)) ||
5852 ! (ha_alter_info->index_add_buffer=
5853 (uint*) thd->alloc(sizeof(uint) *
5854 alter_info->key_list.elements)))
5855 DBUG_RETURN(true);
5856
5857 /* First we setup ha_alter_flags based on what was detected by parser. */
5858 if (alter_info->flags & Alter_info::ALTER_ADD_COLUMN)
5859 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_COLUMN;
5860 if (alter_info->flags & Alter_info::ALTER_DROP_COLUMN)
5861 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_COLUMN;
5862 /*
5863 Comparing new and old default values of column is cumbersome.
5864 So instead of using such a comparison for detecting if default
5865 has really changed we rely on flags set by parser to get an
5866 approximate value for storage engine flag.
5867 */
5868 if (alter_info->flags & (Alter_info::ALTER_CHANGE_COLUMN |
5869 Alter_info::ALTER_CHANGE_COLUMN_DEFAULT))
5870 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_DEFAULT;
5871 if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY)
5872 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_FOREIGN_KEY;
5873 if (alter_info->flags & Alter_info::DROP_FOREIGN_KEY)
5874 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_FOREIGN_KEY;
5875 if (alter_info->flags & Alter_info::ALTER_OPTIONS)
5876 ha_alter_info->handler_flags|= Alter_inplace_info::CHANGE_CREATE_OPTION;
5877 if (alter_info->flags & Alter_info::ALTER_RENAME)
5878 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_RENAME;
5879 /* Check partition changes */
5880 if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION)
5881 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_PARTITION;
5882 if (alter_info->flags & Alter_info::ALTER_DROP_PARTITION)
5883 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_PARTITION;
5884 if (alter_info->flags & Alter_info::ALTER_PARTITION)
5885 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_PARTITION;
5886 if (alter_info->flags & Alter_info::ALTER_COALESCE_PARTITION)
5887 ha_alter_info->handler_flags|= Alter_inplace_info::COALESCE_PARTITION;
5888 if (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION)
5889 ha_alter_info->handler_flags|= Alter_inplace_info::REORGANIZE_PARTITION;
5890 if (alter_info->flags & Alter_info::ALTER_TABLE_REORG)
5891 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_TABLE_REORG;
5892 if (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING)
5893 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_REMOVE_PARTITIONING;
5894 if (alter_info->flags & Alter_info::ALTER_ALL_PARTITION)
5895 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ALL_PARTITION;
5896 /* Check for: ALTER TABLE FORCE, ALTER TABLE ENGINE and OPTIMIZE TABLE. */
5897 if (alter_info->flags & Alter_info::ALTER_RECREATE)
5898 ha_alter_info->handler_flags|= Alter_inplace_info::RECREATE_TABLE;
5899
5900 /*
5901 If we altering table with old VARCHAR fields we will be automatically
5902 upgrading VARCHAR column types.
5903 */
5904 if (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)
5905 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
5906
5907 /*
5908 Go through fields in old version of table and detect changes to them.
5909 We don't want to rely solely on Alter_info flags for this since:
5910 a) new definition of column can be fully identical to the old one
5911 despite the fact that this column is mentioned in MODIFY clause.
5912 b) even if new column type differs from its old column from metadata
5913 point of view, it might be identical from storage engine point
5914 of view (e.g. when ENUM('a','b') is changed to ENUM('a','b',c')).
5915 c) flags passed to storage engine contain more detailed information
5916 about nature of changes than those provided from parser.
5917 */
5918 for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
5919 {
5920 /* Clear marker for renamed or dropped field
5921 which we are going to set later. */
5922 field->flags&= ~(FIELD_IS_RENAMED | FIELD_IS_DROPPED);
5923
5924 /* Use transformed info to evaluate flags for storage engine. */
5925 uint new_field_index= 0;
5926 new_field_it.init(alter_info->create_list);
5927 while ((new_field= new_field_it++))
5928 {
5929 if (new_field->field == field)
5930 break;
5931 new_field_index++;
5932 }
5933
5934 if (new_field)
5935 {
5936 /* Field is not dropped. Evaluate changes bitmap for it. */
5937
5938 /*
5939 Check if type of column has changed to some incompatible type.
5940 */
5941 switch (field->is_equal(new_field))
5942 {
5943 case IS_EQUAL_NO:
5944 /* New column type is incompatible with old one. */
5945 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
5946 break;
5947 case IS_EQUAL_YES:
5948 /*
5949 New column is the same as the old one or the fully compatible with
5950 it (for example, ENUM('a','b') was changed to ENUM('a','b','c')).
5951 Such a change if any can ALWAYS be carried out by simply updating
5952 data-dictionary without even informing storage engine.
5953 No flag is set in this case.
5954 */
5955 break;
5956 case IS_EQUAL_PACK_LENGTH:
5957 /*
5958 New column type differs from the old one, but has compatible packed
5959 data representation. Depending on storage engine, such a change can
5960 be carried out by simply updating data dictionary without changing
5961 actual data (for example, VARCHAR(300) is changed to VARCHAR(400)).
5962 */
5963 ha_alter_info->handler_flags|= Alter_inplace_info::
5964 ALTER_COLUMN_EQUAL_PACK_LENGTH;
5965 break;
5966 default:
5967 DBUG_ASSERT(0);
5968 /* Safety. */
5969 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
5970 }
5971
5972 bool field_renamed;
5973 /*
5974 InnoDB data dictionary is case sensitive so we should use
5975 string case sensitive comparison between fields.
5976 Note: strcmp branch is to be removed in future when we fix it
5977 in InnoDB.
5978 */
5979 if (ha_alter_info->create_info->db_type->db_type == DB_TYPE_INNODB)
5980 field_renamed= strcmp(field->field_name, new_field->field_name);
5981 else
5982 field_renamed= my_strcasecmp(system_charset_info, field->field_name,
5983 new_field->field_name);
5984
5985 /* Check if field was renamed */
5986 if (field_renamed)
5987 {
5988 field->flags|= FIELD_IS_RENAMED;
5989 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_NAME;
5990 }
5991
5992 /* Check that NULL behavior is same for old and new fields */
5993 if ((new_field->flags & NOT_NULL_FLAG) !=
5994 (uint) (field->flags & NOT_NULL_FLAG))
5995 {
5996 if (new_field->flags & NOT_NULL_FLAG)
5997 ha_alter_info->handler_flags|=
5998 Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE;
5999 else
6000 ha_alter_info->handler_flags|=
6001 Alter_inplace_info::ALTER_COLUMN_NULLABLE;
6002 }
6003
6004 /*
6005 We do not detect changes to default values in this loop.
6006 See comment above for more details.
6007 */
6008
6009 /*
6010 Detect changes in column order.
6011 */
6012 if (field->field_index != new_field_index)
6013 ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_ORDER;
6014
6015 /* Detect changes in storage type of column */
6016 if (new_field->field_storage_type() != field->field_storage_type())
6017 ha_alter_info->handler_flags|=
6018 Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE;
6019
6020 /* Detect changes in column format of column */
6021 if (new_field->column_format() != field->column_format())
6022 ha_alter_info->handler_flags|=
6023 Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT;
6024 }
6025 else
6026 {
6027 /*
6028 Field is not present in new version of table and therefore was dropped.
6029 Corresponding storage engine flag should be already set.
6030 */
6031 DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::DROP_COLUMN);
6032 field->flags|= FIELD_IS_DROPPED;
6033 }
6034 }
6035
6036 #ifndef DBUG_OFF
6037 new_field_it.init(alter_info->create_list);
6038 while ((new_field= new_field_it++))
6039 {
6040 if (! new_field->field)
6041 {
6042 /*
6043 Field is not present in old version of table and therefore was added.
6044 Again corresponding storage engine flag should be already set.
6045 */
6046 DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN);
6047 break;
6048 }
6049 }
6050 #endif /* DBUG_OFF */
6051
6052 /*
6053 Go through keys and check if the original ones are compatible
6054 with new table.
6055 */
6056 KEY *table_key;
6057 KEY *table_key_end= table->key_info + table->s->keys;
6058 KEY *new_key;
6059 KEY *new_key_end=
6060 ha_alter_info->key_info_buffer + ha_alter_info->key_count;
6061
6062 DBUG_PRINT("info", ("index count old: %d new: %d",
6063 table->s->keys, ha_alter_info->key_count));
6064
6065 /*
6066 Step through all keys of the old table and search matching new keys.
6067 */
6068 ha_alter_info->index_drop_count= 0;
6069 ha_alter_info->index_add_count= 0;
6070 for (table_key= table->key_info; table_key < table_key_end; table_key++)
6071 {
6072 /* Search a new key with the same name. */
6073 for (new_key= ha_alter_info->key_info_buffer;
6074 new_key < new_key_end;
6075 new_key++)
6076 {
6077 if (! strcmp(table_key->name, new_key->name))
6078 break;
6079 }
6080 if (new_key >= new_key_end)
6081 {
6082 /* Key not found. Add the key to the drop buffer. */
6083 ha_alter_info->index_drop_buffer
6084 [ha_alter_info->index_drop_count++]=
6085 table_key;
6086 DBUG_PRINT("info", ("index dropped: '%s'", table_key->name));
6087 continue;
6088 }
6089
6090 /* Check that the key types are compatible between old and new tables. */
6091 if ((table_key->algorithm != new_key->algorithm) ||
6092 ((table_key->flags & HA_KEYFLAG_MASK) !=
6093 (new_key->flags & HA_KEYFLAG_MASK)) ||
6094 (table_key->user_defined_key_parts != new_key->user_defined_key_parts))
6095 goto index_changed;
6096
6097 /*
6098 Check that the key parts remain compatible between the old and
6099 new tables.
6100 */
6101 end= table_key->key_part + table_key->user_defined_key_parts;
6102 for (key_part= table_key->key_part, new_part= new_key->key_part;
6103 key_part < end;
6104 key_part++, new_part++)
6105 {
6106 /*
6107 Key definition has changed if we are using a different field or
6108 if the used key part length is different. It makes sense to
6109 check lengths first as in case when fields differ it is likely
6110 that lengths differ too and checking fields is more expensive
6111 in general case.
6112 */
6113 if (key_part->length != new_part->length)
6114 goto index_changed;
6115
6116 new_field= get_field_by_index(alter_info, new_part->fieldnr);
6117
6118 /*
6119 For prefix keys KEY_PART_INFO::field points to cloned Field
6120 object with adjusted length. So below we have to check field
6121 indexes instead of simply comparing pointers to Field objects.
6122 */
6123 if (! new_field->field ||
6124 new_field->field->field_index != key_part->fieldnr - 1)
6125 goto index_changed;
6126 }
6127 continue;
6128
6129 index_changed:
6130 /* Key modified. Add the key / key offset to both buffers. */
6131 ha_alter_info->index_drop_buffer
6132 [ha_alter_info->index_drop_count++]=
6133 table_key;
6134 ha_alter_info->index_add_buffer
6135 [ha_alter_info->index_add_count++]=
6136 new_key - ha_alter_info->key_info_buffer;
6137 /* Mark all old fields which are used in newly created index. */
6138 DBUG_PRINT("info", ("index changed: '%s'", table_key->name));
6139 }
6140 /*end of for (; table_key < table_key_end;) */
6141
6142 /*
6143 Step through all keys of the new table and find matching old keys.
6144 */
6145 for (new_key= ha_alter_info->key_info_buffer;
6146 new_key < new_key_end;
6147 new_key++)
6148 {
6149 /* Search an old key with the same name. */
6150 for (table_key= table->key_info; table_key < table_key_end; table_key++)
6151 {
6152 if (! strcmp(table_key->name, new_key->name))
6153 break;
6154 }
6155 if (table_key >= table_key_end)
6156 {
6157 /* Key not found. Add the offset of the key to the add buffer. */
6158 ha_alter_info->index_add_buffer
6159 [ha_alter_info->index_add_count++]=
6160 new_key - ha_alter_info->key_info_buffer;
6161 DBUG_PRINT("info", ("index added: '%s'", new_key->name));
6162 }
6163 }
6164
6165 /*
6166 Sort index_add_buffer according to how key_info_buffer is sorted.
6167 I.e. with primary keys first - see sort_keys().
6168 */
6169 my_qsort(ha_alter_info->index_add_buffer,
6170 ha_alter_info->index_add_count,
6171 sizeof(uint), (qsort_cmp) compare_uint);
6172
6173 /* Now let us calculate flags for storage engine API. */
6174
6175 /* Count all existing candidate keys. */
6176 for (table_key= table->key_info; table_key < table_key_end; table_key++)
6177 {
6178 /*
6179 Check if key is a candidate key, This key is either already primary key
6180 or could be promoted to primary key if the original primary key is
6181 dropped.
6182 In MySQL one is allowed to create primary key with partial fields (i.e.
6183 primary key which is not considered candidate). For simplicity we count
6184 such key as a candidate key here.
6185 */
6186 if (((uint) (table_key - table->key_info) == table->s->primary_key) ||
6187 is_candidate_key(table_key))
6188 candidate_key_count++;
6189 }
6190
6191 /* Figure out what kind of indexes we are dropping. */
6192 KEY **dropped_key;
6193 KEY **dropped_key_end= ha_alter_info->index_drop_buffer +
6194 ha_alter_info->index_drop_count;
6195
6196 for (dropped_key= ha_alter_info->index_drop_buffer;
6197 dropped_key < dropped_key_end; dropped_key++)
6198 {
6199 table_key= *dropped_key;
6200
6201 if (table_key->flags & HA_NOSAME)
6202 {
6203 /*
6204 Unique key. Check for PRIMARY KEY. Also see comment about primary
6205 and candidate keys above.
6206 */
6207 if ((uint) (table_key - table->key_info) == table->s->primary_key)
6208 {
6209 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_PK_INDEX;
6210 candidate_key_count--;
6211 }
6212 else
6213 {
6214 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_UNIQUE_INDEX;
6215 if (is_candidate_key(table_key))
6216 candidate_key_count--;
6217 }
6218 }
6219 else
6220 ha_alter_info->handler_flags|= Alter_inplace_info::DROP_INDEX;
6221 }
6222
6223 /* Now figure out what kind of indexes we are adding. */
6224 for (uint add_key_idx= 0; add_key_idx < ha_alter_info->index_add_count; add_key_idx++)
6225 {
6226 new_key= ha_alter_info->key_info_buffer + ha_alter_info->index_add_buffer[add_key_idx];
6227
6228 if (new_key->flags & HA_NOSAME)
6229 {
6230 bool is_pk= !my_strcasecmp(system_charset_info, new_key->name, primary_key_name);
6231
6232 if ((!(new_key->flags & HA_KEY_HAS_PART_KEY_SEG) &&
6233 !(new_key->flags & HA_NULL_PART_KEY)) ||
6234 is_pk)
6235 {
6236 /* Candidate key or primary key! */
6237 if (candidate_key_count == 0 || is_pk)
6238 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_PK_INDEX;
6239 else
6240 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_UNIQUE_INDEX;
6241 candidate_key_count++;
6242 }
6243 else
6244 {
6245 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_UNIQUE_INDEX;
6246 }
6247 }
6248 else
6249 ha_alter_info->handler_flags|= Alter_inplace_info::ADD_INDEX;
6250 }
6251
6252 DBUG_RETURN(false);
6253 }
6254
6255
6256 /**
6257 Mark fields participating in newly added indexes in TABLE object which
6258 corresponds to new version of altered table.
6259
6260 @param ha_alter_info Alter_inplace_info describing in-place ALTER.
6261 @param altered_table TABLE object for new version of TABLE in which
6262 fields should be marked.
6263 */
6264
update_altered_table(const Alter_inplace_info & ha_alter_info,TABLE * altered_table)6265 static void update_altered_table(const Alter_inplace_info &ha_alter_info,
6266 TABLE *altered_table)
6267 {
6268 uint field_idx, add_key_idx;
6269 KEY *key;
6270 KEY_PART_INFO *end, *key_part;
6271
6272 /*
6273 Clear marker for all fields, as we are going to set it only
6274 for fields which participate in new indexes.
6275 */
6276 for (field_idx= 0; field_idx < altered_table->s->fields; ++field_idx)
6277 altered_table->field[field_idx]->flags&= ~FIELD_IN_ADD_INDEX;
6278
6279 /*
6280 Go through array of newly added indexes and mark fields
6281 participating in them.
6282 */
6283 for (add_key_idx= 0; add_key_idx < ha_alter_info.index_add_count;
6284 add_key_idx++)
6285 {
6286 key= ha_alter_info.key_info_buffer +
6287 ha_alter_info.index_add_buffer[add_key_idx];
6288
6289 end= key->key_part + key->user_defined_key_parts;
6290 for (key_part= key->key_part; key_part < end; key_part++)
6291 altered_table->field[key_part->fieldnr]->flags|= FIELD_IN_ADD_INDEX;
6292 }
6293 }
6294
6295
6296 /**
6297 Initialize TABLE::field for the new table with appropriate
6298 column defaults. Can be default values from TABLE_SHARE or
6299 function defaults from Create_field.
6300
6301 @param altered_table TABLE object for the new version of the table.
6302 @param create Create_field containing function defaults.
6303 */
6304
set_column_defaults(TABLE * altered_table,List<Create_field> & create)6305 static void set_column_defaults(TABLE *altered_table,
6306 List<Create_field> &create)
6307 {
6308 // Initialize TABLE::field default values
6309 restore_record(altered_table, s->default_values);
6310
6311 List_iterator<Create_field> iter(create);
6312 for (uint i= 0; i < altered_table->s->fields; ++i)
6313 {
6314 const Create_field *definition= iter++;
6315 if (definition->field == NULL) // this column didn't exist in old table.
6316 altered_table->field[i]->evaluate_insert_default_function();
6317 }
6318 }
6319
6320
6321 /**
6322 Compare two tables to see if their metadata are compatible.
6323 One table specified by a TABLE instance, the other using Alter_info
6324 and HA_CREATE_INFO.
6325
6326 @param[in] table The first table.
6327 @param[in] alter_info Alter options, fields and keys for the
6328 second table.
6329 @param[in] create_info Create options for the second table.
6330 @param[out] metadata_equal Result of comparison.
6331
6332 @retval true error
6333 @retval false success
6334 */
6335
mysql_compare_tables(TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,bool * metadata_equal)6336 bool mysql_compare_tables(TABLE *table,
6337 Alter_info *alter_info,
6338 HA_CREATE_INFO *create_info,
6339 bool *metadata_equal)
6340 {
6341 DBUG_ENTER("mysql_compare_tables");
6342
6343 uint changes= IS_EQUAL_NO;
6344 uint key_count;
6345 List_iterator_fast<Create_field> tmp_new_field_it;
6346 THD *thd= table->in_use;
6347 *metadata_equal= false;
6348
6349 /*
6350 Create a copy of alter_info.
6351 To compare definitions, we need to "prepare" the definition - transform it
6352 from parser output to a format that describes the table layout (all column
6353 defaults are initialized, duplicate columns are removed). This is done by
6354 mysql_prepare_create_table. Unfortunately, mysql_prepare_create_table
6355 performs its transformations "in-place", that is, modifies the argument.
6356 Since we would like to keep mysql_compare_tables() idempotent (not altering
6357 any of the arguments) we create a copy of alter_info here and pass it to
6358 mysql_prepare_create_table, then use the result to compare the tables, and
6359 then destroy the copy.
6360 */
6361 Alter_info tmp_alter_info(*alter_info, thd->mem_root);
6362 uint db_options= 0; /* not used */
6363 KEY *key_info_buffer= NULL;
6364
6365 /* Create the prepared information. */
6366 if (mysql_prepare_create_table(thd, "", "",
6367 create_info, &tmp_alter_info,
6368 (table->s->tmp_table != NO_TMP_TABLE),
6369 &db_options,
6370 table->file, &key_info_buffer,
6371 &key_count, 0))
6372 DBUG_RETURN(true);
6373
6374 /* Some very basic checks. */
6375 if (table->s->fields != alter_info->create_list.elements ||
6376 table->s->db_type() != create_info->db_type ||
6377 table->s->tmp_table ||
6378 (table->s->row_type != create_info->row_type))
6379 DBUG_RETURN(false);
6380
6381 /* Go through fields and check if they are compatible. */
6382 tmp_new_field_it.init(tmp_alter_info.create_list);
6383 for (Field **f_ptr= table->field; *f_ptr; f_ptr++)
6384 {
6385 Field *field= *f_ptr;
6386 Create_field *tmp_new_field= tmp_new_field_it++;
6387
6388 /* Check that NULL behavior is the same. */
6389 if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
6390 (uint) (field->flags & NOT_NULL_FLAG))
6391 DBUG_RETURN(false);
6392
6393 /*
6394 mysql_prepare_alter_table() clears HA_OPTION_PACK_RECORD bit when
6395 preparing description of existing table. In ALTER TABLE it is later
6396 updated to correct value by create_table_impl() call.
6397 So to get correct value of this bit in this function we have to
6398 mimic behavior of create_table_impl().
6399 */
6400 if (create_info->row_type == ROW_TYPE_DYNAMIC ||
6401 (tmp_new_field->flags & BLOB_FLAG) ||
6402 (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
6403 create_info->row_type != ROW_TYPE_FIXED))
6404 create_info->table_options|= HA_OPTION_PACK_RECORD;
6405
6406 /* Check if field was renamed */
6407 if (my_strcasecmp(system_charset_info,
6408 field->field_name,
6409 tmp_new_field->field_name))
6410 DBUG_RETURN(false);
6411
6412 /* Evaluate changes bitmap and send to check_if_incompatible_data() */
6413 uint field_changes= field->is_equal(tmp_new_field);
6414 if (field_changes != IS_EQUAL_YES)
6415 DBUG_RETURN(false);
6416
6417 changes|= field_changes;
6418 }
6419
6420 /* Check if changes are compatible with current handler. */
6421 if (table->file->check_if_incompatible_data(create_info, changes))
6422 DBUG_RETURN(false);
6423
6424 /* Go through keys and check if they are compatible. */
6425 KEY *table_key;
6426 KEY *table_key_end= table->key_info + table->s->keys;
6427 KEY *new_key;
6428 KEY *new_key_end= key_info_buffer + key_count;
6429
6430 /* Step through all keys of the first table and search matching keys. */
6431 for (table_key= table->key_info; table_key < table_key_end; table_key++)
6432 {
6433 /* Search a key with the same name. */
6434 for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
6435 {
6436 if (! strcmp(table_key->name, new_key->name))
6437 break;
6438 }
6439 if (new_key >= new_key_end)
6440 DBUG_RETURN(false);
6441
6442 /* Check that the key types are compatible. */
6443 if ((table_key->algorithm != new_key->algorithm) ||
6444 ((table_key->flags & HA_KEYFLAG_MASK) !=
6445 (new_key->flags & HA_KEYFLAG_MASK)) ||
6446 (table_key->user_defined_key_parts != new_key->user_defined_key_parts))
6447 DBUG_RETURN(false);
6448
6449 /* Check that the key parts remain compatible. */
6450 KEY_PART_INFO *table_part;
6451 KEY_PART_INFO *table_part_end= table_key->key_part +
6452 table_key->user_defined_key_parts;
6453 KEY_PART_INFO *new_part;
6454 for (table_part= table_key->key_part, new_part= new_key->key_part;
6455 table_part < table_part_end;
6456 table_part++, new_part++)
6457 {
6458 /*
6459 Key definition is different if we are using a different field or
6460 if the used key part length is different. We know that the fields
6461 are equal. Comparing field numbers is sufficient.
6462 */
6463 if ((table_part->length != new_part->length) ||
6464 (table_part->fieldnr - 1 != new_part->fieldnr))
6465 DBUG_RETURN(false);
6466 }
6467 }
6468
6469 /* Step through all keys of the second table and find matching keys. */
6470 for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
6471 {
6472 /* Search a key with the same name. */
6473 for (table_key= table->key_info; table_key < table_key_end; table_key++)
6474 {
6475 if (! strcmp(table_key->name, new_key->name))
6476 break;
6477 }
6478 if (table_key >= table_key_end)
6479 DBUG_RETURN(false);
6480 }
6481
6482 *metadata_equal= true; // Tables are compatible
6483 DBUG_RETURN(false);
6484 }
6485
6486
6487 /*
6488 Manages enabling/disabling of indexes for ALTER TABLE
6489
6490 SYNOPSIS
6491 alter_table_manage_keys()
6492 table Target table
6493 indexes_were_disabled Whether the indexes of the from table
6494 were disabled
6495 keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
6496
6497 RETURN VALUES
6498 FALSE OK
6499 TRUE Error
6500 */
6501
6502 static
alter_table_manage_keys(TABLE * table,int indexes_were_disabled,Alter_info::enum_enable_or_disable keys_onoff)6503 bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
6504 Alter_info::enum_enable_or_disable keys_onoff)
6505 {
6506 int error= 0;
6507 DBUG_ENTER("alter_table_manage_keys");
6508 DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d",
6509 table, indexes_were_disabled, keys_onoff));
6510
6511 switch (keys_onoff) {
6512 case Alter_info::ENABLE:
6513 error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
6514 break;
6515 case Alter_info::LEAVE_AS_IS:
6516 if (!indexes_were_disabled)
6517 break;
6518 /* fall-through: disabled indexes */
6519 case Alter_info::DISABLE:
6520 error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
6521 }
6522
6523 if (error == HA_ERR_WRONG_COMMAND)
6524 {
6525 push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_NOTE,
6526 ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
6527 table->s->table_name.str);
6528 error= 0;
6529 } else if (error)
6530 table->file->print_error(error, MYF(0));
6531
6532 DBUG_RETURN(error);
6533 }
6534
6535
6536 /**
6537 Check if the pending ALTER TABLE operations support the in-place
6538 algorithm based on restrictions in the SQL layer or given the
6539 nature of the operations themselves. If in-place isn't supported,
6540 it won't be necessary to check with the storage engine.
6541
6542 @param table The original TABLE.
6543 @param create_info Information from the parsing phase about new
6544 table properties.
6545 @param alter_info Data related to detected changes.
6546
6547 @return false In-place is possible, check with storage engine.
6548 @return true Incompatible operations, must use table copy.
6549 */
6550
is_inplace_alter_impossible(TABLE * table,HA_CREATE_INFO * create_info,const Alter_info * alter_info)6551 static bool is_inplace_alter_impossible(TABLE *table,
6552 HA_CREATE_INFO *create_info,
6553 const Alter_info *alter_info)
6554 {
6555 DBUG_ENTER("is_inplace_alter_impossible");
6556
6557 /* At the moment we can't handle altering temporary tables without a copy. */
6558 if (table->s->tmp_table)
6559 DBUG_RETURN(true);
6560
6561 /*
6562 For the ALTER TABLE tbl_name ORDER BY ... we always use copy
6563 algorithm. In theory, this operation can be done in-place by some
6564 engine, but since a) no current engine does this and b) our current
6565 API lacks infrastructure for passing information about table ordering
6566 to storage engine we simply always do copy now.
6567
6568 ENABLE/DISABLE KEYS is a MyISAM/Heap specific operation that is
6569 not supported for in-place in combination with other operations.
6570 Alone, it will be done by simple_rename_or_index_change().
6571 */
6572 if (alter_info->flags & (Alter_info::ALTER_ORDER |
6573 Alter_info::ALTER_KEYS_ONOFF))
6574 DBUG_RETURN(true);
6575
6576 /*
6577 If the table engine is changed explicitly (using ENGINE clause)
6578 or implicitly (e.g. when non-partitioned table becomes
6579 partitioned) a regular alter table (copy) needs to be
6580 performed.
6581 */
6582 if (create_info->db_type != table->s->db_type())
6583 DBUG_RETURN(true);
6584
6585 /*
6586 There was a bug prior to mysql-4.0.25. Number of null fields was
6587 calculated incorrectly. As a result frm and data files gets out of
6588 sync after fast alter table. There is no way to determine by which
6589 mysql version (in 4.0 and 4.1 branches) table was created, thus we
6590 disable fast alter table for all tables created by mysql versions
6591 prior to 5.0 branch.
6592 See BUG#6236.
6593 */
6594 if (!table->s->mysql_version)
6595 DBUG_RETURN(true);
6596
6597 DBUG_RETURN(false);
6598 }
6599
6600
6601 /**
6602 Perform in-place alter table.
6603
6604 @param thd Thread handle.
6605 @param table_list TABLE_LIST for the table to change.
6606 @param table The original TABLE.
6607 @param altered_table TABLE object for new version of the table.
6608 @param ha_alter_info Structure describing ALTER TABLE to be carried
6609 out and serving as a storage place for data
6610 used during different phases.
6611 @param inplace_supported Enum describing the locking requirements.
6612 @param target_mdl_request Metadata request/lock on the target table name.
6613 @param alter_ctx ALTER TABLE runtime context.
6614
6615 @retval true Error
6616 @retval false Success
6617
6618 @note
6619 If mysql_alter_table does not need to copy the table, it is
6620 either an alter table where the storage engine does not
6621 need to know about the change, only the frm will change,
6622 or the storage engine supports performing the alter table
6623 operation directly, in-place without mysql having to copy
6624 the table.
6625
6626 @note This function frees the TABLE object associated with the new version of
6627 the table and removes the .FRM file for it in case of both success and
6628 failure.
6629 */
6630
mysql_inplace_alter_table(THD * thd,TABLE_LIST * table_list,TABLE * table,TABLE * altered_table,Alter_inplace_info * ha_alter_info,enum_alter_inplace_result inplace_supported,MDL_request * target_mdl_request,Alter_table_ctx * alter_ctx)6631 static bool mysql_inplace_alter_table(THD *thd,
6632 TABLE_LIST *table_list,
6633 TABLE *table,
6634 TABLE *altered_table,
6635 Alter_inplace_info *ha_alter_info,
6636 enum_alter_inplace_result inplace_supported,
6637 MDL_request *target_mdl_request,
6638 Alter_table_ctx *alter_ctx)
6639 {
6640 Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
6641 handlerton *db_type= table->s->db_type();
6642 MDL_ticket *mdl_ticket= table->mdl_ticket;
6643 HA_CREATE_INFO *create_info= ha_alter_info->create_info;
6644 Alter_info *alter_info= ha_alter_info->alter_info;
6645 bool reopen_tables= false;
6646
6647 DBUG_ENTER("mysql_inplace_alter_table");
6648
6649 /*
6650 Upgrade to EXCLUSIVE lock if:
6651 - This is requested by the storage engine
6652 - Or the storage engine needs exclusive lock for just the prepare
6653 phase
6654 - Or requested by the user
6655
6656 Note that we handle situation when storage engine needs exclusive
6657 lock for prepare phase under LOCK TABLES in the same way as when
6658 exclusive lock is required for duration of the whole statement.
6659 */
6660 if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK ||
6661 ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE ||
6662 inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) &&
6663 (thd->locked_tables_mode == LTM_LOCK_TABLES ||
6664 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) ||
6665 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
6666 {
6667 if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6668 goto cleanup;
6669 /*
6670 Get rid of all TABLE instances belonging to this thread
6671 except one to be used for in-place ALTER TABLE.
6672
6673 This is mostly needed to satisfy InnoDB assumptions/asserts.
6674 */
6675 close_all_tables_for_name(thd, table->s, alter_ctx->is_table_renamed(),
6676 table);
6677 /*
6678 If we are under LOCK TABLES we will need to reopen tables which we
6679 just have closed in case of error.
6680 */
6681 reopen_tables= true;
6682 }
6683 else if (inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE ||
6684 inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE)
6685 {
6686 /*
6687 Storage engine has requested exclusive lock only for prepare phase
6688 and we are not under LOCK TABLES.
6689 Don't mark TABLE_SHARE as old in this case, as this won't allow opening
6690 of table by other threads during main phase of in-place ALTER TABLE.
6691 */
6692 if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE,
6693 thd->variables.lock_wait_timeout))
6694 goto cleanup;
6695
6696 tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE,
6697 table->s->db.str, table->s->table_name.str,
6698 false);
6699 }
6700
6701 /*
6702 Upgrade to SHARED_NO_WRITE lock if:
6703 - The storage engine needs writes blocked for the whole duration
6704 - Or this is requested by the user
6705 Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE.
6706 */
6707 if ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK ||
6708 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED) &&
6709 thd->mdl_context.upgrade_shared_lock(table->mdl_ticket,
6710 MDL_SHARED_NO_WRITE,
6711 thd->variables.lock_wait_timeout))
6712 {
6713 goto cleanup;
6714 }
6715
6716 // It's now safe to take the table level lock.
6717 if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0))
6718 goto cleanup;
6719
6720 DEBUG_SYNC(thd, "alter_table_inplace_after_lock_upgrade");
6721 THD_STAGE_INFO(thd, stage_alter_inplace_prepare);
6722
6723 switch (inplace_supported) {
6724 case HA_ALTER_ERROR:
6725 case HA_ALTER_INPLACE_NOT_SUPPORTED:
6726 DBUG_ASSERT(0);
6727 // fall through
6728 case HA_ALTER_INPLACE_NO_LOCK:
6729 case HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE:
6730 switch (alter_info->requested_lock) {
6731 case Alter_info::ALTER_TABLE_LOCK_DEFAULT:
6732 case Alter_info::ALTER_TABLE_LOCK_NONE:
6733 ha_alter_info->online= true;
6734 break;
6735 case Alter_info::ALTER_TABLE_LOCK_SHARED:
6736 case Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE:
6737 break;
6738 }
6739 break;
6740 case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
6741 case HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE:
6742 case HA_ALTER_INPLACE_SHARED_LOCK:
6743 break;
6744 }
6745
6746 if (table->file->ha_prepare_inplace_alter_table(altered_table,
6747 ha_alter_info))
6748 {
6749 goto rollback;
6750 }
6751
6752 /*
6753 Downgrade the lock if storage engine has told us that exclusive lock was
6754 necessary only for prepare phase (unless we are not under LOCK TABLES) and
6755 user has not explicitly requested exclusive lock.
6756 */
6757 if ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE ||
6758 inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) &&
6759 !(thd->locked_tables_mode == LTM_LOCK_TABLES ||
6760 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
6761 (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE))
6762 {
6763 /* If storage engine or user requested shared lock downgrade to SNW. */
6764 if (inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE ||
6765 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED)
6766 table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_WRITE);
6767 else
6768 {
6769 DBUG_ASSERT(inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE);
6770 table->mdl_ticket->downgrade_lock(MDL_SHARED_UPGRADABLE);
6771 }
6772 }
6773
6774 DEBUG_SYNC(thd, "alter_table_inplace_after_lock_downgrade");
6775 THD_STAGE_INFO(thd, stage_alter_inplace);
6776
6777 if (table->file->ha_inplace_alter_table(altered_table,
6778 ha_alter_info))
6779 {
6780 goto rollback;
6781 }
6782
6783 // Upgrade to EXCLUSIVE before commit.
6784 if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
6785 goto rollback;
6786
6787 /*
6788 If we are killed after this point, we should ignore and continue.
6789 We have mostly completed the operation at this point, there should
6790 be no long waits left.
6791 */
6792
6793 DBUG_EXECUTE_IF("alter_table_rollback_new_index", {
6794 table->file->ha_commit_inplace_alter_table(altered_table,
6795 ha_alter_info,
6796 false);
6797 my_error(ER_UNKNOWN_ERROR, MYF(0));
6798 goto cleanup;
6799 });
6800
6801 DEBUG_SYNC(thd, "alter_table_inplace_before_commit");
6802 THD_STAGE_INFO(thd, stage_alter_inplace_commit);
6803
6804 if (table->file->ha_commit_inplace_alter_table(altered_table,
6805 ha_alter_info,
6806 true))
6807 {
6808 goto rollback;
6809 }
6810
6811 close_all_tables_for_name(thd, table->s, alter_ctx->is_table_renamed(), NULL);
6812 table_list->table= table= NULL;
6813 close_temporary_table(thd, altered_table, true, false);
6814
6815 /*
6816 Replace the old .FRM with the new .FRM, but keep the old name for now.
6817 Rename to the new name (if needed) will be handled separately below.
6818 */
6819 if (mysql_rename_table(db_type, alter_ctx->new_db, alter_ctx->tmp_name,
6820 alter_ctx->db, alter_ctx->alias,
6821 FN_FROM_IS_TMP | NO_HA_TABLE))
6822 {
6823 // Since changes were done in-place, we can't revert them.
6824 (void) quick_rm_table(thd, db_type,
6825 alter_ctx->new_db, alter_ctx->tmp_name,
6826 FN_IS_TMP | NO_HA_TABLE);
6827 DBUG_RETURN(true);
6828 }
6829
6830 table_list->mdl_request.ticket= mdl_ticket;
6831 if (open_table(thd, table_list, &ot_ctx))
6832 DBUG_RETURN(true);
6833
6834 /*
6835 Tell the handler that the changed frm is on disk and table
6836 has been re-opened
6837 */
6838 table_list->table->file->ha_notify_table_changed();
6839
6840 /*
6841 We might be going to reopen table down on the road, so we have to
6842 restore state of the TABLE object which we used for obtaining of
6843 handler object to make it usable for later reopening.
6844 */
6845 close_thread_table(thd, &thd->open_tables);
6846 table_list->table= NULL;
6847
6848 // Rename altered table if requested.
6849 if (alter_ctx->is_table_renamed())
6850 {
6851 // Remove TABLE and TABLE_SHARE for old name from TDC.
6852 tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
6853 alter_ctx->db, alter_ctx->table_name, false);
6854
6855 if (mysql_rename_table(db_type, alter_ctx->db, alter_ctx->table_name,
6856 alter_ctx->new_db, alter_ctx->new_alias, 0))
6857 {
6858 /*
6859 If the rename fails we will still have a working table
6860 with the old name, but with other changes applied.
6861 */
6862 DBUG_RETURN(true);
6863 }
6864 if (Table_triggers_list::change_table_name(thd,
6865 alter_ctx->db,
6866 alter_ctx->alias,
6867 alter_ctx->table_name,
6868 alter_ctx->new_db,
6869 alter_ctx->new_alias))
6870 {
6871 /*
6872 If the rename of trigger files fails, try to rename the table
6873 back so we at least have matching table and trigger files.
6874 */
6875 (void) mysql_rename_table(db_type,
6876 alter_ctx->new_db, alter_ctx->new_alias,
6877 alter_ctx->db, alter_ctx->alias, NO_FK_CHECKS);
6878 DBUG_RETURN(true);
6879 }
6880 }
6881
6882 DBUG_RETURN(false);
6883
6884 rollback:
6885 table->file->ha_commit_inplace_alter_table(altered_table,
6886 ha_alter_info,
6887 false);
6888 cleanup:
6889 if (reopen_tables)
6890 {
6891 /* Close the only table instance which is still around. */
6892 close_all_tables_for_name(thd, table->s, alter_ctx->is_table_renamed(), NULL);
6893 if (thd->locked_tables_list.reopen_tables(thd))
6894 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
6895 /* QQ; do something about metadata locks ? */
6896 }
6897 close_temporary_table(thd, altered_table, true, false);
6898 // Delete temporary .frm/.par
6899 (void) quick_rm_table(thd, create_info->db_type, alter_ctx->new_db,
6900 alter_ctx->tmp_name, FN_IS_TMP | NO_HA_TABLE);
6901 DBUG_RETURN(true);
6902 }
6903
6904 /**
6905 maximum possible length for certain blob types.
6906
6907 @param[in] type Blob type (e.g. MYSQL_TYPE_TINY_BLOB)
6908
6909 @return
6910 length
6911 */
6912
6913 static uint
blob_length_by_type(enum_field_types type)6914 blob_length_by_type(enum_field_types type)
6915 {
6916 switch (type)
6917 {
6918 case MYSQL_TYPE_TINY_BLOB:
6919 return 255;
6920 case MYSQL_TYPE_BLOB:
6921 return 65535;
6922 case MYSQL_TYPE_MEDIUM_BLOB:
6923 return 16777215;
6924 case MYSQL_TYPE_LONG_BLOB:
6925 return 4294967295U;
6926 default:
6927 DBUG_ASSERT(0); // we should never go here
6928 return 0;
6929 }
6930 }
6931
6932
6933 /**
6934 Convert the old temporal data types to the new temporal
6935 type format for ADD/CHANGE COLUMN, ADD INDEXES and ALTER
6936 FORCE ALTER operation.
6937
6938 @param thd Thread context.
6939 @param alter_info Alter info parameters.
6940
6941 @retval true Error.
6942 @retval false Either the old temporal data types
6943 are not present or they are present
6944 and have been successfully upgraded.
6945 */
6946
6947 static bool
upgrade_old_temporal_types(THD * thd,Alter_info * alter_info)6948 upgrade_old_temporal_types(THD *thd, Alter_info *alter_info)
6949 {
6950 bool old_temporal_type_present= false;
6951
6952 DBUG_ENTER("upgrade_old_temporal_types");
6953
6954 if (!((alter_info->flags & Alter_info::ALTER_ADD_COLUMN) ||
6955 (alter_info->flags & Alter_info::ALTER_ADD_INDEX) ||
6956 (alter_info->flags & Alter_info::ALTER_CHANGE_COLUMN) ||
6957 (alter_info->flags & Alter_info::ALTER_RECREATE)))
6958 DBUG_RETURN(false);
6959
6960 /*
6961 Upgrade the old temporal types if any, for ADD/CHANGE COLUMN/
6962 ADD INDEXES and FORCE ALTER operation.
6963 */
6964 Create_field *def;
6965 List_iterator<Create_field> create_it(alter_info->create_list);
6966
6967 while ((def= create_it++))
6968 {
6969 // Check if any old temporal type is present.
6970 if ((def->sql_type == MYSQL_TYPE_TIME) ||
6971 (def->sql_type == MYSQL_TYPE_DATETIME) ||
6972 (def->sql_type == MYSQL_TYPE_TIMESTAMP))
6973 {
6974 old_temporal_type_present= true;
6975 break;
6976 }
6977 }
6978
6979 // Upgrade is not required since there are no old temporal types.
6980 if (!old_temporal_type_present)
6981 DBUG_RETURN(false);
6982
6983 // Upgrade old temporal types to the new temporal types.
6984 create_it.rewind();
6985 while ((def= create_it++))
6986 {
6987 enum enum_field_types sql_type;
6988 Item *default_value= def->def, *update_value= NULL;
6989
6990 /*
6991 Set CURRENT_TIMESTAMP as default/update value based on
6992 the unireg_check value.
6993 */
6994
6995 if ((def->sql_type == MYSQL_TYPE_DATETIME ||
6996 def->sql_type == MYSQL_TYPE_TIMESTAMP)
6997 && (def->unireg_check != Field::NONE))
6998 {
6999 Item_func_now_local *now = new (thd->mem_root) Item_func_now_local(0);
7000 if (!now)
7001 DBUG_RETURN(true);
7002
7003 if (def->unireg_check == Field::TIMESTAMP_DN_FIELD)
7004 default_value= now;
7005 else if (def->unireg_check == Field::TIMESTAMP_UN_FIELD)
7006 update_value= now;
7007 else if (def->unireg_check == Field::TIMESTAMP_DNUN_FIELD)
7008 {
7009 update_value= now;
7010 default_value= now;
7011 }
7012 }
7013
7014 switch (def->sql_type)
7015 {
7016 case MYSQL_TYPE_TIME:
7017 sql_type= MYSQL_TYPE_TIME2;
7018 break;
7019 case MYSQL_TYPE_DATETIME:
7020 sql_type= MYSQL_TYPE_DATETIME2;
7021 break;
7022 case MYSQL_TYPE_TIMESTAMP:
7023 sql_type= MYSQL_TYPE_TIMESTAMP2;
7024 break;
7025 default:
7026 continue;
7027 }
7028
7029 // Replace the old temporal field with the new temporal field.
7030 Create_field *temporal_field= NULL;
7031 if (!(temporal_field= new (thd->mem_root) Create_field()) ||
7032 temporal_field->init(thd, def->field_name, sql_type, NULL, NULL,
7033 (def->flags & NOT_NULL_FLAG), default_value,
7034 update_value, &def->comment, def->change, NULL,
7035 NULL, 0))
7036 DBUG_RETURN(true);
7037
7038 temporal_field->field= def->field;
7039 create_it.replace(temporal_field);
7040 }
7041
7042 // Report a NOTE informing about the upgrade.
7043 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
7044 ER_OLD_TEMPORALS_UPGRADED,
7045 ER(ER_OLD_TEMPORALS_UPGRADED));
7046 DBUG_RETURN(false);
7047 }
7048
7049
7050 /**
7051 Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
7052
7053 This function transforms parse output of ALTER TABLE - lists of
7054 columns and keys to add, drop or modify into, essentially,
7055 CREATE TABLE definition - a list of columns and keys of the new
7056 table. While doing so, it also performs some (bug not all)
7057 semantic checks.
7058
7059 This function is invoked when we know that we're going to
7060 perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE
7061 is not possible, perhaps because the ALTER statement contains
7062 instructions that require change in table data, not only in
7063 table definition or indexes.
7064
7065 @param[in,out] thd thread handle. Used as a memory pool
7066 and source of environment information.
7067 @param[in] table the source table, open and locked
7068 Used as an interface to the storage engine
7069 to acquire additional information about
7070 the original table.
7071 @param[in,out] create_info A blob with CREATE/ALTER TABLE
7072 parameters
7073 @param[in,out] alter_info Another blob with ALTER/CREATE parameters.
7074 Originally create_info was used only in
7075 CREATE TABLE and alter_info only in ALTER TABLE.
7076 But since ALTER might end-up doing CREATE,
7077 this distinction is gone and we just carry
7078 around two structures.
7079 @param[in,out] alter_ctx Runtime context for ALTER TABLE.
7080
7081 @return
7082 Fills various create_info members based on information retrieved
7083 from the storage engine.
7084 Sets create_info->varchar if the table has a VARCHAR column.
7085 Prepares alter_info->create_list and alter_info->key_list with
7086 columns and keys of the new table.
7087 @retval TRUE error, out of memory or a semantical error in ALTER
7088 TABLE instructions
7089 @retval FALSE success
7090 */
7091
7092 bool
mysql_prepare_alter_table(THD * thd,TABLE * table,HA_CREATE_INFO * create_info,Alter_info * alter_info,Alter_table_ctx * alter_ctx)7093 mysql_prepare_alter_table(THD *thd, TABLE *table,
7094 HA_CREATE_INFO *create_info,
7095 Alter_info *alter_info,
7096 Alter_table_ctx *alter_ctx)
7097 {
7098 /* New column definitions are added here */
7099 List<Create_field> new_create_list;
7100 /* New key definitions are added here */
7101 List<Key> new_key_list;
7102 List_iterator<Alter_drop> drop_it(alter_info->drop_list);
7103 List_iterator<Create_field> def_it(alter_info->create_list);
7104 List_iterator<Alter_column> alter_it(alter_info->alter_list);
7105 List_iterator<Key> key_it(alter_info->key_list);
7106 List_iterator<Create_field> find_it(new_create_list);
7107 List_iterator<Create_field> field_it(new_create_list);
7108 List<Key_part_spec> key_parts;
7109 uint db_create_options= (table->s->db_create_options
7110 & ~(HA_OPTION_PACK_RECORD));
7111 uint used_fields= create_info->used_fields;
7112 KEY *key_info=table->key_info;
7113 bool rc= TRUE;
7114
7115 DBUG_ENTER("mysql_prepare_alter_table");
7116
7117 create_info->varchar= FALSE;
7118 /* Let new create options override the old ones */
7119 if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
7120 create_info->min_rows= table->s->min_rows;
7121 if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
7122 create_info->max_rows= table->s->max_rows;
7123 if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
7124 create_info->avg_row_length= table->s->avg_row_length;
7125 if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
7126 create_info->default_table_charset= table->s->table_charset;
7127 if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
7128 {
7129 /* Table has an autoincrement, copy value to new table */
7130 table->file->info(HA_STATUS_AUTO);
7131 create_info->auto_increment_value= table->file->stats.auto_increment_value;
7132 }
7133 if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
7134 create_info->key_block_size= table->s->key_block_size;
7135
7136 if (!(used_fields & HA_CREATE_USED_STATS_SAMPLE_PAGES))
7137 create_info->stats_sample_pages= table->s->stats_sample_pages;
7138
7139 if (!(used_fields & HA_CREATE_USED_STATS_AUTO_RECALC))
7140 create_info->stats_auto_recalc= table->s->stats_auto_recalc;
7141
7142 if (!create_info->tablespace)
7143 create_info->tablespace= table->s->tablespace;
7144
7145 if (create_info->storage_media == HA_SM_DEFAULT)
7146 create_info->storage_media= table->s->default_storage_media;
7147
7148 /* Creation of federated table with LIKE clause needs connection string */
7149 if (!(used_fields & HA_CREATE_USED_CONNECTION))
7150 create_info->connect_string= table->s->connect_string;
7151
7152 restore_record(table, s->default_values); // Empty record for DEFAULT
7153 Create_field *def;
7154
7155 /*
7156 First collect all fields from table which isn't in drop_list
7157 */
7158 Field **f_ptr,*field;
7159 for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
7160 {
7161 if (field->type() == MYSQL_TYPE_STRING)
7162 create_info->varchar= TRUE;
7163 /* Check if field should be dropped */
7164 Alter_drop *drop;
7165 drop_it.rewind();
7166 while ((drop=drop_it++))
7167 {
7168 if (drop->type == Alter_drop::COLUMN &&
7169 !my_strcasecmp(system_charset_info,field->field_name, drop->name))
7170 {
7171 /* Reset auto_increment value if it was dropped */
7172 if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
7173 !(used_fields & HA_CREATE_USED_AUTO))
7174 {
7175 create_info->auto_increment_value=0;
7176 create_info->used_fields|=HA_CREATE_USED_AUTO;
7177 }
7178 break;
7179 }
7180 }
7181 if (drop)
7182 {
7183 drop_it.remove();
7184 continue;
7185 }
7186 /* Check if field is changed */
7187 def_it.rewind();
7188 while ((def=def_it++))
7189 {
7190 if (def->change &&
7191 !my_strcasecmp(system_charset_info,field->field_name, def->change))
7192 break;
7193 }
7194 if (def)
7195 { // Field is changed
7196 def->field=field;
7197 /*
7198 Add column being updated to the list of new columns.
7199 Note that columns with AFTER clauses are added to the end
7200 of the list for now. Their positions will be corrected later.
7201 */
7202 new_create_list.push_back(def);
7203 if (!def->after)
7204 {
7205 /*
7206 If this ALTER TABLE doesn't have an AFTER clause for the modified
7207 column then remove this column from the list of columns to be
7208 processed. So later we can iterate over the columns remaining
7209 in this list and process modified columns with AFTER clause or
7210 add new columns.
7211 */
7212 def_it.remove();
7213 }
7214 }
7215 else
7216 {
7217 /*
7218 This field was not dropped and not changed, add it to the list
7219 for the new table.
7220 */
7221 def= new Create_field(field, field);
7222 new_create_list.push_back(def);
7223 alter_it.rewind(); // Change default if ALTER
7224 Alter_column *alter;
7225 while ((alter=alter_it++))
7226 {
7227 if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
7228 break;
7229 }
7230 if (alter)
7231 {
7232 if (def->flags & BLOB_FLAG)
7233 {
7234 my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
7235 goto err;
7236 }
7237 if ((def->def=alter->def)) // Use new default
7238 def->flags&= ~NO_DEFAULT_VALUE_FLAG;
7239 else
7240 def->flags|= NO_DEFAULT_VALUE_FLAG;
7241 alter_it.remove();
7242 }
7243 }
7244 }
7245 def_it.rewind();
7246 while ((def=def_it++)) // Add new columns
7247 {
7248 if (def->change && ! def->field)
7249 {
7250 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
7251 goto err;
7252 }
7253 /*
7254 Check that the DATE/DATETIME not null field we are going to add is
7255 either has a default value or the '0000-00-00' is allowed by the
7256 set sql mode.
7257 If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
7258 flag to allow ALTER TABLE only if the table to be altered is empty.
7259 */
7260 if ((def->sql_type == MYSQL_TYPE_DATE ||
7261 def->sql_type == MYSQL_TYPE_NEWDATE ||
7262 def->sql_type == MYSQL_TYPE_DATETIME ||
7263 def->sql_type == MYSQL_TYPE_DATETIME2) &&
7264 !alter_ctx->datetime_field &&
7265 !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
7266 thd->variables.sql_mode & MODE_NO_ZERO_DATE)
7267 {
7268 alter_ctx->datetime_field= def;
7269 alter_ctx->error_if_not_empty= true;
7270 }
7271 if (!def->after)
7272 new_create_list.push_back(def);
7273 else
7274 {
7275 Create_field *find;
7276 if (def->change)
7277 {
7278 find_it.rewind();
7279 /*
7280 For columns being modified with AFTER clause we should first remove
7281 these columns from the list and then add them back at their correct
7282 positions.
7283 */
7284 while ((find=find_it++))
7285 {
7286 /*
7287 Create_fields representing changed columns are added directly
7288 from Alter_info::create_list to new_create_list. We can therefore
7289 safely use pointer equality rather than name matching here.
7290 This prevents removing the wrong column in case of column rename.
7291 */
7292 if (find == def)
7293 {
7294 find_it.remove();
7295 break;
7296 }
7297 }
7298 }
7299 if (def->after == first_keyword)
7300 new_create_list.push_front(def);
7301 else
7302 {
7303 find_it.rewind();
7304 while ((find=find_it++))
7305 {
7306 if (!my_strcasecmp(system_charset_info, def->after, find->field_name))
7307 break;
7308 }
7309 if (!find)
7310 {
7311 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
7312 goto err;
7313 }
7314 find_it.after(def); // Put column after this
7315 }
7316 }
7317 }
7318 if (alter_info->alter_list.elements)
7319 {
7320 my_error(ER_BAD_FIELD_ERROR, MYF(0),
7321 alter_info->alter_list.head()->name, table->s->table_name.str);
7322 goto err;
7323 }
7324 if (!new_create_list.elements)
7325 {
7326 my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
7327 MYF(0));
7328 goto err;
7329 }
7330
7331 /*
7332 Collect all keys which isn't in drop list. Add only those
7333 for which some fields exists.
7334 */
7335
7336 for (uint i=0 ; i < table->s->keys ; i++,key_info++)
7337 {
7338 char *key_name= key_info->name;
7339 bool index_column_dropped= false;
7340 Alter_drop *drop;
7341 drop_it.rewind();
7342 while ((drop=drop_it++))
7343 {
7344 if (drop->type == Alter_drop::KEY &&
7345 !my_strcasecmp(system_charset_info,key_name, drop->name))
7346 break;
7347 }
7348 if (drop)
7349 {
7350 drop_it.remove();
7351 continue;
7352 }
7353
7354 KEY_PART_INFO *key_part= key_info->key_part;
7355 key_parts.empty();
7356 for (uint j=0 ; j < key_info->user_defined_key_parts ; j++,key_part++)
7357 {
7358 if (!key_part->field)
7359 continue; // Wrong field (from UNIREG)
7360 const char *key_part_name=key_part->field->field_name;
7361 Create_field *cfield;
7362 field_it.rewind();
7363 while ((cfield=field_it++))
7364 {
7365 if (cfield->change)
7366 {
7367 if (!my_strcasecmp(system_charset_info, key_part_name,
7368 cfield->change))
7369 break;
7370 }
7371 else if (!my_strcasecmp(system_charset_info,
7372 key_part_name, cfield->field_name))
7373 break;
7374 }
7375 if (!cfield)
7376 {
7377 /*
7378 We are dropping a column associated with an index.
7379 */
7380 index_column_dropped= true;
7381 continue; // Field is removed
7382 }
7383 uint key_part_length=key_part->length;
7384 if (cfield->field) // Not new field
7385 {
7386 /*
7387 If the field can't have only a part used in a key according to its
7388 new type, or should not be used partially according to its
7389 previous type, or the field length is less than the key part
7390 length, unset the key part length.
7391
7392 We also unset the key part length if it is the same as the
7393 old field's length, so the whole new field will be used.
7394
7395 BLOBs may have cfield->length == 0, which is why we test it before
7396 checking whether cfield->length < key_part_length (in chars).
7397
7398 In case of TEXTs we check the data type maximum length *in bytes*
7399 to key part length measured *in characters* (i.e. key_part_length
7400 devided to mbmaxlen). This is because it's OK to have:
7401 CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8);
7402 In case of this example:
7403 - data type maximum length is 255.
7404 - key_part_length is 1016 (=254*4, where 4 is mbmaxlen)
7405 */
7406 if (!Field::type_can_have_key_part(cfield->field->type()) ||
7407 !Field::type_can_have_key_part(cfield->sql_type) ||
7408 /* spatial keys can't have sub-key length */
7409 (key_info->flags & HA_SPATIAL) ||
7410 (cfield->field->field_length == key_part_length &&
7411 !f_is_blob(key_part->key_type)) ||
7412 (cfield->length && (((cfield->sql_type >= MYSQL_TYPE_TINY_BLOB &&
7413 cfield->sql_type <= MYSQL_TYPE_BLOB) ?
7414 blob_length_by_type(cfield->sql_type) :
7415 cfield->length) <
7416 key_part_length / key_part->field->charset()->mbmaxlen)))
7417 key_part_length= 0; // Use whole field
7418 }
7419 key_part_length /= key_part->field->charset()->mbmaxlen;
7420 key_parts.push_back(new Key_part_spec(cfield->field_name,
7421 strlen(cfield->field_name),
7422 key_part_length));
7423 }
7424 if (key_parts.elements)
7425 {
7426 KEY_CREATE_INFO key_create_info;
7427 Key *key;
7428 enum Key::Keytype key_type;
7429 memset(&key_create_info, 0, sizeof(key_create_info));
7430
7431 key_create_info.algorithm= key_info->algorithm;
7432 if (key_info->flags & HA_USES_BLOCK_SIZE)
7433 key_create_info.block_size= key_info->block_size;
7434 if (key_info->flags & HA_USES_PARSER)
7435 key_create_info.parser_name= *plugin_name(key_info->parser);
7436 if (key_info->flags & HA_USES_COMMENT)
7437 key_create_info.comment= key_info->comment;
7438
7439 if (key_info->flags & HA_SPATIAL)
7440 key_type= Key::SPATIAL;
7441 else if (key_info->flags & HA_NOSAME)
7442 {
7443 if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
7444 key_type= Key::PRIMARY;
7445 else
7446 key_type= Key::UNIQUE;
7447 }
7448 else if (key_info->flags & HA_FULLTEXT)
7449 key_type= Key::FULLTEXT;
7450 else
7451 key_type= Key::MULTIPLE;
7452
7453 if (index_column_dropped)
7454 {
7455 /*
7456 We have dropped a column associated with an index,
7457 this warrants a check for duplicate indexes
7458 */
7459 key_create_info.check_for_duplicate_indexes= true;
7460 }
7461
7462 key= new Key(key_type, key_name, strlen(key_name),
7463 &key_create_info,
7464 MY_TEST(key_info->flags & HA_GENERATED_KEY),
7465 key_parts);
7466 new_key_list.push_back(key);
7467 }
7468 }
7469 {
7470 Key *key;
7471 while ((key=key_it++)) // Add new keys
7472 {
7473 new_key_list.push_back(key);
7474 if (key->name.str &&
7475 !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
7476 {
7477 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
7478 goto err;
7479 }
7480 }
7481 }
7482
7483 if (alter_info->drop_list.elements)
7484 {
7485 Alter_drop *drop;
7486 drop_it.rewind();
7487 while ((drop=drop_it++)) {
7488 switch (drop->type) {
7489 case Alter_drop::KEY:
7490 case Alter_drop::COLUMN:
7491 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
7492 alter_info->drop_list.head()->name);
7493 goto err;
7494 case Alter_drop::FOREIGN_KEY:
7495 // Leave the DROP FOREIGN KEY names in the alter_info->drop_list.
7496 break;
7497 }
7498 }
7499 }
7500 if (alter_info->alter_list.elements)
7501 {
7502 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
7503 alter_info->alter_list.head()->name);
7504 goto err;
7505 }
7506
7507 if (!create_info->comment.str)
7508 {
7509 create_info->comment.str= table->s->comment.str;
7510 create_info->comment.length= table->s->comment.length;
7511 }
7512
7513 /* Do not pass the update_create_info through to each partition. */
7514 if (table->file->ht->db_type == DB_TYPE_PARTITION_DB)
7515 create_info->data_file_name = (char*) -1;
7516
7517 table->file->update_create_info(create_info);
7518 if ((create_info->table_options &
7519 (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
7520 (used_fields & HA_CREATE_USED_PACK_KEYS))
7521 db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
7522 if ((create_info->table_options &
7523 (HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT)) ||
7524 (used_fields & HA_CREATE_USED_STATS_PERSISTENT))
7525 db_create_options&= ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT);
7526 if (create_info->table_options &
7527 (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
7528 db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
7529 if (create_info->table_options &
7530 (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
7531 db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
7532 HA_OPTION_NO_DELAY_KEY_WRITE);
7533 create_info->table_options|= db_create_options;
7534
7535 if (table->s->tmp_table)
7536 create_info->options|=HA_LEX_CREATE_TMP_TABLE;
7537
7538 rc= FALSE;
7539 alter_info->create_list.swap(new_create_list);
7540 alter_info->key_list.swap(new_key_list);
7541 err:
7542 DBUG_RETURN(rc);
7543 }
7544
7545
7546 /**
7547 Get Create_field object for newly created table by its name
7548 in the old version of table.
7549
7550 @param alter_info Alter_info describing newly created table.
7551 @param old_name Name of field in old table.
7552
7553 @returns Pointer to Create_field object, NULL - if field is
7554 not present in new version of table.
7555 */
7556
get_field_by_old_name(Alter_info * alter_info,const char * old_name)7557 static Create_field *get_field_by_old_name(Alter_info *alter_info,
7558 const char *old_name)
7559 {
7560 List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
7561 Create_field *new_field;
7562
7563 while ((new_field= new_field_it++))
7564 {
7565 if (new_field->field &&
7566 (my_strcasecmp(system_charset_info,
7567 new_field->field->field_name,
7568 old_name) == 0))
7569 break;
7570 }
7571 return new_field;
7572 }
7573
7574
7575 /** Type of change to foreign key column, */
7576
7577 enum fk_column_change_type
7578 {
7579 FK_COLUMN_NO_CHANGE, FK_COLUMN_DATA_CHANGE,
7580 FK_COLUMN_RENAMED, FK_COLUMN_DROPPED
7581 };
7582
7583
7584 /**
7585 Check that ALTER TABLE's changes on columns of a foreign key are allowed.
7586
7587 @param[in] thd Thread context.
7588 @param[in] alter_info Alter_info describing changes to be done
7589 by ALTER TABLE.
7590 @param[in] fk_columns List of columns of the foreign key to check.
7591 @param[out] bad_column_name Name of field on which ALTER TABLE tries to
7592 do prohibited operation.
7593
7594 @note This function takes into account value of @@foreign_key_checks
7595 setting.
7596
7597 @retval FK_COLUMN_NO_CHANGE No significant changes are to be done on
7598 foreign key columns.
7599 @retval FK_COLUMN_DATA_CHANGE ALTER TABLE might result in value
7600 change in foreign key column (and
7601 foreign_key_checks is on).
7602 @retval FK_COLUMN_RENAMED Foreign key column is renamed.
7603 @retval FK_COLUMN_DROPPED Foreign key column is dropped.
7604 */
7605
7606 static enum fk_column_change_type
fk_check_column_changes(THD * thd,Alter_info * alter_info,List<LEX_STRING> & fk_columns,const char ** bad_column_name)7607 fk_check_column_changes(THD *thd, Alter_info *alter_info,
7608 List<LEX_STRING> &fk_columns,
7609 const char **bad_column_name)
7610 {
7611 List_iterator_fast<LEX_STRING> column_it(fk_columns);
7612 LEX_STRING *column;
7613
7614 *bad_column_name= NULL;
7615
7616 while ((column= column_it++))
7617 {
7618 Create_field *new_field= get_field_by_old_name(alter_info, column->str);
7619
7620 if (new_field)
7621 {
7622 Field *old_field= new_field->field;
7623
7624 if (my_strcasecmp(system_charset_info, old_field->field_name,
7625 new_field->field_name))
7626 {
7627 /*
7628 Copy algorithm doesn't support proper renaming of columns in
7629 the foreign key yet. At the moment we lack API which will tell
7630 SE that foreign keys should be updated to use new name of column
7631 like it happens in case of in-place algorithm.
7632 */
7633 *bad_column_name= column->str;
7634 return FK_COLUMN_RENAMED;
7635 }
7636
7637 if ((old_field->is_equal(new_field) == IS_EQUAL_NO) ||
7638 ((new_field->flags & NOT_NULL_FLAG) &&
7639 !(old_field->flags & NOT_NULL_FLAG)))
7640 {
7641 if (!(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
7642 {
7643 /*
7644 Column in a FK has changed significantly. Unless
7645 foreign_key_checks are off we prohibit this since this
7646 means values in this column might be changed by ALTER
7647 and thus referential integrity might be broken,
7648 */
7649 *bad_column_name= column->str;
7650 return FK_COLUMN_DATA_CHANGE;
7651 }
7652 }
7653 }
7654 else
7655 {
7656 /*
7657 Column in FK was dropped. Most likely this will break
7658 integrity constraints of InnoDB data-dictionary (and thus
7659 InnoDB will emit an error), so we prohibit this right away
7660 even if foreign_key_checks are off.
7661 This also includes a rare case when another field replaces
7662 field being dropped since it is easy to break referential
7663 integrity in this case.
7664 */
7665 *bad_column_name= column->str;
7666 return FK_COLUMN_DROPPED;
7667 }
7668 }
7669
7670 return FK_COLUMN_NO_CHANGE;
7671 }
7672
7673
7674 /**
7675 Check if ALTER TABLE we are about to execute using COPY algorithm
7676 is not supported as it might break referential integrity.
7677
7678 @note If foreign_key_checks is disabled (=0), we allow to break
7679 referential integrity. But we still disallow some operations
7680 like dropping or renaming columns in foreign key since they
7681 are likely to break consistency of InnoDB data-dictionary
7682 and thus will end-up in error anyway.
7683
7684 @param[in] thd Thread context.
7685 @param[in] table Table to be altered.
7686 @param[in] alter_info Lists of fields, keys to be changed, added
7687 or dropped.
7688 @param[out] alter_ctx ALTER TABLE runtime context.
7689 Alter_table_ctx::fk_error_if_delete flag
7690 is set if deletion during alter can break
7691 foreign key integrity.
7692
7693 @retval false Success.
7694 @retval true Error, ALTER - tries to do change which is not compatible
7695 with foreign key definitions on the table.
7696 */
7697
fk_prepare_copy_alter_table(THD * thd,TABLE * table,Alter_info * alter_info,Alter_table_ctx * alter_ctx)7698 static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
7699 Alter_info *alter_info,
7700 Alter_table_ctx *alter_ctx)
7701 {
7702 List <FOREIGN_KEY_INFO> fk_parent_key_list;
7703 List <FOREIGN_KEY_INFO> fk_child_key_list;
7704 FOREIGN_KEY_INFO *f_key;
7705
7706 DBUG_ENTER("fk_prepare_copy_alter_table");
7707
7708 table->file->get_parent_foreign_key_list(thd, &fk_parent_key_list);
7709
7710 /* OOM when building list. */
7711 if (thd->is_error())
7712 DBUG_RETURN(true);
7713
7714 /*
7715 Remove from the list all foreign keys in which table participates as
7716 parent which are to be dropped by this ALTER TABLE. This is possible
7717 when a foreign key has the same table as child and parent.
7718 */
7719 List_iterator<FOREIGN_KEY_INFO> fk_parent_key_it(fk_parent_key_list);
7720
7721 while ((f_key= fk_parent_key_it++))
7722 {
7723 Alter_drop *drop;
7724 List_iterator_fast<Alter_drop> drop_it(alter_info->drop_list);
7725
7726 while ((drop= drop_it++))
7727 {
7728 /*
7729 InnoDB treats foreign key names in case-insensitive fashion.
7730 So we do it here too. For database and table name type of
7731 comparison used depends on lower-case-table-names setting.
7732 For l_c_t_n = 0 we use case-sensitive comparison, for
7733 l_c_t_n > 0 modes case-insensitive comparison is used.
7734 */
7735 if ((drop->type == Alter_drop::FOREIGN_KEY) &&
7736 (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
7737 drop->name) == 0) &&
7738 (my_strcasecmp(table_alias_charset, f_key->foreign_db->str,
7739 table->s->db.str) == 0) &&
7740 (my_strcasecmp(table_alias_charset, f_key->foreign_table->str,
7741 table->s->table_name.str) == 0))
7742 fk_parent_key_it.remove();
7743 }
7744 }
7745
7746 /*
7747 If there are FKs in which this table is parent which were not
7748 dropped we need to prevent ALTER deleting rows from the table,
7749 as it might break referential integrity. OTOH it is OK to do
7750 so if foreign_key_checks are disabled.
7751 */
7752 if (!fk_parent_key_list.is_empty() &&
7753 !(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
7754 alter_ctx->set_fk_error_if_delete_row(fk_parent_key_list.head());
7755
7756 fk_parent_key_it.rewind();
7757 while ((f_key= fk_parent_key_it++))
7758 {
7759 enum fk_column_change_type changes;
7760 const char *bad_column_name;
7761
7762 changes= fk_check_column_changes(thd, alter_info,
7763 f_key->referenced_fields,
7764 &bad_column_name);
7765
7766 switch(changes)
7767 {
7768 case FK_COLUMN_NO_CHANGE:
7769 /* No significant changes. We can proceed with ALTER! */
7770 break;
7771 case FK_COLUMN_DATA_CHANGE:
7772 {
7773 char buff[NAME_LEN*2+2];
7774 strxnmov(buff, sizeof(buff)-1, f_key->foreign_db->str, ".",
7775 f_key->foreign_table->str, NullS);
7776 my_error(ER_FK_COLUMN_CANNOT_CHANGE_CHILD, MYF(0), bad_column_name,
7777 f_key->foreign_id->str, buff);
7778 DBUG_RETURN(true);
7779 }
7780 case FK_COLUMN_RENAMED:
7781 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
7782 "ALGORITHM=COPY",
7783 ER(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME),
7784 "ALGORITHM=INPLACE");
7785 DBUG_RETURN(true);
7786 case FK_COLUMN_DROPPED:
7787 {
7788 char buff[NAME_LEN*2+2];
7789 strxnmov(buff, sizeof(buff)-1, f_key->foreign_db->str, ".",
7790 f_key->foreign_table->str, NullS);
7791 my_error(ER_FK_COLUMN_CANNOT_DROP_CHILD, MYF(0), bad_column_name,
7792 f_key->foreign_id->str, buff);
7793 DBUG_RETURN(true);
7794 }
7795 default:
7796 DBUG_ASSERT(0);
7797 }
7798 }
7799
7800 table->file->get_foreign_key_list(thd, &fk_child_key_list);
7801
7802 /* OOM when building list. */
7803 if (thd->is_error())
7804 DBUG_RETURN(true);
7805
7806 /*
7807 Remove from the list all foreign keys which are to be dropped
7808 by this ALTER TABLE.
7809 */
7810 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
7811
7812 while ((f_key= fk_key_it++))
7813 {
7814 Alter_drop *drop;
7815 List_iterator_fast<Alter_drop> drop_it(alter_info->drop_list);
7816
7817 while ((drop= drop_it++))
7818 {
7819 /* Names of foreign keys in InnoDB are case-insensitive. */
7820 if ((drop->type == Alter_drop::FOREIGN_KEY) &&
7821 (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
7822 drop->name) == 0))
7823 fk_key_it.remove();
7824 }
7825 }
7826
7827 fk_key_it.rewind();
7828 while ((f_key= fk_key_it++))
7829 {
7830 enum fk_column_change_type changes;
7831 const char *bad_column_name;
7832
7833 changes= fk_check_column_changes(thd, alter_info,
7834 f_key->foreign_fields,
7835 &bad_column_name);
7836
7837 switch(changes)
7838 {
7839 case FK_COLUMN_NO_CHANGE:
7840 /* No significant changes. We can proceed with ALTER! */
7841 break;
7842 case FK_COLUMN_DATA_CHANGE:
7843 my_error(ER_FK_COLUMN_CANNOT_CHANGE, MYF(0), bad_column_name,
7844 f_key->foreign_id->str);
7845 DBUG_RETURN(true);
7846 case FK_COLUMN_RENAMED:
7847 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
7848 "ALGORITHM=COPY",
7849 ER(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME),
7850 "ALGORITHM=INPLACE");
7851 DBUG_RETURN(true);
7852 case FK_COLUMN_DROPPED:
7853 my_error(ER_FK_COLUMN_CANNOT_DROP, MYF(0), bad_column_name,
7854 f_key->foreign_id->str);
7855 DBUG_RETURN(true);
7856 default:
7857 DBUG_ASSERT(0);
7858 }
7859 }
7860
7861 DBUG_RETURN(false);
7862 }
7863
7864
7865 /**
7866 Rename table and/or turn indexes on/off without touching .FRM
7867
7868 @param thd Thread handler
7869 @param table_list TABLE_LIST for the table to change
7870 @param keys_onoff ENABLE or DISABLE KEYS?
7871 @param alter_ctx ALTER TABLE runtime context.
7872
7873 @return Operation status
7874 @retval false Success
7875 @retval true Failure
7876 */
7877
7878 static bool
simple_rename_or_index_change(THD * thd,TABLE_LIST * table_list,Alter_info::enum_enable_or_disable keys_onoff,Alter_table_ctx * alter_ctx)7879 simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
7880 Alter_info::enum_enable_or_disable keys_onoff,
7881 Alter_table_ctx *alter_ctx)
7882 {
7883 TABLE *table= table_list->table;
7884 MDL_ticket *mdl_ticket= table->mdl_ticket;
7885 int error= 0;
7886 DBUG_ENTER("simple_rename_or_index_change");
7887
7888 if (keys_onoff != Alter_info::LEAVE_AS_IS)
7889 {
7890 if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
7891 DBUG_RETURN(true);
7892
7893 // It's now safe to take the table level lock.
7894 if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0))
7895 DBUG_RETURN(true);
7896
7897 if (keys_onoff == Alter_info::ENABLE)
7898 {
7899 DEBUG_SYNC(thd,"alter_table_enable_indexes");
7900 DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
7901 error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
7902 }
7903 else if (keys_onoff == Alter_info::DISABLE)
7904 error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
7905
7906 if (error == HA_ERR_WRONG_COMMAND)
7907 {
7908 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
7909 ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
7910 table->alias);
7911 error= 0;
7912 }
7913 else if (error > 0)
7914 {
7915 table->file->print_error(error, MYF(0));
7916 error= -1;
7917 }
7918 }
7919
7920 if (!error && alter_ctx->is_table_renamed())
7921 {
7922 THD_STAGE_INFO(thd, stage_rename);
7923 handlerton *old_db_type= table->s->db_type();
7924 /*
7925 Then do a 'simple' rename of the table. First we need to close all
7926 instances of 'source' table.
7927 Note that if wait_while_table_is_used() returns error here (i.e. if
7928 this thread was killed) then it must be that previous step of
7929 simple rename did nothing and therefore we can safely return
7930 without additional clean-up.
7931 */
7932 if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
7933 DBUG_RETURN(true);
7934 close_all_tables_for_name(thd, table->s, true, NULL);
7935
7936 if (mysql_rename_table(old_db_type, alter_ctx->db, alter_ctx->table_name,
7937 alter_ctx->new_db, alter_ctx->new_alias, 0))
7938 error= -1;
7939 else if (Table_triggers_list::change_table_name(thd,
7940 alter_ctx->db,
7941 alter_ctx->alias,
7942 alter_ctx->table_name,
7943 alter_ctx->new_db,
7944 alter_ctx->new_alias))
7945 {
7946 (void) mysql_rename_table(old_db_type,
7947 alter_ctx->new_db, alter_ctx->new_alias,
7948 alter_ctx->db, alter_ctx->table_name,
7949 NO_FK_CHECKS);
7950 error= -1;
7951 }
7952 }
7953
7954 if (!error)
7955 {
7956 error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
7957 if (!error)
7958 my_ok(thd);
7959 }
7960 table_list->table= NULL; // For query cache
7961 query_cache_invalidate3(thd, table_list, 0);
7962
7963 if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
7964 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
7965 {
7966 /*
7967 Under LOCK TABLES we should adjust meta-data locks before finishing
7968 statement. Otherwise we can rely on them being released
7969 along with the implicit commit.
7970 */
7971 if (alter_ctx->is_table_renamed())
7972 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
7973 else
7974 mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
7975 }
7976 DBUG_RETURN(error != 0);
7977 }
7978
7979
7980 /**
7981 Alter table
7982
7983 @param thd Thread handle
7984 @param new_db If there is a RENAME clause
7985 @param new_name If there is a RENAME clause
7986 @param create_info Information from the parsing phase about new
7987 table properties.
7988 @param table_list The table to change.
7989 @param alter_info Lists of fields, keys to be changed, added
7990 or dropped.
7991 @param order_num How many ORDER BY fields has been specified.
7992 @param order List of fields to ORDER BY.
7993 @param ignore Whether we have ALTER IGNORE TABLE
7994
7995 @retval true Error
7996 @retval false Success
7997
7998 This is a veery long function and is everything but the kitchen sink :)
7999 It is used to alter a table and not only by ALTER TABLE but also
8000 CREATE|DROP INDEX are mapped on this function.
8001
8002 When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS,
8003 or both, then this function short cuts its operation by renaming
8004 the table and/or enabling/disabling the keys. In this case, the FRM is
8005 not changed, directly by mysql_alter_table. However, if there is a
8006 RENAME + change of a field, or an index, the short cut is not used.
8007 See how `create_list` is used to generate the new FRM regarding the
8008 structure of the fields. The same is done for the indices of the table.
8009
8010 Altering a table can be done in two ways. The table can be modified
8011 directly using an in-place algorithm, or the changes can be done using
8012 an intermediate temporary table (copy). In-place is the preferred
8013 algorithm as it avoids copying table data. The storage engine
8014 selects which algorithm to use in check_if_supported_inplace_alter()
8015 based on information about the table changes from fill_alter_inplace_info().
8016 */
8017
mysql_alter_table(THD * thd,char * new_db,char * new_name,HA_CREATE_INFO * create_info,TABLE_LIST * table_list,Alter_info * alter_info,uint order_num,ORDER * order,bool ignore)8018 bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
8019 HA_CREATE_INFO *create_info,
8020 TABLE_LIST *table_list,
8021 Alter_info *alter_info,
8022 uint order_num, ORDER *order, bool ignore)
8023 {
8024 DBUG_ENTER("mysql_alter_table");
8025
8026 /*
8027 Check if we attempt to alter mysql.slow_log or
8028 mysql.general_log table and return an error if
8029 it is the case.
8030 TODO: this design is obsolete and will be removed.
8031 */
8032 int table_kind= check_if_log_table(table_list->db_length, table_list->db,
8033 table_list->table_name_length,
8034 table_list->table_name, false);
8035
8036 if (table_kind)
8037 {
8038 /* Disable alter of enabled log tables */
8039 if (logger.is_log_table_enabled(table_kind))
8040 {
8041 my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
8042 DBUG_RETURN(true);
8043 }
8044
8045 /* Disable alter of log tables to unsupported engine */
8046 if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
8047 (!create_info->db_type || /* unknown engine */
8048 !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
8049 {
8050 my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
8051 DBUG_RETURN(true);
8052 }
8053
8054 #ifdef WITH_PARTITION_STORAGE_ENGINE
8055 if (alter_info->flags & Alter_info::ALTER_PARTITION)
8056 {
8057 my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
8058 DBUG_RETURN(true);
8059 }
8060 #endif
8061 }
8062
8063 THD_STAGE_INFO(thd, stage_init);
8064
8065 /*
8066 Code below can handle only base tables so ensure that we won't open a view.
8067 Note that RENAME TABLE the only ALTER clause which is supported for views
8068 has been already processed.
8069 */
8070 table_list->required_type= FRMTYPE_TABLE;
8071
8072 Alter_table_prelocking_strategy alter_prelocking_strategy;
8073
8074 DEBUG_SYNC(thd, "alter_table_before_open_tables");
8075 uint tables_opened;
8076 bool error= open_tables(thd, &table_list, &tables_opened, 0,
8077 &alter_prelocking_strategy);
8078
8079 DEBUG_SYNC(thd, "alter_opened_table");
8080
8081 #ifdef WITH_WSREP
8082 DBUG_EXECUTE_IF("sync.alter_opened_table",
8083 {
8084 const char act[]=
8085 "now "
8086 "wait_for signal.alter_opened_table";
8087 DBUG_ASSERT(!debug_sync_set_action(thd,
8088 STRING_WITH_LEN(act)));
8089 };);
8090 #endif // WITH_WSREP
8091
8092 if (error)
8093 DBUG_RETURN(true);
8094
8095 TABLE *table= table_list->table;
8096 table->use_all_columns();
8097 MDL_ticket *mdl_ticket= table->mdl_ticket;
8098
8099 /*
8100 Prohibit changing of the UNION list of a non-temporary MERGE table
8101 under LOCK tables. It would be quite difficult to reuse a shrinked
8102 set of tables from the old table or to open a new TABLE object for
8103 an extended list and verify that they belong to locked tables.
8104 */
8105 if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
8106 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
8107 (create_info->used_fields & HA_CREATE_USED_UNION) &&
8108 (table->s->tmp_table == NO_TMP_TABLE))
8109 {
8110 my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
8111 DBUG_RETURN(true);
8112 }
8113
8114 Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name);
8115
8116 /*
8117 Add old and new (if any) databases to the list of accessed databases
8118 for this statement. Needed for MTS.
8119 */
8120 thd->add_to_binlog_accessed_dbs(alter_ctx.db);
8121 if (alter_ctx.is_database_changed())
8122 thd->add_to_binlog_accessed_dbs(alter_ctx.new_db);
8123
8124 MDL_request target_mdl_request;
8125
8126 /* Check that we are not trying to rename to an existing table */
8127 if (alter_ctx.is_table_renamed())
8128 {
8129 if (table->s->tmp_table != NO_TMP_TABLE)
8130 {
8131 if (find_temporary_table(thd, alter_ctx.new_db, alter_ctx.new_name))
8132 {
8133 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias);
8134 DBUG_RETURN(true);
8135 }
8136 }
8137 else
8138 {
8139 MDL_request_list mdl_requests;
8140 MDL_request target_db_mdl_request;
8141
8142 target_mdl_request.init(MDL_key::TABLE,
8143 alter_ctx.new_db, alter_ctx.new_name,
8144 MDL_EXCLUSIVE, MDL_TRANSACTION);
8145 mdl_requests.push_front(&target_mdl_request);
8146
8147 /*
8148 If we are moving the table to a different database, we also
8149 need IX lock on the database name so that the target database
8150 is protected by MDL while the table is moved.
8151 */
8152 if (alter_ctx.is_database_changed())
8153 {
8154 target_db_mdl_request.init(MDL_key::SCHEMA, alter_ctx.new_db, "",
8155 MDL_INTENTION_EXCLUSIVE,
8156 MDL_TRANSACTION);
8157 mdl_requests.push_front(&target_db_mdl_request);
8158 }
8159
8160 /*
8161 Global intention exclusive lock must have been already acquired when
8162 table to be altered was open, so there is no need to do it here.
8163 */
8164 DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::GLOBAL,
8165 "", "",
8166 MDL_INTENTION_EXCLUSIVE));
8167
8168 if (thd->mdl_context.acquire_locks(&mdl_requests,
8169 thd->variables.lock_wait_timeout))
8170 DBUG_RETURN(true);
8171
8172 DEBUG_SYNC(thd, "locked_table_name");
8173 /*
8174 Table maybe does not exist, but we got an exclusive lock
8175 on the name, now we can safely try to find out for sure.
8176 */
8177 if (!access(alter_ctx.get_new_filename(), F_OK))
8178 {
8179 /* Table will be closed in do_command() */
8180 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias);
8181 DBUG_RETURN(true);
8182 }
8183 }
8184 }
8185
8186 if (!create_info->db_type)
8187 {
8188 #ifdef WITH_PARTITION_STORAGE_ENGINE
8189 if (table->part_info &&
8190 create_info->used_fields & HA_CREATE_USED_ENGINE)
8191 {
8192 /*
8193 This case happens when the user specified
8194 ENGINE = x where x is a non-existing storage engine
8195 We set create_info->db_type to default_engine_type
8196 to ensure we don't change underlying engine type
8197 due to a erroneously given engine name.
8198 */
8199 create_info->db_type= table->part_info->default_engine_type;
8200 }
8201 else
8202 #endif
8203 create_info->db_type= table->s->db_type();
8204 }
8205
8206 if (check_engine(thd, alter_ctx.new_db, alter_ctx.new_name, create_info))
8207 DBUG_RETURN(true);
8208
8209 if ((create_info->db_type != table->s->db_type() ||
8210 alter_info->flags & Alter_info::ALTER_PARTITION) &&
8211 !table->file->can_switch_engines())
8212 {
8213 my_error(ER_ROW_IS_REFERENCED, MYF(0));
8214 DBUG_RETURN(true);
8215 }
8216
8217 /*
8218 If foreign key is added then check permission to access parent table.
8219
8220 In function "check_fk_parent_table_access", create_info->db_type is used
8221 to identify whether engine supports FK constraint or not. Since
8222 create_info->db_type is set here, check to parent table access is delayed
8223 till this point for the alter operation.
8224 */
8225 if ((alter_info->flags & Alter_info::ADD_FOREIGN_KEY) &&
8226 check_fk_parent_table_access(thd, alter_ctx.new_db,
8227 create_info, alter_info))
8228 DBUG_RETURN(true);
8229
8230 /*
8231 If this is an ALTER TABLE and no explicit row type specified reuse
8232 the table's row type.
8233 Note : this is the same as if the row type was specified explicitly.
8234 */
8235 if (create_info->row_type == ROW_TYPE_NOT_USED)
8236 {
8237 /* ALTER TABLE without explicit row type */
8238 create_info->row_type= table->s->row_type;
8239 }
8240 else
8241 {
8242 /* ALTER TABLE with specific row type */
8243 create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
8244 }
8245
8246 DBUG_PRINT("info", ("old type: %s new type: %s",
8247 ha_resolve_storage_engine_name(table->s->db_type()),
8248 ha_resolve_storage_engine_name(create_info->db_type)));
8249 if (ha_check_storage_engine_flag(table->s->db_type(), HTON_ALTER_NOT_SUPPORTED) ||
8250 ha_check_storage_engine_flag(create_info->db_type, HTON_ALTER_NOT_SUPPORTED))
8251 {
8252 DBUG_PRINT("info", ("doesn't support alter"));
8253 my_error(ER_ILLEGAL_HA, MYF(0), table_list->table_name);
8254 DBUG_RETURN(true);
8255 }
8256
8257 THD_STAGE_INFO(thd, stage_setup);
8258 if (!(alter_info->flags & ~(Alter_info::ALTER_RENAME |
8259 Alter_info::ALTER_KEYS_ONOFF)) &&
8260 alter_info->requested_algorithm !=
8261 Alter_info::ALTER_TABLE_ALGORITHM_COPY &&
8262 !table->s->tmp_table) // no need to touch frm
8263 {
8264 // This requires X-lock, no other lock levels supported.
8265 if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT &&
8266 alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
8267 {
8268 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
8269 "LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
8270 DBUG_RETURN(true);
8271 }
8272 DBUG_RETURN(simple_rename_or_index_change(thd, table_list,
8273 alter_info->keys_onoff,
8274 &alter_ctx));
8275 }
8276
8277 /* We have to do full alter table. */
8278
8279 #ifdef WITH_PARTITION_STORAGE_ENGINE
8280 bool partition_changed= false;
8281 partition_info *new_part_info= NULL;
8282 {
8283 if (prep_alter_part_table(thd, table, alter_info, create_info,
8284 &alter_ctx, &partition_changed,
8285 &new_part_info))
8286 {
8287 DBUG_RETURN(true);
8288 }
8289 }
8290 #endif
8291
8292 if (mysql_prepare_alter_table(thd, table, create_info, alter_info,
8293 &alter_ctx))
8294 {
8295 DBUG_RETURN(true);
8296 }
8297
8298 set_table_default_charset(thd, create_info, alter_ctx.db);
8299
8300 #ifdef WITH_PARTITION_STORAGE_ENGINE
8301 if (new_part_info)
8302 {
8303 /*
8304 ALGORITHM and LOCK clauses are generally not allowed by the
8305 parser for operations related to partitioning.
8306 The exceptions are ALTER_PARTITION and ALTER_REMOVE_PARTITIONING.
8307 For consistency, we report ER_ALTER_OPERATION_NOT_SUPPORTED here.
8308 */
8309 if (alter_info->requested_lock !=
8310 Alter_info::ALTER_TABLE_LOCK_DEFAULT)
8311 {
8312 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
8313 "LOCK=NONE/SHARED/EXCLUSIVE",
8314 ER(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION),
8315 "LOCK=DEFAULT");
8316 DBUG_RETURN(true);
8317 }
8318 else if (alter_info->requested_algorithm !=
8319 Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
8320 {
8321 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
8322 "ALGORITHM=COPY/INPLACE",
8323 ER(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION),
8324 "ALGORITHM=DEFAULT");
8325 DBUG_RETURN(true);
8326 }
8327
8328 /*
8329 Upgrade from MDL_SHARED_UPGRADABLE to MDL_SHARED_NO_WRITE.
8330 Afterwards it's safe to take the table level lock.
8331 */
8332 if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE,
8333 thd->variables.lock_wait_timeout)
8334 || lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
8335 {
8336 DBUG_RETURN(true);
8337 }
8338
8339 // In-place execution of ALTER TABLE for partitioning.
8340 DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
8341 create_info, table_list,
8342 alter_ctx.db,
8343 alter_ctx.table_name,
8344 new_part_info));
8345 }
8346 #endif
8347
8348 /*
8349 Use copy algorithm if:
8350 - old_alter_table system variable is set without in-place requested using
8351 the ALGORITHM clause.
8352 - Or if in-place is impossible for given operation.
8353 - Changes to partitioning which were not handled by fast_alter_part_table()
8354 needs to be handled using table copying algorithm unless the engine
8355 supports auto-partitioning as such engines can do some changes
8356 using in-place API.
8357 */
8358 if ((thd->variables.old_alter_table &&
8359 alter_info->requested_algorithm !=
8360 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
8361 || is_inplace_alter_impossible(table, create_info, alter_info)
8362 #ifdef WITH_PARTITION_STORAGE_ENGINE
8363 || (partition_changed &&
8364 !(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION))
8365 #endif
8366 )
8367 {
8368 if (alter_info->requested_algorithm ==
8369 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
8370 {
8371 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
8372 "ALGORITHM=INPLACE", "ALGORITHM=COPY");
8373 DBUG_RETURN(true);
8374 }
8375 alter_info->requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY;
8376 }
8377
8378 /*
8379 If 'avoid_temporal_upgrade' mode is not enabled, then the
8380 pre MySQL 5.6.4 old temporal types if present is upgraded to the
8381 current format.
8382 */
8383
8384 mysql_mutex_lock(&LOCK_global_system_variables);
8385 bool check_temporal_upgrade= !avoid_temporal_upgrade;
8386 mysql_mutex_unlock(&LOCK_global_system_variables);
8387
8388 if (check_temporal_upgrade)
8389 {
8390 if (upgrade_old_temporal_types(thd, alter_info))
8391 DBUG_RETURN(true);
8392 }
8393
8394 /*
8395 ALTER TABLE ... ENGINE to the same engine is a common way to
8396 request table rebuild. Set ALTER_RECREATE flag to force table
8397 rebuild.
8398 */
8399 if (create_info->db_type == table->s->db_type() &&
8400 create_info->used_fields & HA_CREATE_USED_ENGINE)
8401 alter_info->flags|= Alter_info::ALTER_RECREATE;
8402
8403 /*
8404 If the old table had partitions and we are doing ALTER TABLE ...
8405 engine= <new_engine>, the new table must preserve the original
8406 partitioning. This means that the new engine is still the
8407 partitioning engine, not the engine specified in the parser.
8408 This is discovered in prep_alter_part_table, which in such case
8409 updates create_info->db_type.
8410 It's therefore important that the assignment below is done
8411 after prep_alter_part_table.
8412 */
8413 handlerton *new_db_type= create_info->db_type;
8414 handlerton *old_db_type= table->s->db_type();
8415 TABLE *new_table= NULL;
8416 ha_rows copied=0,deleted=0;
8417
8418 /*
8419 Handling of symlinked tables:
8420 If no rename:
8421 Create new data file and index file on the same disk as the
8422 old data and index files.
8423 Copy data.
8424 Rename new data file over old data file and new index file over
8425 old index file.
8426 Symlinks are not changed.
8427
8428 If rename:
8429 Create new data file and index file on the same disk as the
8430 old data and index files. Create also symlinks to point at
8431 the new tables.
8432 Copy data.
8433 At end, rename intermediate tables, and symlinks to intermediate
8434 table, to final table name.
8435 Remove old table and old symlinks
8436
8437 If rename is made to another database:
8438 Create new tables in new database.
8439 Copy data.
8440 Remove old table and symlinks.
8441 */
8442 char index_file[FN_REFLEN], data_file[FN_REFLEN];
8443
8444 if (!alter_ctx.is_database_changed())
8445 {
8446 if (create_info->index_file_name)
8447 {
8448 /* Fix index_file_name to have 'tmp_name' as basename */
8449 strmov(index_file, alter_ctx.tmp_name);
8450 create_info->index_file_name=fn_same(index_file,
8451 create_info->index_file_name,
8452 1);
8453 }
8454 if (create_info->data_file_name)
8455 {
8456 /* Fix data_file_name to have 'tmp_name' as basename */
8457 strmov(data_file, alter_ctx.tmp_name);
8458 create_info->data_file_name=fn_same(data_file,
8459 create_info->data_file_name,
8460 1);
8461 }
8462 }
8463 else
8464 {
8465 /* Ignore symlink if db is changed. */
8466 create_info->data_file_name=create_info->index_file_name=0;
8467 }
8468
8469 DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
8470 DBUG_EXECUTE_IF("sleep_before_create_table_no_lock",
8471 my_sleep(100000););
8472 /* We can abort alter table for any table type */
8473 thd->abort_on_warning= !ignore && thd->is_strict_mode();
8474
8475 /*
8476 Promote first timestamp column, when explicit_defaults_for_timestamp
8477 is not set
8478 */
8479 if (!thd->variables.explicit_defaults_for_timestamp)
8480 promote_first_timestamp_column(&alter_info->create_list);
8481
8482 /*
8483 Create .FRM for new version of table with a temporary name.
8484 We don't log the statement, it will be logged later.
8485
8486 Keep information about keys in newly created table as it
8487 will be used later to construct Alter_inplace_info object
8488 and by fill_alter_inplace_info() call.
8489 */
8490 KEY *key_info;
8491 uint key_count;
8492 /*
8493 Remember if the new definition has new VARCHAR column;
8494 create_info->varchar will be reset in create_table_impl()/
8495 mysql_prepare_create_table().
8496 */
8497 bool varchar= create_info->varchar;
8498
8499 tmp_disable_binlog(thd);
8500 error= create_table_impl(thd, alter_ctx.new_db, alter_ctx.tmp_name,
8501 alter_ctx.table_name,
8502 alter_ctx.get_tmp_path(),
8503 create_info, alter_info,
8504 true, 0, true, NULL,
8505 &key_info, &key_count);
8506 reenable_binlog(thd);
8507 thd->abort_on_warning= false;
8508 if (error)
8509 DBUG_RETURN(true);
8510
8511 /* Remember that we have not created table in storage engine yet. */
8512 bool no_ha_table= true;
8513
8514 if (alter_info->requested_algorithm != Alter_info::ALTER_TABLE_ALGORITHM_COPY)
8515 {
8516 Alter_inplace_info ha_alter_info(create_info, alter_info,
8517 key_info, key_count,
8518 #ifdef WITH_PARTITION_STORAGE_ENGINE
8519 thd->work_part_info,
8520 #else
8521 NULL,
8522 #endif
8523 ignore);
8524 TABLE *altered_table= NULL;
8525 bool use_inplace= true;
8526
8527 /* Fill the Alter_inplace_info structure. */
8528 if (fill_alter_inplace_info(thd, table, varchar, &ha_alter_info))
8529 goto err_new_table_cleanup;
8530
8531 // We assume that the table is non-temporary.
8532 DBUG_ASSERT(!table->s->tmp_table);
8533
8534 if (!(altered_table= open_table_uncached(thd, alter_ctx.get_tmp_path(),
8535 alter_ctx.new_db,
8536 alter_ctx.tmp_name,
8537 true, false)))
8538 goto err_new_table_cleanup;
8539
8540 /* Set markers for fields in TABLE object for altered table. */
8541 update_altered_table(ha_alter_info, altered_table);
8542
8543 /*
8544 Mark all columns in 'altered_table' as used to allow usage
8545 of its record[0] buffer and Field objects during in-place
8546 ALTER TABLE.
8547 */
8548 altered_table->column_bitmaps_set_no_signal(&altered_table->s->all_set,
8549 &altered_table->s->all_set);
8550
8551 set_column_defaults(altered_table, alter_info->create_list);
8552
8553 if (ha_alter_info.handler_flags == 0)
8554 {
8555 /*
8556 No-op ALTER, no need to call handler API functions.
8557
8558 If this code path is entered for an ALTER statement that
8559 should not be a real no-op, new handler flags should be added
8560 and fill_alter_inplace_info() adjusted.
8561
8562 Note that we can end up here if an ALTER statement has clauses
8563 that cancel each other out (e.g. ADD/DROP identically index).
8564
8565 Also note that we ignore the LOCK clause here.
8566 */
8567 close_temporary_table(thd, altered_table, true, false);
8568 (void) quick_rm_table(thd, new_db_type, alter_ctx.new_db,
8569 alter_ctx.tmp_name, FN_IS_TMP | NO_HA_TABLE);
8570 goto end_inplace;
8571 }
8572
8573 // Ask storage engine whether to use copy or in-place
8574 enum_alter_inplace_result inplace_supported=
8575 table->file->check_if_supported_inplace_alter(altered_table,
8576 &ha_alter_info);
8577
8578 switch (inplace_supported) {
8579 case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
8580 // If SHARED lock and no particular algorithm was requested, use COPY.
8581 if (alter_info->requested_lock ==
8582 Alter_info::ALTER_TABLE_LOCK_SHARED &&
8583 alter_info->requested_algorithm ==
8584 Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
8585 {
8586 use_inplace= false;
8587 }
8588 // Otherwise, if weaker lock was requested, report errror.
8589 else if (alter_info->requested_lock ==
8590 Alter_info::ALTER_TABLE_LOCK_NONE ||
8591 alter_info->requested_lock ==
8592 Alter_info::ALTER_TABLE_LOCK_SHARED)
8593 {
8594 ha_alter_info.report_unsupported_error("LOCK=NONE/SHARED",
8595 "LOCK=EXCLUSIVE");
8596 close_temporary_table(thd, altered_table, true, false);
8597 goto err_new_table_cleanup;
8598 }
8599 break;
8600 case HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE:
8601 case HA_ALTER_INPLACE_SHARED_LOCK:
8602 // If weaker lock was requested, report errror.
8603 if (alter_info->requested_lock ==
8604 Alter_info::ALTER_TABLE_LOCK_NONE)
8605 {
8606 ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
8607 close_temporary_table(thd, altered_table, true, false);
8608 goto err_new_table_cleanup;
8609 }
8610 break;
8611 case HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE:
8612 case HA_ALTER_INPLACE_NO_LOCK:
8613 break;
8614 case HA_ALTER_INPLACE_NOT_SUPPORTED:
8615 // If INPLACE was requested, report error.
8616 if (alter_info->requested_algorithm ==
8617 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
8618 {
8619 ha_alter_info.report_unsupported_error("ALGORITHM=INPLACE",
8620 "ALGORITHM=COPY");
8621 close_temporary_table(thd, altered_table, true, false);
8622 goto err_new_table_cleanup;
8623 }
8624 // COPY with LOCK=NONE is not supported, no point in trying.
8625 if (alter_info->requested_lock ==
8626 Alter_info::ALTER_TABLE_LOCK_NONE)
8627 {
8628 ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
8629 close_temporary_table(thd, altered_table, true, false);
8630 goto err_new_table_cleanup;
8631 }
8632 // Otherwise use COPY
8633 use_inplace= false;
8634 break;
8635 case HA_ALTER_ERROR:
8636 default:
8637 close_temporary_table(thd, altered_table, true, false);
8638 goto err_new_table_cleanup;
8639 }
8640
8641 if (use_inplace)
8642 {
8643 if (mysql_inplace_alter_table(thd, table_list, table,
8644 altered_table,
8645 &ha_alter_info,
8646 inplace_supported, &target_mdl_request,
8647 &alter_ctx))
8648 {
8649 DBUG_RETURN(true);
8650 }
8651
8652 goto end_inplace;
8653 }
8654 else
8655 {
8656 close_temporary_table(thd, altered_table, true, false);
8657 }
8658 }
8659
8660 /* ALTER TABLE using copy algorithm. */
8661
8662 /* Check if ALTER TABLE is compatible with foreign key definitions. */
8663 if (fk_prepare_copy_alter_table(thd, table, alter_info, &alter_ctx))
8664 goto err_new_table_cleanup;
8665
8666 if (!table->s->tmp_table)
8667 {
8668 // COPY algorithm doesn't work with concurrent writes.
8669 if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
8670 {
8671 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
8672 "LOCK=NONE",
8673 ER(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY),
8674 "LOCK=SHARED");
8675 goto err_new_table_cleanup;
8676 }
8677
8678 // If EXCLUSIVE lock is requested, upgrade already.
8679 if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE &&
8680 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
8681 goto err_new_table_cleanup;
8682
8683 /*
8684 Otherwise upgrade to SHARED_NO_WRITE.
8685 Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE.
8686 */
8687 if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE &&
8688 thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE,
8689 thd->variables.lock_wait_timeout))
8690 goto err_new_table_cleanup;
8691
8692 DEBUG_SYNC(thd, "alter_table_copy_after_lock_upgrade");
8693 }
8694
8695 // It's now safe to take the table level lock.
8696 if (lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
8697 goto err_new_table_cleanup;
8698
8699 {
8700 if (ha_create_table(thd, alter_ctx.get_tmp_path(),
8701 alter_ctx.new_db, alter_ctx.tmp_name,
8702 create_info, false))
8703 goto err_new_table_cleanup;
8704
8705 /* Mark that we have created table in storage engine. */
8706 no_ha_table= false;
8707
8708 if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
8709 {
8710 if (!open_table_uncached(thd, alter_ctx.get_tmp_path(),
8711 alter_ctx.new_db, alter_ctx.tmp_name,
8712 true, true))
8713 goto err_new_table_cleanup;
8714 }
8715 }
8716
8717
8718 /* Open the table since we need to copy the data. */
8719 if (table->s->tmp_table != NO_TMP_TABLE)
8720 {
8721 TABLE_LIST tbl;
8722 tbl.init_one_table(alter_ctx.new_db, strlen(alter_ctx.new_db),
8723 alter_ctx.tmp_name, strlen(alter_ctx.tmp_name),
8724 alter_ctx.tmp_name, TL_READ_NO_INSERT);
8725 /* Table is in thd->temporary_tables */
8726 (void) open_temporary_table(thd, &tbl);
8727 new_table= tbl.table;
8728 }
8729 else
8730 {
8731 /* table is a normal table: Create temporary table in same directory */
8732 /* Open our intermediate table. */
8733 new_table= open_table_uncached(thd, alter_ctx.get_tmp_path(),
8734 alter_ctx.new_db, alter_ctx.tmp_name,
8735 true, true);
8736 }
8737 if (!new_table)
8738 goto err_new_table_cleanup;
8739 /*
8740 Note: In case of MERGE table, we do not attach children. We do not
8741 copy data for MERGE tables. Only the children have data.
8742 */
8743
8744 /* Copy the data if necessary. */
8745 thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
8746 thd->cuted_fields=0L;
8747
8748 /*
8749 We do not copy data for MERGE tables. Only the children have data.
8750 MERGE tables have HA_NO_COPY_ON_ALTER set.
8751 */
8752 if (!(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
8753 {
8754 new_table->next_number_field=new_table->found_next_number_field;
8755 THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
8756 DBUG_EXECUTE_IF("abort_copy_table", {
8757 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
8758 goto err_new_table_cleanup;
8759 });
8760 if (copy_data_between_tables(table, new_table,
8761 alter_info->create_list, ignore,
8762 order_num, order, &copied, &deleted,
8763 alter_info->keys_onoff,
8764 &alter_ctx))
8765 goto err_new_table_cleanup;
8766 }
8767 else
8768 {
8769 /* Should be MERGE only */
8770 DBUG_ASSERT(new_table->file->ht->db_type == DB_TYPE_MRG_MYISAM);
8771 if (!table->s->tmp_table &&
8772 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
8773 goto err_new_table_cleanup;
8774 THD_STAGE_INFO(thd, stage_manage_keys);
8775 DEBUG_SYNC(thd, "alter_table_manage_keys");
8776 alter_table_manage_keys(table, table->file->indexes_are_disabled(),
8777 alter_info->keys_onoff);
8778 if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
8779 goto err_new_table_cleanup;
8780 }
8781 thd->count_cuted_fields= CHECK_FIELD_IGNORE;
8782
8783 if (table->s->tmp_table != NO_TMP_TABLE)
8784 {
8785 /* Close lock if this is a transactional table */
8786 if (thd->lock)
8787 {
8788 if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
8789 thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
8790 {
8791 mysql_unlock_tables(thd, thd->lock);
8792 thd->lock= NULL;
8793 }
8794 else
8795 {
8796 /*
8797 If LOCK TABLES list is not empty and contains this table,
8798 unlock the table and remove the table from this list.
8799 */
8800 mysql_lock_remove(thd, thd->lock, table);
8801 }
8802 }
8803 /* Remove link to old table and rename the new one */
8804 close_temporary_table(thd, table, true, true);
8805 /* Should pass the 'new_name' as we store table name in the cache */
8806 if (rename_temporary_table(thd, new_table,
8807 alter_ctx.new_db, alter_ctx.new_name))
8808 goto err_new_table_cleanup;
8809 /* We don't replicate alter table statement on temporary tables */
8810 if (!thd->is_current_stmt_binlog_format_row() &&
8811 write_bin_log(thd, true, thd->query(), thd->query_length()))
8812 DBUG_RETURN(true);
8813 goto end_temporary;
8814 }
8815
8816 /*
8817 Close the intermediate table that will be the new table, but do
8818 not delete it! Even altough MERGE tables do not have their children
8819 attached here it is safe to call close_temporary_table().
8820 */
8821 close_temporary_table(thd, new_table, true, false);
8822 new_table= NULL;
8823
8824 DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
8825
8826 /*
8827 Data is copied. Now we:
8828 1) Wait until all other threads will stop using old version of table
8829 by upgrading shared metadata lock to exclusive one.
8830 2) Close instances of table open by this thread and replace them
8831 with placeholders to simplify reopen process.
8832 3) Rename the old table to a temp name, rename the new one to the
8833 old name.
8834 4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
8835 we reopen new version of table.
8836 5) Write statement to the binary log.
8837 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
8838 remove placeholders and release metadata locks.
8839 7) If we are not not under LOCK TABLES we rely on the caller
8840 (mysql_execute_command()) to release metadata locks.
8841 */
8842
8843 THD_STAGE_INFO(thd, stage_rename_result_table);
8844
8845 if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
8846 goto err_new_table_cleanup;
8847
8848 close_all_tables_for_name(thd, table->s, alter_ctx.is_table_renamed(), NULL);
8849 table_list->table= table= NULL; /* Safety */
8850
8851 /*
8852 Rename the old table to temporary name to have a backup in case
8853 anything goes wrong while renaming the new table.
8854 */
8855 char backup_name[32];
8856 my_snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%lx", tmp_file_prefix,
8857 current_pid, thd->thread_id);
8858 if (lower_case_table_names)
8859 my_casedn_str(files_charset_info, backup_name);
8860 if (mysql_rename_table(old_db_type, alter_ctx.db, alter_ctx.table_name,
8861 alter_ctx.db, backup_name, FN_TO_IS_TMP))
8862 {
8863 // Rename to temporary name failed, delete the new table, abort ALTER.
8864 (void) quick_rm_table(thd, new_db_type, alter_ctx.new_db,
8865 alter_ctx.tmp_name, FN_IS_TMP);
8866 goto err_with_mdl;
8867 }
8868
8869 // Rename the new table to the correct name.
8870 if (mysql_rename_table(new_db_type, alter_ctx.new_db, alter_ctx.tmp_name,
8871 alter_ctx.new_db, alter_ctx.new_alias,
8872 FN_FROM_IS_TMP))
8873 {
8874 // Rename failed, delete the temporary table.
8875 (void) quick_rm_table(thd, new_db_type, alter_ctx.new_db,
8876 alter_ctx.tmp_name, FN_IS_TMP);
8877
8878 // Restore the backup of the original table to the old name.
8879 (void) mysql_rename_table(old_db_type, alter_ctx.db, backup_name,
8880 alter_ctx.db, alter_ctx.alias,
8881 FN_FROM_IS_TMP | NO_FK_CHECKS);
8882
8883 goto err_with_mdl;
8884 }
8885
8886 // Check if we renamed the table and if so update trigger files.
8887 if (alter_ctx.is_table_renamed() &&
8888 Table_triggers_list::change_table_name(thd,
8889 alter_ctx.db,
8890 alter_ctx.alias,
8891 alter_ctx.table_name,
8892 alter_ctx.new_db,
8893 alter_ctx.new_alias))
8894 {
8895 // Rename succeeded, delete the new table.
8896 (void) quick_rm_table(thd, new_db_type,
8897 alter_ctx.new_db, alter_ctx.new_alias, 0);
8898 // Restore the backup of the original table to the old name.
8899 (void) mysql_rename_table(old_db_type, alter_ctx.db, backup_name,
8900 alter_ctx.db, alter_ctx.alias,
8901 FN_FROM_IS_TMP | NO_FK_CHECKS);
8902 goto err_with_mdl;
8903 }
8904
8905 // ALTER TABLE succeeded, delete the backup of the old table.
8906 if (quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, FN_IS_TMP))
8907 {
8908 /*
8909 The fact that deletion of the backup failed is not critical
8910 error, but still worth reporting as it might indicate serious
8911 problem with server.
8912 */
8913 goto err_with_mdl;
8914 }
8915
8916 end_inplace:
8917
8918 if (thd->locked_tables_list.reopen_tables(thd))
8919 goto err_with_mdl;
8920
8921 THD_STAGE_INFO(thd, stage_end);
8922
8923 DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
8924 DEBUG_SYNC(thd, "alter_table_before_main_binlog");
8925
8926 ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
8927 thd->query(), thd->query_length(),
8928 alter_ctx.db, alter_ctx.table_name);
8929
8930 DBUG_ASSERT(!(mysql_bin_log.is_open() &&
8931 thd->is_current_stmt_binlog_format_row() &&
8932 (create_info->options & HA_LEX_CREATE_TMP_TABLE)));
8933 if (write_bin_log(thd, true, thd->query(), thd->query_length()))
8934 DBUG_RETURN(true);
8935
8936 if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
8937 {
8938 /*
8939 For the alter table to be properly flushed to the logs, we
8940 have to open the new table. If not, we get a problem on server
8941 shutdown. But we do not need to attach MERGE children.
8942 */
8943 TABLE *t_table;
8944 t_table= open_table_uncached(thd, alter_ctx.get_new_path(),
8945 alter_ctx.new_db, alter_ctx.new_name,
8946 false, true);
8947 if (t_table)
8948 intern_close_table(t_table);
8949 else
8950 sql_print_warning("Could not open table %s.%s after rename\n",
8951 alter_ctx.new_db, alter_ctx.table_name);
8952 ha_flush_logs(old_db_type);
8953 }
8954 table_list->table= NULL; // For query cache
8955 query_cache_invalidate3(thd, table_list, false);
8956
8957 if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
8958 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
8959 {
8960 if (alter_ctx.is_table_renamed())
8961 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
8962 else
8963 mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
8964 }
8965
8966 end_temporary:
8967 my_snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name),
8968 ER(ER_INSERT_INFO),
8969 (ulong) (copied + deleted), (ulong) deleted,
8970 (ulong) thd->get_stmt_da()->current_statement_warn_count());
8971 my_ok(thd, copied + deleted, 0L, alter_ctx.tmp_name);
8972 DBUG_RETURN(false);
8973
8974 err_new_table_cleanup:
8975 if (new_table)
8976 {
8977 /* close_temporary_table() frees the new_table pointer. */
8978 close_temporary_table(thd, new_table, true, true);
8979 }
8980 else
8981 (void) quick_rm_table(thd, new_db_type,
8982 alter_ctx.new_db, alter_ctx.tmp_name,
8983 (FN_IS_TMP | (no_ha_table ? NO_HA_TABLE : 0)));
8984
8985 /*
8986 No default value was provided for a DATE/DATETIME field, the
8987 current sql_mode doesn't allow the '0000-00-00' value and
8988 the table to be altered isn't empty.
8989 Report error here.
8990 */
8991 if (alter_ctx.error_if_not_empty &&
8992 thd->get_stmt_da()->current_row_for_warning())
8993 {
8994 uint f_length;
8995 enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
8996 switch (alter_ctx.datetime_field->sql_type)
8997 {
8998 case MYSQL_TYPE_DATE:
8999 case MYSQL_TYPE_NEWDATE:
9000 f_length= MAX_DATE_WIDTH; // "0000-00-00";
9001 t_type= MYSQL_TIMESTAMP_DATE;
9002 break;
9003 case MYSQL_TYPE_DATETIME:
9004 case MYSQL_TYPE_DATETIME2:
9005 f_length= MAX_DATETIME_WIDTH; // "0000-00-00 00:00:00";
9006 t_type= MYSQL_TIMESTAMP_DATETIME;
9007 break;
9008 default:
9009 /* Shouldn't get here. */
9010 f_length= 0;
9011 DBUG_ASSERT(0);
9012 }
9013 bool save_abort_on_warning= thd->abort_on_warning;
9014 thd->abort_on_warning= true;
9015 make_truncated_value_warning(thd, Sql_condition::WARN_LEVEL_WARN,
9016 ErrConvString(my_zero_datetime6, f_length),
9017 t_type,
9018 alter_ctx.datetime_field->field_name);
9019 thd->abort_on_warning= save_abort_on_warning;
9020 }
9021
9022 DBUG_RETURN(true);
9023
9024 err_with_mdl:
9025 /*
9026 An error happened while we were holding exclusive name metadata lock
9027 on table being altered. To be safe under LOCK TABLES we should
9028 remove all references to the altered table from the list of locked
9029 tables and release the exclusive metadata lock.
9030 */
9031 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
9032 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
9033 DBUG_RETURN(true);
9034 }
9035 /* mysql_alter_table */
9036
9037
9038
9039 /**
9040 Prepare the transaction for the alter table's copy phase.
9041 */
9042
mysql_trans_prepare_alter_copy_data(THD * thd)9043 bool mysql_trans_prepare_alter_copy_data(THD *thd)
9044 {
9045 DBUG_ENTER("mysql_prepare_alter_copy_data");
9046 /*
9047 Turn off recovery logging since rollback of an alter table is to
9048 delete the new table so there is no need to log the changes to it.
9049
9050 This needs to be done before external_lock.
9051 */
9052 if (ha_enable_transaction(thd, FALSE))
9053 DBUG_RETURN(TRUE);
9054 DBUG_RETURN(FALSE);
9055 }
9056
9057
9058 /**
9059 Commit the copy phase of the alter table.
9060 */
9061
mysql_trans_commit_alter_copy_data(THD * thd)9062 bool mysql_trans_commit_alter_copy_data(THD *thd)
9063 {
9064 bool error= FALSE;
9065 DBUG_ENTER("mysql_commit_alter_copy_data");
9066
9067 if (ha_enable_transaction(thd, TRUE))
9068 DBUG_RETURN(TRUE);
9069
9070 /*
9071 Ensure that the new table is saved properly to disk before installing
9072 the new .frm.
9073 And that InnoDB's internal latches are released, to avoid deadlock
9074 when waiting on other instances of the table before rename (Bug#54747).
9075 */
9076 if (trans_commit_stmt(thd))
9077 error= TRUE;
9078 if (trans_commit_implicit(thd))
9079 error= TRUE;
9080
9081 DBUG_RETURN(error);
9082 }
9083
9084
9085 static int
copy_data_between_tables(TABLE * from,TABLE * to,List<Create_field> & create,bool ignore,uint order_num,ORDER * order,ha_rows * copied,ha_rows * deleted,Alter_info::enum_enable_or_disable keys_onoff,Alter_table_ctx * alter_ctx)9086 copy_data_between_tables(TABLE *from,TABLE *to,
9087 List<Create_field> &create,
9088 bool ignore,
9089 uint order_num, ORDER *order,
9090 ha_rows *copied,
9091 ha_rows *deleted,
9092 Alter_info::enum_enable_or_disable keys_onoff,
9093 Alter_table_ctx *alter_ctx)
9094 {
9095 int error;
9096 Copy_field *copy,*copy_end;
9097 ulong found_count,delete_count;
9098 THD *thd= current_thd;
9099 READ_RECORD info;
9100 TABLE_LIST tables;
9101 List<Item> fields;
9102 List<Item> all_fields;
9103 ha_rows examined_rows;
9104 ha_rows found_rows;
9105 bool auto_increment_field_copied= 0;
9106 sql_mode_t save_sql_mode;
9107 ulonglong prev_insert_id;
9108 DBUG_ENTER("copy_data_between_tables");
9109
9110 if (mysql_trans_prepare_alter_copy_data(thd))
9111 DBUG_RETURN(-1);
9112
9113 if (!(copy= new Copy_field[to->s->fields]))
9114 DBUG_RETURN(-1); /* purecov: inspected */
9115
9116 if (to->file->ha_external_lock(thd, F_WRLCK))
9117 DBUG_RETURN(-1);
9118
9119 /* We need external lock before we can disable/enable keys */
9120 alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
9121
9122 /* We can abort alter table for any table type */
9123 thd->abort_on_warning= !ignore && thd->is_strict_mode();
9124
9125 from->file->info(HA_STATUS_VARIABLE);
9126 to->file->ha_start_bulk_insert(from->file->stats.records);
9127
9128 save_sql_mode= thd->variables.sql_mode;
9129
9130 List_iterator<Create_field> it(create);
9131 Create_field *def;
9132 copy_end=copy;
9133 for (Field **ptr=to->field ; *ptr ; ptr++)
9134 {
9135 def=it++;
9136 if (def->field)
9137 {
9138 if (*ptr == to->next_number_field)
9139 {
9140 auto_increment_field_copied= TRUE;
9141 /*
9142 If we are going to copy contents of one auto_increment column to
9143 another auto_increment column it is sensible to preserve zeroes.
9144 This condition also covers case when we are don't actually alter
9145 auto_increment column.
9146 */
9147 if (def->field == from->found_next_number_field)
9148 thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
9149 }
9150 (copy_end++)->set(*ptr,def->field,0);
9151 }
9152
9153 }
9154
9155 found_count=delete_count=0;
9156
9157 if (order)
9158 {
9159 if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
9160 {
9161 char warn_buff[MYSQL_ERRMSG_SIZE];
9162 my_snprintf(warn_buff, sizeof(warn_buff),
9163 "ORDER BY ignored as there is a user-defined clustered index"
9164 " in the table '%-.192s'", from->s->table_name.str);
9165 push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
9166 warn_buff);
9167 }
9168 else
9169 {
9170 from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
9171 MYF(MY_FAE | MY_ZEROFILL));
9172 memset(&tables, 0, sizeof(tables));
9173 tables.table= from;
9174 tables.alias= tables.table_name= from->s->table_name.str;
9175 tables.db= from->s->db.str;
9176 error= 1;
9177
9178 if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
9179 setup_order(thd, thd->lex->select_lex.ref_pointer_array,
9180 &tables, fields, all_fields, order))
9181 goto err;
9182 Filesort fsort(order, HA_POS_ERROR, NULL);
9183 if ((from->sort.found_records= filesort(thd, from, &fsort,
9184 true,
9185 &examined_rows, &found_rows)) ==
9186 HA_POS_ERROR)
9187 goto err;
9188 }
9189 };
9190
9191 /* Tell handler that we have values for all columns in the to table */
9192 to->use_all_columns();
9193 if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE))
9194 {
9195 error= 1;
9196 goto err;
9197 }
9198 if (ignore && !alter_ctx->fk_error_if_delete_row)
9199 to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
9200 thd->get_stmt_da()->reset_current_row_for_warning();
9201
9202 set_column_defaults(to, create);
9203
9204 while (!(error=info.read_record(&info)))
9205 {
9206 if (thd->killed)
9207 {
9208 thd->send_kill_message();
9209 error= 1;
9210 break;
9211 }
9212 /* Return error if source table isn't empty. */
9213 if (alter_ctx->error_if_not_empty)
9214 {
9215 error= 1;
9216 break;
9217 }
9218 if (to->next_number_field)
9219 {
9220 if (auto_increment_field_copied)
9221 to->auto_increment_field_not_null= TRUE;
9222 else
9223 to->next_number_field->reset();
9224 }
9225
9226 for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
9227 {
9228 copy_ptr->do_copy(copy_ptr);
9229 }
9230 prev_insert_id= to->file->next_insert_id;
9231
9232 error=to->file->ha_write_row(to->record[0]);
9233 to->auto_increment_field_not_null= FALSE;
9234 if (error)
9235 {
9236 if (to->file->is_fatal_error(error, HA_CHECK_DUP))
9237 {
9238 /* Not a duplicate key error. */
9239 to->file->print_error(error, MYF(0));
9240 break;
9241 }
9242 else
9243 {
9244 /* Duplicate key error. */
9245 if (alter_ctx->fk_error_if_delete_row)
9246 {
9247 /*
9248 We are trying to omit a row from the table which serves as parent
9249 in a foreign key. This might have broken referential integrity so
9250 emit an error. Note that we can't ignore this error even if we are
9251 executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
9252 doesn't allow to break unique or foreign key constraints,
9253 */
9254 my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
9255 alter_ctx->fk_error_id,
9256 alter_ctx->fk_error_table);
9257 break;
9258 }
9259
9260 if (ignore)
9261 {
9262 /* This ALTER IGNORE TABLE. Simply skip row and continue. */
9263 to->file->restore_auto_increment(prev_insert_id);
9264 delete_count++;
9265 }
9266 else
9267 {
9268 /* Ordinary ALTER TABLE. Report duplicate key error. */
9269 uint key_nr= to->file->get_dup_key(error);
9270 if ((int) key_nr >= 0)
9271 {
9272 const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
9273 if (key_nr == 0 &&
9274 (to->key_info[0].key_part[0].field->flags &
9275 AUTO_INCREMENT_FLAG))
9276 err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
9277 print_keydup_error(to, key_nr == MAX_KEY ? NULL :
9278 &to->key_info[key_nr],
9279 err_msg, MYF(0));
9280 }
9281 else
9282 to->file->print_error(error, MYF(0));
9283 break;
9284 }
9285 }
9286 }
9287 else
9288 found_count++;
9289 thd->get_stmt_da()->inc_current_row_for_warning();
9290 }
9291 end_read_record(&info);
9292 free_io_cache(from);
9293 delete [] copy; // This is never 0
9294
9295 if (to->file->ha_end_bulk_insert() && error <= 0)
9296 {
9297 to->file->print_error(my_errno,MYF(0));
9298 error= 1;
9299 }
9300 to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
9301
9302 if (mysql_trans_commit_alter_copy_data(thd))
9303 error= 1;
9304
9305 err:
9306 thd->variables.sql_mode= save_sql_mode;
9307 thd->abort_on_warning= 0;
9308 free_io_cache(from);
9309 *copied= found_count;
9310 *deleted=delete_count;
9311 to->file->ha_release_auto_increment();
9312 if (to->file->ha_external_lock(thd,F_UNLCK))
9313 error=1;
9314 if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
9315 error= 1;
9316 DBUG_RETURN(error > 0 ? -1 : 0);
9317 }
9318
9319
9320 /*
9321 Recreates tables by calling mysql_alter_table().
9322
9323 SYNOPSIS
9324 mysql_recreate_table()
9325 thd Thread handler
9326 tables Tables to recreate
9327 table_copy Recreate the table by using
9328 ALTER TABLE COPY algorithm
9329
9330 RETURN
9331 Like mysql_alter_table().
9332 */
mysql_recreate_table(THD * thd,TABLE_LIST * table_list,bool table_copy)9333 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
9334 {
9335 HA_CREATE_INFO create_info;
9336 Alter_info alter_info;
9337
9338 DBUG_ENTER("mysql_recreate_table");
9339 DBUG_ASSERT(!table_list->next_global);
9340 /* Set lock type which is appropriate for ALTER TABLE. */
9341 table_list->lock_type= TL_READ_NO_INSERT;
9342 /* Same applies to MDL request. */
9343 table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
9344
9345 memset(&create_info, 0, sizeof(create_info));
9346 create_info.row_type=ROW_TYPE_NOT_USED;
9347 create_info.default_table_charset=default_charset_info;
9348 /* Force alter table to recreate table */
9349 alter_info.flags= (Alter_info::ALTER_CHANGE_COLUMN |
9350 Alter_info::ALTER_RECREATE);
9351
9352 if (table_copy)
9353 alter_info.requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY;
9354
9355 DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
9356 table_list, &alter_info, 0,
9357 (ORDER *) 0, 0));
9358 }
9359
9360
mysql_checksum_table(THD * thd,TABLE_LIST * tables,HA_CHECK_OPT * check_opt)9361 bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
9362 HA_CHECK_OPT *check_opt)
9363 {
9364 TABLE_LIST *table;
9365 List<Item> field_list;
9366 Item *item;
9367 Protocol *protocol= thd->protocol;
9368 DBUG_ENTER("mysql_checksum_table");
9369
9370 /*
9371 CHECKSUM TABLE returns results and rollbacks statement transaction,
9372 so it should not be used in stored function or trigger.
9373 */
9374 DBUG_ASSERT(! thd->in_sub_stmt);
9375
9376 field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
9377 item->maybe_null= 1;
9378 field_list.push_back(item= new Item_int(NAME_STRING("Checksum"),
9379 (longlong) 1,
9380 MY_INT64_NUM_DECIMAL_DIGITS));
9381 item->maybe_null= 1;
9382 if (protocol->send_result_set_metadata(&field_list,
9383 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
9384 DBUG_RETURN(TRUE);
9385
9386 /*
9387 Close all temporary tables which were pre-open to simplify
9388 privilege checking. Clear all references to closed tables.
9389 */
9390 close_thread_tables(thd);
9391 for (table= tables; table; table= table->next_local)
9392 table->table= NULL;
9393
9394 /* Open one table after the other to keep lock time as short as possible. */
9395 for (table= tables; table; table= table->next_local)
9396 {
9397 char table_name[NAME_LEN*2+2];
9398 TABLE *t;
9399 TABLE_LIST *save_next_global;
9400
9401 strxmov(table_name, table->db ,".", table->table_name, NullS);
9402
9403 /* Remember old 'next' pointer and break the list. */
9404 save_next_global= table->next_global;
9405 table->next_global= NULL;
9406 table->lock_type= TL_READ;
9407 /* Allow to open real tables only. */
9408 table->required_type= FRMTYPE_TABLE;
9409
9410 if (open_temporary_tables(thd, table) ||
9411 open_and_lock_tables(thd, table, FALSE, 0))
9412 {
9413 t= NULL;
9414 }
9415 else
9416 t= table->table;
9417
9418 table->next_global= save_next_global;
9419
9420 protocol->prepare_for_resend();
9421 protocol->store(table_name, system_charset_info);
9422
9423 if (!t)
9424 {
9425 /* Table didn't exist */
9426 protocol->store_null();
9427 }
9428 else
9429 {
9430 if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
9431 !(check_opt->flags & T_EXTEND))
9432 protocol->store((ulonglong)t->file->checksum());
9433 else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
9434 (check_opt->flags & T_QUICK))
9435 protocol->store_null();
9436 else
9437 {
9438 /* calculating table's checksum */
9439 ha_checksum crc= 0;
9440 uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
9441
9442 t->use_all_columns();
9443
9444 if (t->file->ha_rnd_init(1))
9445 protocol->store_null();
9446 else
9447 {
9448 for (;;)
9449 {
9450 if (thd->killed)
9451 {
9452 /*
9453 we've been killed; let handler clean up, and remove the
9454 partial current row from the recordset (embedded lib)
9455 */
9456 t->file->ha_rnd_end();
9457 thd->protocol->remove_last_row();
9458 goto err;
9459 }
9460 ha_checksum row_crc= 0;
9461 int error= t->file->ha_rnd_next(t->record[0]);
9462 if (unlikely(error))
9463 {
9464 if (error == HA_ERR_RECORD_DELETED)
9465 continue;
9466 break;
9467 }
9468 if (t->s->null_bytes)
9469 {
9470 /* fix undefined null bits */
9471 t->record[0][t->s->null_bytes-1] |= null_mask;
9472 if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
9473 t->record[0][0] |= 1;
9474
9475 row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
9476 }
9477
9478 for (uint i= 0; i < t->s->fields; i++ )
9479 {
9480 Field *f= t->field[i];
9481
9482 /*
9483 BLOB and VARCHAR have pointers in their field, we must convert
9484 to string; GEOMETRY is implemented on top of BLOB.
9485 BIT may store its data among NULL bits, convert as well.
9486 */
9487 switch (f->type()) {
9488 case MYSQL_TYPE_BLOB:
9489 case MYSQL_TYPE_VARCHAR:
9490 case MYSQL_TYPE_GEOMETRY:
9491 case MYSQL_TYPE_BIT:
9492 {
9493 String tmp;
9494 f->val_str(&tmp);
9495 row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
9496 tmp.length());
9497 break;
9498 }
9499 default:
9500 row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
9501 break;
9502 }
9503 }
9504
9505 crc+= row_crc;
9506 }
9507 protocol->store((ulonglong)crc);
9508 t->file->ha_rnd_end();
9509 }
9510 }
9511 trans_rollback_stmt(thd);
9512 close_thread_tables(thd);
9513 }
9514
9515 if (thd->transaction_rollback_request)
9516 {
9517 /*
9518 If transaction rollback was requested we honor it. To do this we
9519 abort statement and return error as not only CHECKSUM TABLE is
9520 rolled back but the whole transaction in which it was used.
9521 */
9522 thd->protocol->remove_last_row();
9523 goto err;
9524 }
9525
9526 /* Hide errors from client. Return NULL for problematic tables instead. */
9527 thd->clear_error();
9528
9529 if (protocol->write())
9530 goto err;
9531 }
9532
9533 my_eof(thd);
9534 DBUG_RETURN(FALSE);
9535
9536 err:
9537 DBUG_RETURN(TRUE);
9538 }
9539
9540 /**
9541 @brief Check if the table can be created in the specified storage engine.
9542
9543 Checks if the storage engine is enabled and supports the given table
9544 type (e.g. normal, temporary, system). May do engine substitution
9545 if the requested engine is disabled.
9546
9547 @param thd Thread descriptor.
9548 @param db_name Database name.
9549 @param table_name Name of table to be created.
9550 @param create_info Create info from parser, including engine.
9551
9552 @retval true Engine not available/supported, error has been reported.
9553 @retval false Engine available/supported.
9554 */
check_engine(THD * thd,const char * db_name,const char * table_name,HA_CREATE_INFO * create_info)9555 static bool check_engine(THD *thd, const char *db_name,
9556 const char *table_name, HA_CREATE_INFO *create_info)
9557 {
9558 DBUG_ENTER("check_engine");
9559 handlerton **new_engine= &create_info->db_type;
9560 handlerton *req_engine= *new_engine;
9561 bool no_substitution=
9562 MY_TEST(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
9563 if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine),
9564 no_substitution, 1)))
9565 DBUG_RETURN(true);
9566
9567 if (req_engine && req_engine != *new_engine)
9568 {
9569 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
9570 ER_WARN_USING_OTHER_HANDLER,
9571 ER(ER_WARN_USING_OTHER_HANDLER),
9572 ha_resolve_storage_engine_name(*new_engine),
9573 table_name);
9574 }
9575 if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
9576 ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
9577 {
9578 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
9579 {
9580 my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
9581 ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
9582 *new_engine= 0;
9583 DBUG_RETURN(true);
9584 }
9585 *new_engine= myisam_hton;
9586 }
9587
9588 /*
9589 Check, if the given table name is system table, and if the storage engine
9590 does supports it.
9591 */
9592 if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
9593 !ha_check_if_supported_system_table(*new_engine, db_name, table_name))
9594 {
9595 my_error(ER_UNSUPPORTED_ENGINE, MYF(0),
9596 ha_resolve_storage_engine_name(*new_engine), db_name, table_name);
9597 *new_engine= NULL;
9598 DBUG_RETURN(true);
9599 }
9600
9601 DBUG_RETURN(false);
9602 }
9603