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