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