1 /*
2 Copyright (c) 2000, 2019, Oracle and/or its affiliates.
3 Copyright (c) 2010, 2022, MariaDB
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
17 */
18
19 /* drop and alter of tables */
20
21 #include "mariadb.h"
22 #include "sql_priv.h"
23 #include "unireg.h"
24 #include "debug_sync.h"
25 #include "sql_table.h"
26 #include "sql_parse.h" // test_if_data_home_dir
27 #include "sql_cache.h" // query_cache_*
28 #include "sql_base.h" // lock_table_names
29 #include "lock.h" // mysql_unlock_tables
30 #include "strfunc.h" // find_type2, find_set
31 #include "sql_truncate.h" // regenerate_locked_table
32 #include "ha_partition.h" // PAR_EXT
33 // mem_alloc_error,
34 // partition_info
35 // NOT_A_PARTITION_ID
36 #include "sql_db.h" // load_db_opt_by_name
37 #include "records.h" // init_read_record, end_read_record
38 #include "filesort.h" // filesort_free_buffers
39 #include "sql_select.h" // setup_order
40 #include "sql_handler.h" // mysql_ha_rm_tables
41 #include "discover.h" // readfrm
42 #include "my_pthread.h" // pthread_mutex_t
43 #include "log_event.h" // Query_log_event
44 #include "sql_statistics.h"
45 #include <hash.h>
46 #include <myisam.h>
47 #include <my_dir.h>
48 #include "create_options.h"
49 #include "sp_head.h"
50 #include "sp.h"
51 #include "sql_trigger.h"
52 #include "sql_parse.h"
53 #include "sql_show.h"
54 #include "transaction.h"
55 #include "sql_audit.h"
56 #include "sql_sequence.h"
57 #include "tztime.h"
58 #include "sql_insert.h" // binlog_drop_table
59 #include <algorithm>
60
61 #ifdef __WIN__
62 #include <io.h>
63 #endif
64
65 const char *primary_key_name="PRIMARY";
66
67 static int check_if_keyname_exists(const char *name,KEY *start, KEY *end);
68 static char *make_unique_key_name(THD *, const char *, KEY *, KEY *);
69 static bool make_unique_constraint_name(THD *, LEX_CSTRING *, const char *,
70 List<Virtual_column_info> *, uint *);
71 static const char *make_unique_invisible_field_name(THD *, const char *,
72 List<Create_field> *);
73 static int copy_data_between_tables(THD *, TABLE *,TABLE *,
74 List<Create_field> &, bool, uint, ORDER *,
75 ha_rows *, ha_rows *,
76 Alter_info::enum_enable_or_disable,
77 Alter_table_ctx *);
78 static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
79 Key *key);
80 static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
81 uint *, handler *, KEY **, uint *, int,
82 const LEX_CSTRING db,
83 const LEX_CSTRING table_name);
84 static uint blob_length_by_type(enum_field_types type);
85 static bool fix_constraints_names(THD *, List<Virtual_column_info> *,
86 const HA_CREATE_INFO *);
87
88 /**
89 @brief Helper function for explain_filename
90 @param thd Thread handle
91 @param to_p Explained name in system_charset_info
92 @param end_p End of the to_p buffer
93 @param name Name to be converted
94 @param name_len Length of the name, in bytes
95 */
add_identifier(THD * thd,char * to_p,const char * end_p,const char * name,size_t name_len)96 static char* add_identifier(THD* thd, char *to_p, const char * end_p,
97 const char* name, size_t name_len)
98 {
99 uint res;
100 uint errors;
101 const char *conv_name, *conv_name_end;
102 char tmp_name[FN_REFLEN];
103 char conv_string[FN_REFLEN];
104 int quote;
105
106 DBUG_ENTER("add_identifier");
107 if (!name[name_len])
108 conv_name= name;
109 else
110 {
111 strnmov(tmp_name, name, name_len);
112 tmp_name[name_len]= 0;
113 conv_name= tmp_name;
114 }
115 res= strconvert(&my_charset_filename, conv_name, name_len,
116 system_charset_info,
117 conv_string, FN_REFLEN, &errors);
118 if (unlikely(!res || errors))
119 {
120 DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors));
121 conv_name= name;
122 conv_name_end= name + name_len;
123 }
124 else
125 {
126 DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
127 conv_name= conv_string;
128 conv_name_end= conv_string + res;
129 }
130
131 quote= (likely(thd) ?
132 get_quote_char_for_identifier(thd, conv_name, res - 1) :
133 '`');
134
135 if (quote != EOF && (end_p - to_p > 2))
136 {
137 *(to_p++)= (char) quote;
138 while (*conv_name && (end_p - to_p - 1) > 0)
139 {
140 int length= system_charset_info->charlen(conv_name, conv_name_end);
141 if (length <= 0)
142 length= 1;
143 if (length == 1 && *conv_name == (char) quote)
144 {
145 if ((end_p - to_p) < 3)
146 break;
147 *(to_p++)= (char) quote;
148 *(to_p++)= *(conv_name++);
149 }
150 else if (((long) length) < (end_p - to_p))
151 {
152 to_p= strnmov(to_p, conv_name, length);
153 conv_name+= length;
154 }
155 else
156 break; /* string already filled */
157 }
158 if (end_p > to_p) {
159 *(to_p++)= (char) quote;
160 if (end_p > to_p)
161 *to_p= 0; /* terminate by NUL, but do not include it in the count */
162 }
163 }
164 else
165 to_p= strnmov(to_p, conv_name, end_p - to_p);
166 DBUG_RETURN(to_p);
167 }
168
169
170 /**
171 @brief Explain a path name by split it to database, table etc.
172
173 @details Break down the path name to its logic parts
174 (database, table, partition, subpartition).
175 filename_to_tablename cannot be used on partitions, due to the #P# part.
176 There can be up to 6 '#', #P# for partition, #SP# for subpartition
177 and #TMP# or #REN# for temporary or renamed partitions.
178 This should be used when something should be presented to a user in a
179 diagnostic, error etc. when it would be useful to know what a particular
180 file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc.
181
182 Examples:
183
184 t1#P#p1 table t1 partition p1
185 t1#P#p1#SP#sp1 table t1 partition p1 subpartition sp1
186 t1#P#p1#SP#sp1#TMP# table t1 partition p1 subpartition sp1 temporary
187 t1#P#p1#SP#sp1#REN# table t1 partition p1 subpartition sp1 renamed
188
189 @param thd Thread handle
190 @param from Path name in my_charset_filename
191 Null terminated in my_charset_filename, normalized
192 to use '/' as directory separation character.
193 @param to Explained name in system_charset_info
194 @param to_length Size of to buffer
195 @param explain_mode Requested output format.
196 EXPLAIN_ALL_VERBOSE ->
197 [Database `db`, ]Table `tbl`[,[ Temporary| Renamed]
198 Partition `p` [, Subpartition `sp`]]
199 EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl`
200 [[ Temporary| Renamed] Partition `p`
201 [, Subpartition `sp`]]
202 EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |*
203 [,[ Temporary| Renamed] Partition `p`
204 [, Subpartition `sp`]] *|
205 (| is really a /, and it is all in one line)
206
207 @retval Length of returned string
208 */
209
explain_filename(THD * thd,const char * from,char * to,uint to_length,enum_explain_filename_mode explain_mode)210 uint explain_filename(THD* thd,
211 const char *from,
212 char *to,
213 uint to_length,
214 enum_explain_filename_mode explain_mode)
215 {
216 char *to_p= to;
217 char *end_p= to_p + to_length;
218 const char *db_name= NULL;
219 size_t db_name_len= 0;
220 const char *table_name;
221 size_t table_name_len= 0;
222 const char *part_name= NULL;
223 size_t part_name_len= 0;
224 const char *subpart_name= NULL;
225 size_t subpart_name_len= 0;
226 uint part_type= NORMAL_PART_NAME;
227
228 const char *tmp_p;
229 DBUG_ENTER("explain_filename");
230 DBUG_PRINT("enter", ("from '%s'", from));
231 tmp_p= from;
232 table_name= from;
233 /*
234 If '/' then take last directory part as database.
235 '/' is the directory separator, not FN_LIB_CHAR
236 */
237 while ((tmp_p= strchr(tmp_p, '/')))
238 {
239 db_name= table_name;
240 /* calculate the length */
241 db_name_len= (int)(tmp_p - db_name);
242 tmp_p++;
243 table_name= tmp_p;
244 }
245 tmp_p= table_name;
246 /* Look if there are partition tokens in the table name. */
247 while ((tmp_p= strchr(tmp_p, '#')))
248 {
249 tmp_p++;
250 switch (tmp_p[0]) {
251 case 'P':
252 case 'p':
253 if (tmp_p[1] == '#')
254 {
255 part_name= tmp_p + 2;
256 tmp_p+= 2;
257 }
258 break;
259 case 'S':
260 case 's':
261 if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#')
262 {
263 part_name_len= (int)(tmp_p - part_name - 1);
264 subpart_name= tmp_p + 3;
265 tmp_p+= 3;
266 }
267 break;
268 case 'T':
269 case 't':
270 if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
271 (tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
272 tmp_p[3] == '#' && !tmp_p[4])
273 {
274 part_type= TEMP_PART_NAME;
275 tmp_p+= 4;
276 }
277 break;
278 case 'R':
279 case 'r':
280 if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
281 (tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
282 tmp_p[3] == '#' && !tmp_p[4])
283 {
284 part_type= RENAMED_PART_NAME;
285 tmp_p+= 4;
286 }
287 break;
288 default:
289 /* Not partition name part. */
290 ;
291 }
292 }
293 if (part_name)
294 {
295 table_name_len= (int)(part_name - table_name - 3);
296 if (subpart_name)
297 subpart_name_len= strlen(subpart_name);
298 else
299 part_name_len= strlen(part_name);
300 if (part_type != NORMAL_PART_NAME)
301 {
302 if (subpart_name)
303 subpart_name_len-= 5;
304 else
305 part_name_len-= 5;
306 }
307 }
308 else
309 table_name_len= strlen(table_name);
310 if (db_name)
311 {
312 if (explain_mode == EXPLAIN_ALL_VERBOSE)
313 {
314 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME),
315 end_p - to_p);
316 *(to_p++)= ' ';
317 to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
318 to_p= strnmov(to_p, ", ", end_p - to_p);
319 }
320 else
321 {
322 to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
323 to_p= strnmov(to_p, ".", end_p - to_p);
324 }
325 }
326 if (explain_mode == EXPLAIN_ALL_VERBOSE)
327 {
328 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p);
329 *(to_p++)= ' ';
330 to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
331 }
332 else
333 to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
334 if (part_name)
335 {
336 if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
337 to_p= strnmov(to_p, " /* ", end_p - to_p);
338 else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE)
339 to_p= strnmov(to_p, " ", end_p - to_p);
340 else
341 to_p= strnmov(to_p, ", ", end_p - to_p);
342 if (part_type != NORMAL_PART_NAME)
343 {
344 if (part_type == TEMP_PART_NAME)
345 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
346 end_p - to_p);
347 else
348 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME),
349 end_p - to_p);
350 to_p= strnmov(to_p, " ", end_p - to_p);
351 }
352 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME),
353 end_p - to_p);
354 *(to_p++)= ' ';
355 to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len);
356 if (subpart_name)
357 {
358 to_p= strnmov(to_p, ", ", end_p - to_p);
359 to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME),
360 end_p - to_p);
361 *(to_p++)= ' ';
362 to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len);
363 }
364 if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
365 to_p= strnmov(to_p, " */", end_p - to_p);
366 }
367 DBUG_PRINT("exit", ("to '%s'", to));
368 DBUG_RETURN((uint)(to_p - to));
369 }
370
371
372 /*
373 Translate a file name to a table name (WL #1324).
374
375 SYNOPSIS
376 filename_to_tablename()
377 from The file name in my_charset_filename.
378 to OUT The table name in system_charset_info.
379 to_length The size of the table name buffer.
380
381 RETURN
382 Table name length.
383 */
384
filename_to_tablename(const char * from,char * to,size_t to_length,bool stay_quiet)385 uint filename_to_tablename(const char *from, char *to, size_t to_length,
386 bool stay_quiet)
387 {
388 uint errors;
389 size_t res;
390 DBUG_ENTER("filename_to_tablename");
391 DBUG_PRINT("enter", ("from '%s'", from));
392
393 res= strconvert(&my_charset_filename, from, FN_REFLEN,
394 system_charset_info, to, to_length, &errors);
395 if (unlikely(errors)) // Old 5.0 name
396 {
397 res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
398 to);
399 if (!stay_quiet)
400 sql_print_error("Invalid (old?) table or database name '%s'", from);
401 }
402
403 DBUG_PRINT("exit", ("to '%s'", to));
404 DBUG_RETURN((uint)res);
405 }
406
407
408 /**
409 Check if given string begins with "#mysql50#" prefix
410
411 @param name string to check cut
412
413 @retval
414 FALSE no prefix found
415 @retval
416 TRUE prefix found
417 */
418
check_mysql50_prefix(const char * name)419 bool check_mysql50_prefix(const char *name)
420 {
421 return (name[0] == '#' &&
422 !strncmp(name, MYSQL50_TABLE_NAME_PREFIX,
423 MYSQL50_TABLE_NAME_PREFIX_LENGTH));
424 }
425
426
427 /**
428 Check if given string begins with "#mysql50#" prefix, cut it if so.
429
430 @param from string to check and cut
431 @param to[out] buffer for result string
432 @param to_length its size
433
434 @retval
435 0 no prefix found
436 @retval
437 non-0 result string length
438 */
439
check_n_cut_mysql50_prefix(const char * from,char * to,size_t to_length)440 uint check_n_cut_mysql50_prefix(const char *from, char *to, size_t to_length)
441 {
442 if (check_mysql50_prefix(from))
443 return (uint) (strmake(to, from + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
444 to_length - 1) - to);
445 return 0;
446 }
447
448
check_if_frm_exists(char * path,const char * db,const char * table)449 static bool check_if_frm_exists(char *path, const char *db, const char *table)
450 {
451 fn_format(path, table, db, reg_ext, MYF(0));
452 return !access(path, F_OK);
453 }
454
455
456 /*
457 Translate a table name to a file name (WL #1324).
458
459 SYNOPSIS
460 tablename_to_filename()
461 from The table name in system_charset_info.
462 to OUT The file name in my_charset_filename.
463 to_length The size of the file name buffer.
464
465 RETURN
466 File name length.
467 */
468
tablename_to_filename(const char * from,char * to,size_t to_length)469 uint tablename_to_filename(const char *from, char *to, size_t to_length)
470 {
471 uint errors, length;
472 DBUG_ENTER("tablename_to_filename");
473 DBUG_PRINT("enter", ("from '%s'", from));
474
475 if ((length= check_n_cut_mysql50_prefix(from, to, to_length)))
476 {
477 /*
478 Check if the name supplied is a valid mysql 5.0 name and
479 make the name a zero length string if it's not.
480 Note that just returning zero length is not enough :
481 a lot of places don't check the return value and expect
482 a zero terminated string.
483 */
484 if (check_table_name(to, length, TRUE))
485 {
486 to[0]= 0;
487 length= 0;
488 }
489 DBUG_RETURN(length);
490 }
491 length= strconvert(system_charset_info, from, FN_REFLEN,
492 &my_charset_filename, to, to_length, &errors);
493 if (check_if_legal_tablename(to) &&
494 length + 4 < to_length)
495 {
496 memcpy(to + length, "@@@", 4);
497 length+= 3;
498 }
499 DBUG_PRINT("exit", ("to '%s'", to));
500 DBUG_RETURN(length);
501 }
502
503
504 /*
505 Creates path to a file: mysql_data_dir/db/table.ext
506
507 SYNOPSIS
508 build_table_filename()
509 buff Where to write result in my_charset_filename.
510 This may be the same as table_name.
511 bufflen buff size
512 db Database name in system_charset_info.
513 table_name Table name in system_charset_info.
514 ext File extension.
515 flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
516 table_name is temporary, do not change.
517
518 NOTES
519
520 Uses database and table name, and extension to create
521 a file name in mysql_data_dir. Database and table
522 names are converted from system_charset_info into "fscs".
523 Unless flags indicate a temporary table name.
524 'db' is always converted.
525 'ext' is not converted.
526
527 The conversion suppression is required for ALTER TABLE. This
528 statement creates intermediate tables. These are regular
529 (non-temporary) tables with a temporary name. Their path names must
530 be derivable from the table name. So we cannot use
531 build_tmptable_filename() for them.
532
533 RETURN
534 path length
535 */
536
build_table_filename(char * buff,size_t bufflen,const char * db,const char * table_name,const char * ext,uint flags)537 uint build_table_filename(char *buff, size_t bufflen, const char *db,
538 const char *table_name, const char *ext, uint flags)
539 {
540 char dbbuff[FN_REFLEN];
541 char tbbuff[FN_REFLEN];
542 DBUG_ENTER("build_table_filename");
543 DBUG_PRINT("enter", ("db: '%s' table_name: '%s' ext: '%s' flags: %x",
544 db, table_name, ext, flags));
545
546 (void) tablename_to_filename(db, dbbuff, sizeof(dbbuff));
547
548 /* Check if this is a temporary table name. Allow it if a corresponding .frm file exists */
549 if (is_prefix(table_name, tmp_file_prefix) && strlen(table_name) < NAME_CHAR_LEN &&
550 check_if_frm_exists(tbbuff, dbbuff, table_name))
551 flags|= FN_IS_TMP;
552
553 if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
554 strmake(tbbuff, table_name, sizeof(tbbuff)-1);
555 else
556 (void) tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
557
558 char *end = buff + bufflen;
559 /* Don't add FN_ROOTDIR if mysql_data_home already includes it */
560 char *pos = strnmov(buff, mysql_data_home, bufflen);
561 size_t rootdir_len= strlen(FN_ROOTDIR);
562 if (pos - rootdir_len >= buff &&
563 memcmp(pos - rootdir_len, FN_ROOTDIR, rootdir_len) != 0)
564 pos= strnmov(pos, FN_ROOTDIR, end - pos);
565 pos= strxnmov(pos, end - pos, dbbuff, FN_ROOTDIR, NullS);
566 #ifdef USE_SYMDIR
567 if (!(flags & SKIP_SYMDIR_ACCESS))
568 {
569 unpack_dirname(buff, buff);
570 pos= strend(buff);
571 }
572 #endif
573 pos= strxnmov(pos, end - pos, tbbuff, ext, NullS);
574
575 DBUG_PRINT("exit", ("buff: '%s'", buff));
576 DBUG_RETURN((uint)(pos - buff));
577 }
578
579
580 /**
581 Create path to a temporary table mysql_tmpdir/#sql-temptable-1234-12-1
582 (i.e. to its .FRM file but without an extension).
583
584 @param thd The thread handle.
585 @param buff Where to write result in my_charset_filename.
586 @param bufflen buff size
587
588 @note
589 Uses current_pid, thread_id, and tmp_table counter to create
590 a file name in mysql_tmpdir.
591
592 @return Path length.
593 */
594
build_tmptable_filename(THD * thd,char * buff,size_t bufflen)595 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
596 {
597 DBUG_ENTER("build_tmptable_filename");
598
599 char *p= strnmov(buff, mysql_tmpdir, bufflen);
600 my_snprintf(p, bufflen - (p - buff), "/%s-temptable-%lx-%llx-%x",
601 tmp_file_prefix, current_pid,
602 thd->thread_id, thd->tmp_table++);
603
604 if (lower_case_table_names)
605 {
606 /* Convert all except tmpdir to lower case */
607 my_casedn_str(files_charset_info, p);
608 }
609
610 size_t length= unpack_filename(buff, buff);
611 DBUG_PRINT("exit", ("buff: '%s'", buff));
612 DBUG_RETURN((uint)length);
613 }
614
615 /*
616 --------------------------------------------------------------------------
617
618 MODULE: DDL log
619 -----------------
620
621 This module is used to ensure that we can recover from crashes that occur
622 in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2;
623 We need to ensure that both t1 and t2 are dropped and not only t1 and
624 also that each table drop is entirely done and not "half-baked".
625
626 To support this we create log entries for each meta-data statement in the
627 ddl log while we are executing. These entries are dropped when the
628 operation is completed.
629
630 At recovery those entries that were not completed will be executed.
631
632 There is only one ddl log in the system and it is protected by a mutex
633 and there is a global struct that contains information about its current
634 state.
635
636 History:
637 First version written in 2006 by Mikael Ronstrom
638 --------------------------------------------------------------------------
639 */
640
641 struct st_global_ddl_log
642 {
643 /*
644 We need to adjust buffer size to be able to handle downgrades/upgrades
645 where IO_SIZE has changed. We'll set the buffer size such that we can
646 handle that the buffer size was upto 4 times bigger in the version
647 that wrote the DDL log.
648 */
649 char file_entry_buf[4*IO_SIZE];
650 char file_name_str[FN_REFLEN];
651 char *file_name;
652 DDL_LOG_MEMORY_ENTRY *first_free;
653 DDL_LOG_MEMORY_ENTRY *first_used;
654 uint num_entries;
655 File file_id;
656 uint name_len;
657 uint io_size;
658 bool inited;
659 bool do_release;
660 bool recovery_phase;
st_global_ddl_logst_global_ddl_log661 st_global_ddl_log() : inited(false), do_release(false) {}
662 };
663
664 st_global_ddl_log global_ddl_log;
665
666 mysql_mutex_t LOCK_gdl;
667
668 #define DDL_LOG_ENTRY_TYPE_POS 0
669 #define DDL_LOG_ACTION_TYPE_POS 1
670 #define DDL_LOG_PHASE_POS 2
671 #define DDL_LOG_NEXT_ENTRY_POS 4
672 #define DDL_LOG_NAME_POS 8
673
674 #define DDL_LOG_NUM_ENTRY_POS 0
675 #define DDL_LOG_NAME_LEN_POS 4
676 #define DDL_LOG_IO_SIZE_POS 8
677
678 /**
679 Read one entry from ddl log file.
680
681 @param entry_no Entry number to read
682
683 @return Operation status
684 @retval true Error
685 @retval false Success
686 */
687
read_ddl_log_file_entry(uint entry_no)688 static bool read_ddl_log_file_entry(uint entry_no)
689 {
690 bool error= FALSE;
691 File file_id= global_ddl_log.file_id;
692 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
693 size_t io_size= global_ddl_log.io_size;
694 DBUG_ENTER("read_ddl_log_file_entry");
695
696 mysql_mutex_assert_owner(&LOCK_gdl);
697 if (mysql_file_pread(file_id, file_entry_buf, io_size, io_size * entry_no,
698 MYF(MY_WME)) != io_size)
699 error= TRUE;
700 DBUG_RETURN(error);
701 }
702
703
704 /**
705 Write one entry to ddl log file.
706
707 @param entry_no Entry number to write
708
709 @return Operation status
710 @retval true Error
711 @retval false Success
712 */
713
write_ddl_log_file_entry(uint entry_no)714 static bool write_ddl_log_file_entry(uint entry_no)
715 {
716 bool error= FALSE;
717 File file_id= global_ddl_log.file_id;
718 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
719 DBUG_ENTER("write_ddl_log_file_entry");
720
721 mysql_mutex_assert_owner(&LOCK_gdl);
722 if (mysql_file_pwrite(file_id, file_entry_buf,
723 IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
724 error= TRUE;
725 DBUG_RETURN(error);
726 }
727
728
729 /**
730 Sync the ddl log file.
731
732 @return Operation status
733 @retval FALSE Success
734 @retval TRUE Error
735 */
736
737
sync_ddl_log_file()738 static bool sync_ddl_log_file()
739 {
740 DBUG_ENTER("sync_ddl_log_file");
741 DBUG_RETURN(mysql_file_sync(global_ddl_log.file_id, MYF(MY_WME)));
742 }
743
744
745 /**
746 Write ddl log header.
747
748 @return Operation status
749 @retval TRUE Error
750 @retval FALSE Success
751 */
752
write_ddl_log_header()753 static bool write_ddl_log_header()
754 {
755 uint16 const_var;
756 DBUG_ENTER("write_ddl_log_header");
757
758 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
759 global_ddl_log.num_entries);
760 const_var= FN_REFLEN;
761 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_LEN_POS],
762 (ulong) const_var);
763 const_var= IO_SIZE;
764 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_IO_SIZE_POS],
765 (ulong) const_var);
766 if (write_ddl_log_file_entry(0UL))
767 {
768 sql_print_error("Error writing ddl log header");
769 DBUG_RETURN(TRUE);
770 }
771 DBUG_RETURN(sync_ddl_log_file());
772 }
773
774
775 /**
776 Create ddl log file name.
777 @param file_name Filename setup
778 */
779
create_ddl_log_file_name(char * file_name)780 static inline void create_ddl_log_file_name(char *file_name)
781 {
782 strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS);
783 }
784
785
786 /**
787 Read header of ddl log file.
788
789 When we read the ddl log header we get information about maximum sizes
790 of names in the ddl log and we also get information about the number
791 of entries in the ddl log.
792
793 @return Last entry in ddl log (0 if no entries)
794 */
795
read_ddl_log_header()796 static uint read_ddl_log_header()
797 {
798 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
799 char file_name[FN_REFLEN];
800 uint entry_no;
801 bool successful_open= FALSE;
802 DBUG_ENTER("read_ddl_log_header");
803
804 mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_SLOW);
805 mysql_mutex_lock(&LOCK_gdl);
806 create_ddl_log_file_name(file_name);
807 if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
808 file_name,
809 O_RDWR | O_BINARY, MYF(0))) >= 0)
810 {
811 if (read_ddl_log_file_entry(0UL))
812 {
813 /* Write message into error log */
814 sql_print_error("Failed to read ddl log file in recovery");
815 }
816 else
817 successful_open= TRUE;
818 }
819 if (successful_open)
820 {
821 entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
822 global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
823 global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
824 DBUG_ASSERT(global_ddl_log.io_size <=
825 sizeof(global_ddl_log.file_entry_buf));
826 }
827 else
828 {
829 entry_no= 0;
830 }
831 global_ddl_log.first_free= NULL;
832 global_ddl_log.first_used= NULL;
833 global_ddl_log.num_entries= 0;
834 global_ddl_log.do_release= true;
835 mysql_mutex_unlock(&LOCK_gdl);
836 DBUG_RETURN(entry_no);
837 }
838
839
840 /**
841 Convert from ddl_log_entry struct to file_entry_buf binary blob.
842
843 @param ddl_log_entry filled in ddl_log_entry struct.
844 */
845
set_global_from_ddl_log_entry(const DDL_LOG_ENTRY * ddl_log_entry)846 static void set_global_from_ddl_log_entry(const DDL_LOG_ENTRY *ddl_log_entry)
847 {
848 mysql_mutex_assert_owner(&LOCK_gdl);
849 global_ddl_log.file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]=
850 (char)DDL_LOG_ENTRY_CODE;
851 global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS]=
852 (char)ddl_log_entry->action_type;
853 global_ddl_log.file_entry_buf[DDL_LOG_PHASE_POS]= 0;
854 int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NEXT_ENTRY_POS],
855 ddl_log_entry->next_entry);
856 DBUG_ASSERT(strlen(ddl_log_entry->name) < FN_REFLEN);
857 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
858 ddl_log_entry->name, FN_REFLEN - 1);
859 if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION ||
860 ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION ||
861 ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
862 {
863 DBUG_ASSERT(strlen(ddl_log_entry->from_name) < FN_REFLEN);
864 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN],
865 ddl_log_entry->from_name, FN_REFLEN - 1);
866 }
867 else
868 global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN]= 0;
869 DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < FN_REFLEN);
870 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (2*FN_REFLEN)],
871 ddl_log_entry->handler_name, FN_REFLEN - 1);
872 if (ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
873 {
874 DBUG_ASSERT(strlen(ddl_log_entry->tmp_name) < FN_REFLEN);
875 strmake(&global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (3*FN_REFLEN)],
876 ddl_log_entry->tmp_name, FN_REFLEN - 1);
877 }
878 else
879 global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS + (3*FN_REFLEN)]= 0;
880 }
881
882
883 /**
884 Convert from file_entry_buf binary blob to ddl_log_entry struct.
885
886 @param[out] ddl_log_entry struct to fill in.
887
888 @note Strings (names) are pointing to the global_ddl_log structure,
889 so LOCK_gdl needs to be hold until they are read or copied.
890 */
891
set_ddl_log_entry_from_global(DDL_LOG_ENTRY * ddl_log_entry,const uint read_entry)892 static void set_ddl_log_entry_from_global(DDL_LOG_ENTRY *ddl_log_entry,
893 const uint read_entry)
894 {
895 char *file_entry_buf= (char*) global_ddl_log.file_entry_buf;
896 uint inx;
897 uchar single_char;
898
899 mysql_mutex_assert_owner(&LOCK_gdl);
900 ddl_log_entry->entry_pos= read_entry;
901 single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS];
902 ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char;
903 single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS];
904 ddl_log_entry->action_type= (enum ddl_log_action_code)single_char;
905 ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS];
906 ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]);
907 ddl_log_entry->name= &file_entry_buf[DDL_LOG_NAME_POS];
908 inx= DDL_LOG_NAME_POS + global_ddl_log.name_len;
909 ddl_log_entry->from_name= &file_entry_buf[inx];
910 inx+= global_ddl_log.name_len;
911 ddl_log_entry->handler_name= &file_entry_buf[inx];
912 if (ddl_log_entry->action_type == DDL_LOG_EXCHANGE_ACTION)
913 {
914 inx+= global_ddl_log.name_len;
915 ddl_log_entry->tmp_name= &file_entry_buf[inx];
916 }
917 else
918 ddl_log_entry->tmp_name= NULL;
919 }
920
921
922 /**
923 Read a ddl log entry.
924
925 Read a specified entry in the ddl log.
926
927 @param read_entry Number of entry to read
928 @param[out] entry_info Information from entry
929
930 @return Operation status
931 @retval TRUE Error
932 @retval FALSE Success
933 */
934
read_ddl_log_entry(uint read_entry,DDL_LOG_ENTRY * ddl_log_entry)935 static bool read_ddl_log_entry(uint read_entry, DDL_LOG_ENTRY *ddl_log_entry)
936 {
937 DBUG_ENTER("read_ddl_log_entry");
938
939 if (read_ddl_log_file_entry(read_entry))
940 {
941 DBUG_RETURN(TRUE);
942 }
943 set_ddl_log_entry_from_global(ddl_log_entry, read_entry);
944 DBUG_RETURN(FALSE);
945 }
946
947
948 /**
949 Initialise ddl log.
950
951 Write the header of the ddl log file and length of names. Also set
952 number of entries to zero.
953
954 @return Operation status
955 @retval TRUE Error
956 @retval FALSE Success
957 */
958
init_ddl_log()959 static bool init_ddl_log()
960 {
961 char file_name[FN_REFLEN];
962 DBUG_ENTER("init_ddl_log");
963
964 if (global_ddl_log.inited)
965 goto end;
966
967 global_ddl_log.io_size= IO_SIZE;
968 global_ddl_log.name_len= FN_REFLEN;
969 create_ddl_log_file_name(file_name);
970 if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log,
971 file_name, CREATE_MODE,
972 O_RDWR | O_TRUNC | O_BINARY,
973 MYF(MY_WME))) < 0)
974 {
975 /* Couldn't create ddl log file, this is serious error */
976 sql_print_error("Failed to open ddl log file");
977 DBUG_RETURN(TRUE);
978 }
979 global_ddl_log.inited= TRUE;
980 if (write_ddl_log_header())
981 {
982 (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
983 global_ddl_log.inited= FALSE;
984 DBUG_RETURN(TRUE);
985 }
986
987 end:
988 DBUG_RETURN(FALSE);
989 }
990
991
992 /**
993 Sync ddl log file.
994
995 @return Operation status
996 @retval TRUE Error
997 @retval FALSE Success
998 */
999
sync_ddl_log_no_lock()1000 static bool sync_ddl_log_no_lock()
1001 {
1002 DBUG_ENTER("sync_ddl_log_no_lock");
1003
1004 mysql_mutex_assert_owner(&LOCK_gdl);
1005 if ((!global_ddl_log.recovery_phase) &&
1006 init_ddl_log())
1007 {
1008 DBUG_RETURN(TRUE);
1009 }
1010 DBUG_RETURN(sync_ddl_log_file());
1011 }
1012
1013
1014 /**
1015 @brief Deactivate an individual entry.
1016
1017 @details For complex rename operations we need to deactivate individual
1018 entries.
1019
1020 During replace operations where we start with an existing table called
1021 t1 and a replacement table called t1#temp or something else and where
1022 we want to delete t1 and rename t1#temp to t1 this is not possible to
1023 do in a safe manner unless the ddl log is informed of the phases in
1024 the change.
1025
1026 Delete actions are 1-phase actions that can be ignored immediately after
1027 being executed.
1028 Rename actions from x to y is also a 1-phase action since there is no
1029 interaction with any other handlers named x and y.
1030 Replace action where drop y and x -> y happens needs to be a two-phase
1031 action. Thus the first phase will drop y and the second phase will
1032 rename x -> y.
1033
1034 @param entry_no Entry position of record to change
1035
1036 @return Operation status
1037 @retval TRUE Error
1038 @retval FALSE Success
1039 */
1040
deactivate_ddl_log_entry_no_lock(uint entry_no)1041 static bool deactivate_ddl_log_entry_no_lock(uint entry_no)
1042 {
1043 uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
1044 DBUG_ENTER("deactivate_ddl_log_entry_no_lock");
1045
1046 mysql_mutex_assert_owner(&LOCK_gdl);
1047 if (!read_ddl_log_file_entry(entry_no))
1048 {
1049 if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
1050 {
1051 /*
1052 Log entry, if complete mark it done (IGNORE).
1053 Otherwise increase the phase by one.
1054 */
1055 if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
1056 file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
1057 (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
1058 file_entry_buf[DDL_LOG_PHASE_POS] == 1) ||
1059 (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION &&
1060 file_entry_buf[DDL_LOG_PHASE_POS] >= EXCH_PHASE_TEMP_TO_FROM))
1061 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
1062 else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
1063 {
1064 DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0);
1065 file_entry_buf[DDL_LOG_PHASE_POS]= 1;
1066 }
1067 else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION)
1068 {
1069 DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] <=
1070 EXCH_PHASE_FROM_TO_NAME);
1071 file_entry_buf[DDL_LOG_PHASE_POS]++;
1072 }
1073 else
1074 {
1075 DBUG_ASSERT(0);
1076 }
1077 if (write_ddl_log_file_entry(entry_no))
1078 {
1079 sql_print_error("Error in deactivating log entry. Position = %u",
1080 entry_no);
1081 DBUG_RETURN(TRUE);
1082 }
1083 }
1084 }
1085 else
1086 {
1087 sql_print_error("Failed in reading entry before deactivating it");
1088 DBUG_RETURN(TRUE);
1089 }
1090 DBUG_RETURN(FALSE);
1091 }
1092
1093
1094 /**
1095 Execute one action in a ddl log entry
1096
1097 @param ddl_log_entry Information in action entry to execute
1098
1099 @return Operation status
1100 @retval TRUE Error
1101 @retval FALSE Success
1102 */
1103
execute_ddl_log_action(THD * thd,DDL_LOG_ENTRY * ddl_log_entry)1104 static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
1105 {
1106 bool frm_action= FALSE;
1107 LEX_CSTRING handler_name;
1108 handler *file= NULL;
1109 MEM_ROOT mem_root;
1110 int error= 1;
1111 char to_path[FN_REFLEN];
1112 char from_path[FN_REFLEN];
1113 handlerton *hton;
1114 DBUG_ENTER("execute_ddl_log_action");
1115
1116 mysql_mutex_assert_owner(&LOCK_gdl);
1117 if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE)
1118 {
1119 DBUG_RETURN(FALSE);
1120 }
1121 DBUG_PRINT("ddl_log",
1122 ("execute type %c next %u name '%s' from_name '%s' handler '%s'"
1123 " tmp_name '%s'",
1124 ddl_log_entry->action_type,
1125 ddl_log_entry->next_entry,
1126 ddl_log_entry->name,
1127 ddl_log_entry->from_name,
1128 ddl_log_entry->handler_name,
1129 ddl_log_entry->tmp_name));
1130 handler_name.str= (char*)ddl_log_entry->handler_name;
1131 handler_name.length= strlen(ddl_log_entry->handler_name);
1132 init_sql_alloc(key_memory_gdl, &mem_root, TABLE_ALLOC_BLOCK_SIZE, 0,
1133 MYF(MY_THREAD_SPECIFIC));
1134 if (!strcmp(ddl_log_entry->handler_name, reg_ext))
1135 frm_action= TRUE;
1136 else
1137 {
1138 plugin_ref plugin= ha_resolve_by_name(thd, &handler_name, false);
1139 if (!plugin)
1140 {
1141 my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), ddl_log_entry->handler_name);
1142 goto error;
1143 }
1144 hton= plugin_data(plugin, handlerton*);
1145 file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
1146 if (unlikely(!file))
1147 goto error;
1148 }
1149 switch (ddl_log_entry->action_type)
1150 {
1151 case DDL_LOG_REPLACE_ACTION:
1152 case DDL_LOG_DELETE_ACTION:
1153 {
1154 if (ddl_log_entry->phase == 0)
1155 {
1156 if (frm_action)
1157 {
1158 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
1159 if (unlikely((error= mysql_file_delete(key_file_frm, to_path,
1160 MYF(MY_WME |
1161 MY_IGNORE_ENOENT)))))
1162 break;
1163 #ifdef WITH_PARTITION_STORAGE_ENGINE
1164 strxmov(to_path, ddl_log_entry->name, PAR_EXT, NullS);
1165 (void) mysql_file_delete(key_file_partition_ddl_log, to_path,
1166 MYF(0));
1167 #endif
1168 }
1169 else
1170 {
1171 if (unlikely((error= hton->drop_table(hton, ddl_log_entry->name))))
1172 {
1173 if (!non_existing_table_error(error))
1174 break;
1175 }
1176 }
1177 if ((deactivate_ddl_log_entry_no_lock(ddl_log_entry->entry_pos)))
1178 break;
1179 (void) sync_ddl_log_no_lock();
1180 error= 0;
1181 if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
1182 break;
1183 }
1184 DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
1185 /*
1186 Fall through and perform the rename action of the replace
1187 action. We have already indicated the success of the delete
1188 action in the log entry by stepping up the phase.
1189 */
1190 }
1191 /* fall through */
1192 case DDL_LOG_RENAME_ACTION:
1193 {
1194 error= TRUE;
1195 if (frm_action)
1196 {
1197 strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
1198 strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
1199 if (mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME)))
1200 break;
1201 #ifdef WITH_PARTITION_STORAGE_ENGINE
1202 strxmov(to_path, ddl_log_entry->name, PAR_EXT, NullS);
1203 strxmov(from_path, ddl_log_entry->from_name, PAR_EXT, NullS);
1204 (void) mysql_file_rename(key_file_partition_ddl_log, from_path, to_path, MYF(MY_WME));
1205 #endif
1206 }
1207 else
1208 {
1209 if (file->ha_rename_table(ddl_log_entry->from_name,
1210 ddl_log_entry->name))
1211 break;
1212 }
1213 if ((deactivate_ddl_log_entry_no_lock(ddl_log_entry->entry_pos)))
1214 break;
1215 (void) sync_ddl_log_no_lock();
1216 error= FALSE;
1217 break;
1218 }
1219 case DDL_LOG_EXCHANGE_ACTION:
1220 {
1221 /* We hold LOCK_gdl, so we can alter global_ddl_log.file_entry_buf */
1222 char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf;
1223 /* not yet implemented for frm */
1224 DBUG_ASSERT(!frm_action);
1225 /*
1226 Using a case-switch here to revert all currently done phases,
1227 since it will fall through until the first phase is undone.
1228 */
1229 switch (ddl_log_entry->phase) {
1230 case EXCH_PHASE_TEMP_TO_FROM:
1231 /* tmp_name -> from_name possibly done */
1232 (void) file->ha_rename_table(ddl_log_entry->from_name,
1233 ddl_log_entry->tmp_name);
1234 /* decrease the phase and sync */
1235 file_entry_buf[DDL_LOG_PHASE_POS]--;
1236 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1237 break;
1238 if (sync_ddl_log_no_lock())
1239 break;
1240 /* fall through */
1241 case EXCH_PHASE_FROM_TO_NAME:
1242 /* from_name -> name possibly done */
1243 (void) file->ha_rename_table(ddl_log_entry->name,
1244 ddl_log_entry->from_name);
1245 /* decrease the phase and sync */
1246 file_entry_buf[DDL_LOG_PHASE_POS]--;
1247 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1248 break;
1249 if (sync_ddl_log_no_lock())
1250 break;
1251 /* fall through */
1252 case EXCH_PHASE_NAME_TO_TEMP:
1253 /* name -> tmp_name possibly done */
1254 (void) file->ha_rename_table(ddl_log_entry->tmp_name,
1255 ddl_log_entry->name);
1256 /* disable the entry and sync */
1257 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
1258 if (write_ddl_log_file_entry(ddl_log_entry->entry_pos))
1259 break;
1260 if (sync_ddl_log_no_lock())
1261 break;
1262 error= FALSE;
1263 break;
1264 default:
1265 DBUG_ASSERT(0);
1266 break;
1267 }
1268
1269 break;
1270 }
1271 default:
1272 DBUG_ASSERT(0);
1273 break;
1274 }
1275 delete file;
1276 error:
1277 free_root(&mem_root, MYF(0));
1278 DBUG_RETURN(error);
1279 }
1280
1281
1282 /**
1283 Get a free entry in the ddl log
1284
1285 @param[out] active_entry A ddl log memory entry returned
1286
1287 @return Operation status
1288 @retval TRUE Error
1289 @retval FALSE Success
1290 */
1291
get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY ** active_entry,bool * write_header)1292 static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
1293 bool *write_header)
1294 {
1295 DDL_LOG_MEMORY_ENTRY *used_entry;
1296 DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used;
1297 DBUG_ENTER("get_free_ddl_log_entry");
1298
1299 if (global_ddl_log.first_free == NULL)
1300 {
1301 if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(key_memory_DDL_LOG_MEMORY_ENTRY,
1302 sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
1303 {
1304 sql_print_error("Failed to allocate memory for ddl log free list");
1305 DBUG_RETURN(TRUE);
1306 }
1307 global_ddl_log.num_entries++;
1308 used_entry->entry_pos= global_ddl_log.num_entries;
1309 *write_header= TRUE;
1310 }
1311 else
1312 {
1313 used_entry= global_ddl_log.first_free;
1314 global_ddl_log.first_free= used_entry->next_log_entry;
1315 *write_header= FALSE;
1316 }
1317 /*
1318 Move from free list to used list
1319 */
1320 used_entry->next_log_entry= first_used;
1321 used_entry->prev_log_entry= NULL;
1322 used_entry->next_active_log_entry= NULL;
1323 global_ddl_log.first_used= used_entry;
1324 if (first_used)
1325 first_used->prev_log_entry= used_entry;
1326
1327 *active_entry= used_entry;
1328 DBUG_RETURN(FALSE);
1329 }
1330
1331
1332 /**
1333 Execute one entry in the ddl log.
1334
1335 Executing an entry means executing a linked list of actions.
1336
1337 @param first_entry Reference to first action in entry
1338
1339 @return Operation status
1340 @retval TRUE Error
1341 @retval FALSE Success
1342 */
1343
execute_ddl_log_entry_no_lock(THD * thd,uint first_entry)1344 static bool execute_ddl_log_entry_no_lock(THD *thd, uint first_entry)
1345 {
1346 DDL_LOG_ENTRY ddl_log_entry;
1347 uint read_entry= first_entry;
1348 DBUG_ENTER("execute_ddl_log_entry_no_lock");
1349
1350 mysql_mutex_assert_owner(&LOCK_gdl);
1351 do
1352 {
1353 if (read_ddl_log_entry(read_entry, &ddl_log_entry))
1354 {
1355 /* Write to error log and continue with next log entry */
1356 sql_print_error("Failed to read entry = %u from ddl log",
1357 read_entry);
1358 break;
1359 }
1360 DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE ||
1361 ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE);
1362
1363 if (execute_ddl_log_action(thd, &ddl_log_entry))
1364 {
1365 /* Write to error log and continue with next log entry */
1366 sql_print_error("Failed to execute action for entry = %u from ddl log",
1367 read_entry);
1368 break;
1369 }
1370 read_entry= ddl_log_entry.next_entry;
1371 } while (read_entry);
1372 DBUG_RETURN(FALSE);
1373 }
1374
1375
1376 /*
1377 External interface methods for the DDL log Module
1378 ---------------------------------------------------
1379 */
1380
1381 /**
1382 Write a ddl log entry.
1383
1384 A careful write of the ddl log is performed to ensure that we can
1385 handle crashes occurring during CREATE and ALTER TABLE processing.
1386
1387 @param ddl_log_entry Information about log entry
1388 @param[out] entry_written Entry information written into
1389
1390 @return Operation status
1391 @retval TRUE Error
1392 @retval FALSE Success
1393 */
1394
write_ddl_log_entry(DDL_LOG_ENTRY * ddl_log_entry,DDL_LOG_MEMORY_ENTRY ** active_entry)1395 bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
1396 DDL_LOG_MEMORY_ENTRY **active_entry)
1397 {
1398 bool error, write_header;
1399 DBUG_ENTER("write_ddl_log_entry");
1400
1401 mysql_mutex_assert_owner(&LOCK_gdl);
1402 if (init_ddl_log())
1403 {
1404 DBUG_RETURN(TRUE);
1405 }
1406 set_global_from_ddl_log_entry(ddl_log_entry);
1407 if (get_free_ddl_log_entry(active_entry, &write_header))
1408 {
1409 DBUG_RETURN(TRUE);
1410 }
1411 error= FALSE;
1412 DBUG_PRINT("ddl_log",
1413 ("write type %c next %u name '%s' from_name '%s' handler '%s'"
1414 " tmp_name '%s'",
1415 (char) global_ddl_log.file_entry_buf[DDL_LOG_ACTION_TYPE_POS],
1416 ddl_log_entry->next_entry,
1417 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS],
1418 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1419 + FN_REFLEN],
1420 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1421 + (2*FN_REFLEN)],
1422 (char*) &global_ddl_log.file_entry_buf[DDL_LOG_NAME_POS
1423 + (3*FN_REFLEN)]));
1424 if (unlikely(write_ddl_log_file_entry((*active_entry)->entry_pos)))
1425 {
1426 error= TRUE;
1427 sql_print_error("Failed to write entry_no = %u",
1428 (*active_entry)->entry_pos);
1429 }
1430 if (write_header && likely(!error))
1431 {
1432 (void) sync_ddl_log_no_lock();
1433 if (write_ddl_log_header())
1434 error= TRUE;
1435 }
1436 if (unlikely(error))
1437 release_ddl_log_memory_entry(*active_entry);
1438 DBUG_RETURN(error);
1439 }
1440
1441
1442 /**
1443 @brief Write final entry in the ddl log.
1444
1445 @details This is the last write in the ddl log. The previous log entries
1446 have already been written but not yet synched to disk.
1447 We write a couple of log entries that describes action to perform.
1448 This entries are set-up in a linked list, however only when a first
1449 execute entry is put as the first entry these will be executed.
1450 This routine writes this first.
1451
1452 @param first_entry First entry in linked list of entries
1453 to execute, if 0 = NULL it means that
1454 the entry is removed and the entries
1455 are put into the free list.
1456 @param complete Flag indicating we are simply writing
1457 info about that entry has been completed
1458 @param[in,out] active_entry Entry to execute, 0 = NULL if the entry
1459 is written first time and needs to be
1460 returned. In this case the entry written
1461 is returned in this parameter
1462
1463 @return Operation status
1464 @retval TRUE Error
1465 @retval FALSE Success
1466 */
1467
write_execute_ddl_log_entry(uint first_entry,bool complete,DDL_LOG_MEMORY_ENTRY ** active_entry)1468 bool write_execute_ddl_log_entry(uint first_entry,
1469 bool complete,
1470 DDL_LOG_MEMORY_ENTRY **active_entry)
1471 {
1472 bool write_header= FALSE;
1473 char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
1474 DBUG_ENTER("write_execute_ddl_log_entry");
1475
1476 mysql_mutex_assert_owner(&LOCK_gdl);
1477 if (init_ddl_log())
1478 {
1479 DBUG_RETURN(TRUE);
1480 }
1481 if (!complete)
1482 {
1483 /*
1484 We haven't synched the log entries yet, we synch them now before
1485 writing the execute entry. If complete is true we haven't written
1486 any log entries before, we are only here to write the execute
1487 entry to indicate it is done.
1488 */
1489 (void) sync_ddl_log_no_lock();
1490 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
1491 }
1492 else
1493 file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE;
1494 file_entry_buf[DDL_LOG_ACTION_TYPE_POS]= 0; /* Ignored for execute entries */
1495 file_entry_buf[DDL_LOG_PHASE_POS]= 0;
1496 int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry);
1497 file_entry_buf[DDL_LOG_NAME_POS]= 0;
1498 file_entry_buf[DDL_LOG_NAME_POS + FN_REFLEN]= 0;
1499 file_entry_buf[DDL_LOG_NAME_POS + 2*FN_REFLEN]= 0;
1500 if (!(*active_entry))
1501 {
1502 if (get_free_ddl_log_entry(active_entry, &write_header))
1503 {
1504 DBUG_RETURN(TRUE);
1505 }
1506 write_header= TRUE;
1507 }
1508 if (write_ddl_log_file_entry((*active_entry)->entry_pos))
1509 {
1510 sql_print_error("Error writing execute entry in ddl log");
1511 release_ddl_log_memory_entry(*active_entry);
1512 DBUG_RETURN(TRUE);
1513 }
1514 (void) sync_ddl_log_no_lock();
1515 if (write_header)
1516 {
1517 if (write_ddl_log_header())
1518 {
1519 release_ddl_log_memory_entry(*active_entry);
1520 DBUG_RETURN(TRUE);
1521 }
1522 }
1523 DBUG_RETURN(FALSE);
1524 }
1525
1526
1527 /**
1528 Deactivate an individual entry.
1529
1530 @details see deactivate_ddl_log_entry_no_lock.
1531
1532 @param entry_no Entry position of record to change
1533
1534 @return Operation status
1535 @retval TRUE Error
1536 @retval FALSE Success
1537 */
1538
deactivate_ddl_log_entry(uint entry_no)1539 bool deactivate_ddl_log_entry(uint entry_no)
1540 {
1541 bool error;
1542 DBUG_ENTER("deactivate_ddl_log_entry");
1543
1544 mysql_mutex_lock(&LOCK_gdl);
1545 error= deactivate_ddl_log_entry_no_lock(entry_no);
1546 mysql_mutex_unlock(&LOCK_gdl);
1547 DBUG_RETURN(error);
1548 }
1549
1550
1551 /**
1552 Sync ddl log file.
1553
1554 @return Operation status
1555 @retval TRUE Error
1556 @retval FALSE Success
1557 */
1558
sync_ddl_log()1559 bool sync_ddl_log()
1560 {
1561 bool error;
1562 DBUG_ENTER("sync_ddl_log");
1563
1564 mysql_mutex_lock(&LOCK_gdl);
1565 error= sync_ddl_log_no_lock();
1566 mysql_mutex_unlock(&LOCK_gdl);
1567
1568 DBUG_RETURN(error);
1569 }
1570
1571
1572 /**
1573 Release a log memory entry.
1574 @param log_memory_entry Log memory entry to release
1575 */
1576
release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY * log_entry)1577 void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry)
1578 {
1579 DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free;
1580 DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry;
1581 DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry;
1582 DBUG_ENTER("release_ddl_log_memory_entry");
1583
1584 mysql_mutex_assert_owner(&LOCK_gdl);
1585 global_ddl_log.first_free= log_entry;
1586 log_entry->next_log_entry= first_free;
1587
1588 if (prev_log_entry)
1589 prev_log_entry->next_log_entry= next_log_entry;
1590 else
1591 global_ddl_log.first_used= next_log_entry;
1592 if (next_log_entry)
1593 next_log_entry->prev_log_entry= prev_log_entry;
1594 DBUG_VOID_RETURN;
1595 }
1596
1597
1598 /**
1599 Execute one entry in the ddl log.
1600
1601 Executing an entry means executing a linked list of actions.
1602
1603 @param first_entry Reference to first action in entry
1604
1605 @return Operation status
1606 @retval TRUE Error
1607 @retval FALSE Success
1608 */
1609
execute_ddl_log_entry(THD * thd,uint first_entry)1610 bool execute_ddl_log_entry(THD *thd, uint first_entry)
1611 {
1612 bool error;
1613 DBUG_ENTER("execute_ddl_log_entry");
1614
1615 mysql_mutex_lock(&LOCK_gdl);
1616 error= execute_ddl_log_entry_no_lock(thd, first_entry);
1617 mysql_mutex_unlock(&LOCK_gdl);
1618 DBUG_RETURN(error);
1619 }
1620
1621
1622 /**
1623 Close the ddl log.
1624 */
1625
close_ddl_log()1626 static void close_ddl_log()
1627 {
1628 DBUG_ENTER("close_ddl_log");
1629 if (global_ddl_log.file_id >= 0)
1630 {
1631 (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
1632 global_ddl_log.file_id= (File) -1;
1633 }
1634 DBUG_VOID_RETURN;
1635 }
1636
1637
1638 /**
1639 Execute the ddl log at recovery of MySQL Server.
1640 */
1641
execute_ddl_log_recovery()1642 void execute_ddl_log_recovery()
1643 {
1644 uint num_entries, i;
1645 THD *thd;
1646 DDL_LOG_ENTRY ddl_log_entry;
1647 char file_name[FN_REFLEN];
1648 static char recover_query_string[]= "INTERNAL DDL LOG RECOVER IN PROGRESS";
1649 DBUG_ENTER("execute_ddl_log_recovery");
1650
1651 /*
1652 Initialise global_ddl_log struct
1653 */
1654 bzero(global_ddl_log.file_entry_buf, sizeof(global_ddl_log.file_entry_buf));
1655 global_ddl_log.inited= FALSE;
1656 global_ddl_log.recovery_phase= TRUE;
1657 global_ddl_log.io_size= IO_SIZE;
1658 global_ddl_log.file_id= (File) -1;
1659
1660 /*
1661 To be able to run this from boot, we allocate a temporary THD
1662 */
1663 if (!(thd=new THD(0)))
1664 DBUG_VOID_RETURN;
1665 thd->thread_stack= (char*) &thd;
1666 thd->store_globals();
1667
1668 thd->set_query(recover_query_string, strlen(recover_query_string));
1669
1670 /* this also initialize LOCK_gdl */
1671 num_entries= read_ddl_log_header();
1672 mysql_mutex_lock(&LOCK_gdl);
1673 for (i= 1; i < num_entries + 1; i++)
1674 {
1675 if (read_ddl_log_entry(i, &ddl_log_entry))
1676 {
1677 sql_print_error("Failed to read entry no = %u from ddl log",
1678 i);
1679 continue;
1680 }
1681 if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE)
1682 {
1683 if (execute_ddl_log_entry_no_lock(thd, ddl_log_entry.next_entry))
1684 {
1685 /* Real unpleasant scenario but we continue anyways. */
1686 continue;
1687 }
1688 }
1689 }
1690 close_ddl_log();
1691 create_ddl_log_file_name(file_name);
1692 (void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0));
1693 global_ddl_log.recovery_phase= FALSE;
1694 mysql_mutex_unlock(&LOCK_gdl);
1695 thd->reset_query();
1696 delete thd;
1697 DBUG_VOID_RETURN;
1698 }
1699
1700
1701 /**
1702 Release all memory allocated to the ddl log.
1703 */
1704
release_ddl_log()1705 void release_ddl_log()
1706 {
1707 DDL_LOG_MEMORY_ENTRY *free_list;
1708 DDL_LOG_MEMORY_ENTRY *used_list;
1709 DBUG_ENTER("release_ddl_log");
1710
1711 if (!global_ddl_log.do_release)
1712 DBUG_VOID_RETURN;
1713
1714 mysql_mutex_lock(&LOCK_gdl);
1715 free_list= global_ddl_log.first_free;
1716 used_list= global_ddl_log.first_used;
1717 while (used_list)
1718 {
1719 DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
1720 my_free(used_list);
1721 used_list= tmp;
1722 }
1723 while (free_list)
1724 {
1725 DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
1726 my_free(free_list);
1727 free_list= tmp;
1728 }
1729 close_ddl_log();
1730 global_ddl_log.inited= 0;
1731 mysql_mutex_unlock(&LOCK_gdl);
1732 mysql_mutex_destroy(&LOCK_gdl);
1733 global_ddl_log.do_release= false;
1734 DBUG_VOID_RETURN;
1735 }
1736
1737
1738 /*
1739 ---------------------------------------------------------------------------
1740
1741 END MODULE DDL log
1742 --------------------
1743
1744 ---------------------------------------------------------------------------
1745 */
1746
1747
1748 /**
1749 @brief construct a temporary shadow file name.
1750
1751 @details Make a shadow file name used by ALTER TABLE to construct the
1752 modified table (with keeping the original). The modified table is then
1753 moved back as original table. The name must start with the temp file
1754 prefix so it gets filtered out by table files listing routines.
1755
1756 @param[out] buff buffer to receive the constructed name
1757 @param bufflen size of buff
1758 @param lpt alter table data structure
1759
1760 @retval path length
1761 */
1762
build_table_shadow_filename(char * buff,size_t bufflen,ALTER_PARTITION_PARAM_TYPE * lpt)1763 uint build_table_shadow_filename(char *buff, size_t bufflen,
1764 ALTER_PARTITION_PARAM_TYPE *lpt)
1765 {
1766 char tmp_name[FN_REFLEN];
1767 my_snprintf(tmp_name, sizeof (tmp_name), "%s-shadow-%lx-%s", tmp_file_prefix,
1768 (ulong) current_thd->thread_id, lpt->table_name.str);
1769 return build_table_filename(buff, bufflen, lpt->db.str, tmp_name, "",
1770 FN_IS_TMP);
1771 }
1772
1773
1774 /*
1775 SYNOPSIS
1776 mysql_write_frm()
1777 lpt Struct carrying many parameters needed for this
1778 method
1779 flags Flags as defined below
1780 WFRM_INITIAL_WRITE If set we need to prepare table before
1781 creating the frm file
1782 WFRM_INSTALL_SHADOW If set we should install the new frm
1783 WFRM_KEEP_SHARE If set we know that the share is to be
1784 retained and thus we should ensure share
1785 object is correct, if not set we don't
1786 set the new partition syntax string since
1787 we know the share object is destroyed.
1788 WFRM_PACK_FRM If set we should pack the frm file and delete
1789 the frm file
1790
1791 RETURN VALUES
1792 TRUE Error
1793 FALSE Success
1794
1795 DESCRIPTION
1796 A support method that creates a new frm file and in this process it
1797 regenerates the partition data. It works fine also for non-partitioned
1798 tables since it only handles partitioned data if it exists.
1799 */
1800
mysql_write_frm(ALTER_PARTITION_PARAM_TYPE * lpt,uint flags)1801 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
1802 {
1803 /*
1804 Prepare table to prepare for writing a new frm file where the
1805 partitions in add/drop state have temporarily changed their state
1806 We set tmp_table to avoid get errors on naming of primary key index.
1807 */
1808 int error= 0;
1809 char path[FN_REFLEN+1];
1810 char shadow_path[FN_REFLEN+1];
1811 char shadow_frm_name[FN_REFLEN+1];
1812 char frm_name[FN_REFLEN+1];
1813 #ifdef WITH_PARTITION_STORAGE_ENGINE
1814 char *part_syntax_buf;
1815 uint syntax_len;
1816 #endif
1817 DBUG_ENTER("mysql_write_frm");
1818
1819 /*
1820 Build shadow frm file name
1821 */
1822 build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
1823 strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
1824 if (flags & WFRM_WRITE_SHADOW)
1825 {
1826 if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info,
1827 &lpt->db_options, lpt->table->file,
1828 &lpt->key_info_buffer, &lpt->key_count,
1829 C_ALTER_TABLE, lpt->db, lpt->table_name))
1830 {
1831 DBUG_RETURN(TRUE);
1832 }
1833 #ifdef WITH_PARTITION_STORAGE_ENGINE
1834 {
1835 partition_info *part_info= lpt->table->part_info;
1836 if (part_info)
1837 {
1838 part_syntax_buf= generate_partition_syntax_for_frm(lpt->thd, part_info,
1839 &syntax_len, lpt->create_info, lpt->alter_info);
1840 if (!part_syntax_buf)
1841 DBUG_RETURN(TRUE);
1842 part_info->part_info_string= part_syntax_buf;
1843 part_info->part_info_len= syntax_len;
1844 }
1845 }
1846 #endif
1847 /* Write shadow frm file */
1848 lpt->create_info->table_options= lpt->db_options;
1849 LEX_CUSTRING frm= build_frm_image(lpt->thd, lpt->table_name,
1850 lpt->create_info,
1851 lpt->alter_info->create_list,
1852 lpt->key_count, lpt->key_info_buffer,
1853 lpt->table->file);
1854 if (!frm.str)
1855 {
1856 error= 1;
1857 goto end;
1858 }
1859
1860 int error= writefile(shadow_frm_name, lpt->db.str, lpt->table_name.str,
1861 lpt->create_info->tmp_table(), frm.str, frm.length);
1862 my_free(const_cast<uchar*>(frm.str));
1863
1864 if (unlikely(error) ||
1865 unlikely(lpt->table->file->
1866 ha_create_partitioning_metadata(shadow_path,
1867 NULL, CHF_CREATE_FLAG)))
1868 {
1869 mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
1870 error= 1;
1871 goto end;
1872 }
1873 }
1874 if (flags & WFRM_INSTALL_SHADOW)
1875 {
1876 #ifdef WITH_PARTITION_STORAGE_ENGINE
1877 partition_info *part_info= lpt->part_info;
1878 #endif
1879 /*
1880 Build frm file name
1881 */
1882 build_table_filename(path, sizeof(path) - 1, lpt->db.str,
1883 lpt->table_name.str, "", 0);
1884 strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS);
1885 /*
1886 When we are changing to use new frm file we need to ensure that we
1887 don't collide with another thread in process to open the frm file.
1888 We start by deleting the .frm file and possible .par file. Then we
1889 write to the DDL log that we have completed the delete phase by
1890 increasing the phase of the log entry. Next step is to rename the
1891 new .frm file and the new .par file to the real name. After
1892 completing this we write a new phase to the log entry that will
1893 deactivate it.
1894 */
1895 if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
1896 #ifdef WITH_PARTITION_STORAGE_ENGINE
1897 lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
1898 CHF_DELETE_FLAG) ||
1899 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
1900 (sync_ddl_log(), FALSE) ||
1901 mysql_file_rename(key_file_frm,
1902 shadow_frm_name, frm_name, MYF(MY_WME)) ||
1903 lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
1904 CHF_RENAME_FLAG))
1905 #else
1906 mysql_file_rename(key_file_frm,
1907 shadow_frm_name, frm_name, MYF(MY_WME)))
1908 #endif
1909 {
1910 error= 1;
1911 goto err;
1912 }
1913 #ifdef WITH_PARTITION_STORAGE_ENGINE
1914 if (part_info && (flags & WFRM_KEEP_SHARE))
1915 {
1916 TABLE_SHARE *share= lpt->table->s;
1917 char *tmp_part_syntax_str;
1918 part_syntax_buf= generate_partition_syntax_for_frm(lpt->thd,
1919 part_info, &syntax_len, lpt->create_info, lpt->alter_info);
1920 if (!part_syntax_buf)
1921 {
1922 error= 1;
1923 goto err;
1924 }
1925 if (share->partition_info_buffer_size < syntax_len + 1)
1926 {
1927 share->partition_info_buffer_size= syntax_len+1;
1928 if (!(tmp_part_syntax_str= (char*) strmake_root(&share->mem_root,
1929 part_syntax_buf,
1930 syntax_len)))
1931 {
1932 error= 1;
1933 goto err;
1934 }
1935 share->partition_info_str= tmp_part_syntax_str;
1936 }
1937 else
1938 memcpy((char*) share->partition_info_str, part_syntax_buf,
1939 syntax_len + 1);
1940 share->partition_info_str_len= part_info->part_info_len= syntax_len;
1941 part_info->part_info_string= part_syntax_buf;
1942 }
1943 #endif
1944
1945 err:
1946 #ifdef WITH_PARTITION_STORAGE_ENGINE
1947 deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
1948 part_info->frm_log_entry= NULL;
1949 (void) sync_ddl_log();
1950 #endif
1951 ;
1952 }
1953
1954 end:
1955 DBUG_RETURN(error);
1956 }
1957
1958
1959 /*
1960 SYNOPSIS
1961 write_bin_log()
1962 thd Thread object
1963 clear_error is clear_error to be called
1964 query Query to log
1965 query_length Length of query
1966 is_trans if the event changes either
1967 a trans or non-trans engine.
1968
1969 RETURN VALUES
1970 NONE
1971
1972 DESCRIPTION
1973 Write the binlog if open, routine used in multiple places in this
1974 file
1975 */
1976
write_bin_log(THD * thd,bool clear_error,char const * query,ulong query_length,bool is_trans)1977 int write_bin_log(THD *thd, bool clear_error,
1978 char const *query, ulong query_length, bool is_trans)
1979 {
1980 int error= 0;
1981 if (mysql_bin_log.is_open())
1982 {
1983 int errcode= 0;
1984 thd_proc_info(thd, "Writing to binlog");
1985 if (clear_error)
1986 thd->clear_error();
1987 else
1988 errcode= query_error_code(thd, TRUE);
1989 error= thd->binlog_query(THD::STMT_QUERY_TYPE,
1990 query, query_length, is_trans, FALSE, FALSE,
1991 errcode) > 0;
1992 thd_proc_info(thd, 0);
1993 }
1994 return error;
1995 }
1996
1997
1998 /*
1999 Write to binary log with optional adding "IF EXISTS"
2000
2001 The query is taken from thd->query()
2002 */
2003
write_bin_log_with_if_exists(THD * thd,bool clear_error,bool is_trans,bool add_if_exists)2004 int write_bin_log_with_if_exists(THD *thd, bool clear_error,
2005 bool is_trans, bool add_if_exists)
2006 {
2007 int result;
2008 ulonglong save_option_bits= thd->variables.option_bits;
2009 if (add_if_exists)
2010 thd->variables.option_bits|= OPTION_IF_EXISTS;
2011 result= write_bin_log(thd, clear_error, thd->query(), thd->query_length(),
2012 is_trans);
2013 thd->variables.option_bits= save_option_bits;
2014 return result;
2015 }
2016
2017
2018 /*
2019 delete (drop) tables.
2020
2021 SYNOPSIS
2022 mysql_rm_table()
2023 thd Thread handle
2024 tables List of tables to delete
2025 if_exists If 1, don't give error if one table doesn't exists
2026 drop_temporary 1 if DROP TEMPORARY
2027 drop_sequence 1 if DROP SEQUENCE
2028 dont_log_query 1 if no write to binary log and no send of ok
2029
2030 NOTES
2031 Will delete all tables that can be deleted and give a compact error
2032 messages for tables that could not be deleted.
2033 If a table is in use, we will wait for all users to free the table
2034 before dropping it
2035
2036 Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but
2037 not if under LOCK TABLES.
2038
2039 RETURN
2040 FALSE OK. In this case ok packet is sent to user
2041 TRUE Error
2042
2043 */
2044
mysql_rm_table(THD * thd,TABLE_LIST * tables,bool if_exists,bool drop_temporary,bool drop_sequence,bool dont_log_query)2045 bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists,
2046 bool drop_temporary, bool drop_sequence,
2047 bool dont_log_query)
2048 {
2049 bool error;
2050 Drop_table_error_handler err_handler;
2051 TABLE_LIST *table;
2052 DBUG_ENTER("mysql_rm_table");
2053
2054 /* Disable drop of enabled log tables, must be done before name locking */
2055 for (table= tables; table; table= table->next_local)
2056 {
2057 if (check_if_log_table(table, TRUE, "DROP"))
2058 DBUG_RETURN(true);
2059 }
2060
2061 if (!drop_temporary)
2062 {
2063 if (!thd->locked_tables_mode)
2064 {
2065 if (drop_sequence)
2066 {
2067 /* We are trying to drop a sequence.
2068 Change all temporary tables that are not sequences to
2069 normal tables so that we can try to drop them instead.
2070 If we don't do this, we will get an error 'not a sequence'
2071 when trying to drop a sequence that is hidden by a temporary
2072 table.
2073 */
2074 for (table= tables; table; table= table->next_global)
2075 {
2076 if (table->open_type == OT_TEMPORARY_OR_BASE &&
2077 is_temporary_table(table) && !table->table->s->sequence)
2078 {
2079 thd->mark_tmp_table_as_free_for_reuse(table->table);
2080 table->table= NULL;
2081 }
2082 }
2083 }
2084 if (lock_table_names(thd, tables, NULL,
2085 thd->variables.lock_wait_timeout, 0))
2086 DBUG_RETURN(true);
2087 }
2088 else
2089 {
2090 for (table= tables; table; table= table->next_local)
2091 {
2092 if (is_temporary_table(table))
2093 {
2094 /*
2095 A temporary table.
2096
2097 Don't try to find a corresponding MDL lock or assign it
2098 to table->mdl_request.ticket. There can't be metadata
2099 locks for temporary tables: they are local to the session.
2100
2101 Later in this function we release the MDL lock only if
2102 table->mdl_requeset.ticket is not NULL. Thus here we
2103 ensure that we won't release the metadata lock on the base
2104 table locked with LOCK TABLES as a side effect of temporary
2105 table drop.
2106 */
2107 DBUG_ASSERT(table->mdl_request.ticket == NULL);
2108 }
2109 else
2110 {
2111 /*
2112 Not a temporary table.
2113
2114 Since 'tables' list can't contain duplicates (this is ensured
2115 by parser) it is safe to cache pointer to the TABLE instances
2116 in its elements.
2117 */
2118 table->table= find_table_for_mdl_upgrade(thd, table->db.str,
2119 table->table_name.str, NULL);
2120 if (!table->table)
2121 DBUG_RETURN(true);
2122 table->mdl_request.ticket= table->table->mdl_ticket;
2123 }
2124 }
2125 }
2126 /* We remove statistics for table last, after we have the DDL lock */
2127 for (table= tables; table; table= table->next_local)
2128 {
2129 LEX_CSTRING db_name= table->db;
2130 LEX_CSTRING table_name= table->table_name;
2131 if (table->open_type == OT_BASE_ONLY ||
2132 !thd->find_temporary_table(table))
2133 (void) delete_statistics_for_table(thd, &db_name, &table_name);
2134 }
2135 }
2136
2137 /* mark for close and remove all cached entries */
2138 thd->push_internal_handler(&err_handler);
2139 error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
2140 false, drop_sequence, dont_log_query,
2141 false);
2142 thd->pop_internal_handler();
2143
2144 if (unlikely(error))
2145 DBUG_RETURN(TRUE);
2146 if (!dont_log_query)
2147 my_ok(thd);
2148 DBUG_RETURN(FALSE);
2149 }
2150
2151
2152 /**
2153 Find the comment in the query.
2154 That's auxiliary function to be used handling DROP TABLE [comment].
2155
2156 @param thd Thread handler
2157 @param comment_pos How many characters to skip before the comment.
2158 Can be either 9 for DROP TABLE or
2159 17 for DROP TABLE IF EXISTS
2160 @param comment_start returns the beginning of the comment if found.
2161
2162 @retval 0 no comment found
2163 @retval >0 the lenght of the comment found
2164
2165 */
comment_length(THD * thd,uint32 comment_pos,const char ** comment_start)2166 static uint32 comment_length(THD *thd, uint32 comment_pos,
2167 const char **comment_start)
2168 {
2169 /* We use uchar * here to make array indexing portable */
2170 const uchar *query= (uchar*) thd->query();
2171 const uchar *query_end= (uchar*) query + thd->query_length();
2172 const uchar *const state_map= thd->charset()->state_map;
2173
2174 for (; query < query_end; query++)
2175 {
2176 if (state_map[static_cast<uchar>(*query)] == MY_LEX_SKIP)
2177 continue;
2178 if (comment_pos-- == 0)
2179 break;
2180 }
2181 if (query > query_end - 3 /* comment can't be shorter than 4 */ ||
2182 state_map[static_cast<uchar>(*query)] != MY_LEX_LONG_COMMENT || query[1] != '*')
2183 return 0;
2184
2185 *comment_start= (char*) query;
2186
2187 for (query+= 3; query < query_end; query++)
2188 {
2189 if (query[-1] == '*' && query[0] == '/')
2190 return (uint32)((char*) query - *comment_start + 1);
2191 }
2192 return 0;
2193 }
2194
2195 /**
2196 Execute the drop of a normal or temporary table.
2197
2198 @param thd Thread handler
2199 @param tables Tables to drop
2200 @param if_exists If set, don't give an error if table doesn't exists.
2201 In this case we give an warning of level 'NOTE'
2202 @param drop_temporary Only drop temporary tables
2203 @param drop_view Allow to delete VIEW .frm
2204 @param dont_log_query Don't write query to log files. This will also not
2205 generate warnings if the handler files doesn't exists
2206 @param dont_free_locks Don't do automatic UNLOCK TABLE if no more locked
2207 tables
2208
2209 @retval 0 ok
2210 @retval 1 Error
2211 @retval -1 Thread was killed
2212
2213 @note This function assumes that metadata locks have already been taken.
2214 It is also assumed that the tables have been removed from TDC.
2215
2216 @note This function assumes that temporary tables to be dropped have
2217 been pre-opened using corresponding table list elements.
2218
2219 @todo When logging to the binary log, we should log
2220 tmp_tables and transactional tables as separate statements if we
2221 are in a transaction; This is needed to get these tables into the
2222 cached binary log that is only written on COMMIT.
2223 The current code only writes DROP statements that only uses temporary
2224 tables to the cache binary log. This should be ok on most cases, but
2225 not all.
2226 */
2227
mysql_rm_table_no_locks(THD * thd,TABLE_LIST * tables,bool if_exists,bool drop_temporary,bool drop_view,bool drop_sequence,bool dont_log_query,bool dont_free_locks)2228 int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
2229 bool drop_temporary, bool drop_view,
2230 bool drop_sequence,
2231 bool dont_log_query,
2232 bool dont_free_locks)
2233 {
2234 TABLE_LIST *table;
2235 char path[FN_REFLEN + 1];
2236 LEX_CSTRING alias= null_clex_str;
2237 StringBuffer<160> unknown_tables(system_charset_info);
2238 uint not_found_errors= 0;
2239 int error= 0;
2240 int non_temp_tables_count= 0;
2241 bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
2242 bool non_tmp_table_deleted= 0;
2243 bool is_drop_tmp_if_exists_added= 0;
2244 bool was_view= 0, log_if_exists= if_exists;
2245 const char *object_to_drop= (drop_sequence) ? "SEQUENCE" : "TABLE";
2246 String normal_tables;
2247 String built_trans_tmp_query, built_non_trans_tmp_query;
2248 DBUG_ENTER("mysql_rm_table_no_locks");
2249
2250 unknown_tables.length(0);
2251 /*
2252 Prepares the drop statements that will be written into the binary
2253 log as follows:
2254
2255 1 - If we are not processing a "DROP TEMPORARY" it prepares a
2256 "DROP".
2257
2258 2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
2259 not true.
2260
2261 3 - If the current format is row, the IF EXISTS token needs to be
2262 appended because one does not know if CREATE TEMPORARY was previously
2263 written to the binary log.
2264
2265 4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
2266
2267 5 - For temporary tables, there is a need to differentiate tables
2268 in transactional and non-transactional storage engines. For that,
2269 reason, two types of drop statements are prepared.
2270
2271 The need to different the type of tables when dropping a temporary
2272 table stems from the fact that such drop does not commit an ongoing
2273 transaction and changes to non-transactional tables must be written
2274 ahead of the transaction in some circumstances.
2275
2276 6- Slave SQL thread ignores all replicate-* filter rules
2277 for temporary tables with 'IF EXISTS' clause. (See sql/sql_parse.cc:
2278 mysql_execute_command() for details). These commands will be binlogged
2279 as they are, even if the default database (from USE `db`) is not present
2280 on the Slave. This can cause point in time recovery failures later
2281 when user uses the slave's binlog to re-apply. Hence at the time of binary
2282 logging, these commands will be written with fully qualified table names
2283 and use `db` will be suppressed.
2284 */
2285
2286 normal_tables.set_charset(thd->charset());
2287 if (!dont_log_query)
2288 {
2289 built_trans_tmp_query.set_charset(system_charset_info);
2290 built_trans_tmp_query.append("DROP TEMPORARY ");
2291 built_trans_tmp_query.append(object_to_drop);
2292 built_trans_tmp_query.append(' ');
2293 if (thd->is_current_stmt_binlog_format_row() || if_exists)
2294 {
2295 is_drop_tmp_if_exists_added= true;
2296 built_trans_tmp_query.append("IF EXISTS ");
2297 }
2298 built_non_trans_tmp_query.set_charset(system_charset_info);
2299 built_non_trans_tmp_query.copy(built_trans_tmp_query);
2300 }
2301
2302 for (table= tables; table; table= table->next_local)
2303 {
2304 bool is_trans= 0, temporary_table_was_dropped= 0;
2305 bool table_creation_was_logged= 0;
2306 bool wrong_drop_sequence= 0;
2307 bool table_dropped= 0;
2308 const LEX_CSTRING db= table->db;
2309 const LEX_CSTRING table_name= table->table_name;
2310 handlerton *hton= 0;
2311 Table_type table_type;
2312 size_t path_length= 0;
2313 char *path_end= 0;
2314 error= 0;
2315
2316 DBUG_PRINT("table", ("table_l: '%s'.'%s' table: %p s: %p",
2317 db.str, table_name.str, table->table,
2318 table->table ? table->table->s : NULL));
2319
2320 /*
2321 If we are in locked tables mode and are dropping a temporary table,
2322 the ticket should be NULL to ensure that we don't release a lock
2323 on a base table later.
2324 */
2325 DBUG_ASSERT(!(thd->locked_tables_mode &&
2326 table->open_type != OT_BASE_ONLY &&
2327 thd->find_temporary_table(table) &&
2328 table->mdl_request.ticket != NULL));
2329
2330 if (drop_sequence && table->table &&
2331 table->table->s->table_type != TABLE_TYPE_SEQUENCE)
2332 {
2333 if (if_exists)
2334 {
2335 char buff[FN_REFLEN];
2336 String tbl_name(buff, sizeof(buff), system_charset_info);
2337 tbl_name.length(0);
2338 tbl_name.append(&db);
2339 tbl_name.append('.');
2340 tbl_name.append(&table->table_name);
2341 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
2342 ER_NOT_SEQUENCE2, ER_THD(thd, ER_NOT_SEQUENCE2),
2343 tbl_name.c_ptr_safe());
2344
2345 /*
2346 Our job is done here. This statement was added to avoid executing
2347 unnecessary code farther below which in some strange corner cases
2348 caused the server to crash (see MDEV-17896).
2349 */
2350 continue;
2351 }
2352 /* "DROP SEQUENCE" but a sequence table was not found */
2353 unknown_tables.append(&db);
2354 unknown_tables.append('.');
2355 unknown_tables.append(&table_name);
2356 unknown_tables.append(',');
2357 error= ENOENT;
2358 not_found_errors++;
2359 continue;
2360 }
2361
2362 /* First try to delete temporary tables and temporary sequences */
2363 if ((table->open_type != OT_BASE_ONLY && is_temporary_table(table)))
2364 {
2365 table_creation_was_logged= table->table->s->table_creation_was_logged;
2366 if (thd->drop_temporary_table(table->table, &is_trans, true))
2367 error= 1;
2368 else
2369 {
2370 table->table= 0;
2371 temporary_table_was_dropped= 1;
2372 }
2373 }
2374
2375 if ((drop_temporary && if_exists) || temporary_table_was_dropped)
2376 {
2377 /*
2378 This handles the case of temporary tables. We have the following cases:
2379
2380 - "DROP TEMPORARY" was executed and table was dropped
2381 temporary_table_was_dropped == 1
2382 - "DROP TEMPORARY IF EXISTS" was specified but no temporary table
2383 existed
2384 temporary_table_was_dropped == 0
2385 */
2386 if (!dont_log_query && table_creation_was_logged)
2387 {
2388 if (is_trans)
2389 trans_tmp_table_deleted= TRUE;
2390 else
2391 non_trans_tmp_table_deleted= TRUE;
2392
2393 String *built_ptr_query=
2394 (is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
2395 /*
2396 Write the database name if it is not the current one or if
2397 thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY'
2398 query.
2399 */
2400 if (thd->db.str == NULL || cmp(&db, &thd->db) ||
2401 is_drop_tmp_if_exists_added )
2402 {
2403 append_identifier(thd, built_ptr_query, &db);
2404 built_ptr_query->append(".");
2405 }
2406 append_identifier(thd, built_ptr_query, &table_name);
2407 built_ptr_query->append(",");
2408 }
2409 /*
2410 This means that a temporary table was droped and as such there
2411 is no need to proceed with the code that tries to drop a regular
2412 table.
2413 */
2414 if (temporary_table_was_dropped)
2415 continue;
2416 }
2417 else if (!drop_temporary)
2418 {
2419 non_temp_tables_count++;
2420
2421 DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db.str,
2422 table_name.str, MDL_SHARED));
2423
2424 alias= (lower_case_table_names == 2) ? table->alias : table_name;
2425 /* remove .frm file and engine files */
2426 path_length= build_table_filename(path, sizeof(path) - 1, db.str,
2427 alias.str, reg_ext, 0);
2428 path_end= path + path_length - reg_ext_length;
2429 }
2430
2431 DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
2432 if (drop_temporary)
2433 {
2434 /* "DROP TEMPORARY" but a temporary table was not found */
2435 unknown_tables.append(&db);
2436 unknown_tables.append('.');
2437 unknown_tables.append(&table_name);
2438 unknown_tables.append(',');
2439 error= ENOENT;
2440 not_found_errors++;
2441 continue;
2442 }
2443
2444 {
2445 char engine_buf[NAME_CHAR_LEN + 1];
2446 LEX_CSTRING engine= { engine_buf, 0 };
2447
2448 table_type= dd_frm_type(thd, path, &engine);
2449 if (table_type == TABLE_TYPE_NORMAL || table_type == TABLE_TYPE_SEQUENCE)
2450 {
2451 plugin_ref p= plugin_lock_by_name(thd, &engine,
2452 MYSQL_STORAGE_ENGINE_PLUGIN);
2453 hton= p ? plugin_hton(p) : NULL;
2454 }
2455 // note that for TABLE_TYPE_VIEW and TABLE_TYPE_UNKNOWN hton == NULL
2456 }
2457
2458 thd->replication_flags= 0;
2459 was_view= table_type == TABLE_TYPE_VIEW;
2460 if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) ||
2461 (table_type != TABLE_TYPE_SEQUENCE && drop_sequence))
2462 {
2463 /*
2464 One of the following cases happened:
2465 . "DROP" but table was not found
2466 . "DROP TABLE" statement, but it's a view.
2467 . "DROP SEQUENCE", but it's not a sequence
2468 */
2469 wrong_drop_sequence= drop_sequence && hton;
2470 error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1;
2471 tdc_remove_table(thd, db.str, table_name.str);
2472 }
2473 else
2474 {
2475 if (WSREP(thd) && hton && !wsrep_should_replicate_ddl(thd, hton->db_type))
2476 {
2477 error= 1;
2478 goto err;
2479 }
2480
2481 if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
2482 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
2483 {
2484 if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED))
2485 {
2486 error= -1;
2487 goto err;
2488 }
2489 close_all_tables_for_name(thd, table->table->s,
2490 HA_EXTRA_PREPARE_FOR_DROP, NULL);
2491 table->table= 0;
2492 }
2493 else
2494 tdc_remove_table(thd, db.str, table_name.str);
2495
2496 /* Check that we have an exclusive lock on the table to be dropped. */
2497 DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, db.str,
2498 table_name.str, MDL_EXCLUSIVE));
2499
2500 // Remove extension for delete
2501 *path_end= '\0';
2502
2503 if (hton && hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
2504 log_if_exists= 1;
2505
2506 bool enoent_warning= !dont_log_query && !(hton && hton->discover_table);
2507 error= ha_delete_table(thd, hton, path, &db, &table_name, enoent_warning);
2508
2509 if (!error)
2510 table_dropped= 1;
2511 else if (error < 0)
2512 error= 0; // Table didn't exists
2513 else if (error)
2514 {
2515 if (thd->is_killed())
2516 {
2517 error= -1;
2518 goto err;
2519 }
2520 }
2521
2522 /*
2523 Delete the .frm file if we managed to delete the table from the
2524 engine or the table didn't exists in the engine
2525 */
2526 strmov(path_end, reg_ext);
2527 if ((likely(!error) || non_existing_table_error(error)) &&
2528 !access(path, F_OK))
2529 {
2530 int frm_delete_error= 0;
2531 /* Delete the table definition file */
2532 if (hton && (hton->discover_table || error))
2533 {
2534 /*
2535 Table type is using discovery and may not need a .frm file
2536 or the .frm file existed but no table in engine.
2537 Delete it silently if it exists
2538 */
2539 if (mysql_file_delete(key_file_frm, path,
2540 MYF(MY_WME | MY_IGNORE_ENOENT)))
2541 frm_delete_error= my_errno;
2542 }
2543 else if (unlikely(mysql_file_delete(key_file_frm, path,
2544 !error ? MYF(MY_WME) :
2545 MYF(MY_WME | MY_IGNORE_ENOENT))))
2546 {
2547 frm_delete_error= my_errno;
2548 DBUG_ASSERT(frm_delete_error);
2549 }
2550
2551 if (frm_delete_error)
2552 {
2553 /* Remember unexpected error from dropping the .frm file */
2554 error= frm_delete_error;
2555 }
2556 else
2557 {
2558 error= 0; // We succeeded to delete the frm
2559 table_dropped= 1;
2560 }
2561 }
2562 }
2563
2564 /*
2565 If there was no .frm file and the table is not temporary,
2566 scan all engines try to drop the table from there.
2567 This is to ensure we don't have any partial table files left.
2568 */
2569 if (non_existing_table_error(error) && !wrong_drop_sequence)
2570 {
2571 int ferror= 0;
2572 DBUG_ASSERT(!was_view);
2573
2574 /* Remove extension for delete */
2575 *path_end= '\0';
2576 ferror= ha_delete_table_force(thd, path, &db, &table_name);
2577 if (!ferror)
2578 {
2579 table_dropped= 1;
2580 error= 0;
2581 }
2582 if (ferror <= 0)
2583 {
2584 ferror= 0; // Ignore table not found
2585
2586 /* Delete the frm file again (just in case it was rediscovered) */
2587 strmov(path_end, reg_ext);
2588 if (mysql_file_delete(key_file_frm, path, MYF(MY_WME|MY_IGNORE_ENOENT)))
2589 ferror= my_errno;
2590 }
2591 if (!error)
2592 error= ferror;
2593 }
2594
2595 /*
2596 This may be set
2597 - by the storage engine in handler::delete_table()
2598 - when deleting a table without .frm file: delete_table_force() will
2599 check if the storage engine that had the table had
2600 HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE flag
2601 */
2602 if (thd->replication_flags & OPTION_IF_EXISTS)
2603 log_if_exists= 1;
2604
2605 if (likely(!error) || non_existing_table_error(error))
2606 {
2607 if (Table_triggers_list::drop_all_triggers(thd, &db, &table_name,
2608 MYF(MY_WME | MY_IGNORE_ENOENT)))
2609 error= error ? error : -1;
2610 }
2611
2612 if (error)
2613 {
2614 StringBuffer<FN_REFLEN> tbl_name(system_charset_info);
2615 uint is_note= (if_exists && (was_view || wrong_drop_sequence) ?
2616 ME_NOTE : 0);
2617
2618 tbl_name.length(0);
2619 tbl_name.append(&db);
2620 tbl_name.append('.');
2621 tbl_name.append(&table_name);
2622
2623 if (!non_existing_table_error(error) || is_note)
2624 {
2625 /*
2626 Error from engine already given. Here we only have to take
2627 care about errors for trying to drop view or sequence
2628 */
2629 if (was_view)
2630 my_error(ER_IT_IS_A_VIEW, MYF(is_note), tbl_name.c_ptr_safe());
2631 else if (wrong_drop_sequence)
2632 my_error(ER_NOT_SEQUENCE2, MYF(is_note), tbl_name.c_ptr_safe());
2633 if (is_note)
2634 error= ENOENT;
2635 }
2636 else
2637 {
2638 not_found_errors++;
2639 if (unknown_tables.append(tbl_name) || unknown_tables.append(','))
2640 {
2641 error= 1;
2642 goto err;
2643 }
2644 }
2645 }
2646
2647 /*
2648 Don't give an error if we are using IF EXISTS for a table that
2649 didn't exists
2650 */
2651 if (if_exists && non_existing_table_error(error))
2652 error= 0;
2653
2654 if (!error && table_dropped)
2655 {
2656 PSI_CALL_drop_table_share(temporary_table_was_dropped,
2657 db.str, (uint)db.length,
2658 table_name.str, (uint)table_name.length);
2659 mysql_audit_drop_table(thd, table);
2660 }
2661
2662 if (!dont_log_query &&
2663 (!error || table_dropped || non_existing_table_error(error)))
2664 {
2665 non_tmp_table_deleted|= (if_exists || table_dropped);
2666 /*
2667 Don't write the database name if it is the current one (or if
2668 thd->db is NULL).
2669 */
2670 if (thd->db.str == NULL || cmp(&db, &thd->db) != 0)
2671 {
2672 append_identifier(thd, &normal_tables, &db);
2673 normal_tables.append(".");
2674 }
2675
2676 append_identifier(thd, &normal_tables, &table_name);
2677 normal_tables.append(",");
2678 }
2679 DBUG_PRINT("table", ("table: %p s: %p", table->table,
2680 table->table ? table->table->s : NULL));
2681 }
2682 DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
2683 thd->thread_specific_used= TRUE;
2684 error= 0;
2685
2686 err:
2687 if (unknown_tables.length() > 1)
2688 {
2689 uint is_note= if_exists ? ME_NOTE : 0;
2690 unknown_tables.chop();
2691 my_error((drop_sequence ? ER_UNKNOWN_SEQUENCES : ER_BAD_TABLE_ERROR),
2692 MYF(is_note), unknown_tables.c_ptr_safe());
2693 }
2694 error= thd->is_error();
2695
2696 /*
2697 We are always logging drop of temporary tables.
2698 The reason is to handle the following case:
2699 - Use statement based replication
2700 - CREATE TEMPORARY TABLE foo (logged)
2701 - set row based replication
2702 - DROP TEMPORAY TABLE foo (needs to be logged)
2703 This should be fixed so that we remember if creation of the
2704 temporary table was logged and only log it if the creation was
2705 logged.
2706 */
2707
2708 if (non_trans_tmp_table_deleted ||
2709 trans_tmp_table_deleted || non_tmp_table_deleted)
2710 {
2711 if (non_trans_tmp_table_deleted || trans_tmp_table_deleted)
2712 thd->transaction->stmt.mark_dropped_temp_table();
2713
2714 query_cache_invalidate3(thd, tables, 0);
2715 if (!dont_log_query && mysql_bin_log.is_open())
2716 {
2717 if (non_trans_tmp_table_deleted)
2718 {
2719 /* Chop of the last comma */
2720 built_non_trans_tmp_query.chop();
2721 built_non_trans_tmp_query.append(" /* generated by server */");
2722 error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
2723 built_non_trans_tmp_query.ptr(),
2724 built_non_trans_tmp_query.length(),
2725 FALSE, FALSE,
2726 is_drop_tmp_if_exists_added,
2727 0) > 0);
2728 }
2729 if (trans_tmp_table_deleted)
2730 {
2731 /* Chop of the last comma */
2732 built_trans_tmp_query.chop();
2733 built_trans_tmp_query.append(" /* generated by server */");
2734 error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
2735 built_trans_tmp_query.ptr(),
2736 built_trans_tmp_query.length(),
2737 TRUE, FALSE,
2738 is_drop_tmp_if_exists_added,
2739 0) > 0);
2740 }
2741 if (non_tmp_table_deleted)
2742 {
2743 String built_query;
2744 const char *comment_start;
2745 uint32 comment_len;
2746
2747 built_query.set_charset(thd->charset());
2748 built_query.append("DROP ");
2749 built_query.append(object_to_drop);
2750 built_query.append(' ');
2751 if (log_if_exists)
2752 built_query.append("IF EXISTS ");
2753
2754 /* Preserve comment in original query */
2755 if ((comment_len= comment_length(thd, if_exists ? 17:9,
2756 &comment_start)))
2757 {
2758 built_query.append(comment_start, comment_len);
2759 built_query.append(" ");
2760 }
2761
2762 /* Chop of the last comma */
2763 normal_tables.chop();
2764 built_query.append(normal_tables.ptr(), normal_tables.length());
2765 built_query.append(" /* generated by server */");
2766 error |= (thd->binlog_query(THD::STMT_QUERY_TYPE,
2767 built_query.ptr(),
2768 built_query.length(),
2769 TRUE, FALSE, FALSE, 0) > 0);
2770 }
2771 }
2772 }
2773
2774 if (!drop_temporary)
2775 {
2776 /*
2777 Under LOCK TABLES we should release meta-data locks on the tables
2778 which were dropped.
2779
2780 Leave LOCK TABLES mode if we managed to drop all tables which were
2781 locked. Additional check for 'non_temp_tables_count' is to avoid
2782 leaving LOCK TABLES mode if we have dropped only temporary tables.
2783 */
2784 if (thd->locked_tables_mode)
2785 {
2786 if (thd->lock && thd->lock->table_count == 0 &&
2787 non_temp_tables_count > 0 && !dont_free_locks)
2788 {
2789 if (thd->locked_tables_list.unlock_locked_tables(thd))
2790 error= 1;
2791 goto end;
2792 }
2793 for (table= tables; table; table= table->next_local)
2794 {
2795 /* Drop locks for all successfully dropped tables. */
2796 if (table->table == NULL && table->mdl_request.ticket)
2797 {
2798 /*
2799 Under LOCK TABLES we may have several instances of table open
2800 and locked and therefore have to remove several metadata lock
2801 requests associated with them.
2802 */
2803 thd->mdl_context.release_all_locks_for_name(table->mdl_request.ticket);
2804 }
2805 }
2806 }
2807 /*
2808 Rely on the caller to implicitly commit the transaction
2809 and release metadata locks.
2810 */
2811 }
2812
2813 end:
2814 DBUG_RETURN(error || thd->is_error());
2815 }
2816
2817
2818 /**
2819 Log the drop of a table.
2820
2821 @param thd Thread handler
2822 @param db_name Database name
2823 @param table_name Table name
2824 @param temporary_table 1 if table was a temporary table
2825
2826 This code is only used in the case of failed CREATE OR REPLACE TABLE
2827 when the original table was dropped but we could not create the new one.
2828 */
2829
log_drop_table(THD * thd,const LEX_CSTRING * db_name,const LEX_CSTRING * table_name,bool temporary_table)2830 bool log_drop_table(THD *thd, const LEX_CSTRING *db_name,
2831 const LEX_CSTRING *table_name,
2832 bool temporary_table)
2833 {
2834 char buff[NAME_LEN*2 + 80];
2835 String query(buff, sizeof(buff), system_charset_info);
2836 bool error;
2837 DBUG_ENTER("log_drop_table");
2838
2839 if (!mysql_bin_log.is_open())
2840 DBUG_RETURN(0);
2841
2842 query.length(0);
2843 query.append(STRING_WITH_LEN("DROP "));
2844 if (temporary_table)
2845 query.append(STRING_WITH_LEN("TEMPORARY "));
2846 query.append(STRING_WITH_LEN("TABLE IF EXISTS "));
2847 append_identifier(thd, &query, db_name);
2848 query.append(".");
2849 append_identifier(thd, &query, table_name);
2850 query.append(STRING_WITH_LEN("/* Generated to handle "
2851 "failed CREATE OR REPLACE */"));
2852
2853 /*
2854 In case of temporary tables we don't have to log the database name
2855 in the binary log. We log this for non temporary tables, as the slave
2856 may use a filter to ignore queries for a specific database.
2857 */
2858 error= thd->binlog_query(THD::STMT_QUERY_TYPE,
2859 query.ptr(), query.length(),
2860 FALSE, FALSE, temporary_table, 0) > 0;
2861 DBUG_RETURN(error);
2862 }
2863
2864
2865 /**
2866 Quickly remove a table without bin logging
2867
2868 @param thd Thread context.
2869 @param base The handlerton handle.
2870 @param db The database name.
2871 @param table_name The table name.
2872 @param flags Flags for build_table_filename() as well as describing
2873 if handler files / .FRM should be deleted as well.
2874
2875 @return False in case of success, True otherwise.
2876 */
2877
quick_rm_table(THD * thd,handlerton * base,const LEX_CSTRING * db,const LEX_CSTRING * table_name,uint flags,const char * table_path)2878 bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
2879 const LEX_CSTRING *table_name, uint flags,
2880 const char *table_path)
2881 {
2882 char path[FN_REFLEN + 1];
2883 int error= 0;
2884 DBUG_ENTER("quick_rm_table");
2885
2886 size_t path_length= table_path ?
2887 (strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) :
2888 build_table_filename(path, sizeof(path)-1, db->str, table_name->str,
2889 reg_ext, flags);
2890 if (!(flags & NO_FRM_RENAME))
2891 if (mysql_file_delete(key_file_frm, path, MYF(0)))
2892 error= 1; /* purecov: inspected */
2893 path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
2894 if ((flags & (NO_HA_TABLE | NO_PAR_TABLE)) == NO_HA_TABLE)
2895 {
2896 handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
2897 if (!file)
2898 DBUG_RETURN(true);
2899 (void) file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG);
2900 delete file;
2901 }
2902 if (!(flags & (FRM_ONLY|NO_HA_TABLE)))
2903 if (ha_delete_table(thd, base, path, db, table_name, 0) > 0)
2904 error= 1;
2905
2906 if (likely(error == 0))
2907 {
2908 PSI_CALL_drop_table_share(flags & FN_IS_TMP, db->str, (uint)db->length,
2909 table_name->str, (uint)table_name->length);
2910 }
2911
2912 DBUG_RETURN(error);
2913 }
2914
2915
2916 /*
2917 Sort keys in the following order:
2918 - PRIMARY KEY
2919 - UNIQUE keys where all column are NOT NULL
2920 - UNIQUE keys that don't contain partial segments
2921 - Other UNIQUE keys
2922 - LONG UNIQUE keys
2923 - Normal keys
2924 - Fulltext keys
2925
2926 This will make checking for duplicated keys faster and ensure that
2927 PRIMARY keys are prioritized.
2928 */
2929
sort_keys(KEY * a,KEY * b)2930 static int sort_keys(KEY *a, KEY *b)
2931 {
2932 ulong a_flags= a->flags, b_flags= b->flags;
2933
2934 /*
2935 Do not reorder LONG_HASH indexes, because they must match the order
2936 of their LONG_UNIQUE_HASH_FIELD's.
2937 */
2938 if (a->algorithm == HA_KEY_ALG_LONG_HASH &&
2939 b->algorithm == HA_KEY_ALG_LONG_HASH)
2940 return a->usable_key_parts - b->usable_key_parts;
2941
2942 if (a_flags & HA_NOSAME)
2943 {
2944 if (!(b_flags & HA_NOSAME))
2945 return -1;
2946 /*
2947 Long Unique keys should always be last unique key.
2948 Before this patch they used to change order wrt to partial keys (MDEV-19049)
2949 */
2950 if (a->algorithm == HA_KEY_ALG_LONG_HASH)
2951 return 1;
2952 if (b->algorithm == HA_KEY_ALG_LONG_HASH)
2953 return -1;
2954 if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
2955 {
2956 /* Sort NOT NULL keys before other keys */
2957 return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
2958 }
2959 if (a->name.str == primary_key_name)
2960 return -1;
2961 if (b->name.str == primary_key_name)
2962 return 1;
2963 /* Sort keys don't containing partial segments before others */
2964 if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
2965 return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
2966 }
2967 else if (b_flags & HA_NOSAME)
2968 return 1; // Prefer b
2969
2970 if ((a_flags ^ b_flags) & HA_FULLTEXT)
2971 {
2972 return (a_flags & HA_FULLTEXT) ? 1 : -1;
2973 }
2974 /*
2975 Prefer original key order. usable_key_parts contains here
2976 the original key position.
2977 */
2978 return a->usable_key_parts - b->usable_key_parts;
2979 }
2980
2981 /*
2982 Check TYPELIB (set or enum) for duplicates
2983
2984 SYNOPSIS
2985 check_duplicates_in_interval()
2986 set_or_name "SET" or "ENUM" string for warning message
2987 name name of the checked column
2988 typelib list of values for the column
2989 dup_val_count returns count of duplicate elements
2990
2991 DESCRIPTION
2992 This function prints an warning for each value in list
2993 which has some duplicates on its right
2994
2995 RETURN VALUES
2996 0 ok
2997 1 Error
2998 */
2999
check_duplicates_in_interval(const char * set_or_name,const char * name,const TYPELIB * typelib,CHARSET_INFO * cs,unsigned int * dup_val_count)3000 bool check_duplicates_in_interval(const char *set_or_name,
3001 const char *name, const TYPELIB *typelib,
3002 CHARSET_INFO *cs, unsigned int *dup_val_count)
3003 {
3004 TYPELIB tmp= *typelib;
3005 const char **cur_value= typelib->type_names;
3006 unsigned int *cur_length= typelib->type_lengths;
3007 *dup_val_count= 0;
3008
3009 for ( ; tmp.count > 1; cur_value++, cur_length++)
3010 {
3011 tmp.type_names++;
3012 tmp.type_lengths++;
3013 tmp.count--;
3014 if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
3015 {
3016 THD *thd= current_thd;
3017 ErrConvString err(*cur_value, *cur_length, cs);
3018 if (current_thd->is_strict_mode())
3019 {
3020 my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
3021 name, err.ptr(), set_or_name);
3022 return 1;
3023 }
3024 push_warning_printf(thd,Sql_condition::WARN_LEVEL_NOTE,
3025 ER_DUPLICATED_VALUE_IN_TYPE,
3026 ER_THD(thd, ER_DUPLICATED_VALUE_IN_TYPE),
3027 name, err.ptr(), set_or_name);
3028 (*dup_val_count)++;
3029 }
3030 }
3031 return 0;
3032 }
3033
3034
3035 bool Column_definition::
prepare_charset_for_string(const Column_derived_attributes * dattr)3036 prepare_charset_for_string(const Column_derived_attributes *dattr)
3037 {
3038 if (!charset)
3039 charset= dattr->charset();
3040 return (flags & BINCMP_FLAG) && !(charset= find_bin_collation(charset));
3041 }
3042
3043
prepare_stage2_blob(handler * file,ulonglong table_flags,uint field_flags)3044 bool Column_definition::prepare_stage2_blob(handler *file,
3045 ulonglong table_flags,
3046 uint field_flags)
3047 {
3048 if (table_flags & HA_NO_BLOBS)
3049 {
3050 my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type());
3051 return true;
3052 }
3053 pack_flag= field_flags |
3054 pack_length_to_packflag(pack_length - portable_sizeof_char_ptr);
3055 if (charset->state & MY_CS_BINSORT)
3056 pack_flag|= FIELDFLAG_BINARY;
3057 length= 8; // Unireg field length
3058 return false;
3059 }
3060
3061
prepare_stage2_typelib(const char * type_name,uint field_flags,uint * dup_val_count)3062 bool Column_definition::prepare_stage2_typelib(const char *type_name,
3063 uint field_flags,
3064 uint *dup_val_count)
3065 {
3066 pack_flag= pack_length_to_packflag(pack_length) | field_flags;
3067 if (charset->state & MY_CS_BINSORT)
3068 pack_flag|= FIELDFLAG_BINARY;
3069 return check_duplicates_in_interval(type_name, field_name.str, interval,
3070 charset, dup_val_count);
3071 }
3072
3073
pack_flag_numeric() const3074 uint Column_definition::pack_flag_numeric() const
3075 {
3076 return (FIELDFLAG_NUMBER |
3077 (flags & UNSIGNED_FLAG ? 0 : FIELDFLAG_DECIMAL) |
3078 (flags & ZEROFILL_FLAG ? FIELDFLAG_ZEROFILL : 0));
3079 }
3080
3081
prepare_stage2_varchar(ulonglong table_flags)3082 bool Column_definition::prepare_stage2_varchar(ulonglong table_flags)
3083 {
3084 pack_flag= (charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0;
3085 return false;
3086 }
3087
3088
3089 /*
3090 Prepare a Column_definition instance for packing
3091 Members such as pack_flag are valid after this call.
3092
3093 @param IN handler - storage engine handler,
3094 or NULL if preparing for an SP variable
3095 @param IN table_flags - table flags
3096
3097 @retval false - ok
3098 @retval true - error (not supported type, bad definition, etc)
3099 */
3100
prepare_stage2(handler * file,ulonglong table_flags)3101 bool Column_definition::prepare_stage2(handler *file,
3102 ulonglong table_flags)
3103 {
3104 DBUG_ENTER("Column_definition::prepare_stage2");
3105
3106 /*
3107 This code came from mysql_prepare_create_table.
3108 Indent preserved to make patching easier
3109 */
3110 DBUG_ASSERT(charset);
3111
3112 if (type_handler()->Column_definition_prepare_stage2(this, file, table_flags))
3113 DBUG_RETURN(true);
3114
3115 if (!(flags & NOT_NULL_FLAG) ||
3116 (vcol_info)) /* Make virtual columns allow NULL values */
3117 pack_flag|= FIELDFLAG_MAYBE_NULL;
3118 if (flags & NO_DEFAULT_VALUE_FLAG)
3119 pack_flag|= FIELDFLAG_NO_DEFAULT;
3120 DBUG_RETURN(false);
3121 }
3122
3123
3124 /**
3125 Modifies the first column definition whose SQL type is TIMESTAMP
3126 by adding the features DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
3127
3128 If the first TIMESTAMP column appears to be nullable, or to have an
3129 explicit default, or to be a virtual column, or to be part of table period,
3130 then no promotion is done.
3131
3132 @param column_definitions The list of column definitions, in the physical
3133 order in which they appear in the table.
3134 */
3135
promote_first_timestamp_column(List<Create_field> * column_definitions)3136 void promote_first_timestamp_column(List<Create_field> *column_definitions)
3137 {
3138 for (Create_field &column_definition : *column_definitions)
3139 {
3140 if (column_definition.is_timestamp_type() || // TIMESTAMP
3141 column_definition.unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
3142 {
3143 DBUG_PRINT("info", ("field-ptr:%p", column_definition.field));
3144 if ((column_definition.flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
3145 column_definition.default_value == NULL && // no constant default,
3146 column_definition.unireg_check == Field::NONE && // no function default
3147 column_definition.vcol_info == NULL &&
3148 column_definition.period == NULL &&
3149 !(column_definition.flags & VERS_SYSTEM_FIELD)) // column isn't generated
3150 {
3151 DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to "
3152 "DEFAULT CURRENT_TIMESTAMP ON UPDATE "
3153 "CURRENT_TIMESTAMP",
3154 column_definition.field_name.str
3155 ));
3156 column_definition.unireg_check= Field::TIMESTAMP_DNUN_FIELD;
3157 }
3158 return;
3159 }
3160 }
3161 }
3162
key_cmp(const Key_part_spec & a,const Key_part_spec & b)3163 static bool key_cmp(const Key_part_spec &a, const Key_part_spec &b)
3164 {
3165 return a.length == b.length &&
3166 !lex_string_cmp(system_charset_info, &a.field_name, &b.field_name);
3167 }
3168
3169 /**
3170 Check if there is a duplicate key. Report a warning for every duplicate key.
3171
3172 @param thd Thread context.
3173 @param key Key to be checked.
3174 @param key_info Key meta-data info.
3175 @param key_list List of existing keys.
3176 */
check_duplicate_key(THD * thd,const Key * key,const KEY * key_info,const List<Key> * key_list)3177 static void check_duplicate_key(THD *thd, const Key *key, const KEY *key_info,
3178 const List<Key> *key_list)
3179 {
3180 /*
3181 We only check for duplicate indexes if it is requested and the
3182 key is not auto-generated.
3183
3184 Check is requested if the key was explicitly created or altered
3185 by the user (unless it's a foreign key).
3186 */
3187 if (!key->key_create_info.check_for_duplicate_indexes || key->generated)
3188 return;
3189
3190 for (const Key &k : *key_list)
3191 {
3192 // Looking for a similar key...
3193
3194 if (&k == key)
3195 break;
3196
3197 if (k.generated ||
3198 (key->type != k.type) ||
3199 (key->key_create_info.algorithm != k.key_create_info.algorithm) ||
3200 (key->columns.elements != k.columns.elements))
3201 {
3202 // Keys are different.
3203 continue;
3204 }
3205
3206 if (std::equal(key->columns.begin(), key->columns.end(), k.columns.begin(),
3207 key_cmp))
3208 {
3209 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_DUP_INDEX,
3210 ER_THD(thd, ER_DUP_INDEX), key_info->name.str);
3211 return;
3212 }
3213 }
3214 }
3215
3216
prepare_stage1_typelib(THD * thd,MEM_ROOT * mem_root,handler * file,ulonglong table_flags)3217 bool Column_definition::prepare_stage1_typelib(THD *thd,
3218 MEM_ROOT *mem_root,
3219 handler *file,
3220 ulonglong table_flags)
3221 {
3222 /*
3223 Pass the last parameter to prepare_interval_field() as follows:
3224 - If we are preparing for an SP variable (file is NULL), we pass "false",
3225 to force allocation and full copying of TYPELIB values on the given
3226 mem_root, even if no character set conversion is needed. This is needed
3227 because a life cycle of an SP variable is longer than the current query.
3228
3229 - If we are preparing for a CREATE TABLE, (file != NULL), we pass "true".
3230 This will create the typelib in runtime memory - we will free the
3231 occupied memory at the same time when we free this
3232 sql_field -- at the end of execution.
3233 Pass "true" as the last argument to reuse "interval_list"
3234 values in "interval" in cases when no character conversion is needed,
3235 to avoid extra copying.
3236 */
3237 if (prepare_interval_field(mem_root, file != NULL))
3238 return true; // E.g. wrong values with commas: SET('a,b')
3239 create_length_to_internal_length_typelib();
3240
3241 DBUG_ASSERT(file || !default_value); // SP variables have no default_value
3242 if (default_value && default_value->expr->basic_const_item())
3243 {
3244 if ((charset != default_value->expr->collation.collation &&
3245 prepare_stage1_convert_default(thd, mem_root, charset)) ||
3246 prepare_stage1_check_typelib_default())
3247 return true;
3248 }
3249 return false;
3250 }
3251
3252
prepare_stage1_string(THD * thd,MEM_ROOT * mem_root,handler * file,ulonglong table_flags)3253 bool Column_definition::prepare_stage1_string(THD *thd,
3254 MEM_ROOT *mem_root,
3255 handler *file,
3256 ulonglong table_flags)
3257 {
3258 create_length_to_internal_length_string();
3259 if (prepare_blob_field(thd))
3260 return true;
3261 DBUG_ASSERT(file || !default_value); // SP variables have no default_value
3262 /*
3263 Convert the default value from client character
3264 set into the column character set if necessary.
3265 We can only do this for constants as we have not yet run fix_fields.
3266 But not for blobs, as they will be stored as SQL expressions, not
3267 written down into the record image.
3268 */
3269 if (!(flags & BLOB_FLAG) && default_value &&
3270 default_value->expr->basic_const_item() &&
3271 charset != default_value->expr->collation.collation)
3272 {
3273 if (prepare_stage1_convert_default(thd, mem_root, charset))
3274 return true;
3275 }
3276 return false;
3277 }
3278
3279
prepare_stage1_bit(THD * thd,MEM_ROOT * mem_root,handler * file,ulonglong table_flags)3280 bool Column_definition::prepare_stage1_bit(THD *thd,
3281 MEM_ROOT *mem_root,
3282 handler *file,
3283 ulonglong table_flags)
3284 {
3285 pack_flag= FIELDFLAG_NUMBER;
3286 if (!(table_flags & HA_CAN_BIT_FIELD))
3287 pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
3288 create_length_to_internal_length_bit();
3289 return false;
3290 }
3291
3292
prepare_stage1(THD * thd,MEM_ROOT * mem_root,handler * file,ulonglong table_flags,const Column_derived_attributes * derived_attr)3293 bool Column_definition::prepare_stage1(THD *thd,
3294 MEM_ROOT *mem_root,
3295 handler *file,
3296 ulonglong table_flags,
3297 const Column_derived_attributes
3298 *derived_attr)
3299 {
3300 return type_handler()->Column_definition_prepare_stage1(thd, mem_root,
3301 this, file,
3302 table_flags,
3303 derived_attr);
3304 }
3305
3306
prepare_stage1_convert_default(THD * thd,MEM_ROOT * mem_root,CHARSET_INFO * cs)3307 bool Column_definition::prepare_stage1_convert_default(THD *thd,
3308 MEM_ROOT *mem_root,
3309 CHARSET_INFO *cs)
3310 {
3311 DBUG_ASSERT(thd->mem_root == mem_root);
3312 Item *item;
3313 if (!(item= default_value->expr->safe_charset_converter(thd, cs)))
3314 {
3315 my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str);
3316 return true; // Could not convert
3317 }
3318 /* Fix for prepare statement */
3319 thd->change_item_tree(&default_value->expr, item);
3320 return false;
3321 }
3322
3323
prepare_stage1_check_typelib_default()3324 bool Column_definition::prepare_stage1_check_typelib_default()
3325 {
3326 StringBuffer<MAX_FIELD_WIDTH> str;
3327 String *def= default_value->expr->val_str(&str);
3328 bool not_found;
3329 if (def == NULL) /* SQL "NULL" maps to NULL */
3330 {
3331 not_found= flags & NOT_NULL_FLAG;
3332 }
3333 else
3334 {
3335 not_found= false;
3336 if (real_field_type() == MYSQL_TYPE_SET)
3337 {
3338 char *not_used;
3339 uint not_used2;
3340 find_set(interval, def->ptr(), def->length(),
3341 charset, ¬_used, ¬_used2, ¬_found);
3342 }
3343 else /* MYSQL_TYPE_ENUM */
3344 {
3345 def->length(charset->lengthsp(def->ptr(), def->length()));
3346 not_found= !find_type2(interval, def->ptr(), def->length(), charset);
3347 }
3348 }
3349 if (not_found)
3350 {
3351 my_error(ER_INVALID_DEFAULT, MYF(0), field_name.str);
3352 return true;
3353 }
3354 return false;
3355 }
3356 /*
3357 This function adds a invisible field to field_list
3358 SYNOPSIS
3359 mysql_add_invisible_field()
3360 thd Thread Object
3361 field_list list of all table fields
3362 field_name name/prefix of invisible field
3363 ( Prefix in the case when it is
3364 *INVISIBLE_FULL*
3365 and given name is duplicate)
3366 type_handler field data type
3367 invisible
3368 default value
3369 RETURN VALUE
3370 Create_field pointer
3371 */
mysql_add_invisible_field(THD * thd,List<Create_field> * field_list,const char * field_name,Type_handler * type_handler,field_visibility_t invisible,Item * default_value)3372 int mysql_add_invisible_field(THD *thd, List<Create_field> * field_list,
3373 const char *field_name, Type_handler *type_handler,
3374 field_visibility_t invisible, Item* default_value)
3375 {
3376 Create_field *fld= new(thd->mem_root)Create_field();
3377 const char *new_name= NULL;
3378 /* Get unique field name if invisible == INVISIBLE_FULL */
3379 if (invisible == INVISIBLE_FULL)
3380 {
3381 if ((new_name= make_unique_invisible_field_name(thd, field_name,
3382 field_list)))
3383 {
3384 fld->field_name.str= new_name;
3385 fld->field_name.length= strlen(new_name);
3386 }
3387 else
3388 return 1; //Should not happen
3389 }
3390 else
3391 {
3392 fld->field_name.str= thd->strmake(field_name, strlen(field_name));
3393 fld->field_name.length= strlen(field_name);
3394 }
3395 fld->set_handler(type_handler);
3396 fld->invisible= invisible;
3397 if (default_value)
3398 {
3399 Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
3400 v->expr= default_value;
3401 v->utf8= 0;
3402 fld->default_value= v;
3403 }
3404 field_list->push_front(fld, thd->mem_root);
3405 return 0;
3406 }
3407
3408 #define LONG_HASH_FIELD_NAME_LENGTH 30
make_long_hash_field_name(LEX_CSTRING * buf,uint num)3409 static inline void make_long_hash_field_name(LEX_CSTRING *buf, uint num)
3410 {
3411 buf->length= my_snprintf((char *)buf->str,
3412 LONG_HASH_FIELD_NAME_LENGTH, "DB_ROW_HASH_%u", num);
3413 }
3414
3415 /**
3416 Add fully invisible hash field to table in case of long
3417 unique column
3418 @param thd Thread Context.
3419 @param create_list List of table fields.
3420 @param key_info current long unique key info
3421 */
add_hash_field(THD * thd,List<Create_field> * create_list,KEY * key_info)3422 static Create_field * add_hash_field(THD * thd, List<Create_field> *create_list,
3423 KEY *key_info)
3424 {
3425 List_iterator<Create_field> it(*create_list);
3426 Create_field *dup_field, *cf= new (thd->mem_root) Create_field();
3427 cf->flags|= UNSIGNED_FLAG | LONG_UNIQUE_HASH_FIELD;
3428 cf->decimals= 0;
3429 cf->length= cf->char_length= cf->pack_length= HA_HASH_FIELD_LENGTH;
3430 cf->invisible= INVISIBLE_FULL;
3431 cf->pack_flag|= FIELDFLAG_MAYBE_NULL;
3432 cf->vcol_info= new (thd->mem_root) Virtual_column_info();
3433 cf->vcol_info->stored_in_db= false;
3434 uint num= 1;
3435 LEX_CSTRING field_name;
3436 field_name.str= (char *)thd->alloc(LONG_HASH_FIELD_NAME_LENGTH);
3437 make_long_hash_field_name(&field_name, num);
3438 /*
3439 Check for collisions
3440 */
3441 while ((dup_field= it++))
3442 {
3443 if (!my_strcasecmp(system_charset_info, field_name.str, dup_field->field_name.str))
3444 {
3445 num++;
3446 make_long_hash_field_name(&field_name, num);
3447 it.rewind();
3448 }
3449 }
3450 cf->field_name= field_name;
3451 cf->set_handler(&type_handler_slonglong);
3452 key_info->algorithm= HA_KEY_ALG_LONG_HASH;
3453 create_list->push_back(cf,thd->mem_root);
3454 return cf;
3455 }
3456
3457 Key *
mysql_add_invisible_index(THD * thd,List<Key> * key_list,LEX_CSTRING * field_name,enum Key::Keytype type)3458 mysql_add_invisible_index(THD *thd, List<Key> *key_list,
3459 LEX_CSTRING* field_name, enum Key::Keytype type)
3460 {
3461 Key *key= new (thd->mem_root) Key(type, &null_clex_str, HA_KEY_ALG_UNDEF,
3462 false, DDL_options(DDL_options::OPT_NONE));
3463 key->columns.push_back(new(thd->mem_root) Key_part_spec(field_name, 0, true),
3464 thd->mem_root);
3465 key_list->push_back(key, thd->mem_root);
3466 return key;
3467 }
3468
3469
Key_part_spec_init_ft(Key_part_spec * part,const Column_definition & def) const3470 bool Type_handler_string::Key_part_spec_init_ft(Key_part_spec *part,
3471 const Column_definition &def)
3472 const
3473 {
3474 /*
3475 Set length to 0. It's set to the real column width later for CHAR.
3476 It has to be the correct col width for CHAR, as its data are not
3477 prefixed with length (unlike blobs).
3478 */
3479 part->length= 0;
3480 return !Charset(def.charset).is_good_for_ft();
3481 }
3482
3483
Key_part_spec_init_ft(Key_part_spec * part,const Column_definition & def) const3484 bool Type_handler_varchar::Key_part_spec_init_ft(Key_part_spec *part,
3485 const Column_definition &def)
3486 const
3487 {
3488 part->length= 0;
3489 return !Charset(def.charset).is_good_for_ft();
3490 }
3491
3492
3493 bool
Key_part_spec_init_ft(Key_part_spec * part,const Column_definition & def) const3494 Type_handler_blob_common::Key_part_spec_init_ft(Key_part_spec *part,
3495 const Column_definition &def)
3496 const
3497 {
3498 /*
3499 Set keyseg length to 1 for blobs.
3500 It's ignored in ft code: the data length is taken from the length prefix.
3501 */
3502 part->length= 1;
3503 return !Charset(def.charset).is_good_for_ft();
3504 }
3505
3506
3507 static bool
key_add_part_check_null(const handler * file,KEY * key_info,const Column_definition * sql_field,const Key_part_spec * column)3508 key_add_part_check_null(const handler *file, KEY *key_info,
3509 const Column_definition *sql_field,
3510 const Key_part_spec *column)
3511 {
3512 if (!(sql_field->flags & NOT_NULL_FLAG))
3513 {
3514 key_info->flags|= HA_NULL_PART_KEY;
3515 if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
3516 {
3517 my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
3518 return true;
3519 }
3520 }
3521 return false;
3522 }
3523
3524
3525 /*
3526 Preparation for table creation
3527
3528 SYNOPSIS
3529 mysql_prepare_create_table()
3530 thd Thread object.
3531 create_info Create information (like MAX_ROWS).
3532 alter_info List of columns and indexes to create
3533 db_options INOUT Table options (like HA_OPTION_PACK_RECORD).
3534 file The handler for the new table.
3535 key_info_buffer OUT An array of KEY structs for the indexes.
3536 key_count OUT The number of elements in the array.
3537 create_table_mode C_ORDINARY_CREATE, C_ALTER_TABLE,
3538 C_CREATE_SELECT, C_ASSISTED_DISCOVERY
3539
3540 DESCRIPTION
3541 Prepares the table and key structures for table creation.
3542
3543 NOTES
3544 sets create_info->varchar if the table has a varchar
3545
3546 RETURN VALUES
3547 FALSE OK
3548 TRUE error
3549 */
3550
3551 static int
mysql_prepare_create_table(THD * thd,HA_CREATE_INFO * create_info,Alter_info * alter_info,uint * db_options,handler * file,KEY ** key_info_buffer,uint * key_count,int create_table_mode,const LEX_CSTRING db,const LEX_CSTRING table_name)3552 mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
3553 Alter_info *alter_info, uint *db_options,
3554 handler *file, KEY **key_info_buffer,
3555 uint *key_count, int create_table_mode,
3556 const LEX_CSTRING db, const LEX_CSTRING table_name)
3557 {
3558 const char *key_name;
3559 Create_field *sql_field,*dup_field;
3560 uint field,null_fields,max_key_length;
3561 ulong record_offset= 0;
3562 KEY_PART_INFO *key_part_info;
3563 int field_no,dup_no;
3564 int select_field_pos,auto_increment=0;
3565 List_iterator_fast<Create_field> it(alter_info->create_list);
3566 List_iterator<Create_field> it2(alter_info->create_list);
3567 uint total_uneven_bit_length= 0;
3568 int select_field_count= C_CREATE_SELECT(create_table_mode);
3569 bool tmp_table= create_table_mode == C_ALTER_TABLE;
3570 const bool create_simple= thd->lex->create_simple();
3571 bool is_hash_field_needed= false;
3572 const Column_derived_attributes dattr(create_info->default_table_charset);
3573 const Column_bulk_alter_attributes
3574 battr(create_info->alter_table_convert_to_charset);
3575 DBUG_ENTER("mysql_prepare_create_table");
3576
3577 DBUG_EXECUTE_IF("test_pseudo_invisible",{
3578 mysql_add_invisible_field(thd, &alter_info->create_list,
3579 "invisible", &type_handler_slong, INVISIBLE_SYSTEM,
3580 new (thd->mem_root)Item_int(thd, 9));
3581 });
3582 DBUG_EXECUTE_IF("test_completely_invisible",{
3583 mysql_add_invisible_field(thd, &alter_info->create_list,
3584 "invisible", &type_handler_slong, INVISIBLE_FULL,
3585 new (thd->mem_root)Item_int(thd, 9));
3586 });
3587 DBUG_EXECUTE_IF("test_invisible_index",{
3588 LEX_CSTRING temp;
3589 temp.str= "invisible";
3590 temp.length= strlen("invisible");
3591 mysql_add_invisible_index(thd, &alter_info->key_list
3592 , &temp, Key::MULTIPLE);
3593 });
3594 LEX_CSTRING* connect_string = &create_info->connect_string;
3595 if (connect_string->length != 0 &&
3596 connect_string->length > CONNECT_STRING_MAXLEN &&
3597 (system_charset_info->charpos(connect_string->str,
3598 (connect_string->str +
3599 connect_string->length),
3600 CONNECT_STRING_MAXLEN)
3601 < connect_string->length))
3602 {
3603 my_error(ER_WRONG_STRING_LENGTH, MYF(0),
3604 connect_string->str, "CONNECTION", CONNECT_STRING_MAXLEN);
3605 DBUG_RETURN(TRUE);
3606 }
3607
3608 select_field_pos= alter_info->create_list.elements - select_field_count;
3609 null_fields= 0;
3610 create_info->varchar= 0;
3611 max_key_length= file->max_key_length();
3612
3613 /* Handle creation of sequences */
3614 if (create_info->sequence)
3615 {
3616 if (!(file->ha_table_flags() & HA_CAN_TABLES_WITHOUT_ROLLBACK))
3617 {
3618 my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), file->table_type(),
3619 "SEQUENCE");
3620 DBUG_RETURN(TRUE);
3621 }
3622
3623 /* The user specified fields: check that structure is ok */
3624 if (check_sequence_fields(thd->lex, &alter_info->create_list))
3625 DBUG_RETURN(TRUE);
3626 }
3627
3628 for (field_no=0; (sql_field=it++) ; field_no++)
3629 {
3630 /* Virtual fields are always NULL */
3631 if (sql_field->vcol_info)
3632 sql_field->flags&= ~NOT_NULL_FLAG;
3633
3634 /*
3635 Initialize length from its original value (number of characters),
3636 which was set in the parser. This is necessary if we're
3637 executing a prepared statement for the second time.
3638 */
3639 sql_field->length= sql_field->char_length;
3640
3641 if (sql_field->bulk_alter(&dattr, &battr))
3642 DBUG_RETURN(true);
3643
3644 if (sql_field->prepare_stage1(thd, thd->mem_root,
3645 file, file->ha_table_flags(),
3646 &dattr))
3647 DBUG_RETURN(true);
3648
3649 DBUG_ASSERT(sql_field->charset);
3650
3651 if (sql_field->real_field_type() == MYSQL_TYPE_BIT &&
3652 file->ha_table_flags() & HA_CAN_BIT_FIELD)
3653 total_uneven_bit_length+= sql_field->length & 7;
3654
3655 if (!(sql_field->flags & NOT_NULL_FLAG))
3656 null_fields++;
3657
3658 if (check_column_name(sql_field->field_name.str))
3659 {
3660 my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name.str);
3661 DBUG_RETURN(TRUE);
3662 }
3663
3664 /* Check if we have used the same field name before */
3665 for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
3666 {
3667 if (lex_string_cmp(system_charset_info,
3668 &sql_field->field_name,
3669 &dup_field->field_name) == 0)
3670 {
3671 /*
3672 If this was a CREATE ... SELECT statement, accept a field
3673 redefinition if we are changing a field in the SELECT part
3674 */
3675 if (field_no < select_field_pos || dup_no >= select_field_pos ||
3676 dup_field->invisible >= INVISIBLE_SYSTEM)
3677 {
3678 my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name.str);
3679 DBUG_RETURN(TRUE);
3680 }
3681 else
3682 {
3683 /* Field redefined */
3684
3685 /*
3686 If we are replacing a BIT field, revert the increment
3687 of total_uneven_bit_length that was done above.
3688 */
3689 if (sql_field->real_field_type() == MYSQL_TYPE_BIT &&
3690 file->ha_table_flags() & HA_CAN_BIT_FIELD)
3691 total_uneven_bit_length-= sql_field->length & 7;
3692
3693 /*
3694 We're making one field from two, the result field will have
3695 dup_field->flags as flags. If we've incremented null_fields
3696 because of sql_field->flags, decrement it back.
3697 */
3698 if (!(sql_field->flags & NOT_NULL_FLAG))
3699 null_fields--;
3700
3701 if (sql_field->redefine_stage1(dup_field, file))
3702 DBUG_RETURN(true);
3703
3704 it2.remove(); // Remove first (create) definition
3705 select_field_pos--;
3706 break;
3707 }
3708 }
3709 }
3710 /* Don't pack rows in old tables if the user has requested this */
3711 if ((sql_field->flags & BLOB_FLAG) ||
3712 (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR &&
3713 create_info->row_type != ROW_TYPE_FIXED))
3714 (*db_options)|= HA_OPTION_PACK_RECORD;
3715 it2.rewind();
3716 }
3717
3718 /* record_offset will be increased with 'length-of-null-bits' later */
3719 record_offset= 0;
3720 null_fields+= total_uneven_bit_length;
3721
3722 it.rewind();
3723 while ((sql_field=it++))
3724 {
3725 DBUG_ASSERT(sql_field->charset != 0);
3726 if (sql_field->prepare_stage2(file, file->ha_table_flags()))
3727 DBUG_RETURN(TRUE);
3728 if (sql_field->real_field_type() == MYSQL_TYPE_VARCHAR)
3729 create_info->varchar= TRUE;
3730 sql_field->offset= record_offset;
3731 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
3732 auto_increment++;
3733 if (parse_option_list(thd, create_info->db_type, &sql_field->option_struct,
3734 &sql_field->option_list,
3735 create_info->db_type->field_options, FALSE,
3736 thd->mem_root))
3737 DBUG_RETURN(TRUE);
3738 /*
3739 For now skip fields that are not physically stored in the database
3740 (virtual fields) and update their offset later
3741 (see the next loop).
3742 */
3743 if (sql_field->stored_in_db())
3744 record_offset+= sql_field->pack_length;
3745 if (sql_field->flags & VERS_SYSTEM_FIELD)
3746 continue;
3747 }
3748 /* Update virtual fields' offset and give error if
3749 All fields are invisible */
3750 bool is_all_invisible= true;
3751 it.rewind();
3752 while ((sql_field=it++))
3753 {
3754 if (!sql_field->stored_in_db())
3755 {
3756 sql_field->offset= record_offset;
3757 record_offset+= sql_field->pack_length;
3758 }
3759 if (sql_field->invisible == VISIBLE)
3760 is_all_invisible= false;
3761 }
3762 if (is_all_invisible)
3763 {
3764 my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
3765 DBUG_RETURN(TRUE);
3766 }
3767 if (auto_increment > 1)
3768 {
3769 my_message(ER_WRONG_AUTO_KEY, ER_THD(thd, ER_WRONG_AUTO_KEY), MYF(0));
3770 DBUG_RETURN(TRUE);
3771 }
3772 if (auto_increment &&
3773 (file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
3774 {
3775 my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, MYF(0), file->table_type());
3776 DBUG_RETURN(TRUE);
3777 }
3778
3779 /*
3780 CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows
3781 inserted in the created table depends on the order of the rows fetched
3782 from the select tables. This order may differ on master and slave. We
3783 therefore mark it as unsafe.
3784 */
3785 if (select_field_count > 0 && auto_increment)
3786 thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
3787
3788 /* Create keys */
3789
3790 List_iterator<Key> key_iterator(alter_info->key_list);
3791 List_iterator<Key> key_iterator2(alter_info->key_list);
3792 uint key_parts=0, fk_key_count=0;
3793 bool primary_key=0,unique_key=0;
3794 Key *key, *key2;
3795 uint tmp, key_number;
3796 /* special marker for keys to be ignored */
3797 static char ignore_key[1];
3798
3799 /* Calculate number of key segements */
3800 *key_count= 0;
3801
3802 while ((key=key_iterator++))
3803 {
3804 DBUG_PRINT("info", ("key name: '%s' type: %d", key->name.str ? key->name.str :
3805 "(none)" , key->type));
3806 if (key->type == Key::FOREIGN_KEY)
3807 {
3808 fk_key_count++;
3809 Foreign_key *fk_key= (Foreign_key*) key;
3810 if (fk_key->validate(alter_info->create_list))
3811 DBUG_RETURN(TRUE);
3812 if (fk_key->ref_columns.elements)
3813 {
3814 if (fk_key->ref_columns.elements != fk_key->columns.elements)
3815 {
3816 my_error(ER_WRONG_FK_DEF, MYF(0),
3817 (fk_key->name.str ? fk_key->name.str :
3818 "foreign key without name"),
3819 ER_THD(thd, ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
3820 DBUG_RETURN(TRUE);
3821 }
3822 }
3823 else
3824 fk_key->ref_columns.append(&fk_key->columns);
3825 continue;
3826 }
3827 (*key_count)++;
3828 tmp=file->max_key_parts();
3829 if (key->columns.elements > tmp)
3830 {
3831 my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
3832 DBUG_RETURN(TRUE);
3833 }
3834 if (check_ident_length(&key->name))
3835 DBUG_RETURN(TRUE);
3836 key_iterator2.rewind ();
3837 if (key->type != Key::FOREIGN_KEY)
3838 {
3839 while ((key2 = key_iterator2++) != key)
3840 {
3841 /*
3842 foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
3843 'generated', and a generated key is a prefix of the other key.
3844 Then we do not need the generated shorter key.
3845 */
3846 if ((key2->type != Key::FOREIGN_KEY &&
3847 key2->name.str != ignore_key &&
3848 !foreign_key_prefix(key, key2)))
3849 {
3850 /* TODO: issue warning message */
3851 /* mark that the generated key should be ignored */
3852 if (!key2->generated ||
3853 (key->generated && key->columns.elements <
3854 key2->columns.elements))
3855 key->name.str= ignore_key;
3856 else
3857 {
3858 key2->name.str= ignore_key;
3859 key_parts-= key2->columns.elements;
3860 (*key_count)--;
3861 }
3862 break;
3863 }
3864 }
3865 }
3866 if (key->name.str != ignore_key)
3867 key_parts+=key->columns.elements;
3868 else
3869 (*key_count)--;
3870 if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
3871 !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
3872 {
3873 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
3874 DBUG_RETURN(TRUE);
3875 }
3876 if (key->type == Key::PRIMARY && key->name.str &&
3877 my_strcasecmp(system_charset_info, key->name.str, primary_key_name) != 0)
3878 {
3879 bool sav_abort_on_warning= thd->abort_on_warning;
3880 thd->abort_on_warning= FALSE; /* Don't make an error out of this. */
3881 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
3882 ER_WRONG_NAME_FOR_INDEX,
3883 "Name '%-.100s' ignored for PRIMARY key.",
3884 key->name.str);
3885 thd->abort_on_warning= sav_abort_on_warning;
3886 }
3887 }
3888
3889 KEY *key_info= *key_info_buffer= (KEY*)thd->calloc(sizeof(KEY) * (*key_count));
3890 if (!*key_info_buffer)
3891 DBUG_RETURN(true); // Out of memory
3892
3893 key_iterator.rewind();
3894 while ((key=key_iterator++))
3895 {
3896 if (key->name.str == ignore_key || key->type == Key::FOREIGN_KEY)
3897 continue;
3898 /* Create the key->ame based on the first column (if not given) */
3899 if (key->type == Key::PRIMARY)
3900 {
3901 if (primary_key)
3902 {
3903 my_message(ER_MULTIPLE_PRI_KEY, ER_THD(thd, ER_MULTIPLE_PRI_KEY),
3904 MYF(0));
3905 DBUG_RETURN(true);
3906 }
3907 key_name=primary_key_name;
3908 primary_key=1;
3909 }
3910 else if (!(key_name= key->name.str))
3911 {
3912 auto field_name= key->columns.elem(0)->field_name;
3913 it.rewind();
3914 while ((sql_field=it++) &&
3915 lex_string_cmp(system_charset_info,
3916 &field_name,
3917 &sql_field->field_name));
3918 if (sql_field)
3919 field_name= sql_field->field_name;
3920 key_name=make_unique_key_name(thd, field_name.str,
3921 *key_info_buffer, key_info);
3922 }
3923 if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
3924 {
3925 my_error(ER_DUP_KEYNAME, MYF(0), key_name);
3926 DBUG_RETURN(true);
3927 }
3928
3929 key_info->name.str= (char*) key_name;
3930 key_info->name.length= strlen(key_name);
3931 key->name= key_info->name;
3932
3933 int parts_added= append_system_key_parts(thd, create_info, key);
3934 if (parts_added < 0)
3935 DBUG_RETURN(true);
3936 key_parts += parts_added;
3937 key_info++;
3938 }
3939 tmp=file->max_keys();
3940 if (*key_count > tmp)
3941 {
3942 my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
3943 DBUG_RETURN(TRUE);
3944 }
3945
3946 key_part_info=(KEY_PART_INFO*) thd->calloc(sizeof(KEY_PART_INFO)*key_parts);
3947 if (!key_part_info)
3948 DBUG_RETURN(true); // Out of memory
3949
3950 key_info= *key_info_buffer;
3951 key_iterator.rewind();
3952 key_number=0;
3953 for (; (key=key_iterator++) ; key_number++)
3954 {
3955 uint key_length=0;
3956 Create_field *auto_increment_key= 0;
3957 Key_part_spec *column;
3958
3959 is_hash_field_needed= false;
3960 if (key->name.str == ignore_key)
3961 {
3962 /* ignore redundant keys */
3963 do
3964 key=key_iterator++;
3965 while (key && key->name.str == ignore_key);
3966 if (!key)
3967 break;
3968 }
3969
3970 switch (key->type) {
3971 case Key::MULTIPLE:
3972 key_info->flags= 0;
3973 break;
3974 case Key::FULLTEXT:
3975 key_info->flags= HA_FULLTEXT;
3976 if ((key_info->parser_name= &key->key_create_info.parser_name)->str)
3977 key_info->flags|= HA_USES_PARSER;
3978 else
3979 key_info->parser_name= 0;
3980 break;
3981 case Key::SPATIAL:
3982 #ifdef HAVE_SPATIAL
3983 key_info->flags= HA_SPATIAL;
3984 break;
3985 #else
3986 my_error(ER_FEATURE_DISABLED, MYF(0),
3987 sym_group_geom.name, sym_group_geom.needed_define);
3988 DBUG_RETURN(TRUE);
3989 #endif
3990 case Key::FOREIGN_KEY:
3991 key_number--; // Skip this key
3992 continue;
3993 default:
3994 key_info->flags = HA_NOSAME;
3995 break;
3996 }
3997 if (key->generated)
3998 key_info->flags|= HA_GENERATED_KEY;
3999
4000 key_info->user_defined_key_parts=(uint8) key->columns.elements;
4001 key_info->key_part=key_part_info;
4002 key_info->usable_key_parts= key_number;
4003 key_info->algorithm= key->key_create_info.algorithm;
4004 key_info->option_list= key->option_list;
4005 if (parse_option_list(thd, create_info->db_type, &key_info->option_struct,
4006 &key_info->option_list,
4007 create_info->db_type->index_options, FALSE,
4008 thd->mem_root))
4009 DBUG_RETURN(TRUE);
4010
4011 if (key->type == Key::FULLTEXT)
4012 {
4013 if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
4014 {
4015 my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0), file->table_type());
4016 DBUG_RETURN(TRUE);
4017 }
4018 }
4019 /*
4020 Make SPATIAL to be RTREE by default
4021 SPATIAL only on BLOB or at least BINARY, this
4022 actually should be replaced by special GEOM type
4023 in near future when new frm file is ready
4024 checking for proper key parts number:
4025 */
4026
4027 /* TODO: Add proper checks if handler supports key_type and algorithm */
4028 if (key_info->flags & HA_SPATIAL)
4029 {
4030 if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
4031 {
4032 my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0), file->table_type());
4033 DBUG_RETURN(TRUE);
4034 }
4035 if (key_info->user_defined_key_parts != 1)
4036 {
4037 my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
4038 DBUG_RETURN(TRUE);
4039 }
4040 }
4041 else if (key_info->algorithm == HA_KEY_ALG_RTREE)
4042 {
4043 #ifdef HAVE_RTREE_KEYS
4044 if ((key_info->user_defined_key_parts & 1) == 1)
4045 {
4046 my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
4047 DBUG_RETURN(TRUE);
4048 }
4049 /* TODO: To be deleted */
4050 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
4051 DBUG_RETURN(TRUE);
4052 #else
4053 my_error(ER_FEATURE_DISABLED, MYF(0),
4054 sym_group_rtree.name, sym_group_rtree.needed_define);
4055 DBUG_RETURN(TRUE);
4056 #endif
4057 }
4058
4059 /* Take block size from key part or table part */
4060 /*
4061 TODO: Add warning if block size changes. We can't do it here, as
4062 this may depend on the size of the key
4063 */
4064 key_info->block_size= (key->key_create_info.block_size ?
4065 key->key_create_info.block_size :
4066 create_info->key_block_size);
4067
4068 /*
4069 Remember block_size for the future if the block size was given
4070 either for key or table and it was given for the key during
4071 create/alter table or we have an active key_block_size for the
4072 table.
4073 The idea is that table specific key_block_size > 0 will only affect
4074 new keys and old keys will remember their original value.
4075 */
4076 if (key_info->block_size &&
4077 ((key->key_create_info.flags & HA_USES_BLOCK_SIZE) ||
4078 create_info->key_block_size))
4079 key_info->flags|= HA_USES_BLOCK_SIZE;
4080
4081 List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
4082 CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
4083 for (uint column_nr=0 ; (column=cols++) ; column_nr++)
4084 {
4085 Key_part_spec *dup_column;
4086
4087 it.rewind();
4088 field=0;
4089 while ((sql_field=it++) &&
4090 lex_string_cmp(system_charset_info,
4091 &column->field_name,
4092 &sql_field->field_name))
4093 field++;
4094 /*
4095 Either field is not present or field visibility is > INVISIBLE_USER
4096 */
4097 if (!sql_field || (sql_field->invisible > INVISIBLE_USER &&
4098 !column->generated))
4099 {
4100 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
4101 DBUG_RETURN(TRUE);
4102 }
4103 if (sql_field->invisible > INVISIBLE_USER &&
4104 !(sql_field->flags & VERS_SYSTEM_FIELD) &&
4105 !key->invisible && DBUG_EVALUATE_IF("test_invisible_index", 0, 1))
4106 {
4107 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
4108 DBUG_RETURN(TRUE);
4109 }
4110 while ((dup_column= cols2++) != column)
4111 {
4112 if (!lex_string_cmp(system_charset_info,
4113 &column->field_name, &dup_column->field_name))
4114 {
4115 my_error(ER_DUP_FIELDNAME, MYF(0), column->field_name.str);
4116 DBUG_RETURN(TRUE);
4117 }
4118 }
4119
4120 if (sql_field->compression_method())
4121 {
4122 my_error(ER_COMPRESSED_COLUMN_USED_AS_KEY, MYF(0),
4123 column->field_name.str);
4124 DBUG_RETURN(TRUE);
4125 }
4126
4127 cols2.rewind();
4128 switch(key->type) {
4129
4130 case Key::FULLTEXT:
4131 if (sql_field->type_handler()->Key_part_spec_init_ft(column,
4132 *sql_field) ||
4133 (ft_key_charset && sql_field->charset != ft_key_charset))
4134 {
4135 my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
4136 DBUG_RETURN(-1);
4137 }
4138 ft_key_charset= sql_field->charset;
4139 break;
4140
4141 case Key::SPATIAL:
4142 if (sql_field->type_handler()->Key_part_spec_init_spatial(column,
4143 *sql_field) ||
4144 sql_field->check_vcol_for_key(thd))
4145 DBUG_RETURN(TRUE);
4146 if (!(sql_field->flags & NOT_NULL_FLAG))
4147 {
4148 my_message(ER_SPATIAL_CANT_HAVE_NULL,
4149 ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
4150 DBUG_RETURN(TRUE);
4151 }
4152 break;
4153
4154 case Key::PRIMARY:
4155 if (sql_field->vcol_info)
4156 {
4157 my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
4158 DBUG_RETURN(TRUE);
4159 }
4160 if (sql_field->type_handler()->Key_part_spec_init_primary(column,
4161 *sql_field,
4162 file))
4163 DBUG_RETURN(TRUE);
4164 if (!(sql_field->flags & NOT_NULL_FLAG))
4165 {
4166 /* Implicitly set primary key fields to NOT NULL for ISO conf. */
4167 sql_field->flags|= NOT_NULL_FLAG;
4168 sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
4169 null_fields--;
4170 }
4171 break;
4172
4173 case Key::MULTIPLE:
4174 if (sql_field->type_handler()->Key_part_spec_init_multiple(column,
4175 *sql_field,
4176 file) ||
4177 sql_field->check_vcol_for_key(thd) ||
4178 key_add_part_check_null(file, key_info, sql_field, column))
4179 DBUG_RETURN(TRUE);
4180 break;
4181
4182 case Key::FOREIGN_KEY:
4183 if (sql_field->type_handler()->Key_part_spec_init_foreign(column,
4184 *sql_field,
4185 file) ||
4186 sql_field->check_vcol_for_key(thd) ||
4187 key_add_part_check_null(file, key_info, sql_field, column))
4188 DBUG_RETURN(TRUE);
4189 break;
4190
4191 case Key::UNIQUE:
4192 if (sql_field->type_handler()->Key_part_spec_init_unique(column,
4193 *sql_field, file,
4194 &is_hash_field_needed) ||
4195 sql_field->check_vcol_for_key(thd) ||
4196 key_add_part_check_null(file, key_info, sql_field, column))
4197 DBUG_RETURN(TRUE);
4198 break;
4199 }
4200
4201 if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
4202 {
4203 DBUG_ASSERT(key->type != Key::FULLTEXT);
4204 DBUG_ASSERT(key->type != Key::SPATIAL);
4205 if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
4206 auto_increment--; // Field is used
4207 auto_increment_key= sql_field;
4208 }
4209
4210 key_part_info->fieldnr= field;
4211 key_part_info->offset= (uint16) sql_field->offset;
4212 key_part_info->key_type=sql_field->pack_flag;
4213 uint key_part_length= sql_field->type_handler()->
4214 calc_key_length(*sql_field);
4215
4216 if (column->length)
4217 {
4218 if (f_is_blob(sql_field->pack_flag))
4219 {
4220 key_part_length= MY_MIN(column->length,
4221 blob_length_by_type(sql_field->real_field_type())
4222 * sql_field->charset->mbmaxlen);
4223 if (key_part_length > max_key_length ||
4224 key_part_length > file->max_key_part_length())
4225 {
4226 if (key->type == Key::MULTIPLE)
4227 {
4228 key_part_length= MY_MIN(max_key_length, file->max_key_part_length());
4229 /* not a critical problem */
4230 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
4231 ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY),
4232 key_part_length);
4233 /* Align key length to multibyte char boundary */
4234 key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
4235 }
4236 }
4237 }
4238 // Catch invalid use of partial keys
4239 else if (!f_is_geom(sql_field->pack_flag) &&
4240 // is the key partial?
4241 column->length != key_part_length &&
4242 // is prefix length bigger than field length?
4243 (column->length > key_part_length ||
4244 // can the field have a partial key?
4245 !sql_field->type_handler()->type_can_have_key_part() ||
4246 // a packed field can't be used in a partial key
4247 f_is_packed(sql_field->pack_flag) ||
4248 // does the storage engine allow prefixed search?
4249 ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
4250 // and is this a 'unique' key?
4251 (key_info->flags & HA_NOSAME))))
4252 {
4253 my_message(ER_WRONG_SUB_KEY, ER_THD(thd, ER_WRONG_SUB_KEY), MYF(0));
4254 DBUG_RETURN(TRUE);
4255 }
4256 else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
4257 key_part_length= column->length;
4258 }
4259 else if (key_part_length == 0 && (sql_field->flags & NOT_NULL_FLAG) &&
4260 !is_hash_field_needed)
4261 {
4262 my_error(ER_WRONG_KEY_COLUMN, MYF(0), file->table_type(),
4263 column->field_name.str);
4264 DBUG_RETURN(TRUE);
4265 }
4266 if (key_part_length > file->max_key_part_length() &&
4267 key->type != Key::FULLTEXT)
4268 {
4269 if (key->type == Key::MULTIPLE)
4270 {
4271 key_part_length= file->max_key_part_length();
4272 /* not a critical problem */
4273 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
4274 ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY),
4275 key_part_length);
4276 /* Align key length to multibyte char boundary */
4277 key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
4278 }
4279 else
4280 {
4281 if (key->type != Key::UNIQUE)
4282 {
4283 key_part_length= MY_MIN(max_key_length, file->max_key_part_length());
4284 my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
4285 DBUG_RETURN(TRUE);
4286 }
4287 }
4288 }
4289
4290 if (key->type == Key::UNIQUE
4291 && key_part_length > MY_MIN(max_key_length,
4292 file->max_key_part_length()))
4293 is_hash_field_needed= true;
4294
4295 /* We can not store key_part_length more then 2^16 - 1 in frm */
4296 if (is_hash_field_needed && column->length > UINT_MAX16)
4297 {
4298 my_error(ER_TOO_LONG_KEYPART, MYF(0), UINT_MAX16);
4299 DBUG_RETURN(TRUE);
4300 }
4301 else
4302 key_part_info->length= (uint16) key_part_length;
4303 /* Use packed keys for long strings on the first column */
4304 if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
4305 !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
4306 (key_part_length >= KEY_DEFAULT_PACK_LENGTH) &&
4307 !is_hash_field_needed)
4308 {
4309 key_info->flags|= sql_field->type_handler()->KEY_pack_flags(column_nr);
4310 }
4311 /* Check if the key segment is partial, set the key flag accordingly */
4312 if (key_part_length != sql_field->type_handler()->
4313 calc_key_length(*sql_field) &&
4314 key_part_length != sql_field->type_handler()->max_octet_length())
4315 key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
4316
4317 key_length+= key_part_length;
4318 key_part_info++;
4319 }
4320 if (!key_info->name.str || check_column_name(key_info->name.str))
4321 {
4322 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name.str);
4323 DBUG_RETURN(TRUE);
4324 }
4325 if (key->type == Key::UNIQUE && !(key_info->flags & HA_NULL_PART_KEY))
4326 unique_key=1;
4327 key_info->key_length=(uint16) key_length;
4328 if (key_info->key_length > max_key_length && key->type == Key::UNIQUE)
4329 is_hash_field_needed= true; // for case "a BLOB UNIQUE"
4330 if (key_length > max_key_length && key->type != Key::FULLTEXT &&
4331 !is_hash_field_needed)
4332 {
4333 my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length);
4334 DBUG_RETURN(TRUE);
4335 }
4336
4337 /* Check long unique keys */
4338 if (is_hash_field_needed)
4339 {
4340 if (auto_increment_key)
4341 {
4342 my_error(ER_NO_AUTOINCREMENT_WITH_UNIQUE, MYF(0),
4343 sql_field->field_name.str,
4344 key_info->name.str);
4345 DBUG_RETURN(TRUE);
4346 }
4347 if (key_info->algorithm != HA_KEY_ALG_UNDEF &&
4348 key_info->algorithm != HA_KEY_ALG_HASH )
4349 {
4350 my_error(ER_TOO_LONG_KEY, MYF(0), max_key_length);
4351 DBUG_RETURN(TRUE);
4352 }
4353 }
4354 if (is_hash_field_needed ||
4355 (key_info->algorithm == HA_KEY_ALG_HASH &&
4356 key->type != Key::PRIMARY &&
4357 key_info->flags & HA_NOSAME &&
4358 !(file->ha_table_flags() & HA_CAN_HASH_KEYS ) &&
4359 file->ha_table_flags() & HA_CAN_VIRTUAL_COLUMNS))
4360 {
4361 Create_field *hash_fld= add_hash_field(thd, &alter_info->create_list,
4362 key_info);
4363 if (!hash_fld)
4364 DBUG_RETURN(TRUE);
4365 hash_fld->offset= record_offset;
4366 hash_fld->charset= create_info->default_table_charset;
4367 record_offset+= hash_fld->pack_length;
4368 if (key_info->flags & HA_NULL_PART_KEY)
4369 null_fields++;
4370 else
4371 {
4372 hash_fld->flags|= NOT_NULL_FLAG;
4373 hash_fld->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
4374 }
4375 }
4376 if (validate_comment_length(thd, &key->key_create_info.comment,
4377 INDEX_COMMENT_MAXLEN,
4378 ER_TOO_LONG_INDEX_COMMENT,
4379 key_info->name.str))
4380 DBUG_RETURN(TRUE);
4381
4382 key_info->comment.length= key->key_create_info.comment.length;
4383 if (key_info->comment.length > 0)
4384 {
4385 key_info->flags|= HA_USES_COMMENT;
4386 key_info->comment.str= key->key_create_info.comment.str;
4387 }
4388
4389 // Check if a duplicate index is defined.
4390 check_duplicate_key(thd, key, key_info, &alter_info->key_list);
4391
4392 key_info->without_overlaps= key->without_overlaps;
4393 if (key_info->without_overlaps)
4394 {
4395 if (key_info->algorithm == HA_KEY_ALG_HASH ||
4396 key_info->algorithm == HA_KEY_ALG_LONG_HASH)
4397
4398 {
4399 without_overlaps_err:
4400 my_error(ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS, MYF(0), key_info->name.str);
4401 DBUG_RETURN(true);
4402 }
4403 key_iterator2.rewind();
4404 while ((key2 = key_iterator2++))
4405 {
4406 if (key2->type != Key::FOREIGN_KEY)
4407 continue;
4408 DBUG_ASSERT(key != key2);
4409 Foreign_key *fk= (Foreign_key*) key2;
4410 if (fk->update_opt != FK_OPTION_CASCADE)
4411 continue;
4412 for (Key_part_spec& kp: key->columns)
4413 {
4414 for (Key_part_spec& kp2: fk->columns)
4415 {
4416 if (!lex_string_cmp(system_charset_info, &kp.field_name,
4417 &kp2.field_name))
4418 {
4419 goto without_overlaps_err;
4420 }
4421 }
4422 }
4423 }
4424 create_info->period_info.unique_keys++;
4425 }
4426
4427 key_info++;
4428 }
4429
4430 if (!unique_key && !primary_key && !create_info->sequence &&
4431 (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
4432 {
4433 my_message(ER_REQUIRES_PRIMARY_KEY, ER_THD(thd, ER_REQUIRES_PRIMARY_KEY),
4434 MYF(0));
4435 DBUG_RETURN(TRUE);
4436 }
4437 if (auto_increment > 0)
4438 {
4439 my_message(ER_WRONG_AUTO_KEY, ER_THD(thd, ER_WRONG_AUTO_KEY), MYF(0));
4440 DBUG_RETURN(TRUE);
4441 }
4442 /*
4443 We cannot do qsort of key info if MyISAM/Aria does inplace. These engines
4444 do not synchronise key info on inplace alter and that qsort is
4445 indeterministic (MDEV-25803).
4446
4447 Yet we do not know whether we do inplace or not. That detection is done
4448 after this create_table_impl() and that cannot be changed because of chicken
4449 and egg problem (inplace processing requires key info made by
4450 create_table_impl()).
4451
4452 MyISAM/Aria cannot add index inplace so we are safe to qsort key info in
4453 that case. And if we don't add index then we do not need qsort at all.
4454 */
4455 if (!(create_info->options & HA_SKIP_KEY_SORT))
4456 {
4457 /*
4458 Sort keys in optimized order.
4459
4460 Note: PK must be always first key, otherwise init_from_binary_frm_image()
4461 can not understand it.
4462 */
4463 my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
4464 (qsort_cmp) sort_keys);
4465 }
4466 create_info->null_bits= null_fields;
4467
4468 /* Check fields. */
4469 Item::Check_table_name_prm walk_prm(db, table_name);
4470 it.rewind();
4471 while ((sql_field=it++))
4472 {
4473 Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
4474
4475 /*
4476 Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
4477 it is NOT NULL, not an AUTO_INCREMENT field, not a TIMESTAMP and not
4478 updated trough a NOW() function.
4479 */
4480 if (!sql_field->default_value &&
4481 !sql_field->has_default_function() &&
4482 (sql_field->flags & NOT_NULL_FLAG) &&
4483 (!sql_field->is_timestamp_type() ||
4484 opt_explicit_defaults_for_timestamp)&&
4485 !sql_field->vers_sys_field())
4486 {
4487 sql_field->flags|= NO_DEFAULT_VALUE_FLAG;
4488 sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
4489 }
4490
4491 if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
4492 !sql_field->default_value && !sql_field->vcol_info &&
4493 !sql_field->vers_sys_field() &&
4494 sql_field->is_timestamp_type() &&
4495 !opt_explicit_defaults_for_timestamp &&
4496 (sql_field->flags & NOT_NULL_FLAG) &&
4497 (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
4498 {
4499 /*
4500 An error should be reported if:
4501 - NO_ZERO_DATE SQL mode is active;
4502 - there is no explicit DEFAULT clause (default column value);
4503 - this is a TIMESTAMP column;
4504 - the column is not NULL;
4505 - this is not the DEFAULT CURRENT_TIMESTAMP column.
4506
4507 In other words, an error should be reported if
4508 - NO_ZERO_DATE SQL mode is active;
4509 - the column definition is equivalent to
4510 'column_name TIMESTAMP DEFAULT 0'.
4511 */
4512
4513 my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name.str);
4514 DBUG_RETURN(TRUE);
4515 }
4516 if (sql_field->invisible == INVISIBLE_USER &&
4517 sql_field->flags & NOT_NULL_FLAG &&
4518 sql_field->flags & NO_DEFAULT_VALUE_FLAG)
4519 {
4520 my_error(ER_INVISIBLE_NOT_NULL_WITHOUT_DEFAULT, MYF(0),
4521 sql_field->field_name.str);
4522 DBUG_RETURN(TRUE);
4523 }
4524
4525 if (create_simple)
4526 {
4527 /*
4528 NOTE: we cannot do this in check_vcol_func_processor() as there is already
4529 no table name qualifier in expression.
4530 */
4531 if (sql_field->vcol_info && sql_field->vcol_info->expr &&
4532 sql_field->vcol_info->expr->walk(&Item::check_table_name_processor,
4533 false, (void *) &walk_prm))
4534 {
4535 my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "GENERATED ALWAYS");
4536 DBUG_RETURN(TRUE);
4537 }
4538
4539 if (sql_field->default_value &&
4540 sql_field->default_value->expr->walk(&Item::check_table_name_processor,
4541 false, (void *) &walk_prm))
4542 {
4543 my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "DEFAULT");
4544 DBUG_RETURN(TRUE);
4545 }
4546
4547 if (sql_field->check_constraint &&
4548 sql_field->check_constraint->expr->walk(&Item::check_table_name_processor,
4549 false, (void *) &walk_prm))
4550 {
4551 my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "CHECK");
4552 DBUG_RETURN(TRUE);
4553 }
4554 }
4555 }
4556
4557 /* Check table level constraints */
4558 create_info->check_constraint_list= &alter_info->check_constraint_list;
4559 {
4560 List_iterator_fast<Virtual_column_info> c_it(alter_info->check_constraint_list);
4561 Virtual_column_info *check;
4562 while ((check= c_it++))
4563 {
4564 if (create_simple && check->expr->walk(&Item::check_table_name_processor, false,
4565 (void *) &walk_prm))
4566 {
4567 my_error(ER_BAD_FIELD_ERROR, MYF(0), walk_prm.field.c_ptr(), "CHECK");
4568 DBUG_RETURN(TRUE);
4569 }
4570 if (!check->name.length || check->automatic_name)
4571 {
4572 if (check_expression(check, &check->name, VCOL_CHECK_TABLE, alter_info))
4573 DBUG_RETURN(TRUE);
4574 continue;
4575 }
4576
4577 {
4578 /* Check that there's no repeating table CHECK constraint names. */
4579 List_iterator_fast<Virtual_column_info>
4580 dup_it(alter_info->check_constraint_list);
4581 const Virtual_column_info *dup_check;
4582 while ((dup_check= dup_it++) && dup_check != check)
4583 {
4584 if (!lex_string_cmp(system_charset_info,
4585 &check->name, &dup_check->name))
4586 {
4587 my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name.str);
4588 DBUG_RETURN(TRUE);
4589 }
4590 }
4591 }
4592
4593 /* Check that there's no repeating key constraint names. */
4594 List_iterator_fast<Key> key_it(alter_info->key_list);
4595 while (const Key *key= key_it++)
4596 {
4597 /*
4598 Not all keys considered to be the CONSTRAINT
4599 Noly Primary Key UNIQUE and Foreign keys.
4600 */
4601 if (key->type != Key::PRIMARY && key->type != Key::UNIQUE &&
4602 key->type != Key::FOREIGN_KEY)
4603 continue;
4604
4605 if (check->name.length == key->name.length &&
4606 my_strcasecmp(system_charset_info,
4607 check->name.str, key->name.str) == 0)
4608 {
4609 my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name.str);
4610 DBUG_RETURN(TRUE);
4611 }
4612 }
4613
4614 if (check_string_char_length(&check->name, 0, NAME_CHAR_LEN,
4615 system_charset_info, 1))
4616 {
4617 my_error(ER_TOO_LONG_IDENT, MYF(0), check->name.str);
4618 DBUG_RETURN(TRUE);
4619 }
4620 if (check_expression(check, &check->name, VCOL_CHECK_TABLE))
4621 DBUG_RETURN(TRUE);
4622 }
4623 }
4624
4625 /* Give warnings for not supported table options */
4626 extern handlerton *maria_hton;
4627 if (file->partition_ht() != maria_hton && create_info->transactional &&
4628 !file->has_transaction_manager())
4629 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4630 ER_ILLEGAL_HA_CREATE_OPTION,
4631 ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION),
4632 file->engine_name()->str,
4633 create_info->transactional == HA_CHOICE_YES
4634 ? "TRANSACTIONAL=1" : "TRANSACTIONAL=0");
4635
4636 if (parse_option_list(thd, file->partition_ht(), &create_info->option_struct,
4637 &create_info->option_list,
4638 file->partition_ht()->table_options, FALSE,
4639 thd->mem_root))
4640 DBUG_RETURN(TRUE);
4641
4642 DBUG_RETURN(FALSE);
4643 }
4644
4645 /**
4646 check comment length of table, column, index and partition
4647
4648 If comment length is more than the standard length
4649 truncate it and store the comment length upto the standard
4650 comment length size
4651
4652 @param thd Thread handle
4653 @param[in,out] comment Comment
4654 @param max_len Maximum allowed comment length
4655 @param err_code Error message
4656 @param name Name of commented object
4657
4658 @return Operation status
4659 @retval true Error found
4660 @retval false On Success
4661 */
validate_comment_length(THD * thd,LEX_CSTRING * comment,size_t max_len,uint err_code,const char * name)4662 bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len,
4663 uint err_code, const char *name)
4664 {
4665 DBUG_ENTER("validate_comment_length");
4666 if (comment->length == 0)
4667 DBUG_RETURN(false);
4668
4669 size_t tmp_len=
4670 Well_formed_prefix(system_charset_info, *comment, max_len).length();
4671 if (tmp_len < comment->length)
4672 {
4673 if (comment->length <= max_len)
4674 {
4675 if (thd->is_strict_mode())
4676 {
4677 my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
4678 system_charset_info->csname, comment->str);
4679 DBUG_RETURN(true);
4680 }
4681 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
4682 ER_INVALID_CHARACTER_STRING,
4683 ER_THD(thd, ER_INVALID_CHARACTER_STRING),
4684 system_charset_info->csname, comment->str);
4685 comment->length= tmp_len;
4686 DBUG_RETURN(false);
4687 }
4688 if (thd->is_strict_mode())
4689 {
4690 my_error(err_code, MYF(0), name, static_cast<ulong>(max_len));
4691 DBUG_RETURN(true);
4692 }
4693 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, err_code,
4694 ER_THD(thd, err_code), name,
4695 static_cast<ulong>(max_len));
4696 comment->length= tmp_len;
4697 }
4698 DBUG_RETURN(false);
4699 }
4700
4701
4702 /*
4703 Set table default charset, if not set
4704
4705 SYNOPSIS
4706 set_table_default_charset()
4707 create_info Table create information
4708
4709 DESCRIPTION
4710 If the table character set was not given explicitly,
4711 let's fetch the database default character set and
4712 apply it to the table.
4713 */
4714
set_table_default_charset(THD * thd,HA_CREATE_INFO * create_info,const LEX_CSTRING & db)4715 static void set_table_default_charset(THD *thd, HA_CREATE_INFO *create_info,
4716 const LEX_CSTRING &db)
4717 {
4718 /*
4719 If the table character set was not given explicitly,
4720 let's fetch the database default character set and
4721 apply it to the table.
4722 */
4723 if (!create_info->default_table_charset)
4724 {
4725 Schema_specification_st db_info;
4726
4727 load_db_opt_by_name(thd, db.str, &db_info);
4728
4729 create_info->default_table_charset= db_info.default_table_charset;
4730 }
4731 }
4732
4733
4734 /*
4735 Extend long VARCHAR fields to blob & prepare field if it's a blob
4736
4737 SYNOPSIS
4738 prepare_blob_field()
4739
4740 RETURN
4741 0 ok
4742 1 Error (sql_field can't be converted to blob)
4743 In this case the error is given
4744 */
4745
prepare_blob_field(THD * thd)4746 bool Column_definition::prepare_blob_field(THD *thd)
4747 {
4748 DBUG_ENTER("Column_definition::prepare_blob_field");
4749
4750 if (length > MAX_FIELD_VARCHARLENGTH && !(flags & BLOB_FLAG))
4751 {
4752 /* Convert long VARCHAR columns to TEXT or BLOB */
4753 char warn_buff[MYSQL_ERRMSG_SIZE];
4754
4755 if (thd->is_strict_mode())
4756 {
4757 my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name.str,
4758 static_cast<ulong>(MAX_FIELD_VARCHARLENGTH / charset->mbmaxlen));
4759 DBUG_RETURN(1);
4760 }
4761 set_handler(&type_handler_blob);
4762 flags|= BLOB_FLAG;
4763 my_snprintf(warn_buff, sizeof(warn_buff), ER_THD(thd, ER_AUTO_CONVERT),
4764 field_name.str,
4765 (charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
4766 (charset == &my_charset_bin) ? "BLOB" : "TEXT");
4767 push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
4768 warn_buff);
4769 }
4770
4771 if ((flags & BLOB_FLAG) && length)
4772 {
4773 if (real_field_type() == FIELD_TYPE_BLOB ||
4774 real_field_type() == FIELD_TYPE_TINY_BLOB ||
4775 real_field_type() == FIELD_TYPE_MEDIUM_BLOB)
4776 {
4777 /* The user has given a length to the blob column */
4778 set_handler(Type_handler::blob_type_handler((uint) length));
4779 pack_length= type_handler()->calc_pack_length(0);
4780 }
4781 length= 0;
4782 }
4783 DBUG_RETURN(0);
4784 }
4785
4786
4787 /*
4788 Preparation of Create_field for SP function return values.
4789 Based on code used in the inner loop of mysql_prepare_create_table()
4790 above.
4791
4792 SYNOPSIS
4793 sp_prepare_create_field()
4794 thd Thread object
4795 mem_root Memory root to allocate components on (e.g. interval)
4796
4797 DESCRIPTION
4798 Prepares the field structures for field creation.
4799
4800 */
4801
sp_prepare_create_field(THD * thd,MEM_ROOT * mem_root)4802 bool Column_definition::sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root)
4803 {
4804 DBUG_ASSERT(charset);
4805 const Column_derived_attributes dattr(&my_charset_bin);
4806 return prepare_stage1(thd, mem_root, NULL, HA_CAN_GEOMETRY, &dattr) ||
4807 prepare_stage2(NULL, HA_CAN_GEOMETRY);
4808 }
4809
4810
4811 /**
4812 Appends key parts generated by mariadb server.
4813 Adds row_end in UNIQUE keys for system versioning,
4814 and period fields for WITHOUT OVERLAPS.
4815 @param thd Thread data
4816 @param create_info Table create info
4817 @param key Parsed key
4818 @return a number of key parts added to key.
4819 */
append_system_key_parts(THD * thd,HA_CREATE_INFO * create_info,Key * key)4820 static int append_system_key_parts(THD *thd, HA_CREATE_INFO *create_info,
4821 Key *key)
4822 {
4823 const Lex_ident &row_start_field= create_info->vers_info.as_row.start;
4824 const Lex_ident &row_end_field= create_info->vers_info.as_row.end;
4825 DBUG_ASSERT(!create_info->versioned() || (row_start_field && row_end_field));
4826
4827 int result = 0;
4828 if (create_info->versioned() && (key->type == Key::PRIMARY
4829 || key->type == Key::UNIQUE))
4830 {
4831 Key_part_spec *key_part=NULL;
4832 List_iterator<Key_part_spec> part_it(key->columns);
4833 while ((key_part=part_it++))
4834 {
4835 if (row_start_field.streq(key_part->field_name) ||
4836 row_end_field.streq(key_part->field_name))
4837 break;
4838 }
4839 if (!key_part)
4840 {
4841 key->columns.push_back(new (thd->mem_root)
4842 Key_part_spec(&row_end_field, 0, true));
4843 result++;
4844 }
4845
4846 }
4847
4848 if (key->without_overlaps)
4849 {
4850 DBUG_ASSERT(key->type == Key::PRIMARY || key->type == Key::UNIQUE);
4851 if (!create_info->period_info.is_set()
4852 || !key->period.streq(create_info->period_info.name))
4853 {
4854 my_error(ER_PERIOD_NOT_FOUND, MYF(0), key->period.str);
4855 return -1;
4856 }
4857
4858 const auto &period_start= create_info->period_info.period.start;
4859 const auto &period_end= create_info->period_info.period.end;
4860 List_iterator<Key_part_spec> part_it(key->columns);
4861 while (Key_part_spec *key_part= part_it++)
4862 {
4863 if (period_start.streq(key_part->field_name)
4864 || period_end.streq(key_part->field_name))
4865 {
4866 my_error(ER_KEY_CONTAINS_PERIOD_FIELDS, MYF(0), key->name.str,
4867 key_part->field_name.str);
4868 return -1;
4869 }
4870 }
4871 const auto &period= create_info->period_info.period;
4872 key->columns.push_back(new (thd->mem_root)
4873 Key_part_spec(&period.end, 0, true));
4874 key->columns.push_back(new (thd->mem_root)
4875 Key_part_spec(&period.start, 0, true));
4876 result += 2;
4877 }
4878
4879 return result;
4880 }
4881
mysql_create_frm_image(THD * thd,const LEX_CSTRING & db,const LEX_CSTRING & table_name,HA_CREATE_INFO * create_info,Alter_info * alter_info,int create_table_mode,KEY ** key_info,uint * key_count,LEX_CUSTRING * frm)4882 handler *mysql_create_frm_image(THD *thd, const LEX_CSTRING &db,
4883 const LEX_CSTRING &table_name,
4884 HA_CREATE_INFO *create_info,
4885 Alter_info *alter_info, int create_table_mode,
4886 KEY **key_info, uint *key_count,
4887 LEX_CUSTRING *frm)
4888 {
4889 uint db_options;
4890 handler *file;
4891 DBUG_ENTER("mysql_create_frm_image");
4892
4893 if (!alter_info->create_list.elements)
4894 {
4895 my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
4896 DBUG_RETURN(NULL);
4897 }
4898
4899 set_table_default_charset(thd, create_info, db);
4900
4901 db_options= create_info->table_options_with_row_type();
4902
4903 if (unlikely(!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
4904 create_info->db_type))))
4905 DBUG_RETURN(NULL);
4906
4907 #ifdef WITH_PARTITION_STORAGE_ENGINE
4908 partition_info *part_info= thd->work_part_info;
4909
4910 if (!part_info && create_info->db_type->partition_flags &&
4911 (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION))
4912 {
4913 /*
4914 Table is not defined as a partitioned table but the engine handles
4915 all tables as partitioned. The handler will set up the partition info
4916 object with the default settings.
4917 */
4918 thd->work_part_info= part_info= new partition_info();
4919 if (unlikely(!part_info))
4920 goto err;
4921
4922 file->set_auto_partitions(part_info);
4923 part_info->default_engine_type= create_info->db_type;
4924 part_info->is_auto_partitioned= TRUE;
4925 }
4926 if (part_info)
4927 {
4928 /*
4929 The table has been specified as a partitioned table.
4930 If this is part of an ALTER TABLE the handler will be the partition
4931 handler but we need to specify the default handler to use for
4932 partitions also in the call to check_partition_info. We transport
4933 this information in the default_db_type variable, it is either
4934 DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command.
4935 */
4936 handlerton *part_engine_type= create_info->db_type;
4937 char *part_syntax_buf;
4938 uint syntax_len;
4939 handlerton *engine_type;
4940 List_iterator<partition_element> part_it(part_info->partitions);
4941 partition_element *part_elem;
4942
4943 while ((part_elem= part_it++))
4944 {
4945 if (part_elem->part_comment)
4946 {
4947 LEX_CSTRING comment= { part_elem->part_comment,
4948 strlen(part_elem->part_comment)
4949 };
4950 if (validate_comment_length(thd, &comment,
4951 TABLE_PARTITION_COMMENT_MAXLEN,
4952 ER_TOO_LONG_TABLE_PARTITION_COMMENT,
4953 part_elem->partition_name))
4954 DBUG_RETURN(NULL);
4955 /* cut comment length. Safe to do in all cases */
4956 ((char*)part_elem->part_comment)[comment.length]= '\0';
4957 }
4958 if (part_elem->subpartitions.elements)
4959 {
4960 List_iterator<partition_element> sub_it(part_elem->subpartitions);
4961 partition_element *subpart_elem;
4962 while ((subpart_elem= sub_it++))
4963 {
4964 if (subpart_elem->part_comment)
4965 {
4966 LEX_CSTRING comment= {
4967 subpart_elem->part_comment, strlen(subpart_elem->part_comment)
4968 };
4969 if (validate_comment_length(thd, &comment,
4970 TABLE_PARTITION_COMMENT_MAXLEN,
4971 ER_TOO_LONG_TABLE_PARTITION_COMMENT,
4972 subpart_elem->partition_name))
4973 DBUG_RETURN(NULL);
4974 /* cut comment length. Safe to do in all cases */
4975 ((char*)subpart_elem->part_comment)[comment.length]= '\0';
4976 }
4977 }
4978 }
4979 }
4980
4981 if (create_info->tmp_table())
4982 {
4983 my_error(ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING, MYF(0), "CREATE TEMPORARY TABLE");
4984 goto err;
4985 }
4986 if ((part_engine_type == partition_hton) &&
4987 part_info->default_engine_type)
4988 {
4989 /*
4990 This only happens at ALTER TABLE.
4991 default_engine_type was assigned from the engine set in the ALTER
4992 TABLE command.
4993 */
4994 ;
4995 }
4996 else
4997 {
4998 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
4999 {
5000 part_info->default_engine_type= create_info->db_type;
5001 }
5002 else
5003 {
5004 if (part_info->default_engine_type == NULL)
5005 {
5006 part_info->default_engine_type= ha_default_handlerton(thd);
5007 }
5008 }
5009 }
5010 DBUG_PRINT("info", ("db_type = %s create_info->db_type = %s",
5011 ha_resolve_storage_engine_name(part_info->default_engine_type),
5012 ha_resolve_storage_engine_name(create_info->db_type)));
5013 if (part_info->check_partition_info(thd, &engine_type, file,
5014 create_info, FALSE))
5015 goto err;
5016 part_info->default_engine_type= engine_type;
5017
5018 if (part_info->vers_info && !create_info->versioned())
5019 {
5020 my_error(ER_VERS_NOT_VERSIONED, MYF(0), table_name.str);
5021 goto err;
5022 }
5023
5024 /*
5025 We reverse the partitioning parser and generate a standard format
5026 for syntax stored in frm file.
5027 */
5028 part_syntax_buf= generate_partition_syntax_for_frm(thd, part_info,
5029 &syntax_len, create_info, alter_info);
5030 if (!part_syntax_buf)
5031 goto err;
5032 part_info->part_info_string= part_syntax_buf;
5033 part_info->part_info_len= syntax_len;
5034 if ((!(engine_type->partition_flags &&
5035 ((engine_type->partition_flags() & HA_CAN_PARTITION) ||
5036 (part_info->part_type == VERSIONING_PARTITION &&
5037 engine_type->partition_flags() & HA_ONLY_VERS_PARTITION))
5038 )) ||
5039 create_info->db_type == partition_hton)
5040 {
5041 /*
5042 The handler assigned to the table cannot handle partitioning.
5043 Assign the partition handler as the handler of the table.
5044 */
5045 DBUG_PRINT("info", ("db_type: %s",
5046 ha_resolve_storage_engine_name(create_info->db_type)));
5047 delete file;
5048 create_info->db_type= partition_hton;
5049 if (!(file= get_ha_partition(part_info)))
5050 DBUG_RETURN(NULL);
5051
5052 /*
5053 If we have default number of partitions or subpartitions we
5054 might require to set-up the part_info object such that it
5055 creates a proper .par file. The current part_info object is
5056 only used to create the frm-file and .par-file.
5057 */
5058 if (part_info->use_default_num_partitions &&
5059 part_info->num_parts &&
5060 (int)part_info->num_parts !=
5061 file->get_default_no_partitions(create_info))
5062 {
5063 uint i;
5064 List_iterator<partition_element> part_it(part_info->partitions);
5065 part_it++;
5066 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
5067 for (i= 1; i < part_info->partitions.elements; i++)
5068 (part_it++)->part_state= PART_TO_BE_DROPPED;
5069 }
5070 else if (part_info->is_sub_partitioned() &&
5071 part_info->use_default_num_subpartitions &&
5072 part_info->num_subparts &&
5073 (int)part_info->num_subparts !=
5074 file->get_default_no_partitions(create_info))
5075 {
5076 DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
5077 part_info->num_subparts= file->get_default_no_partitions(create_info);
5078 }
5079 }
5080 else if (create_info->db_type != engine_type)
5081 {
5082 /*
5083 We come here when we don't use a partitioned handler.
5084 Since we use a partitioned table it must be "native partitioned".
5085 We have switched engine from defaults, most likely only specified
5086 engines in partition clauses.
5087 */
5088 delete file;
5089 if (unlikely(!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
5090 engine_type))))
5091 DBUG_RETURN(NULL);
5092 }
5093 }
5094 /*
5095 Unless table's storage engine supports partitioning natively
5096 don't allow foreign keys on partitioned tables (they won't
5097 work work even with InnoDB beneath of partitioning engine).
5098 If storage engine handles partitioning natively (like NDB)
5099 foreign keys support is possible, so we let the engine decide.
5100 */
5101 if (create_info->db_type == partition_hton)
5102 {
5103 List_iterator_fast<Key> key_iterator(alter_info->key_list);
5104 Key *key;
5105 while ((key= key_iterator++))
5106 {
5107 if (key->type == Key::FOREIGN_KEY)
5108 {
5109 my_error(ER_FEATURE_NOT_SUPPORTED_WITH_PARTITIONING, MYF(0),
5110 "FOREIGN KEY");
5111 goto err;
5112 }
5113 }
5114 }
5115 #endif
5116
5117 if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options,
5118 file, key_info, key_count,
5119 create_table_mode, db, table_name))
5120 goto err;
5121 create_info->table_options=db_options;
5122
5123 *frm= build_frm_image(thd, table_name, create_info,
5124 alter_info->create_list, *key_count,
5125 *key_info, file);
5126
5127 if (frm->str)
5128 DBUG_RETURN(file);
5129
5130 err:
5131 delete file;
5132 DBUG_RETURN(NULL);
5133 }
5134
5135
5136 /**
5137 Create a table
5138
5139 @param thd Thread object
5140 @param orig_db Database for error messages
5141 @param orig_table_name Table name for error messages
5142 (it's different from table_name for ALTER TABLE)
5143 @param db Database
5144 @param table_name Table name
5145 @param path Path to table (i.e. to its .FRM file without
5146 the extension).
5147 @param create_info Create information (like MAX_ROWS)
5148 @param alter_info Description of fields and keys for new table
5149 @param create_table_mode C_ORDINARY_CREATE, C_ALTER_TABLE, C_ASSISTED_DISCOVERY
5150 or any positive number (for C_CREATE_SELECT).
5151 @param[out] is_trans Identifies the type of engine where the table
5152 was created: either trans or non-trans.
5153 @param[out] key_info Array of KEY objects describing keys in table
5154 which was created.
5155 @param[out] key_count Number of keys in table which was created.
5156
5157 If one creates a temporary table, its is automatically opened and its
5158 TABLE_SHARE is added to THD::all_temp_tables list.
5159
5160 Note that this function assumes that caller already have taken
5161 exclusive metadata lock on table being created or used some other
5162 way to ensure that concurrent operations won't intervene.
5163 mysql_create_table() is a wrapper that can be used for this.
5164
5165 @retval 0 OK
5166 @retval 1 error
5167 @retval -1 table existed but IF NOT EXISTS was used
5168 */
5169
5170 static
create_table_impl(THD * thd,const LEX_CSTRING & orig_db,const LEX_CSTRING & orig_table_name,const LEX_CSTRING & db,const LEX_CSTRING & table_name,const char * path,const DDL_options_st options,HA_CREATE_INFO * create_info,Alter_info * alter_info,int create_table_mode,bool * is_trans,KEY ** key_info,uint * key_count,LEX_CUSTRING * frm)5171 int create_table_impl(THD *thd, const LEX_CSTRING &orig_db,
5172 const LEX_CSTRING &orig_table_name,
5173 const LEX_CSTRING &db, const LEX_CSTRING &table_name,
5174 const char *path, const DDL_options_st options,
5175 HA_CREATE_INFO *create_info, Alter_info *alter_info,
5176 int create_table_mode, bool *is_trans, KEY **key_info,
5177 uint *key_count, LEX_CUSTRING *frm)
5178 {
5179 LEX_CSTRING *alias;
5180 handler *file= 0;
5181 int error= 1;
5182 bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY;
5183 bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only;
5184 handlerton *exists_hton;
5185 DBUG_ENTER("mysql_create_table_no_lock");
5186 DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d path: %s",
5187 db.str, table_name.str, internal_tmp_table, path));
5188
5189 if (fix_constraints_names(thd, &alter_info->check_constraint_list,
5190 create_info))
5191 DBUG_RETURN(1);
5192
5193 if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
5194 {
5195 if (create_info->data_file_name)
5196 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5197 WARN_OPTION_IGNORED,
5198 ER_THD(thd, WARN_OPTION_IGNORED),
5199 "DATA DIRECTORY");
5200 if (create_info->index_file_name)
5201 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5202 WARN_OPTION_IGNORED,
5203 ER_THD(thd, WARN_OPTION_IGNORED),
5204 "INDEX DIRECTORY");
5205 create_info->data_file_name= create_info->index_file_name= 0;
5206 }
5207 else
5208 {
5209 if (unlikely(error_if_data_home_dir(create_info->data_file_name,
5210 "DATA DIRECTORY")) ||
5211 unlikely(error_if_data_home_dir(create_info->index_file_name,
5212 "INDEX DIRECTORY")) ||
5213 unlikely(check_partition_dirs(thd->lex->part_info)))
5214 goto err;
5215 }
5216
5217 alias= const_cast<LEX_CSTRING*>(table_case_name(create_info, &table_name));
5218
5219 /* Check if table exists */
5220 if (create_info->tmp_table())
5221 {
5222 /*
5223 If a table exists, it must have been pre-opened. Try looking for one
5224 in-use in THD::all_temp_tables list of TABLE_SHAREs.
5225 */
5226 TABLE *tmp_table= thd->find_temporary_table(db.str, table_name.str,
5227 THD::TMP_TABLE_ANY);
5228
5229 if (tmp_table)
5230 {
5231 bool table_creation_was_logged= tmp_table->s->table_creation_was_logged;
5232 if (options.or_replace())
5233 {
5234 /*
5235 We are using CREATE OR REPLACE on an existing temporary table
5236 Remove the old table so that we can re-create it.
5237 */
5238 if (thd->drop_temporary_table(tmp_table, NULL, true))
5239 goto err;
5240 }
5241 else if (options.if_not_exists())
5242 goto warn;
5243 else
5244 {
5245 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias->str);
5246 goto err;
5247 }
5248 /*
5249 We have to log this query, even if it failed later to ensure the
5250 drop is done.
5251 */
5252 if (table_creation_was_logged)
5253 {
5254 thd->variables.option_bits|= OPTION_KEEP_LOG;
5255 thd->log_current_statement= 1;
5256 create_info->table_was_deleted= 1;
5257 }
5258 }
5259 }
5260 else
5261 {
5262 if (ha_check_if_updates_are_ignored(thd, create_info->db_type, "CREATE"))
5263 {
5264 /*
5265 Don't create table. CREATE will still be logged in binary log
5266 This can happen for shared storage engines that supports
5267 ENGINE= in the create statement (Note that S3 doesn't support this.
5268 */
5269 error= 0;
5270 goto err;
5271 }
5272
5273 if (!internal_tmp_table && ha_table_exists(thd, &db, &table_name,
5274 &exists_hton))
5275 {
5276 if (ha_check_if_updates_are_ignored(thd, exists_hton, "CREATE"))
5277 {
5278 /* Don't create table. CREATE will still be logged in binary log */
5279 error= 0;
5280 goto err;
5281 }
5282
5283 if (options.or_replace())
5284 {
5285 (void) delete_statistics_for_table(thd, &db, &table_name);
5286
5287 TABLE_LIST table_list;
5288 table_list.init_one_table(&db, &table_name, 0, TL_WRITE_ALLOW_WRITE);
5289 table_list.table= create_info->table;
5290
5291 if (check_if_log_table(&table_list, TRUE, "CREATE OR REPLACE"))
5292 goto err;
5293
5294 /*
5295 Rollback the empty transaction started in mysql_create_table()
5296 call to open_and_lock_tables() when we are using LOCK TABLES.
5297 */
5298 (void) trans_rollback_stmt(thd);
5299 /* Remove normal table without logging. Keep tables locked */
5300 if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 0, 1, 1))
5301 goto err;
5302
5303 /*
5304 We have to log this query, even if it failed later to ensure the
5305 drop is done.
5306 */
5307 thd->variables.option_bits|= OPTION_KEEP_LOG;
5308 thd->log_current_statement= 1;
5309 create_info->table_was_deleted= 1;
5310 DBUG_EXECUTE_IF("send_kill_after_delete",
5311 thd->set_killed(KILL_QUERY); );
5312
5313 /*
5314 Restart statement transactions for the case of CREATE ... SELECT.
5315 */
5316 if (thd->lex->first_select_lex()->item_list.elements &&
5317 restart_trans_for_tables(thd, thd->lex->query_tables))
5318 goto err;
5319 }
5320 else if (options.if_not_exists())
5321 {
5322 /*
5323 We never come here as part of normal create table as table existance
5324 is checked in open_and_lock_tables(). We may come here as part of
5325 ALTER TABLE when converting a table for a distributed engine to a
5326 a local one.
5327 */
5328
5329 /* Log CREATE IF NOT EXISTS on slave for distributed engines */
5330 if (thd->slave_thread && (exists_hton && exists_hton->flags &
5331 HTON_IGNORE_UPDATES))
5332 thd->log_current_statement= 1;
5333 goto warn;
5334 }
5335 else
5336 {
5337 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name.str);
5338 goto err;
5339 }
5340 }
5341 }
5342
5343 THD_STAGE_INFO(thd, stage_creating_table);
5344
5345 if (check_engine(thd, orig_db.str, orig_table_name.str, create_info))
5346 goto err;
5347
5348 if (create_table_mode == C_ASSISTED_DISCOVERY)
5349 {
5350 /* check that it's used correctly */
5351 DBUG_ASSERT(alter_info->create_list.elements == 0);
5352 DBUG_ASSERT(alter_info->key_list.elements == 0);
5353
5354 TABLE_SHARE share;
5355 handlerton *hton= create_info->db_type;
5356 int ha_err;
5357 Field *no_fields= 0;
5358
5359 if (!hton->discover_table_structure)
5360 {
5361 my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
5362 goto err;
5363 }
5364
5365 init_tmp_table_share(thd, &share, db.str, 0, table_name.str, path);
5366
5367 /* prepare everything for discovery */
5368 share.field= &no_fields;
5369 share.db_plugin= ha_lock_engine(thd, hton);
5370 share.option_list= create_info->option_list;
5371 share.connect_string= create_info->connect_string;
5372
5373 if (parse_engine_table_options(thd, hton, &share))
5374 goto err;
5375
5376 ha_err= hton->discover_table_structure(hton, thd, &share, create_info);
5377
5378 /*
5379 if discovery failed, the plugin will be auto-unlocked, as it
5380 was locked on the THD, see above.
5381 if discovery succeeded, the plugin was replaced by a globally
5382 locked plugin, that will be unlocked by free_table_share()
5383 */
5384 if (ha_err)
5385 share.db_plugin= 0; // will be auto-freed, locked above on the THD
5386
5387 free_table_share(&share);
5388
5389 if (ha_err)
5390 {
5391 my_error(ER_GET_ERRNO, MYF(0), ha_err, hton_name(hton)->str);
5392 goto err;
5393 }
5394 }
5395 else
5396 {
5397 file= mysql_create_frm_image(thd, orig_db, orig_table_name, create_info,
5398 alter_info, create_table_mode, key_info,
5399 key_count, frm);
5400 /*
5401 TODO: remove this check of thd->is_error() (now it intercept
5402 errors in some val_*() methoids and bring some single place to
5403 such error interception).
5404 */
5405 if (!file || thd->is_error())
5406 goto err;
5407
5408 if (thd->variables.keep_files_on_create)
5409 create_info->options|= HA_CREATE_KEEP_FILES;
5410
5411 if (file->ha_create_partitioning_metadata(path, NULL, CHF_CREATE_FLAG))
5412 goto err;
5413
5414 if (!frm_only)
5415 {
5416 if (ha_create_table(thd, path, db.str, table_name.str, create_info, frm))
5417 {
5418 file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG);
5419 deletefrm(path);
5420 goto err;
5421 }
5422 }
5423 }
5424
5425 create_info->table= 0;
5426 if (!frm_only && create_info->tmp_table())
5427 {
5428 TABLE *table= thd->create_and_open_tmp_table(frm, path, db.str,
5429 table_name.str,
5430 false);
5431
5432 if (!table)
5433 {
5434 (void) thd->rm_temporary_table(create_info->db_type, path);
5435 goto err;
5436 }
5437
5438 if (is_trans != NULL)
5439 *is_trans= table->file->has_transactions();
5440
5441 thd->thread_specific_used= TRUE;
5442 create_info->table= table; // Store pointer to table
5443 }
5444
5445 error= 0;
5446 err:
5447 THD_STAGE_INFO(thd, stage_after_create);
5448 delete file;
5449 DBUG_PRINT("exit", ("return: %d", error));
5450 DBUG_RETURN(error);
5451
5452 warn:
5453 error= -1;
5454 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
5455 ER_TABLE_EXISTS_ERROR,
5456 ER_THD(thd, ER_TABLE_EXISTS_ERROR),
5457 alias->str);
5458 goto err;
5459 }
5460
5461 /**
5462 Simple wrapper around create_table_impl() to be used
5463 in various version of CREATE TABLE statement.
5464
5465 @result
5466 1 unspefied error
5467 2 error; Don't log create statement
5468 0 ok
5469 -1 Table was used with IF NOT EXISTS and table existed (warning, not error)
5470 */
5471
mysql_create_table_no_lock(THD * thd,const LEX_CSTRING * db,const LEX_CSTRING * table_name,Table_specification_st * create_info,Alter_info * alter_info,bool * is_trans,int create_table_mode,TABLE_LIST * table_list)5472 int mysql_create_table_no_lock(THD *thd, const LEX_CSTRING *db,
5473 const LEX_CSTRING *table_name,
5474 Table_specification_st *create_info,
5475 Alter_info *alter_info, bool *is_trans,
5476 int create_table_mode, TABLE_LIST *table_list)
5477 {
5478 KEY *not_used_1;
5479 uint not_used_2;
5480 int res;
5481 char path[FN_REFLEN + 1];
5482 LEX_CUSTRING frm= {0,0};
5483
5484 if (create_info->tmp_table())
5485 build_tmptable_filename(thd, path, sizeof(path));
5486 else
5487 {
5488 int length;
5489 const LEX_CSTRING *alias= table_case_name(create_info, table_name);
5490 length= build_table_filename(path, sizeof(path) - 1, db->str, alias->str, "", 0);
5491 // Check if we hit FN_REFLEN bytes along with file extension.
5492 if (length+reg_ext_length > FN_REFLEN)
5493 {
5494 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(path)-1,
5495 path);
5496 return true;
5497 }
5498 }
5499
5500 res= create_table_impl(thd, *db, *table_name, *db, *table_name, path,
5501 *create_info, create_info,
5502 alter_info, create_table_mode,
5503 is_trans, ¬_used_1, ¬_used_2, &frm);
5504 my_free(const_cast<uchar*>(frm.str));
5505
5506 if (!res && create_info->sequence)
5507 {
5508 /* Set create_info.table if temporary table */
5509 if (create_info->tmp_table())
5510 table_list->table= create_info->table;
5511 else
5512 table_list->table= 0;
5513 res= sequence_insert(thd, thd->lex, table_list);
5514 if (res)
5515 {
5516 DBUG_ASSERT(thd->is_error());
5517 /* Drop the table as it wasn't completely done */
5518 if (!mysql_rm_table_no_locks(thd, table_list, 1,
5519 create_info->tmp_table(),
5520 false, true /* Sequence*/,
5521 true /* Don't log_query */,
5522 true /* Don't free locks */ ))
5523 {
5524 /*
5525 From the user point of view, the table creation failed
5526 We return 2 to indicate that this statement doesn't have
5527 to be logged.
5528 */
5529 res= 2;
5530 }
5531 }
5532 }
5533
5534 return res;
5535 }
5536
5537 /**
5538 Implementation of SQLCOM_CREATE_TABLE.
5539
5540 Take the metadata locks (including a shared lock on the affected
5541 schema) and create the table. Is written to be called from
5542 mysql_execute_command(), to which it delegates the common parts
5543 with other commands (i.e. implicit commit before and after,
5544 close of thread tables.
5545 */
5546
mysql_create_table(THD * thd,TABLE_LIST * create_table,Table_specification_st * create_info,Alter_info * alter_info)5547 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
5548 Table_specification_st *create_info,
5549 Alter_info *alter_info)
5550 {
5551 bool is_trans= FALSE;
5552 bool result;
5553 int create_table_mode;
5554 TABLE_LIST *pos_in_locked_tables= 0;
5555 MDL_ticket *mdl_ticket= 0;
5556 DBUG_ENTER("mysql_create_table");
5557
5558 DBUG_ASSERT(create_table == thd->lex->query_tables);
5559
5560 /* Copy temporarily the statement flags to thd for lock_table_names() */
5561 uint save_thd_create_info_options= thd->lex->create_info.options;
5562 thd->lex->create_info.options|= create_info->options;
5563
5564 /* Open or obtain an exclusive metadata lock on table being created */
5565 create_table->db_type= 0;
5566 result= open_and_lock_tables(thd, *create_info, create_table, FALSE, 0);
5567
5568 thd->lex->create_info.options= save_thd_create_info_options;
5569
5570 if (result)
5571 {
5572 if (thd->slave_thread &&
5573 !thd->is_error() && create_table->db_type &&
5574 (create_table->db_type->flags & HTON_IGNORE_UPDATES))
5575 {
5576 /* Table existed in distributed engine. Log query to binary log */
5577 result= 0;
5578 goto err;
5579 }
5580 /* is_error() may be 0 if table existed and we generated a warning */
5581 DBUG_RETURN(thd->is_error());
5582 }
5583 /* The following is needed only in case of lock tables */
5584 if ((create_info->table= create_table->table))
5585 {
5586 pos_in_locked_tables= create_info->table->pos_in_locked_tables;
5587 mdl_ticket= create_table->table->mdl_ticket;
5588 }
5589
5590 /* Got lock. */
5591 DEBUG_SYNC(thd, "locked_table_name");
5592
5593 if (alter_info->create_list.elements || alter_info->key_list.elements)
5594 create_table_mode= C_ORDINARY_CREATE;
5595 else
5596 create_table_mode= C_ASSISTED_DISCOVERY;
5597
5598 if (!opt_explicit_defaults_for_timestamp)
5599 promote_first_timestamp_column(&alter_info->create_list);
5600
5601 /* We can abort create table for any table type */
5602 thd->abort_on_warning= thd->is_strict_mode();
5603
5604 if (mysql_create_table_no_lock(thd, &create_table->db,
5605 &create_table->table_name, create_info,
5606 alter_info,
5607 &is_trans, create_table_mode,
5608 create_table) > 0)
5609 {
5610 result= 1;
5611 goto err;
5612 }
5613
5614 /*
5615 Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
5616 on a non temporary table
5617 */
5618 if (thd->locked_tables_mode && pos_in_locked_tables &&
5619 create_info->or_replace())
5620 {
5621 DBUG_ASSERT(thd->variables.option_bits & OPTION_TABLE_LOCK);
5622 /*
5623 Add back the deleted table and re-created table as a locked table
5624 This should always work as we have a meta lock on the table.
5625 */
5626 thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
5627 if (thd->locked_tables_list.reopen_tables(thd, false))
5628 {
5629 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
5630 result= 1;
5631 goto err;
5632 }
5633 else
5634 {
5635 TABLE *table= pos_in_locked_tables->table;
5636 table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
5637 }
5638 }
5639
5640 err:
5641 thd->abort_on_warning= 0;
5642
5643 /* In RBR or readonly server we don't need to log CREATE TEMPORARY TABLE */
5644 if (!result && create_info->tmp_table() &&
5645 (thd->is_current_stmt_binlog_format_row() || (opt_readonly && !thd->slave_thread)))
5646 {
5647 /* Note that table->s->table_creation_was_logged is not set! */
5648 DBUG_RETURN(result);
5649 }
5650
5651 if (create_info->tmp_table())
5652 thd->transaction->stmt.mark_created_temp_table();
5653
5654 /* Write log if no error or if we already deleted a table */
5655 if (likely(!result) || thd->log_current_statement)
5656 {
5657 if (unlikely(result) && create_info->table_was_deleted &&
5658 pos_in_locked_tables)
5659 {
5660 /*
5661 Possible locked table was dropped. We should remove meta data locks
5662 associated with it and do UNLOCK_TABLES if no more locked tables.
5663 */
5664 (void) thd->locked_tables_list.unlock_locked_table(thd, mdl_ticket);
5665 }
5666 else if (likely(!result) && create_info->table)
5667 {
5668 /*
5669 Remember that table creation was logged so that we know if
5670 we should log a delete of it.
5671 If create_info->table was not set, it's a normal table and
5672 table_creation_was_logged will be set when the share is created.
5673 */
5674 create_info->table->s->table_creation_was_logged= 1;
5675 }
5676 if (unlikely(write_bin_log(thd, result ? FALSE : TRUE, thd->query(),
5677 thd->query_length(), is_trans)))
5678 result= 1;
5679 }
5680 DBUG_RETURN(result);
5681 }
5682
5683
5684 /*
5685 ** Give the key name after the first field with an optional '_#' after
5686 @returns
5687 0 if keyname does not exists
5688 [1..) index + 1 of duplicate key name
5689 **/
5690
5691 static int
check_if_keyname_exists(const char * name,KEY * start,KEY * end)5692 check_if_keyname_exists(const char *name, KEY *start, KEY *end)
5693 {
5694 uint i= 1;
5695 for (KEY *key=start; key != end ; key++, i++)
5696 if (!my_strcasecmp(system_charset_info, name, key->name.str))
5697 return i;
5698 return 0;
5699 }
5700
5701 /**
5702 Returns 1 if field name exists otherwise 0
5703 */
5704 static bool
check_if_field_name_exists(const char * name,List<Create_field> * fields)5705 check_if_field_name_exists(const char *name, List<Create_field> * fields)
5706 {
5707 Create_field *fld;
5708 List_iterator<Create_field>it(*fields);
5709 while ((fld = it++))
5710 {
5711 if (!my_strcasecmp(system_charset_info, fld->field_name.str, name))
5712 return 1;
5713 }
5714 return 0;
5715 }
5716
5717 static char *
make_unique_key_name(THD * thd,const char * field_name,KEY * start,KEY * end)5718 make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
5719 {
5720 char buff[MAX_FIELD_NAME],*buff_end;
5721
5722 if (!check_if_keyname_exists(field_name,start,end) &&
5723 my_strcasecmp(system_charset_info,field_name,primary_key_name))
5724 return (char*) field_name; // Use fieldname
5725 buff_end=strmake(buff,field_name, sizeof(buff)-4);
5726
5727 /*
5728 Only 3 chars + '\0' left, so need to limit to 2 digit
5729 This is ok as we can't have more than 100 keys anyway
5730 */
5731 for (uint i=2 ; i< 100; i++)
5732 {
5733 *buff_end= '_';
5734 int10_to_str(i, buff_end+1, 10);
5735 if (!check_if_keyname_exists(buff,start,end))
5736 return thd->strdup(buff);
5737 }
5738 return (char*) "not_specified"; // Should never happen
5739 }
5740
5741 /**
5742 Make an unique name for constraints without a name
5743 */
5744
make_unique_constraint_name(THD * thd,LEX_CSTRING * name,const char * own_name_base,List<Virtual_column_info> * vcol,uint * nr)5745 static bool make_unique_constraint_name(THD *thd, LEX_CSTRING *name,
5746 const char *own_name_base,
5747 List<Virtual_column_info> *vcol,
5748 uint *nr)
5749 {
5750 char buff[MAX_FIELD_NAME], *end;
5751 List_iterator_fast<Virtual_column_info> it(*vcol);
5752 end=strmov(buff, own_name_base ? own_name_base : "CONSTRAINT_");
5753 for (int round= 0;; round++)
5754 {
5755 Virtual_column_info *check;
5756 char *real_end= end;
5757 if (round == 1 && own_name_base)
5758 *end++= '_';
5759 // if own_base_name provided, try it first
5760 if (round != 0 || !own_name_base)
5761 real_end= int10_to_str((*nr)++, end, 10);
5762 it.rewind();
5763 while ((check= it++))
5764 {
5765 if (check->name.str &&
5766 !my_strcasecmp(system_charset_info, buff, check->name.str))
5767 break;
5768 }
5769 if (!check) // Found unique name
5770 {
5771 name->length= (size_t) (real_end - buff);
5772 name->str= strmake_root(thd->stmt_arena->mem_root, buff, name->length);
5773 return (name->str == NULL);
5774 }
5775 }
5776 return FALSE;
5777 }
5778
5779 /**
5780 INVISIBLE_FULL are internally created. They are completely invisible
5781 to Alter command (Opposite of SYSTEM_INVISIBLE which throws an
5782 error when same name column is added by Alter). So in the case of when
5783 user added a same column name as of INVISIBLE_FULL , we change
5784 INVISIBLE_FULL column name.
5785 */
5786 static const
make_unique_invisible_field_name(THD * thd,const char * field_name,List<Create_field> * fields)5787 char * make_unique_invisible_field_name(THD *thd, const char *field_name,
5788 List<Create_field> *fields)
5789 {
5790 if (!check_if_field_name_exists(field_name, fields))
5791 return field_name;
5792 char buff[MAX_FIELD_NAME], *buff_end;
5793 buff_end= strmake_buf(buff, field_name);
5794 if (buff_end - buff < 5)
5795 return NULL; // Should not happen
5796
5797 for (uint i=1 ; i < 10000; i++)
5798 {
5799 char *real_end= int10_to_str(i, buff_end, 10);
5800 if (check_if_field_name_exists(buff, fields))
5801 continue;
5802 return (const char *)thd->strmake(buff, real_end - buff);
5803 }
5804 return NULL; //Should not happen
5805 }
5806
5807 /****************************************************************************
5808 ** Alter a table definition
5809 ****************************************************************************/
5810
operator !=(const MYSQL_TIME & lhs,const MYSQL_TIME & rhs)5811 bool operator!=(const MYSQL_TIME &lhs, const MYSQL_TIME &rhs)
5812 {
5813 return lhs.year != rhs.year || lhs.month != rhs.month || lhs.day != rhs.day ||
5814 lhs.hour != rhs.hour || lhs.minute != rhs.minute ||
5815 lhs.second_part != rhs.second_part || lhs.neg != rhs.neg ||
5816 lhs.time_type != rhs.time_type;
5817 }
5818
5819 /**
5820 Rename a table.
5821
5822 @param base The handlerton handle.
5823 @param old_db The old database name.
5824 @param old_name The old table name.
5825 @param new_db The new database name.
5826 @param new_name The new table name.
5827 @param flags flags
5828 FN_FROM_IS_TMP old_name is temporary.
5829 FN_TO_IS_TMP new_name is temporary.
5830 NO_FRM_RENAME Don't rename the FRM file
5831 but only the table in the storage engine.
5832 NO_HA_TABLE Don't rename table in engine.
5833 NO_FK_CHECKS Don't check FK constraints during rename.
5834
5835 @return false OK
5836 @return true Error
5837 */
5838
5839 bool
mysql_rename_table(handlerton * base,const LEX_CSTRING * old_db,const LEX_CSTRING * old_name,const LEX_CSTRING * new_db,const LEX_CSTRING * new_name,uint flags)5840 mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
5841 const LEX_CSTRING *old_name, const LEX_CSTRING *new_db,
5842 const LEX_CSTRING *new_name, uint flags)
5843 {
5844 THD *thd= current_thd;
5845 char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
5846 lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
5847 char *from_base= from, *to_base= to;
5848 char tmp_name[SAFE_NAME_LEN+1], tmp_db_name[SAFE_NAME_LEN+1];
5849 handler *file;
5850 int error=0;
5851 ulonglong save_bits= thd->variables.option_bits;
5852 int length;
5853 DBUG_ENTER("mysql_rename_table");
5854 DBUG_ASSERT(base);
5855 DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'",
5856 old_db->str, old_name->str, new_db->str,
5857 new_name->str));
5858
5859 // Temporarily disable foreign key checks
5860 if (flags & NO_FK_CHECKS)
5861 thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
5862
5863 file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
5864
5865 build_table_filename(from, sizeof(from) - 1, old_db->str, old_name->str, "",
5866 flags & FN_FROM_IS_TMP);
5867 length= build_table_filename(to, sizeof(to) - 1, new_db->str,
5868 new_name->str, "", flags & FN_TO_IS_TMP);
5869 // Check if we hit FN_REFLEN bytes along with file extension.
5870 if (length+reg_ext_length > FN_REFLEN)
5871 {
5872 my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(to)-1, to);
5873 DBUG_RETURN(TRUE);
5874 }
5875
5876 /*
5877 If lower_case_table_names == 2 (case-preserving but case-insensitive
5878 file system) and the storage is not HA_FILE_BASED, we need to provide
5879 a lowercase file name, but we leave the .frm in mixed case.
5880 */
5881 if (lower_case_table_names == 2 && file &&
5882 !(file->ha_table_flags() & HA_FILE_BASED))
5883 {
5884 strmov(tmp_name, old_name->str);
5885 my_casedn_str(files_charset_info, tmp_name);
5886 strmov(tmp_db_name, old_db->str);
5887 my_casedn_str(files_charset_info, tmp_db_name);
5888
5889 build_table_filename(lc_from, sizeof(lc_from) - 1, tmp_db_name, tmp_name,
5890 "", flags & FN_FROM_IS_TMP);
5891 from_base= lc_from;
5892
5893 strmov(tmp_name, new_name->str);
5894 my_casedn_str(files_charset_info, tmp_name);
5895 strmov(tmp_db_name, new_db->str);
5896 my_casedn_str(files_charset_info, tmp_db_name);
5897
5898 build_table_filename(lc_to, sizeof(lc_to) - 1, tmp_db_name, tmp_name, "",
5899 flags & FN_TO_IS_TMP);
5900 to_base= lc_to;
5901 }
5902
5903 if (flags & NO_HA_TABLE)
5904 {
5905 if (rename_file_ext(from,to,reg_ext))
5906 error= my_errno;
5907 if (!(flags & NO_PAR_TABLE))
5908 (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
5909 }
5910 else if (!file || likely(!(error=file->ha_rename_table(from_base, to_base))))
5911 {
5912 if (!(flags & NO_FRM_RENAME) && unlikely(rename_file_ext(from,to,reg_ext)))
5913 {
5914 error=my_errno;
5915 if (file)
5916 {
5917 if (error == ENOENT)
5918 error= 0; // this is ok if file->ha_rename_table() succeeded
5919 else
5920 file->ha_rename_table(to_base, from_base); // Restore old file name
5921 }
5922 }
5923 }
5924 delete file;
5925
5926 if (error == HA_ERR_WRONG_COMMAND)
5927 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
5928 else if (error == ENOTDIR)
5929 my_error(ER_BAD_DB_ERROR, MYF(0), new_db->str);
5930 else if (error)
5931 my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
5932 else if (!(flags & FN_IS_TMP))
5933 mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
5934
5935 /*
5936 Remove the old table share from the pfs table share array. The new table
5937 share will be created when the renamed table is first accessed.
5938 */
5939 if (likely(error == 0))
5940 {
5941 PSI_CALL_drop_table_share(flags & FN_FROM_IS_TMP,
5942 old_db->str, (uint)old_db->length,
5943 old_name->str, (uint)old_name->length);
5944 }
5945
5946 // Restore options bits to the original value
5947 thd->variables.option_bits= save_bits;
5948
5949 DBUG_RETURN(error != 0);
5950 }
5951
5952
5953 /*
5954 Create a table identical to the specified table
5955
5956 SYNOPSIS
5957 mysql_create_like_table()
5958 thd Thread object
5959 table Table list element for target table
5960 src_table Table list element for source table
5961 create_info Create info
5962
5963 RETURN VALUES
5964 FALSE OK
5965 TRUE error
5966 */
5967
mysql_create_like_table(THD * thd,TABLE_LIST * table,TABLE_LIST * src_table,Table_specification_st * create_info)5968 bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
5969 TABLE_LIST* src_table,
5970 Table_specification_st *create_info)
5971 {
5972 Table_specification_st local_create_info;
5973 TABLE_LIST *pos_in_locked_tables= 0;
5974 Alter_info local_alter_info;
5975 Alter_table_ctx local_alter_ctx; // Not used
5976 int res= 1;
5977 bool is_trans= FALSE;
5978 bool do_logging= FALSE;
5979 bool force_generated_create= false;
5980 uint not_used;
5981 int create_res;
5982 DBUG_ENTER("mysql_create_like_table");
5983
5984 #ifdef WITH_WSREP
5985 if (WSREP(thd) && !thd->wsrep_applier &&
5986 wsrep_create_like_table(thd, table, src_table, create_info))
5987 {
5988 DBUG_RETURN(res);
5989 }
5990 #endif
5991
5992 /*
5993 We the open source table to get its description in HA_CREATE_INFO
5994 and Alter_info objects. This also acquires a shared metadata lock
5995 on this table which ensures that no concurrent DDL operation will
5996 mess with it.
5997 Also in case when we create non-temporary table open_tables()
5998 call obtains an exclusive metadata lock on target table ensuring
5999 that we can safely perform table creation.
6000 Thus by holding both these locks we ensure that our statement is
6001 properly isolated from all concurrent operations which matter.
6002 */
6003
6004 res= open_tables(thd, *create_info, &thd->lex->query_tables, ¬_used, 0);
6005
6006 if (res)
6007 {
6008 /* is_error() may be 0 if table existed and we generated a warning */
6009 res= thd->is_error();
6010 goto err;
6011 }
6012 /* Ensure we don't try to create something from which we select from */
6013 if (create_info->or_replace() && !create_info->tmp_table())
6014 {
6015 TABLE_LIST *duplicate;
6016 if ((duplicate= unique_table(thd, table, src_table, 0)))
6017 {
6018 update_non_unique_table_error(src_table, "CREATE", duplicate);
6019 goto err;
6020 }
6021 }
6022
6023 src_table->table->use_all_columns();
6024
6025 DEBUG_SYNC(thd, "create_table_like_after_open");
6026
6027 /*
6028 Fill Table_specification_st and Alter_info with the source table description.
6029 Set OR REPLACE and IF NOT EXISTS option as in the CREATE TABLE LIKE
6030 statement.
6031 */
6032 local_create_info.init(create_info->create_like_options());
6033 local_create_info.db_type= src_table->table->s->db_type();
6034 local_create_info.row_type= src_table->table->s->row_type;
6035 local_create_info.alter_info= &local_alter_info;
6036 if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
6037 &local_alter_info, &local_alter_ctx))
6038 goto err;
6039 #ifdef WITH_PARTITION_STORAGE_ENGINE
6040 /* Partition info is not handled by mysql_prepare_alter_table() call. */
6041 if (src_table->table->part_info)
6042 {
6043 /*
6044 The CREATE TABLE LIKE should not inherit the DATA DIRECTORY
6045 and INDEX DIRECTORY from the base table.
6046 So that TRUE argument for the get_clone.
6047 */
6048 thd->work_part_info= src_table->table->part_info->get_clone(thd, TRUE);
6049 }
6050 #endif /*WITH_PARTITION_STORAGE_ENGINE*/
6051
6052 /*
6053 Adjust description of source table before using it for creation of
6054 target table.
6055
6056 Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
6057 temporary table which represents I_S table.
6058 */
6059 if (src_table->schema_table)
6060 local_create_info.max_rows= 0;
6061 /* Replace type of source table with one specified in the statement. */
6062 local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
6063 local_create_info.options|= create_info->options;
6064 /* Reset auto-increment counter for the new table. */
6065 local_create_info.auto_increment_value= 0;
6066 /*
6067 Do not inherit values of DATA and INDEX DIRECTORY options from
6068 the original table. This is documented behavior.
6069 */
6070 local_create_info.data_file_name= local_create_info.index_file_name= NULL;
6071
6072 if (src_table->table->versioned() &&
6073 local_create_info.vers_info.fix_create_like(local_alter_info, local_create_info,
6074 *src_table, *table))
6075 {
6076 goto err;
6077 }
6078
6079 /* The following is needed only in case of lock tables */
6080 if ((local_create_info.table= thd->lex->query_tables->table))
6081 pos_in_locked_tables= local_create_info.table->pos_in_locked_tables;
6082
6083 res= ((create_res=
6084 mysql_create_table_no_lock(thd, &table->db, &table->table_name,
6085 &local_create_info, &local_alter_info,
6086 &is_trans, C_ORDINARY_CREATE,
6087 table)) > 0);
6088 /* Remember to log if we deleted something */
6089 do_logging= thd->log_current_statement;
6090 if (res)
6091 goto err;
6092
6093 /*
6094 Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
6095 on a non temporary table
6096 */
6097 if (thd->locked_tables_mode && pos_in_locked_tables &&
6098 create_info->or_replace())
6099 {
6100 /*
6101 Add back the deleted table and re-created table as a locked table
6102 This should always work as we have a meta lock on the table.
6103 */
6104 thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
6105 if (thd->locked_tables_list.reopen_tables(thd, false))
6106 {
6107 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
6108 res= 1; // We got an error
6109 }
6110 else
6111 {
6112 /*
6113 Get pointer to the newly opened table. We need this to ensure we
6114 don't reopen the table when doing statment logging below.
6115 */
6116 table->table= pos_in_locked_tables->table;
6117 table->table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
6118 }
6119 }
6120 else
6121 {
6122 /*
6123 Ensure that we have an exclusive lock on target table if we are creating
6124 non-temporary table.
6125 If we're creating non-temporary table, then either
6126 - there is an exclusive lock on the table
6127 or
6128 - there was CREATE IF EXIST, and the table was not created
6129 (it existed), and was previously locked
6130 */
6131 DBUG_ASSERT((create_info->tmp_table()) ||
6132 thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db.str,
6133 table->table_name.str,
6134 MDL_EXCLUSIVE) ||
6135 (thd->locked_tables_mode && pos_in_locked_tables &&
6136 create_info->if_not_exists()));
6137 }
6138
6139 DEBUG_SYNC(thd, "create_table_like_before_binlog");
6140
6141 /*
6142 We have to write the query before we unlock the tables.
6143 */
6144 if (thd->is_current_stmt_binlog_disabled())
6145 goto err;
6146
6147 #ifdef ENABLE_WHEN_S3_CAN_CREATE_TABLES
6148 /*
6149 If we do a create based on a shared table, log the full create of the
6150 resulting table. This is needed as a shared table may look different
6151 when the slave executes the command.
6152 */
6153 force_generated_create=
6154 (((src_table->table->file->partition_ht()->flags &
6155 HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) &&
6156 src_table->table->s->db_type() != local_create_info.db_type));
6157 #endif
6158
6159 if (thd->is_current_stmt_binlog_format_row() || force_generated_create)
6160 {
6161 /*
6162 Since temporary tables are not replicated under row-based
6163 replication, CREATE TABLE ... LIKE ... needs special
6164 treatement. We have some cases to consider, according to the
6165 following decision table:
6166
6167 ==== ========= ========= ==============================
6168 Case Target Source Write to binary log
6169 ==== ========= ========= ==============================
6170 1 normal normal Original statement
6171 2 normal temporary Generated statement if the table
6172 was created.
6173 3 temporary normal Nothing
6174 4 temporary temporary Nothing
6175 5 any shared Generated statement if the table
6176 was created if engine changed
6177 ==== ========= ========= ==============================
6178 */
6179 if (!(create_info->tmp_table()) || force_generated_create)
6180 {
6181 // Case 2 & 5
6182 if (src_table->table->s->tmp_table || force_generated_create)
6183 {
6184 char buf[2048];
6185 String query(buf, sizeof(buf), system_charset_info);
6186 query.length(0); // Have to zero it since constructor doesn't
6187 Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN |
6188 MYSQL_OPEN_IGNORE_KILLED);
6189 bool new_table= FALSE; // Whether newly created table is open.
6190
6191 if (create_res != 0)
6192 {
6193 /*
6194 Table or view with same name already existed and we where using
6195 IF EXISTS. Continue without logging anything.
6196 */
6197 do_logging= 0;
6198 goto err;
6199 }
6200 if (!table->table)
6201 {
6202 TABLE_LIST::enum_open_strategy save_open_strategy;
6203 int open_res;
6204 /* Force the newly created table to be opened */
6205 save_open_strategy= table->open_strategy;
6206 table->open_strategy= TABLE_LIST::OPEN_NORMAL;
6207
6208 /*
6209 In order for show_create_table() to work we need to open
6210 destination table if it is not already open (i.e. if it
6211 has not existed before). We don't need acquire metadata
6212 lock in order to do this as we already hold exclusive
6213 lock on this table. The table will be closed by
6214 close_thread_table() at the end of this branch.
6215 */
6216 open_res= open_table(thd, table, &ot_ctx);
6217 /* Restore */
6218 table->open_strategy= save_open_strategy;
6219 if (open_res)
6220 {
6221 res= 1;
6222 goto err;
6223 }
6224 new_table= TRUE;
6225 }
6226 /*
6227 We have to re-test if the table was a view as the view may not
6228 have been opened until just above.
6229 */
6230 if (!table->view)
6231 {
6232 /*
6233 After opening a MERGE table add the children to the query list of
6234 tables, so that children tables info can be used on "CREATE TABLE"
6235 statement generation by the binary log.
6236 Note that placeholders don't have the handler open.
6237 */
6238 if (table->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
6239 goto err;
6240
6241 /*
6242 As the reference table is temporary and may not exist on slave, we
6243 must force the ENGINE to be present into CREATE TABLE.
6244 */
6245 create_info->used_fields|= HA_CREATE_USED_ENGINE;
6246
6247 int result __attribute__((unused))=
6248 show_create_table(thd, table, &query, create_info, WITH_DB_NAME);
6249
6250 DBUG_ASSERT(result == 0); // show_create_table() always return 0
6251 do_logging= FALSE;
6252 if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
6253 {
6254 res= 1;
6255 do_logging= 0;
6256 goto err;
6257 }
6258
6259 if (new_table)
6260 {
6261 DBUG_ASSERT(thd->open_tables == table->table);
6262 /*
6263 When opening the table, we ignored the locked tables
6264 (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table
6265 without risking to close some locked table.
6266 */
6267 close_thread_table(thd, &thd->open_tables);
6268 }
6269 }
6270 }
6271 else // Case 1
6272 do_logging= TRUE;
6273 }
6274 /*
6275 Case 3 and 4 does nothing under RBR
6276 */
6277 }
6278 else
6279 {
6280 DBUG_PRINT("info",
6281 ("res: %d tmp_table: %d create_info->table: %p",
6282 res, create_info->tmp_table(), local_create_info.table));
6283 if (create_info->tmp_table())
6284 {
6285 thd->transaction->stmt.mark_created_temp_table();
6286 if (!res && local_create_info.table)
6287 {
6288 /*
6289 Remember that tmp table creation was logged so that we know if
6290 we should log a delete of it.
6291 */
6292 local_create_info.table->s->table_creation_was_logged= 1;
6293 }
6294 }
6295 do_logging= TRUE;
6296 }
6297
6298 err:
6299 if (do_logging)
6300 {
6301 if (res && create_info->table_was_deleted)
6302 {
6303 /*
6304 Table was not deleted. Original table was deleted.
6305 We have to log it.
6306 */
6307 log_drop_table(thd, &table->db, &table->table_name, create_info->tmp_table());
6308 }
6309 else if (res != 2) // Table was not dropped
6310 {
6311 if (write_bin_log(thd, res ? FALSE : TRUE, thd->query(),
6312 thd->query_length(), is_trans))
6313 res= 1;
6314 }
6315 }
6316
6317 DBUG_RETURN(res != 0);
6318 }
6319
6320
6321 /* table_list should contain just one table */
mysql_discard_or_import_tablespace(THD * thd,TABLE_LIST * table_list,bool discard)6322 int mysql_discard_or_import_tablespace(THD *thd,
6323 TABLE_LIST *table_list,
6324 bool discard)
6325 {
6326 Alter_table_prelocking_strategy alter_prelocking_strategy;
6327 int error;
6328 DBUG_ENTER("mysql_discard_or_import_tablespace");
6329
6330 mysql_audit_alter_table(thd, table_list);
6331
6332 /*
6333 Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
6334 ALTER TABLE
6335 */
6336
6337 THD_STAGE_INFO(thd, stage_discard_or_import_tablespace);
6338
6339 /*
6340 We set this flag so that ha_innobase::open and ::external_lock() do
6341 not complain when we lock the table
6342 */
6343 thd->tablespace_op= TRUE;
6344 /*
6345 Adjust values of table-level and metadata which was set in parser
6346 for the case general ALTER TABLE.
6347 */
6348 table_list->mdl_request.set_type(MDL_EXCLUSIVE);
6349 table_list->lock_type= TL_WRITE;
6350 /* Do not open views. */
6351 table_list->required_type= TABLE_TYPE_NORMAL;
6352
6353 if (open_and_lock_tables(thd, table_list, FALSE, 0,
6354 &alter_prelocking_strategy))
6355 {
6356 thd->tablespace_op=FALSE;
6357 DBUG_RETURN(-1);
6358 }
6359
6360 error= table_list->table->file->ha_discard_or_import_tablespace(discard);
6361
6362 THD_STAGE_INFO(thd, stage_end);
6363
6364 if (unlikely(error))
6365 goto err;
6366
6367 /*
6368 The 0 in the call below means 'not in a transaction', which means
6369 immediate invalidation; that is probably what we wish here
6370 */
6371 query_cache_invalidate3(thd, table_list, 0);
6372
6373 /* The ALTER TABLE is always in its own transaction */
6374 error= trans_commit_stmt(thd);
6375 if (unlikely(trans_commit_implicit(thd)))
6376 error=1;
6377 if (likely(!error))
6378 error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
6379
6380 err:
6381 thd->tablespace_op=FALSE;
6382
6383 if (likely(error == 0))
6384 {
6385 my_ok(thd);
6386 DBUG_RETURN(0);
6387 }
6388
6389 table_list->table->file->print_error(error, MYF(0));
6390
6391 DBUG_RETURN(-1);
6392 }
6393
6394
6395 /**
6396 Check if key is a candidate key, i.e. a unique index with no index
6397 fields partial or nullable.
6398 */
6399
is_candidate_key(KEY * key)6400 static bool is_candidate_key(KEY *key)
6401 {
6402 KEY_PART_INFO *key_part;
6403 KEY_PART_INFO *key_part_end= key->key_part + key->user_defined_key_parts;
6404
6405 if (!(key->flags & HA_NOSAME) || (key->flags & HA_NULL_PART_KEY) ||
6406 (key->flags & HA_KEY_HAS_PART_KEY_SEG))
6407 return false;
6408
6409 for (key_part= key->key_part; key_part < key_part_end; key_part++)
6410 {
6411 if (key_part->key_part_flag & HA_PART_KEY_SEG)
6412 return false;
6413 }
6414 return true;
6415 }
6416
6417
6418 /*
6419 Preparation for table creation
6420
6421 SYNOPSIS
6422 handle_if_exists_option()
6423 thd Thread object.
6424 table The altered table.
6425 alter_info List of columns and indexes to create
6426 period_info Application-time period info
6427
6428 DESCRIPTION
6429 Looks for the IF [NOT] EXISTS options, checks the states and remove items
6430 from the list if existing found.
6431
6432 RETURN VALUES
6433 TRUE error
6434 FALSE OK
6435 */
6436
6437 static bool
handle_if_exists_options(THD * thd,TABLE * table,Alter_info * alter_info,Table_period_info * period_info)6438 handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info,
6439 Table_period_info *period_info)
6440 {
6441 Field **f_ptr;
6442 DBUG_ENTER("handle_if_exists_option");
6443
6444 /* Handle ADD COLUMN IF NOT EXISTS. */
6445 {
6446 List_iterator<Create_field> it(alter_info->create_list);
6447 Create_field *sql_field;
6448
6449 while ((sql_field=it++))
6450 {
6451 if (!sql_field->create_if_not_exists || sql_field->change.str)
6452 continue;
6453 /*
6454 If there is a field with the same name in the table already,
6455 remove the sql_field from the list.
6456 */
6457 for (f_ptr=table->field; *f_ptr; f_ptr++)
6458 {
6459 if (lex_string_cmp(system_charset_info,
6460 &sql_field->field_name,
6461 &(*f_ptr)->field_name) == 0)
6462 goto drop_create_field;
6463 }
6464 {
6465 /*
6466 If in the ADD list there is a field with the same name,
6467 remove the sql_field from the list.
6468 */
6469 List_iterator<Create_field> chk_it(alter_info->create_list);
6470 Create_field *chk_field;
6471 while ((chk_field= chk_it++) && chk_field != sql_field)
6472 {
6473 if (lex_string_cmp(system_charset_info,
6474 &sql_field->field_name,
6475 &chk_field->field_name) == 0)
6476 goto drop_create_field;
6477 }
6478 }
6479 continue;
6480 drop_create_field:
6481 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6482 ER_DUP_FIELDNAME, ER_THD(thd, ER_DUP_FIELDNAME),
6483 sql_field->field_name.str);
6484 it.remove();
6485 if (alter_info->create_list.is_empty())
6486 {
6487 alter_info->flags&= ~ALTER_PARSER_ADD_COLUMN;
6488 if (alter_info->key_list.is_empty())
6489 alter_info->flags&= ~(ALTER_ADD_INDEX | ALTER_ADD_FOREIGN_KEY);
6490 }
6491 }
6492 }
6493
6494 /* Handle MODIFY COLUMN IF EXISTS. */
6495 {
6496 List_iterator<Create_field> it(alter_info->create_list);
6497 Create_field *sql_field;
6498
6499 while ((sql_field=it++))
6500 {
6501 if (!sql_field->create_if_not_exists || !sql_field->change.str)
6502 continue;
6503 /*
6504 If there is NO field with the same name in the table already,
6505 remove the sql_field from the list.
6506 */
6507 for (f_ptr=table->field; *f_ptr; f_ptr++)
6508 {
6509 if (lex_string_cmp(system_charset_info,
6510 &sql_field->change,
6511 &(*f_ptr)->field_name) == 0)
6512 {
6513 break;
6514 }
6515 }
6516 if (unlikely(*f_ptr == NULL))
6517 {
6518 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6519 ER_BAD_FIELD_ERROR,
6520 ER_THD(thd, ER_BAD_FIELD_ERROR),
6521 sql_field->change.str, table->s->table_name.str);
6522 it.remove();
6523 if (alter_info->create_list.is_empty())
6524 {
6525 alter_info->flags&= ~(ALTER_PARSER_ADD_COLUMN | ALTER_CHANGE_COLUMN);
6526 if (alter_info->key_list.is_empty())
6527 alter_info->flags&= ~ALTER_ADD_INDEX;
6528 }
6529 }
6530 }
6531 }
6532
6533 /* Handle ALTER/RENAME COLUMN IF EXISTS. */
6534 {
6535 List_iterator<Alter_column> it(alter_info->alter_list);
6536 Alter_column *acol;
6537
6538 while ((acol=it++))
6539 {
6540 if (!acol->alter_if_exists)
6541 continue;
6542 /*
6543 If there is NO field with the same name in the table already,
6544 remove the acol from the list.
6545 */
6546 for (f_ptr=table->field; *f_ptr; f_ptr++)
6547 {
6548 if (my_strcasecmp(system_charset_info,
6549 acol->name.str, (*f_ptr)->field_name.str) == 0)
6550 break;
6551 }
6552 if (unlikely(*f_ptr == NULL))
6553 {
6554 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6555 ER_BAD_FIELD_ERROR,
6556 ER_THD(thd, ER_BAD_FIELD_ERROR),
6557 acol->name.str, table->s->table_name.str);
6558 it.remove();
6559 if (alter_info->alter_list.is_empty())
6560 {
6561 alter_info->flags&= ~(ALTER_CHANGE_COLUMN_DEFAULT);
6562 }
6563 }
6564 }
6565 }
6566
6567 /* Handle DROP COLUMN/KEY IF EXISTS. */
6568 {
6569 List_iterator<Alter_drop> drop_it(alter_info->drop_list);
6570 Alter_drop *drop;
6571 bool remove_drop;
6572 ulonglong left_flags= 0;
6573 while ((drop= drop_it++))
6574 {
6575 ulonglong cur_flag= 0;
6576 switch (drop->type) {
6577 case Alter_drop::COLUMN:
6578 cur_flag= ALTER_PARSER_DROP_COLUMN;
6579 break;
6580 case Alter_drop::FOREIGN_KEY:
6581 cur_flag= ALTER_DROP_FOREIGN_KEY;
6582 break;
6583 case Alter_drop::KEY:
6584 cur_flag= ALTER_DROP_INDEX;
6585 break;
6586 default:
6587 break;
6588 }
6589 if (!drop->drop_if_exists)
6590 {
6591 left_flags|= cur_flag;
6592 continue;
6593 }
6594 remove_drop= TRUE;
6595 if (drop->type == Alter_drop::COLUMN)
6596 {
6597 /*
6598 If there is NO field with that name in the table,
6599 remove the 'drop' from the list.
6600 */
6601 for (f_ptr=table->field; *f_ptr; f_ptr++)
6602 {
6603 if (my_strcasecmp(system_charset_info,
6604 drop->name, (*f_ptr)->field_name.str) == 0)
6605 {
6606 remove_drop= FALSE;
6607 break;
6608 }
6609 }
6610 }
6611 else if (drop->type == Alter_drop::CHECK_CONSTRAINT)
6612 {
6613 for (uint i=table->s->field_check_constraints;
6614 i < table->s->table_check_constraints;
6615 i++)
6616 {
6617 if (my_strcasecmp(system_charset_info, drop->name,
6618 table->check_constraints[i]->name.str) == 0)
6619 {
6620 remove_drop= FALSE;
6621 break;
6622 }
6623 }
6624 }
6625 else if (drop->type == Alter_drop::PERIOD)
6626 {
6627 if (table->s->period.name.streq(drop->name))
6628 remove_drop= FALSE;
6629 }
6630 else /* Alter_drop::KEY and Alter_drop::FOREIGN_KEY */
6631 {
6632 uint n_key;
6633 if (drop->type != Alter_drop::FOREIGN_KEY)
6634 {
6635 for (n_key=0; n_key < table->s->keys; n_key++)
6636 {
6637 if (my_strcasecmp(system_charset_info,
6638 drop->name,
6639 table->key_info[n_key].name.str) == 0)
6640 {
6641 remove_drop= FALSE;
6642 break;
6643 }
6644 }
6645 }
6646 else
6647 {
6648 List <FOREIGN_KEY_INFO> fk_child_key_list;
6649 FOREIGN_KEY_INFO *f_key;
6650 table->file->get_foreign_key_list(thd, &fk_child_key_list);
6651 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
6652 while ((f_key= fk_key_it++))
6653 {
6654 if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
6655 drop->name) == 0)
6656 {
6657 remove_drop= FALSE;
6658 break;
6659 }
6660 }
6661 }
6662 }
6663
6664 if (!remove_drop)
6665 {
6666 /*
6667 Check if the name appears twice in the DROP list.
6668 */
6669 List_iterator<Alter_drop> chk_it(alter_info->drop_list);
6670 Alter_drop *chk_drop;
6671 while ((chk_drop= chk_it++) && chk_drop != drop)
6672 {
6673 if (drop->type == chk_drop->type &&
6674 my_strcasecmp(system_charset_info,
6675 drop->name, chk_drop->name) == 0)
6676 {
6677 remove_drop= TRUE;
6678 break;
6679 }
6680 }
6681 }
6682
6683 if (remove_drop)
6684 {
6685 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6686 ER_CANT_DROP_FIELD_OR_KEY,
6687 ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
6688 drop->type_name(), drop->name);
6689 drop_it.remove();
6690 }
6691 else
6692 left_flags|= cur_flag;
6693 }
6694 /* Reset state to what's left in drop list */
6695 alter_info->flags&= ~(ALTER_PARSER_DROP_COLUMN |
6696 ALTER_DROP_INDEX |
6697 ALTER_DROP_FOREIGN_KEY);
6698 alter_info->flags|= left_flags;
6699 }
6700
6701 /* Handle RENAME KEY IF EXISTS. */
6702 {
6703 List_iterator<Alter_rename_key> rename_key_it(alter_info->alter_rename_key_list);
6704 Alter_rename_key *rename_key;
6705 while ((rename_key= rename_key_it++))
6706 {
6707 if (!rename_key->alter_if_exists)
6708 continue;
6709 bool exists= false;
6710 for (uint n_key= 0; n_key < table->s->keys; n_key++)
6711 {
6712 if (my_strcasecmp(system_charset_info,
6713 rename_key->old_name.str,
6714 table->key_info[n_key].name.str) == 0)
6715 {
6716 exists= true;
6717 break;
6718 }
6719 }
6720 if (exists)
6721 continue;
6722 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6723 ER_KEY_DOES_NOT_EXISTS,
6724 ER_THD(thd, ER_KEY_DOES_NOT_EXISTS),
6725 rename_key->old_name.str, table->s->table_name.str);
6726 rename_key_it.remove();
6727 }
6728 }
6729
6730 /* ALTER TABLE ADD KEY IF NOT EXISTS */
6731 /* ALTER TABLE ADD FOREIGN KEY IF NOT EXISTS */
6732 {
6733 Key *key;
6734 List_iterator<Key> key_it(alter_info->key_list);
6735 uint n_key;
6736 const char *keyname= NULL;
6737 while ((key=key_it++))
6738 {
6739 if (!key->if_not_exists() && !key->or_replace())
6740 continue;
6741
6742 /* Check if the table already has a PRIMARY KEY */
6743 bool dup_primary_key=
6744 key->type == Key::PRIMARY &&
6745 table->s->primary_key != MAX_KEY &&
6746 (keyname= table->s->key_info[table->s->primary_key].name.str) &&
6747 my_strcasecmp(system_charset_info, keyname, primary_key_name) == 0;
6748 if (dup_primary_key)
6749 goto remove_key;
6750
6751 /* If the name of the key is not specified, */
6752 /* let us check the name of the first key part. */
6753 if ((keyname= key->name.str) == NULL)
6754 {
6755 if (key->type == Key::PRIMARY)
6756 keyname= primary_key_name;
6757 else
6758 {
6759 List_iterator<Key_part_spec> part_it(key->columns);
6760 Key_part_spec *kp;
6761 if ((kp= part_it++))
6762 keyname= kp->field_name.str;
6763 if (keyname == NULL)
6764 continue;
6765 }
6766 }
6767 if (key->type != Key::FOREIGN_KEY)
6768 {
6769 for (n_key=0; n_key < table->s->keys; n_key++)
6770 {
6771 if (my_strcasecmp(system_charset_info,
6772 keyname, table->key_info[n_key].name.str) == 0)
6773 {
6774 goto remove_key;
6775 }
6776 }
6777 }
6778 else
6779 {
6780 List <FOREIGN_KEY_INFO> fk_child_key_list;
6781 FOREIGN_KEY_INFO *f_key;
6782 table->file->get_foreign_key_list(thd, &fk_child_key_list);
6783 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
6784 while ((f_key= fk_key_it++))
6785 {
6786 if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
6787 keyname) == 0)
6788 goto remove_key;
6789 }
6790 }
6791
6792 {
6793 Key *chk_key;
6794 List_iterator<Key> chk_it(alter_info->key_list);
6795 const char *chkname;
6796 while ((chk_key=chk_it++) && chk_key != key)
6797 {
6798 if ((chkname= chk_key->name.str) == NULL)
6799 {
6800 List_iterator<Key_part_spec> part_it(chk_key->columns);
6801 Key_part_spec *kp;
6802 if ((kp= part_it++))
6803 chkname= kp->field_name.str;
6804 if (chkname == NULL)
6805 continue;
6806 }
6807 if (key->type == chk_key->type &&
6808 my_strcasecmp(system_charset_info, keyname, chkname) == 0)
6809 goto remove_key;
6810 }
6811 }
6812 continue;
6813
6814 remove_key:
6815 if (key->if_not_exists())
6816 {
6817 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6818 ER_DUP_KEYNAME, ER_THD(thd, dup_primary_key
6819 ? ER_MULTIPLE_PRI_KEY : ER_DUP_KEYNAME), keyname);
6820 key_it.remove();
6821 if (key->type == Key::FOREIGN_KEY)
6822 {
6823 /* ADD FOREIGN KEY appends two items. */
6824 key_it.remove();
6825 }
6826 if (alter_info->key_list.is_empty())
6827 alter_info->flags&= ~(ALTER_ADD_INDEX | ALTER_ADD_FOREIGN_KEY);
6828 }
6829 else
6830 {
6831 DBUG_ASSERT(key->or_replace());
6832 Alter_drop::drop_type type= (key->type == Key::FOREIGN_KEY) ?
6833 Alter_drop::FOREIGN_KEY : Alter_drop::KEY;
6834 Alter_drop *ad= new (thd->mem_root) Alter_drop(type, key->name.str, FALSE);
6835 if (ad != NULL)
6836 {
6837 // Adding the index into the drop list for replacing
6838 alter_info->flags |= ALTER_DROP_INDEX;
6839 alter_info->drop_list.push_back(ad, thd->mem_root);
6840 }
6841 }
6842 }
6843 }
6844
6845 #ifdef WITH_PARTITION_STORAGE_ENGINE
6846 partition_info *tab_part_info= table->part_info;
6847 thd->work_part_info= thd->lex->part_info;
6848 if (tab_part_info)
6849 {
6850 /* ALTER TABLE ADD PARTITION IF NOT EXISTS */
6851 if ((alter_info->partition_flags & ALTER_PARTITION_ADD) &&
6852 thd->lex->create_info.if_not_exists())
6853 {
6854 partition_info *alt_part_info= thd->lex->part_info;
6855 if (alt_part_info)
6856 {
6857 List_iterator<partition_element> new_part_it(alt_part_info->partitions);
6858 partition_element *pe;
6859 while ((pe= new_part_it++))
6860 {
6861 if (!tab_part_info->has_unique_name(pe))
6862 {
6863 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6864 ER_SAME_NAME_PARTITION,
6865 ER_THD(thd, ER_SAME_NAME_PARTITION),
6866 pe->partition_name);
6867 alter_info->partition_flags&= ~ALTER_PARTITION_ADD;
6868 thd->work_part_info= NULL;
6869 break;
6870 }
6871 }
6872 }
6873 }
6874 /* ALTER TABLE DROP PARTITION IF EXISTS */
6875 if ((alter_info->partition_flags & ALTER_PARTITION_DROP) &&
6876 thd->lex->if_exists())
6877 {
6878 List_iterator<const char> names_it(alter_info->partition_names);
6879 const char *name;
6880
6881 while ((name= names_it++))
6882 {
6883 List_iterator<partition_element> part_it(tab_part_info->partitions);
6884 partition_element *part_elem;
6885 while ((part_elem= part_it++))
6886 {
6887 if (my_strcasecmp(system_charset_info,
6888 part_elem->partition_name, name) == 0)
6889 break;
6890 }
6891 if (!part_elem)
6892 {
6893 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6894 ER_DROP_PARTITION_NON_EXISTENT,
6895 ER_THD(thd, ER_DROP_PARTITION_NON_EXISTENT),
6896 "DROP");
6897 names_it.remove();
6898 }
6899 }
6900 if (alter_info->partition_names.elements == 0)
6901 alter_info->partition_flags&= ~ALTER_PARTITION_DROP;
6902 }
6903 }
6904 #endif /*WITH_PARTITION_STORAGE_ENGINE*/
6905
6906 /* ADD CONSTRAINT IF NOT EXISTS. */
6907 {
6908 List_iterator<Virtual_column_info> it(alter_info->check_constraint_list);
6909 Virtual_column_info *check;
6910 TABLE_SHARE *share= table->s;
6911 uint c;
6912
6913 while ((check=it++))
6914 {
6915 if (!(check->flags & VCOL_CHECK_CONSTRAINT_IF_NOT_EXISTS) &&
6916 check->name.length)
6917 continue;
6918 check->flags= 0;
6919 for (c= share->field_check_constraints;
6920 c < share->table_check_constraints ; c++)
6921 {
6922 Virtual_column_info *dup= table->check_constraints[c];
6923 if (dup->name.length == check->name.length &&
6924 lex_string_cmp(system_charset_info,
6925 &check->name, &dup->name) == 0)
6926 {
6927 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6928 ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME),
6929 "CHECK", check->name.str);
6930 it.remove();
6931 if (alter_info->check_constraint_list.elements == 0)
6932 alter_info->flags&= ~ALTER_ADD_CHECK_CONSTRAINT;
6933
6934 break;
6935 }
6936 }
6937 }
6938 }
6939
6940 /* ADD PERIOD */
6941
6942 if (period_info->create_if_not_exists && table->s->period.name
6943 && table->s->period.name.streq(period_info->name))
6944 {
6945 DBUG_ASSERT(period_info->is_set());
6946 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
6947 ER_DUP_FIELDNAME, ER_THD(thd, ER_DUP_FIELDNAME),
6948 period_info->name.str, table->s->table_name.str);
6949
6950 List_iterator<Virtual_column_info> vit(alter_info->check_constraint_list);
6951 while (vit++ != period_info->constr)
6952 {
6953 // do nothing
6954 }
6955 vit.remove();
6956
6957 *period_info= {};
6958 }
6959
6960 DBUG_RETURN(false);
6961 }
6962
6963
fix_constraints_names(THD * thd,List<Virtual_column_info> * check_constraint_list,const HA_CREATE_INFO * create_info)6964 static bool fix_constraints_names(THD *thd, List<Virtual_column_info>
6965 *check_constraint_list,
6966 const HA_CREATE_INFO *create_info)
6967 {
6968 List_iterator<Virtual_column_info> it((*check_constraint_list));
6969 Virtual_column_info *check;
6970 uint nr= 1;
6971 DBUG_ENTER("fix_constraints_names");
6972 if (!check_constraint_list)
6973 DBUG_RETURN(FALSE);
6974 // Prevent accessing freed memory during generating unique names
6975 while ((check=it++))
6976 {
6977 if (check->automatic_name)
6978 {
6979 check->name.str= NULL;
6980 check->name.length= 0;
6981 }
6982 }
6983 it.rewind();
6984 // Generate unique names if needed
6985 while ((check=it++))
6986 {
6987 if (!check->name.length)
6988 {
6989 check->automatic_name= TRUE;
6990
6991 const char *own_name_base= create_info->period_info.constr == check
6992 ? create_info->period_info.name.str : NULL;
6993
6994 if (make_unique_constraint_name(thd, &check->name,
6995 own_name_base,
6996 check_constraint_list,
6997 &nr))
6998 DBUG_RETURN(TRUE);
6999 }
7000 }
7001 DBUG_RETURN(FALSE);
7002 }
7003
7004
compare_uint(const uint * s,const uint * t)7005 static int compare_uint(const uint *s, const uint *t)
7006 {
7007 return (*s < *t) ? -1 : ((*s > *t) ? 1 : 0);
7008 }
7009
merge(Compare_keys current,Compare_keys add)7010 static Compare_keys merge(Compare_keys current, Compare_keys add) {
7011 if (current == Compare_keys::Equal)
7012 return add;
7013
7014 if (add == Compare_keys::Equal)
7015 return current;
7016
7017 if (current == add)
7018 return current;
7019
7020 if (current == Compare_keys::EqualButComment) {
7021 return Compare_keys::NotEqual;
7022 }
7023
7024 if (current == Compare_keys::EqualButKeyPartLength) {
7025 if (add == Compare_keys::EqualButComment)
7026 return Compare_keys::NotEqual;
7027 DBUG_ASSERT(add == Compare_keys::NotEqual);
7028 return Compare_keys::NotEqual;
7029 }
7030
7031 DBUG_ASSERT(current == Compare_keys::NotEqual);
7032 return current;
7033 }
7034
compare_keys_but_name(const KEY * table_key,const KEY * new_key,Alter_info * alter_info,const TABLE * table,const KEY * const new_pk,const KEY * const old_pk)7035 Compare_keys compare_keys_but_name(const KEY *table_key, const KEY *new_key,
7036 Alter_info *alter_info, const TABLE *table,
7037 const KEY *const new_pk,
7038 const KEY *const old_pk)
7039 {
7040 if (table_key->algorithm != new_key->algorithm)
7041 return Compare_keys::NotEqual;
7042
7043 if ((table_key->flags & HA_KEYFLAG_MASK) !=
7044 (new_key->flags & HA_KEYFLAG_MASK))
7045 return Compare_keys::NotEqual;
7046
7047 if (table_key->user_defined_key_parts != new_key->user_defined_key_parts)
7048 return Compare_keys::NotEqual;
7049
7050 if (table_key->block_size != new_key->block_size)
7051 return Compare_keys::NotEqual;
7052
7053 /*
7054 Rebuild the index if following condition get satisfied:
7055
7056 (i) Old table doesn't have primary key, new table has it and vice-versa
7057 (ii) Primary key changed to another existing index
7058 */
7059 if ((new_key == new_pk) != (table_key == old_pk))
7060 return Compare_keys::NotEqual;
7061
7062 if (engine_options_differ(table_key->option_struct, new_key->option_struct,
7063 table->file->ht->index_options))
7064 return Compare_keys::NotEqual;
7065
7066 Compare_keys result= Compare_keys::Equal;
7067
7068 for (const KEY_PART_INFO *
7069 key_part= table_key->key_part,
7070 *new_part= new_key->key_part,
7071 *end= table_key->key_part + table_key->user_defined_key_parts;
7072 key_part < end; key_part++, new_part++)
7073 {
7074 /*
7075 For prefix keys KEY_PART_INFO::field points to cloned Field
7076 object with adjusted length. So below we have to check field
7077 indexes instead of simply comparing pointers to Field objects.
7078 */
7079 const Create_field &new_field=
7080 *alter_info->create_list.elem(new_part->fieldnr);
7081
7082 if (!new_field.field ||
7083 new_field.field->field_index != key_part->fieldnr - 1)
7084 {
7085 return Compare_keys::NotEqual;
7086 }
7087
7088 auto compare= table->file->compare_key_parts(
7089 *table->field[key_part->fieldnr - 1], new_field, *key_part, *new_part);
7090 result= merge(result, compare);
7091 }
7092
7093 /* Check that key comment is not changed. */
7094 if (cmp(table_key->comment, new_key->comment) != 0)
7095 result= merge(result, Compare_keys::EqualButComment);
7096
7097 return result;
7098 }
7099
7100 /**
7101 Compare original and new versions of a table and fill Alter_inplace_info
7102 describing differences between those versions.
7103
7104 @param thd Thread
7105 @param table The original table.
7106 @param varchar Indicates that new definition has new
7107 VARCHAR column.
7108 @param[in/out] ha_alter_info Data structure which already contains
7109 basic information about create options,
7110 field and keys for the new version of
7111 table and which should be completed with
7112 more detailed information needed for
7113 in-place ALTER.
7114
7115 First argument 'table' contains information of the original
7116 table, which includes all corresponding parts that the new
7117 table has in arguments create_list, key_list and create_info.
7118
7119 Compare the changes between the original and new table definitions.
7120 The result of this comparison is then passed to SE which determines
7121 whether it can carry out these changes in-place.
7122
7123 Mark any changes detected in the ha_alter_flags.
7124 We generally try to specify handler flags only if there are real
7125 changes. But in cases when it is cumbersome to determine if some
7126 attribute has really changed we might choose to set flag
7127 pessimistically, for example, relying on parser output only.
7128
7129 If there are no data changes, but index changes, 'index_drop_buffer'
7130 and/or 'index_add_buffer' are populated with offsets into
7131 table->key_info or key_info_buffer respectively for the indexes
7132 that need to be dropped and/or (re-)created.
7133
7134 Note that this function assumes that it is OK to change Alter_info
7135 and HA_CREATE_INFO which it gets. It is caller who is responsible
7136 for creating copies for this structures if he needs them unchanged.
7137
7138 @retval true error
7139 @retval false success
7140 */
7141
fill_alter_inplace_info(THD * thd,TABLE * table,bool varchar,Alter_inplace_info * ha_alter_info)7142 static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
7143 Alter_inplace_info *ha_alter_info)
7144 {
7145 Field **f_ptr, *field;
7146 List_iterator_fast<Create_field> new_field_it;
7147 Create_field *new_field;
7148 Alter_info *alter_info= ha_alter_info->alter_info;
7149 DBUG_ENTER("fill_alter_inplace_info");
7150 DBUG_PRINT("info", ("alter_info->flags: %llu", alter_info->flags));
7151
7152 /* Allocate result buffers. */
7153 DBUG_ASSERT(ha_alter_info->rename_keys.mem_root() == thd->mem_root);
7154 if (! (ha_alter_info->index_drop_buffer=
7155 (KEY**) thd->alloc(sizeof(KEY*) * table->s->keys)) ||
7156 ! (ha_alter_info->index_add_buffer=
7157 (uint*) thd->alloc(sizeof(uint) *
7158 alter_info->key_list.elements)) ||
7159 ha_alter_info->rename_keys.reserve(ha_alter_info->index_add_count))
7160 DBUG_RETURN(true);
7161
7162 /*
7163 Copy parser flags, but remove some flags that handlers doesn't
7164 need to care about (old engines may not ignore these parser flags).
7165 ALTER_RENAME_COLUMN is replaced by ALTER_COLUMN_NAME.
7166 ALTER_CHANGE_COLUMN_DEFAULT is replaced by ALTER_CHANGE_COLUMN
7167 ALTER_PARSE_ADD_COLUMN, ALTER_PARSE_DROP_COLUMN, ALTER_ADD_INDEX and
7168 ALTER_DROP_INDEX are replaced with versions that have higher granuality.
7169 */
7170
7171 alter_table_operations flags_to_remove=
7172 ALTER_ADD_INDEX | ALTER_DROP_INDEX | ALTER_PARSER_ADD_COLUMN |
7173 ALTER_PARSER_DROP_COLUMN | ALTER_COLUMN_ORDER | ALTER_RENAME_COLUMN |
7174 ALTER_CHANGE_COLUMN;
7175
7176 if (!table->file->native_versioned())
7177 flags_to_remove|= ALTER_COLUMN_UNVERSIONED;
7178
7179 ha_alter_info->handler_flags|= (alter_info->flags & ~flags_to_remove);
7180 /*
7181 Comparing new and old default values of column is cumbersome.
7182 So instead of using such a comparison for detecting if default
7183 has really changed we rely on flags set by parser to get an
7184 approximate value for storage engine flag.
7185 */
7186 if (alter_info->flags & ALTER_CHANGE_COLUMN)
7187 ha_alter_info->handler_flags|= ALTER_COLUMN_DEFAULT;
7188
7189 /*
7190 If we altering table with old VARCHAR fields we will be automatically
7191 upgrading VARCHAR column types.
7192 */
7193 if (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)
7194 ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
7195
7196 DBUG_PRINT("info", ("handler_flags: %llu", ha_alter_info->handler_flags));
7197
7198 /*
7199 Go through fields in old version of table and detect changes to them.
7200 We don't want to rely solely on Alter_info flags for this since:
7201 a) new definition of column can be fully identical to the old one
7202 despite the fact that this column is mentioned in MODIFY clause.
7203 b) even if new column type differs from its old column from metadata
7204 point of view, it might be identical from storage engine point
7205 of view (e.g. when ENUM('a','b') is changed to ENUM('a','b',c')).
7206 c) flags passed to storage engine contain more detailed information
7207 about nature of changes than those provided from parser.
7208 */
7209 bool maybe_alter_vcol= false;
7210 uint field_stored_index= 0;
7211 for (f_ptr= table->field; (field= *f_ptr); f_ptr++,
7212 field_stored_index+= field->stored_in_db())
7213 {
7214 /* Clear marker for renamed or dropped field
7215 which we are going to set later. */
7216 field->flags&= ~(FIELD_IS_RENAMED | FIELD_IS_DROPPED);
7217
7218 /* Use transformed info to evaluate flags for storage engine. */
7219 uint new_field_index= 0, new_field_stored_index= 0;
7220 new_field_it.init(alter_info->create_list);
7221 while ((new_field= new_field_it++))
7222 {
7223 if (new_field->field == field)
7224 break;
7225 new_field_index++;
7226 new_field_stored_index+= new_field->stored_in_db();
7227 }
7228
7229 if (new_field)
7230 {
7231 /* Field is not dropped. Evaluate changes bitmap for it. */
7232
7233 /*
7234 Check if type of column has changed.
7235 */
7236 bool is_equal= field->is_equal(*new_field);
7237 if (!is_equal)
7238 {
7239 if (field->can_be_converted_by_engine(*new_field))
7240 {
7241 /*
7242 New column type differs from the old one, but storage engine can
7243 change it by itself.
7244 (for example, VARCHAR(300) is changed to VARCHAR(400)).
7245 */
7246 ha_alter_info->handler_flags|= ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE;
7247 }
7248 else
7249 {
7250 /* New column type is incompatible with old one. */
7251 ha_alter_info->handler_flags|= field->stored_in_db()
7252 ? ALTER_STORED_COLUMN_TYPE
7253 : ALTER_VIRTUAL_COLUMN_TYPE;
7254
7255 if (table->s->tmp_table == NO_TMP_TABLE)
7256 {
7257 delete_statistics_for_column(thd, table, field);
7258 KEY *key_info= table->key_info;
7259 for (uint i= 0; i < table->s->keys; i++, key_info++)
7260 {
7261 if (!field->part_of_key.is_set(i))
7262 continue;
7263
7264 uint key_parts= table->actual_n_key_parts(key_info);
7265 for (uint j= 0; j < key_parts; j++)
7266 {
7267 if (key_info->key_part[j].fieldnr - 1 == field->field_index)
7268 {
7269 delete_statistics_for_index(
7270 thd, table, key_info,
7271 j >= key_info->user_defined_key_parts);
7272 break;
7273 }
7274 }
7275 }
7276 }
7277 }
7278 }
7279
7280 if (field->vcol_info || new_field->vcol_info)
7281 {
7282 /* base <-> virtual or stored <-> virtual */
7283 if (field->stored_in_db() != new_field->stored_in_db())
7284 ha_alter_info->handler_flags|= ( ALTER_STORED_COLUMN_TYPE |
7285 ALTER_VIRTUAL_COLUMN_TYPE);
7286 if (field->vcol_info && new_field->vcol_info)
7287 {
7288 bool value_changes= !is_equal;
7289 alter_table_operations alter_expr;
7290 if (field->stored_in_db())
7291 alter_expr= ALTER_STORED_GCOL_EXPR;
7292 else
7293 alter_expr= ALTER_VIRTUAL_GCOL_EXPR;
7294 if (!field->vcol_info->is_equal(new_field->vcol_info))
7295 {
7296 ha_alter_info->handler_flags|= alter_expr;
7297 value_changes= true;
7298 }
7299
7300 if ((ha_alter_info->handler_flags & ALTER_COLUMN_DEFAULT)
7301 && !(ha_alter_info->handler_flags & alter_expr))
7302 { /*
7303 a DEFAULT value of a some column was changed. see if this vcol
7304 uses DEFAULT() function. The check is kind of expensive, so don't
7305 do it if ALTER_COLUMN_VCOL is already set.
7306 */
7307 if (field->vcol_info->expr->walk(
7308 &Item::check_func_default_processor, 0, 0))
7309 {
7310 ha_alter_info->handler_flags|= alter_expr;
7311 value_changes= true;
7312 }
7313 }
7314
7315 if (field->vcol_info->is_in_partitioning_expr() ||
7316 field->flags & PART_KEY_FLAG || field->stored_in_db())
7317 {
7318 if (value_changes)
7319 ha_alter_info->handler_flags|= ALTER_COLUMN_VCOL;
7320 else
7321 maybe_alter_vcol= true;
7322 }
7323 }
7324 else /* base <-> stored */
7325 ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
7326 }
7327
7328 /* Check if field was renamed (case-sensitive for detecting case change) */
7329 if (cmp(&field->field_name, &new_field->field_name))
7330 {
7331 field->flags|= FIELD_IS_RENAMED;
7332 ha_alter_info->handler_flags|= ALTER_COLUMN_NAME;
7333 rename_column_in_stat_tables(thd, table, field,
7334 new_field->field_name.str);
7335 }
7336
7337 /* Check that NULL behavior is same for old and new fields */
7338 if ((new_field->flags & NOT_NULL_FLAG) !=
7339 (uint) (field->flags & NOT_NULL_FLAG))
7340 {
7341 if (new_field->flags & NOT_NULL_FLAG)
7342 ha_alter_info->handler_flags|= ALTER_COLUMN_NOT_NULLABLE;
7343 else
7344 ha_alter_info->handler_flags|= ALTER_COLUMN_NULLABLE;
7345 }
7346
7347 /*
7348 We do not detect changes to default values in this loop.
7349 See comment above for more details.
7350 */
7351
7352 /*
7353 Detect changes in column order.
7354 */
7355 if (field->stored_in_db())
7356 {
7357 if (field_stored_index != new_field_stored_index)
7358 ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_ORDER;
7359 }
7360 else
7361 {
7362 if (field->field_index != new_field_index)
7363 ha_alter_info->handler_flags|= ALTER_VIRTUAL_COLUMN_ORDER;
7364 }
7365
7366 /* Detect changes in storage type of column */
7367 if (new_field->field_storage_type() != field->field_storage_type())
7368 ha_alter_info->handler_flags|= ALTER_COLUMN_STORAGE_TYPE;
7369
7370 /* Detect changes in column format of column */
7371 if (new_field->column_format() != field->column_format())
7372 ha_alter_info->handler_flags|= ALTER_COLUMN_COLUMN_FORMAT;
7373
7374 if (engine_options_differ(field->option_struct, new_field->option_struct,
7375 table->file->ht->field_options))
7376 {
7377 ha_alter_info->handler_flags|= ALTER_COLUMN_OPTION;
7378 ha_alter_info->create_info->fields_option_struct[f_ptr - table->field]=
7379 new_field->option_struct;
7380 }
7381 }
7382 else
7383 {
7384 // Field is not present in new version of table and therefore was dropped.
7385 field->flags|= FIELD_IS_DROPPED;
7386 if (field->stored_in_db())
7387 ha_alter_info->handler_flags|= ALTER_DROP_STORED_COLUMN;
7388 else
7389 ha_alter_info->handler_flags|= ALTER_DROP_VIRTUAL_COLUMN;
7390 }
7391 }
7392
7393 if (maybe_alter_vcol)
7394 {
7395 /*
7396 What if one of the normal columns was altered and it was part of the some
7397 virtual column expression? Currently we don't detect this correctly
7398 (FIXME), so let's just say that a vcol *might* be affected if any other
7399 column was altered.
7400 */
7401 if (ha_alter_info->handler_flags & (ALTER_STORED_COLUMN_TYPE |
7402 ALTER_VIRTUAL_COLUMN_TYPE |
7403 ALTER_COLUMN_NOT_NULLABLE |
7404 ALTER_COLUMN_OPTION))
7405 ha_alter_info->handler_flags|= ALTER_COLUMN_VCOL;
7406 }
7407
7408 new_field_it.init(alter_info->create_list);
7409 while ((new_field= new_field_it++))
7410 {
7411 if (! new_field->field)
7412 {
7413 // Field is not present in old version of table and therefore was added.
7414 if (new_field->vcol_info)
7415 {
7416 if (new_field->stored_in_db())
7417 ha_alter_info->handler_flags|= ALTER_ADD_STORED_GENERATED_COLUMN;
7418 else
7419 ha_alter_info->handler_flags|= ALTER_ADD_VIRTUAL_COLUMN;
7420 }
7421 else
7422 ha_alter_info->handler_flags|= ALTER_ADD_STORED_BASE_COLUMN;
7423 }
7424 }
7425
7426 /*
7427 Go through keys and check if the original ones are compatible
7428 with new table.
7429 */
7430 KEY *table_key;
7431 KEY *table_key_end= table->key_info + table->s->keys;
7432 KEY *new_key;
7433 KEY *new_key_end=
7434 ha_alter_info->key_info_buffer + ha_alter_info->key_count;
7435 /*
7436 Primary key index for the new table
7437 */
7438 const KEY* const new_pk= (ha_alter_info->key_count > 0 &&
7439 (!my_strcasecmp(system_charset_info,
7440 ha_alter_info->key_info_buffer->name.str,
7441 primary_key_name) ||
7442 is_candidate_key(ha_alter_info->key_info_buffer))) ?
7443 ha_alter_info->key_info_buffer : NULL;
7444 const KEY *const old_pk= table->s->primary_key == MAX_KEY ? NULL :
7445 table->key_info + table->s->primary_key;
7446
7447 DBUG_PRINT("info", ("index count old: %d new: %d",
7448 table->s->keys, ha_alter_info->key_count));
7449
7450 /*
7451 Step through all keys of the old table and search matching new keys.
7452 */
7453 ha_alter_info->index_drop_count= 0;
7454 ha_alter_info->index_add_count= 0;
7455 for (table_key= table->key_info; table_key < table_key_end; table_key++)
7456 {
7457 /* Search a new key with the same name. */
7458 for (new_key= ha_alter_info->key_info_buffer;
7459 new_key < new_key_end;
7460 new_key++)
7461 {
7462 if (!lex_string_cmp(system_charset_info, &table_key->name,
7463 &new_key->name))
7464 break;
7465 }
7466 if (new_key >= new_key_end)
7467 {
7468 /* Key not found. Add the key to the drop buffer. */
7469 ha_alter_info->index_drop_buffer
7470 [ha_alter_info->index_drop_count++]=
7471 table_key;
7472 DBUG_PRINT("info", ("index dropped: '%s'", table_key->name.str));
7473 continue;
7474 }
7475
7476 switch (compare_keys_but_name(table_key, new_key, alter_info, table, new_pk,
7477 old_pk))
7478 {
7479 case Compare_keys::Equal:
7480 continue;
7481 case Compare_keys::EqualButKeyPartLength:
7482 ha_alter_info->handler_flags|= ALTER_COLUMN_INDEX_LENGTH;
7483 continue;
7484 case Compare_keys::EqualButComment:
7485 ha_alter_info->handler_flags|= ALTER_CHANGE_INDEX_COMMENT;
7486 continue;
7487 case Compare_keys::NotEqual:
7488 break;
7489 }
7490
7491 /* Key modified. Add the key / key offset to both buffers. */
7492 ha_alter_info->index_drop_buffer
7493 [ha_alter_info->index_drop_count++]=
7494 table_key;
7495 ha_alter_info->index_add_buffer
7496 [ha_alter_info->index_add_count++]=
7497 (uint)(new_key - ha_alter_info->key_info_buffer);
7498 /* Mark all old fields which are used in newly created index. */
7499 DBUG_PRINT("info", ("index changed: '%s'", table_key->name.str));
7500 }
7501 /*end of for (; table_key < table_key_end;) */
7502
7503 /*
7504 Step through all keys of the new table and find matching old keys.
7505 */
7506 for (new_key= ha_alter_info->key_info_buffer;
7507 new_key < new_key_end;
7508 new_key++)
7509 {
7510 /* Search an old key with the same name. */
7511 for (table_key= table->key_info; table_key < table_key_end; table_key++)
7512 {
7513 if (!lex_string_cmp(system_charset_info, &table_key->name,
7514 &new_key->name))
7515 break;
7516 }
7517 if (table_key >= table_key_end)
7518 {
7519 /* Key not found. Add the offset of the key to the add buffer. */
7520 ha_alter_info->index_add_buffer
7521 [ha_alter_info->index_add_count++]=
7522 (uint)(new_key - ha_alter_info->key_info_buffer);
7523 DBUG_PRINT("info", ("index added: '%s'", new_key->name.str));
7524 }
7525 else
7526 ha_alter_info->create_info->indexes_option_struct[table_key - table->key_info]=
7527 new_key->option_struct;
7528 }
7529
7530 for (uint i= 0; i < ha_alter_info->index_add_count; i++)
7531 {
7532 uint *add_buffer= ha_alter_info->index_add_buffer;
7533 const KEY *new_key= ha_alter_info->key_info_buffer + add_buffer[i];
7534
7535 for (uint j= 0; j < ha_alter_info->index_drop_count; j++)
7536 {
7537 KEY **drop_buffer= ha_alter_info->index_drop_buffer;
7538 const KEY *old_key= drop_buffer[j];
7539
7540 if (compare_keys_but_name(old_key, new_key, alter_info, table, new_pk,
7541 old_pk) != Compare_keys::Equal)
7542 {
7543 continue;
7544 }
7545
7546 DBUG_ASSERT(
7547 lex_string_cmp(system_charset_info, &old_key->name, &new_key->name));
7548
7549 ha_alter_info->handler_flags|= ALTER_RENAME_INDEX;
7550 ha_alter_info->rename_keys.push_back(
7551 Alter_inplace_info::Rename_key_pair(old_key, new_key));
7552
7553 --ha_alter_info->index_add_count;
7554 --ha_alter_info->index_drop_count;
7555 memmove(add_buffer + i, add_buffer + i + 1,
7556 sizeof(add_buffer[0]) * (ha_alter_info->index_add_count - i));
7557 memmove(drop_buffer + j, drop_buffer + j + 1,
7558 sizeof(drop_buffer[0]) * (ha_alter_info->index_drop_count - j));
7559 --i; // this index once again
7560 break;
7561 }
7562 }
7563
7564 /*
7565 Sort index_add_buffer according to how key_info_buffer is sorted.
7566 I.e. with primary keys first - see sort_keys().
7567 */
7568 my_qsort(ha_alter_info->index_add_buffer,
7569 ha_alter_info->index_add_count,
7570 sizeof(uint), (qsort_cmp) compare_uint);
7571
7572 /* Now let us calculate flags for storage engine API. */
7573
7574 /* Figure out what kind of indexes we are dropping. */
7575 KEY **dropped_key;
7576 KEY **dropped_key_end= ha_alter_info->index_drop_buffer +
7577 ha_alter_info->index_drop_count;
7578
7579 for (dropped_key= ha_alter_info->index_drop_buffer;
7580 dropped_key < dropped_key_end; dropped_key++)
7581 {
7582 table_key= *dropped_key;
7583
7584 if (table_key->flags & HA_NOSAME)
7585 {
7586 if (table_key == old_pk)
7587 ha_alter_info->handler_flags|= ALTER_DROP_PK_INDEX;
7588 else
7589 ha_alter_info->handler_flags|= ALTER_DROP_UNIQUE_INDEX;
7590 }
7591 else
7592 ha_alter_info->handler_flags|= ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX;
7593 }
7594
7595 /* Now figure out what kind of indexes we are adding. */
7596 for (uint add_key_idx= 0; add_key_idx < ha_alter_info->index_add_count; add_key_idx++)
7597 {
7598 new_key= ha_alter_info->key_info_buffer + ha_alter_info->index_add_buffer[add_key_idx];
7599
7600 if (new_key->flags & HA_NOSAME)
7601 {
7602 if (new_key == new_pk)
7603 ha_alter_info->handler_flags|= ALTER_ADD_PK_INDEX;
7604 else
7605 ha_alter_info->handler_flags|= ALTER_ADD_UNIQUE_INDEX;
7606 }
7607 else
7608 ha_alter_info->handler_flags|= ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX;
7609 }
7610
7611 DBUG_PRINT("exit", ("handler_flags: %llu", ha_alter_info->handler_flags));
7612 DBUG_RETURN(false);
7613 }
7614
7615
7616 /**
7617 Mark fields participating in newly added indexes in TABLE object which
7618 corresponds to new version of altered table.
7619
7620 @param ha_alter_info Alter_inplace_info describing in-place ALTER.
7621 @param altered_table TABLE object for new version of TABLE in which
7622 fields should be marked.
7623 */
7624
update_altered_table(const Alter_inplace_info & ha_alter_info,TABLE * altered_table)7625 static void update_altered_table(const Alter_inplace_info &ha_alter_info,
7626 TABLE *altered_table)
7627 {
7628 uint field_idx, add_key_idx;
7629 KEY *key;
7630 KEY_PART_INFO *end, *key_part;
7631
7632 /*
7633 Clear marker for all fields, as we are going to set it only
7634 for fields which participate in new indexes.
7635 */
7636 for (field_idx= 0; field_idx < altered_table->s->fields; ++field_idx)
7637 altered_table->field[field_idx]->flags&= ~FIELD_IN_ADD_INDEX;
7638
7639 /*
7640 Go through array of newly added indexes and mark fields
7641 participating in them.
7642 */
7643 for (add_key_idx= 0; add_key_idx < ha_alter_info.index_add_count;
7644 add_key_idx++)
7645 {
7646 key= ha_alter_info.key_info_buffer +
7647 ha_alter_info.index_add_buffer[add_key_idx];
7648
7649 end= key->key_part + key->user_defined_key_parts;
7650 for (key_part= key->key_part; key_part < end; key_part++)
7651 altered_table->field[key_part->fieldnr]->flags|= FIELD_IN_ADD_INDEX;
7652 }
7653 }
7654
7655
7656 /**
7657 Compare two tables to see if their metadata are compatible.
7658 One table specified by a TABLE instance, the other using Alter_info
7659 and HA_CREATE_INFO.
7660
7661 @param[in] table The first table.
7662 @param[in] alter_info Alter options, fields and keys for the
7663 second table.
7664 @param[in] create_info Create options for the second table.
7665 @param[out] metadata_equal Result of comparison.
7666
7667 @retval true error
7668 @retval false success
7669 */
7670
mysql_compare_tables(TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,bool * metadata_equal)7671 bool mysql_compare_tables(TABLE *table,
7672 Alter_info *alter_info,
7673 HA_CREATE_INFO *create_info,
7674 bool *metadata_equal)
7675 {
7676 DBUG_ENTER("mysql_compare_tables");
7677
7678 uint changes= IS_EQUAL_NO;
7679 uint key_count;
7680 List_iterator_fast<Create_field> tmp_new_field_it;
7681 THD *thd= table->in_use;
7682 *metadata_equal= false;
7683
7684 /*
7685 Create a copy of alter_info.
7686 To compare definitions, we need to "prepare" the definition - transform it
7687 from parser output to a format that describes the table layout (all column
7688 defaults are initialized, duplicate columns are removed). This is done by
7689 mysql_prepare_create_table. Unfortunately, mysql_prepare_create_table
7690 performs its transformations "in-place", that is, modifies the argument.
7691 Since we would like to keep mysql_compare_tables() idempotent (not altering
7692 any of the arguments) we create a copy of alter_info here and pass it to
7693 mysql_prepare_create_table, then use the result to compare the tables, and
7694 then destroy the copy.
7695 */
7696 Alter_info tmp_alter_info(*alter_info, thd->mem_root);
7697 uint db_options= 0; /* not used */
7698 KEY *key_info_buffer= NULL;
7699 LEX_CSTRING db= { table->s->db.str, table->s->db.length };
7700 LEX_CSTRING table_name= { table->s->db.str, table->s->table_name.length };
7701
7702 /* Create the prepared information. */
7703 int create_table_mode= table->s->tmp_table == NO_TMP_TABLE ?
7704 C_ORDINARY_CREATE : C_ALTER_TABLE;
7705 if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info,
7706 &db_options, table->file, &key_info_buffer,
7707 &key_count, create_table_mode, db, table_name))
7708 DBUG_RETURN(1);
7709
7710 /* Some very basic checks. */
7711 if (table->s->fields != alter_info->create_list.elements ||
7712 table->s->db_type() != create_info->db_type ||
7713 table->s->tmp_table ||
7714 (table->s->row_type != create_info->row_type))
7715 DBUG_RETURN(false);
7716
7717 /* Go through fields and check if they are compatible. */
7718 tmp_new_field_it.init(tmp_alter_info.create_list);
7719 for (Field **f_ptr= table->field; *f_ptr; f_ptr++)
7720 {
7721 Field *field= *f_ptr;
7722 Create_field *tmp_new_field= tmp_new_field_it++;
7723
7724 /* Check that NULL behavior is the same. */
7725 if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
7726 (uint) (field->flags & NOT_NULL_FLAG))
7727 DBUG_RETURN(false);
7728
7729 /*
7730 mysql_prepare_alter_table() clears HA_OPTION_PACK_RECORD bit when
7731 preparing description of existing table. In ALTER TABLE it is later
7732 updated to correct value by create_table_impl() call.
7733 So to get correct value of this bit in this function we have to
7734 mimic behavior of create_table_impl().
7735 */
7736 if (create_info->row_type == ROW_TYPE_DYNAMIC ||
7737 create_info->row_type == ROW_TYPE_PAGE ||
7738 (tmp_new_field->flags & BLOB_FLAG) ||
7739 (tmp_new_field->real_field_type() == MYSQL_TYPE_VARCHAR &&
7740 create_info->row_type != ROW_TYPE_FIXED))
7741 create_info->table_options|= HA_OPTION_PACK_RECORD;
7742
7743 /* Check if field was renamed */
7744 if (lex_string_cmp(system_charset_info,
7745 &field->field_name,
7746 &tmp_new_field->field_name))
7747 DBUG_RETURN(false);
7748
7749 /* Evaluate changes bitmap and send to check_if_incompatible_data() */
7750 uint field_changes= field->is_equal(*tmp_new_field);
7751 if (field_changes != IS_EQUAL_YES)
7752 DBUG_RETURN(false);
7753
7754 changes|= field_changes;
7755 }
7756
7757 /* Check if changes are compatible with current handler. */
7758 if (table->file->check_if_incompatible_data(create_info, changes))
7759 DBUG_RETURN(false);
7760
7761 /* Go through keys and check if they are compatible. */
7762 KEY *table_key;
7763 KEY *table_key_end= table->key_info + table->s->keys;
7764 KEY *new_key;
7765 KEY *new_key_end= key_info_buffer + key_count;
7766
7767 /* Step through all keys of the first table and search matching keys. */
7768 for (table_key= table->key_info; table_key < table_key_end; table_key++)
7769 {
7770 /* Search a key with the same name. */
7771 for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
7772 {
7773 if (!lex_string_cmp(system_charset_info, &table_key->name,
7774 &new_key->name))
7775 break;
7776 }
7777 if (new_key >= new_key_end)
7778 DBUG_RETURN(false);
7779
7780 /* Check that the key types are compatible. */
7781 if ((table_key->algorithm != new_key->algorithm) ||
7782 ((table_key->flags & HA_KEYFLAG_MASK) !=
7783 (new_key->flags & HA_KEYFLAG_MASK)) ||
7784 (table_key->user_defined_key_parts !=
7785 new_key->user_defined_key_parts))
7786 DBUG_RETURN(false);
7787
7788 /* Check that the key parts remain compatible. */
7789 KEY_PART_INFO *table_part;
7790 KEY_PART_INFO *table_part_end= table_key->key_part + table_key->user_defined_key_parts;
7791 KEY_PART_INFO *new_part;
7792 for (table_part= table_key->key_part, new_part= new_key->key_part;
7793 table_part < table_part_end;
7794 table_part++, new_part++)
7795 {
7796 /*
7797 Key definition is different if we are using a different field or
7798 if the used key part length is different. We know that the fields
7799 are equal. Comparing field numbers is sufficient.
7800 */
7801 if ((table_part->length != new_part->length) ||
7802 (table_part->fieldnr - 1 != new_part->fieldnr))
7803 DBUG_RETURN(false);
7804 }
7805 }
7806
7807 /* Step through all keys of the second table and find matching keys. */
7808 for (new_key= key_info_buffer; new_key < new_key_end; new_key++)
7809 {
7810 /* Search a key with the same name. */
7811 for (table_key= table->key_info; table_key < table_key_end; table_key++)
7812 {
7813 if (!lex_string_cmp(system_charset_info, &table_key->name,
7814 &new_key->name))
7815 break;
7816 }
7817 if (table_key >= table_key_end)
7818 DBUG_RETURN(false);
7819 }
7820
7821 *metadata_equal= true; // Tables are compatible
7822 DBUG_RETURN(false);
7823 }
7824
7825
7826 /*
7827 Manages enabling/disabling of indexes for ALTER TABLE
7828
7829 SYNOPSIS
7830 alter_table_manage_keys()
7831 table Target table
7832 indexes_were_disabled Whether the indexes of the from table
7833 were disabled
7834 keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
7835
7836 RETURN VALUES
7837 FALSE OK
7838 TRUE Error
7839 */
7840
7841 static
alter_table_manage_keys(TABLE * table,int indexes_were_disabled,Alter_info::enum_enable_or_disable keys_onoff)7842 bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
7843 Alter_info::enum_enable_or_disable keys_onoff)
7844 {
7845 int error= 0;
7846 DBUG_ENTER("alter_table_manage_keys");
7847 DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d",
7848 table, indexes_were_disabled, keys_onoff));
7849
7850 switch (keys_onoff) {
7851 case Alter_info::ENABLE:
7852 DEBUG_SYNC(table->in_use, "alter_table_enable_indexes");
7853 error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
7854 break;
7855 case Alter_info::LEAVE_AS_IS:
7856 if (!indexes_were_disabled)
7857 break;
7858 /* fall through */
7859 case Alter_info::DISABLE:
7860 error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
7861 }
7862
7863 if (unlikely(error))
7864 {
7865 if (error == HA_ERR_WRONG_COMMAND)
7866 {
7867 THD *thd= table->in_use;
7868 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
7869 ER_ILLEGAL_HA, ER_THD(thd, ER_ILLEGAL_HA),
7870 table->file->table_type(),
7871 table->s->db.str, table->s->table_name.str);
7872 error= 0;
7873 }
7874 else
7875 table->file->print_error(error, MYF(0));
7876 }
7877 DBUG_RETURN(error);
7878 }
7879
7880
7881 /**
7882 Check if the pending ALTER TABLE operations support the in-place
7883 algorithm based on restrictions in the SQL layer or given the
7884 nature of the operations themselves. If in-place isn't supported,
7885 it won't be necessary to check with the storage engine.
7886
7887 @param table The original TABLE.
7888 @param create_info Information from the parsing phase about new
7889 table properties.
7890 @param alter_info Data related to detected changes.
7891
7892 @return false In-place is possible, check with storage engine.
7893 @return true Incompatible operations, must use table copy.
7894 */
7895
is_inplace_alter_impossible(TABLE * table,HA_CREATE_INFO * create_info,const Alter_info * alter_info)7896 static bool is_inplace_alter_impossible(TABLE *table,
7897 HA_CREATE_INFO *create_info,
7898 const Alter_info *alter_info)
7899 {
7900 DBUG_ENTER("is_inplace_alter_impossible");
7901
7902 /* At the moment we can't handle altering temporary tables without a copy. */
7903 if (table->s->tmp_table)
7904 DBUG_RETURN(true);
7905
7906 /*
7907 For the ALTER TABLE tbl_name ORDER BY ... we always use copy
7908 algorithm. In theory, this operation can be done in-place by some
7909 engine, but since a) no current engine does this and b) our current
7910 API lacks infrastructure for passing information about table ordering
7911 to storage engine we simply always do copy now.
7912
7913 ENABLE/DISABLE KEYS is a MyISAM/Heap specific operation that is
7914 not supported for in-place in combination with other operations.
7915 Alone, it will be done by simple_rename_or_index_change().
7916 */
7917 if (alter_info->flags & (ALTER_ORDER | ALTER_KEYS_ONOFF))
7918 DBUG_RETURN(true);
7919
7920 /*
7921 If the table engine is changed explicitly (using ENGINE clause)
7922 or implicitly (e.g. when non-partitioned table becomes
7923 partitioned) a regular alter table (copy) needs to be
7924 performed.
7925 */
7926 if (create_info->db_type != table->s->db_type())
7927 DBUG_RETURN(true);
7928
7929 /*
7930 There was a bug prior to mysql-4.0.25. Number of null fields was
7931 calculated incorrectly. As a result frm and data files gets out of
7932 sync after fast alter table. There is no way to determine by which
7933 mysql version (in 4.0 and 4.1 branches) table was created, thus we
7934 disable fast alter table for all tables created by mysql versions
7935 prior to 5.0 branch.
7936 See BUG#6236.
7937 */
7938 if (!table->s->mysql_version)
7939 DBUG_RETURN(true);
7940
7941 /*
7942 If we are using a MySQL 5.7 table with virtual fields, ALTER TABLE must
7943 recreate the table as we need to rewrite generated fields
7944 */
7945 if (table->s->mysql_version > 50700 && table->s->mysql_version < 100000 &&
7946 table->s->virtual_fields)
7947 DBUG_RETURN(TRUE);
7948
7949 DBUG_RETURN(false);
7950 }
7951
7952
7953 /**
7954 Perform in-place alter table.
7955
7956 @param thd Thread handle.
7957 @param table_list TABLE_LIST for the table to change.
7958 @param table The original TABLE.
7959 @param altered_table TABLE object for new version of the table.
7960 @param ha_alter_info Structure describing ALTER TABLE to be carried
7961 out and serving as a storage place for data
7962 used during different phases.
7963 @param target_mdl_request Metadata request/lock on the target table name.
7964 @param alter_ctx ALTER TABLE runtime context.
7965
7966 @retval true Error
7967 @retval false Success
7968
7969 @note
7970 If mysql_alter_table does not need to copy the table, it is
7971 either an alter table where the storage engine does not
7972 need to know about the change, only the frm will change,
7973 or the storage engine supports performing the alter table
7974 operation directly, in-place without mysql having to copy
7975 the table.
7976
7977 @note This function frees the TABLE object associated with the new version of
7978 the table and removes the .FRM file for it in case of both success and
7979 failure.
7980 */
7981
mysql_inplace_alter_table(THD * thd,TABLE_LIST * table_list,TABLE * table,TABLE * altered_table,Alter_inplace_info * ha_alter_info,MDL_request * target_mdl_request,Alter_table_ctx * alter_ctx)7982 static bool mysql_inplace_alter_table(THD *thd,
7983 TABLE_LIST *table_list,
7984 TABLE *table,
7985 TABLE *altered_table,
7986 Alter_inplace_info *ha_alter_info,
7987 MDL_request *target_mdl_request,
7988 Alter_table_ctx *alter_ctx)
7989 {
7990 Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN | MYSQL_OPEN_IGNORE_KILLED);
7991 handlerton *db_type= table->s->db_type();
7992 Alter_info *alter_info= ha_alter_info->alter_info;
7993 bool reopen_tables= false;
7994 bool res;
7995
7996 const enum_alter_inplace_result inplace_supported=
7997 ha_alter_info->inplace_supported;
7998
7999 DBUG_ENTER("mysql_inplace_alter_table");
8000
8001 /* Downgrade DDL lock while we are waiting for exclusive lock below */
8002 backup_set_alter_copy_lock(thd, table);
8003
8004 /*
8005 Upgrade to EXCLUSIVE lock if:
8006 - This is requested by the storage engine
8007 - Or the storage engine needs exclusive lock for just the prepare
8008 phase
8009 - Or requested by the user
8010
8011 Note that we handle situation when storage engine needs exclusive
8012 lock for prepare phase under LOCK TABLES in the same way as when
8013 exclusive lock is required for duration of the whole statement.
8014 */
8015 if (!ha_alter_info->mdl_exclusive_after_prepare &&
8016 (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK ||
8017 ((inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
8018 inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
8019 inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK ||
8020 inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
8021 inplace_supported == HA_ALTER_INPLACE_INSTANT) &&
8022 (thd->locked_tables_mode == LTM_LOCK_TABLES ||
8023 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) ||
8024 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE))
8025 {
8026 if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
8027 goto cleanup;
8028 /*
8029 Get rid of all TABLE instances belonging to this thread
8030 except one to be used for in-place ALTER TABLE.
8031
8032 This is mostly needed to satisfy InnoDB assumptions/asserts.
8033 */
8034 close_all_tables_for_name(thd, table->s,
8035 alter_ctx->is_table_renamed() ?
8036 HA_EXTRA_PREPARE_FOR_RENAME :
8037 HA_EXTRA_NOT_USED,
8038 table);
8039 /*
8040 If we are under LOCK TABLES we will need to reopen tables which we
8041 just have closed in case of error.
8042 */
8043 reopen_tables= true;
8044 }
8045 else if (inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
8046 inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
8047 inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
8048 inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK ||
8049 inplace_supported == HA_ALTER_INPLACE_INSTANT)
8050 {
8051 /*
8052 Storage engine has requested exclusive lock only for prepare phase
8053 and we are not under LOCK TABLES.
8054 Don't mark TABLE_SHARE as old in this case, as this won't allow opening
8055 of table by other threads during main phase of in-place ALTER TABLE.
8056 */
8057 if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE,
8058 thd->variables.lock_wait_timeout))
8059 goto cleanup;
8060
8061 table->s->tdc->flush(thd, false);
8062 }
8063
8064 /*
8065 Upgrade to SHARED_NO_WRITE lock if:
8066 - The storage engine needs writes blocked for the whole duration
8067 - Or this is requested by the user
8068 Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE.
8069 */
8070 if ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK ||
8071 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED) &&
8072 thd->mdl_context.upgrade_shared_lock(table->mdl_ticket,
8073 MDL_SHARED_NO_WRITE,
8074 thd->variables.lock_wait_timeout))
8075 goto cleanup;
8076
8077 // It's now safe to take the table level lock.
8078 if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0))
8079 goto cleanup;
8080
8081 DEBUG_SYNC(thd, "alter_table_inplace_after_lock_upgrade");
8082 THD_STAGE_INFO(thd, stage_alter_inplace_prepare);
8083
8084 switch (inplace_supported) {
8085 case HA_ALTER_ERROR:
8086 case HA_ALTER_INPLACE_NOT_SUPPORTED:
8087 DBUG_ASSERT(0);
8088 // fall through
8089 case HA_ALTER_INPLACE_NO_LOCK:
8090 case HA_ALTER_INPLACE_INSTANT:
8091 case HA_ALTER_INPLACE_COPY_NO_LOCK:
8092 case HA_ALTER_INPLACE_NOCOPY_NO_LOCK:
8093 switch (alter_info->requested_lock) {
8094 case Alter_info::ALTER_TABLE_LOCK_DEFAULT:
8095 case Alter_info::ALTER_TABLE_LOCK_NONE:
8096 ha_alter_info->online= true;
8097 break;
8098 case Alter_info::ALTER_TABLE_LOCK_SHARED:
8099 case Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE:
8100 break;
8101 }
8102 break;
8103 case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
8104 case HA_ALTER_INPLACE_SHARED_LOCK:
8105 case HA_ALTER_INPLACE_COPY_LOCK:
8106 case HA_ALTER_INPLACE_NOCOPY_LOCK:
8107 break;
8108 }
8109
8110 if (table->file->ha_prepare_inplace_alter_table(altered_table,
8111 ha_alter_info))
8112 goto rollback;
8113
8114 /*
8115 Downgrade the lock if storage engine has told us that exclusive lock was
8116 necessary only for prepare phase (unless we are not under LOCK TABLES) and
8117 user has not explicitly requested exclusive lock.
8118 */
8119 if ((inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
8120 inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
8121 inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
8122 inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK) &&
8123 !(thd->locked_tables_mode == LTM_LOCK_TABLES ||
8124 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
8125 (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE))
8126 {
8127 /* If storage engine or user requested shared lock downgrade to SNW. */
8128 if (inplace_supported == HA_ALTER_INPLACE_COPY_LOCK ||
8129 inplace_supported == HA_ALTER_INPLACE_NOCOPY_LOCK ||
8130 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED)
8131 table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_WRITE);
8132 else
8133 {
8134 DBUG_ASSERT(inplace_supported == HA_ALTER_INPLACE_COPY_NO_LOCK ||
8135 inplace_supported == HA_ALTER_INPLACE_NOCOPY_NO_LOCK);
8136 table->mdl_ticket->downgrade_lock(MDL_SHARED_UPGRADABLE);
8137 }
8138 }
8139
8140 DEBUG_SYNC(thd, "alter_table_inplace_after_lock_downgrade");
8141 THD_STAGE_INFO(thd, stage_alter_inplace);
8142
8143 /* We can abort alter table for any table type */
8144 thd->abort_on_warning= !ha_alter_info->ignore && thd->is_strict_mode();
8145 res= table->file->ha_inplace_alter_table(altered_table, ha_alter_info);
8146 thd->abort_on_warning= false;
8147 if (res)
8148 goto rollback;
8149
8150 DEBUG_SYNC(thd, "alter_table_inplace_before_lock_upgrade");
8151 // Upgrade to EXCLUSIVE before commit.
8152 if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
8153 goto rollback;
8154
8155 /* Set MDL_BACKUP_DDL */
8156 if (backup_reset_alter_copy_lock(thd))
8157 goto rollback;
8158
8159 /*
8160 If we are killed after this point, we should ignore and continue.
8161 We have mostly completed the operation at this point, there should
8162 be no long waits left.
8163 */
8164
8165 DBUG_EXECUTE_IF("alter_table_rollback_new_index", {
8166 table->file->ha_commit_inplace_alter_table(altered_table,
8167 ha_alter_info,
8168 false);
8169 my_error(ER_UNKNOWN_ERROR, MYF(0));
8170 goto cleanup;
8171 });
8172
8173 DEBUG_SYNC(thd, "alter_table_inplace_before_commit");
8174 THD_STAGE_INFO(thd, stage_alter_inplace_commit);
8175
8176 {
8177 TR_table trt(thd, true);
8178 if (trt != *table_list && table->file->ht->prepare_commit_versioned)
8179 {
8180 ulonglong trx_start_id= 0;
8181 ulonglong trx_end_id= table->file->ht->prepare_commit_versioned(thd, &trx_start_id);
8182 if (trx_end_id)
8183 {
8184 if (!TR_table::use_transaction_registry)
8185 {
8186 my_error(ER_VERS_TRT_IS_DISABLED, MYF(0));
8187 goto rollback;
8188 }
8189 if (trt.update(trx_start_id, trx_end_id))
8190 {
8191 goto rollback;
8192 }
8193 }
8194 }
8195
8196 if (table->file->ha_commit_inplace_alter_table(altered_table,
8197 ha_alter_info,
8198 true))
8199 {
8200 goto rollback;
8201 }
8202 DEBUG_SYNC(thd, "alter_table_inplace_after_commit");
8203 }
8204
8205 /* Notify the engine that the table definition has changed */
8206
8207 if (table->file->partition_ht()->notify_tabledef_changed)
8208 {
8209 char db_buff[FN_REFLEN], table_buff[FN_REFLEN];
8210 handlerton *hton= table->file->ht;
8211 LEX_CSTRING tmp_db, tmp_table;
8212
8213 tmp_db.str= db_buff;
8214 tmp_table.str= table_buff;
8215 tmp_db.length= tablename_to_filename(table_list->db.str,
8216 db_buff, sizeof(db_buff));
8217 tmp_table.length= tablename_to_filename(table_list->table_name.str,
8218 table_buff, sizeof(table_buff));
8219 if ((hton->notify_tabledef_changed)(hton, &tmp_db, &tmp_table,
8220 table->s->frm_image,
8221 &table->s->tabledef_version,
8222 table->file))
8223 {
8224 my_error(HA_ERR_INCOMPATIBLE_DEFINITION, MYF(0));
8225 DBUG_RETURN(true);
8226 }
8227 }
8228
8229 close_all_tables_for_name(thd, table->s,
8230 alter_ctx->is_table_renamed() ?
8231 HA_EXTRA_PREPARE_FOR_RENAME :
8232 HA_EXTRA_NOT_USED,
8233 NULL);
8234 table_list->table= table= NULL;
8235
8236 /*
8237 Replace the old .FRM with the new .FRM, but keep the old name for now.
8238 Rename to the new name (if needed) will be handled separately below.
8239
8240 TODO: remove this check of thd->is_error() (now it intercept
8241 errors in some val_*() methods and bring some single place to
8242 such error interception).
8243 */
8244 if (mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->tmp_name,
8245 &alter_ctx->db, &alter_ctx->alias,
8246 FN_FROM_IS_TMP | NO_HA_TABLE) ||
8247 thd->is_error())
8248 {
8249 // Since changes were done in-place, we can't revert them.
8250 DBUG_RETURN(true);
8251 }
8252
8253 // Rename altered table if requested.
8254 if (alter_ctx->is_table_renamed())
8255 {
8256 DBUG_ASSERT(!tdc_share_is_cached(thd, alter_ctx->db.str,
8257 alter_ctx->table_name.str));
8258 if (mysql_rename_table(db_type, &alter_ctx->db, &alter_ctx->table_name,
8259 &alter_ctx->new_db, &alter_ctx->new_alias, 0))
8260 {
8261 /*
8262 If the rename fails we will still have a working table
8263 with the old name, but with other changes applied.
8264 */
8265 DBUG_RETURN(true);
8266 }
8267 if (Table_triggers_list::change_table_name(thd,
8268 &alter_ctx->db,
8269 &alter_ctx->alias,
8270 &alter_ctx->table_name,
8271 &alter_ctx->new_db,
8272 &alter_ctx->new_alias))
8273 {
8274 /*
8275 If the rename of trigger files fails, try to rename the table
8276 back so we at least have matching table and trigger files.
8277 */
8278 (void) mysql_rename_table(db_type,
8279 &alter_ctx->new_db, &alter_ctx->new_alias,
8280 &alter_ctx->db, &alter_ctx->alias, NO_FK_CHECKS);
8281 DBUG_RETURN(true);
8282 }
8283 rename_table_in_stat_tables(thd, &alter_ctx->db, &alter_ctx->alias,
8284 &alter_ctx->new_db, &alter_ctx->new_alias);
8285 }
8286
8287 DBUG_RETURN(false);
8288
8289 rollback:
8290 table->file->ha_commit_inplace_alter_table(altered_table,
8291 ha_alter_info,
8292 false);
8293 cleanup:
8294 if (reopen_tables)
8295 {
8296 /* Close the only table instance which is still around. */
8297 close_all_tables_for_name(thd, table->s,
8298 alter_ctx->is_table_renamed() ?
8299 HA_EXTRA_PREPARE_FOR_RENAME :
8300 HA_EXTRA_NOT_USED,
8301 NULL);
8302 if (thd->locked_tables_list.reopen_tables(thd, false))
8303 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
8304 /* QQ; do something about metadata locks ? */
8305 }
8306 DBUG_RETURN(true);
8307 }
8308
8309 /**
8310 maximum possible length for certain blob types.
8311
8312 @param[in] type Blob type (e.g. MYSQL_TYPE_TINY_BLOB)
8313
8314 @return
8315 length
8316 */
8317
8318 static uint
blob_length_by_type(enum_field_types type)8319 blob_length_by_type(enum_field_types type)
8320 {
8321 switch (type)
8322 {
8323 case MYSQL_TYPE_TINY_BLOB:
8324 return 255;
8325 case MYSQL_TYPE_BLOB:
8326 return 65535;
8327 case MYSQL_TYPE_MEDIUM_BLOB:
8328 return 16777215;
8329 case MYSQL_TYPE_LONG_BLOB:
8330 return (uint) UINT_MAX32;
8331 default:
8332 DBUG_ASSERT(0); // we should never go here
8333 return 0;
8334 }
8335 }
8336
8337
8338 static inline
append_drop_column(THD * thd,String * str,Field * field)8339 void append_drop_column(THD *thd, String *str, Field *field)
8340 {
8341 if (str->length())
8342 str->append(STRING_WITH_LEN(", "));
8343 str->append(STRING_WITH_LEN("DROP COLUMN "));
8344 append_identifier(thd, str, &field->field_name);
8345 }
8346
8347
8348 /**
8349 Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
8350
8351 This function transforms parse output of ALTER TABLE - lists of
8352 columns and keys to add, drop or modify into, essentially,
8353 CREATE TABLE definition - a list of columns and keys of the new
8354 table. While doing so, it also performs some (bug not all)
8355 semantic checks.
8356
8357 This function is invoked when we know that we're going to
8358 perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE
8359 is not possible, perhaps because the ALTER statement contains
8360 instructions that require change in table data, not only in
8361 table definition or indexes.
8362
8363 @param[in,out] thd thread handle. Used as a memory pool
8364 and source of environment information.
8365 @param[in] table the source table, open and locked
8366 Used as an interface to the storage engine
8367 to acquire additional information about
8368 the original table.
8369 @param[in,out] create_info A blob with CREATE/ALTER TABLE
8370 parameters
8371 @param[in,out] alter_info Another blob with ALTER/CREATE parameters.
8372 Originally create_info was used only in
8373 CREATE TABLE and alter_info only in ALTER TABLE.
8374 But since ALTER might end-up doing CREATE,
8375 this distinction is gone and we just carry
8376 around two structures.
8377 @param[in,out] alter_ctx Runtime context for ALTER TABLE.
8378
8379 @return
8380 Fills various create_info members based on information retrieved
8381 from the storage engine.
8382 Sets create_info->varchar if the table has a VARCHAR column.
8383 Prepares alter_info->create_list and alter_info->key_list with
8384 columns and keys of the new table.
8385
8386 @retval TRUE error, out of memory or a semantical error in ALTER
8387 TABLE instructions
8388 @retval FALSE success
8389 */
8390
8391 bool
mysql_prepare_alter_table(THD * thd,TABLE * table,HA_CREATE_INFO * create_info,Alter_info * alter_info,Alter_table_ctx * alter_ctx)8392 mysql_prepare_alter_table(THD *thd, TABLE *table,
8393 HA_CREATE_INFO *create_info,
8394 Alter_info *alter_info,
8395 Alter_table_ctx *alter_ctx)
8396 {
8397 /* New column definitions are added here */
8398 List<Create_field> new_create_list;
8399 /* New key definitions are added here */
8400 List<Key> new_key_list;
8401 List<Alter_rename_key> rename_key_list(alter_info->alter_rename_key_list);
8402 List_iterator<Alter_drop> drop_it(alter_info->drop_list);
8403 List_iterator<Create_field> def_it(alter_info->create_list);
8404 List_iterator<Alter_column> alter_it(alter_info->alter_list);
8405 List_iterator<Key> key_it(alter_info->key_list);
8406 List_iterator<Create_field> find_it(new_create_list);
8407 List_iterator<Create_field> field_it(new_create_list);
8408 List<Key_part_spec> key_parts;
8409 List<Virtual_column_info> new_constraint_list;
8410 uint db_create_options= (table->s->db_create_options
8411 & ~(HA_OPTION_PACK_RECORD));
8412 Item::func_processor_rename column_rename_param;
8413 uint used_fields, dropped_sys_vers_fields= 0;
8414 KEY *key_info=table->key_info;
8415 bool rc= TRUE;
8416 bool vers_system_invisible= false;
8417 Create_field *def;
8418 Field **f_ptr,*field;
8419 MY_BITMAP *dropped_fields= NULL; // if it's NULL - no dropped fields
8420 bool drop_period= false;
8421 LEX_CSTRING period_start_name= {nullptr, 0};
8422 LEX_CSTRING period_end_name= {nullptr, 0};
8423 if (table->s->period.name)
8424 {
8425 period_start_name= table->s->period_start_field()->field_name;
8426 period_end_name= table->s->period_end_field()->field_name;
8427 }
8428 DBUG_ENTER("mysql_prepare_alter_table");
8429
8430 /*
8431 Merge incompatible changes flag in case of upgrade of a table from an
8432 old MariaDB or MySQL version. This ensures that we don't try to do an
8433 online alter table if field packing or character set changes are required.
8434 */
8435 create_info->used_fields|= table->s->incompatible_version;
8436 used_fields= create_info->used_fields;
8437
8438 create_info->varchar= FALSE;
8439 /* Let new create options override the old ones */
8440 if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
8441 create_info->min_rows= table->s->min_rows;
8442 if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
8443 create_info->max_rows= table->s->max_rows;
8444 if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
8445 create_info->avg_row_length= table->s->avg_row_length;
8446 if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
8447 create_info->default_table_charset= table->s->table_charset;
8448 if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
8449 {
8450 /* Table has an autoincrement, copy value to new table */
8451 table->file->info(HA_STATUS_AUTO);
8452 create_info->auto_increment_value= table->file->stats.auto_increment_value;
8453 }
8454
8455 if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
8456 create_info->key_block_size= table->s->key_block_size;
8457
8458 if (!(used_fields & HA_CREATE_USED_STATS_SAMPLE_PAGES))
8459 create_info->stats_sample_pages= table->s->stats_sample_pages;
8460
8461 if (!(used_fields & HA_CREATE_USED_STATS_AUTO_RECALC))
8462 create_info->stats_auto_recalc= table->s->stats_auto_recalc;
8463
8464 if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL))
8465 create_info->transactional= table->s->transactional;
8466
8467 if (!(used_fields & HA_CREATE_USED_CONNECTION))
8468 create_info->connect_string= table->s->connect_string;
8469
8470 if (!(used_fields & HA_CREATE_USED_SEQUENCE))
8471 create_info->sequence= table->s->table_type == TABLE_TYPE_SEQUENCE;
8472
8473 column_rename_param.db_name= table->s->db;
8474 column_rename_param.table_name= table->s->table_name;
8475 if (column_rename_param.fields.copy(&alter_info->create_list, thd->mem_root))
8476 DBUG_RETURN(1); // OOM
8477
8478 restore_record(table, s->default_values); // Empty record for DEFAULT
8479
8480 if ((create_info->fields_option_struct= (ha_field_option_struct**)
8481 thd->calloc(sizeof(void*) * table->s->fields)) == NULL ||
8482 (create_info->indexes_option_struct= (ha_index_option_struct**)
8483 thd->calloc(sizeof(void*) * table->s->keys)) == NULL)
8484 DBUG_RETURN(1);
8485
8486 create_info->option_list= merge_engine_table_options(table->s->option_list,
8487 create_info->option_list, thd->mem_root);
8488
8489 /*
8490 First collect all fields from table which isn't in drop_list
8491 */
8492 bitmap_clear_all(&table->tmp_set);
8493 for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
8494 {
8495 if (field->invisible == INVISIBLE_FULL)
8496 continue;
8497 Alter_drop *drop;
8498 if (field->type() == MYSQL_TYPE_VARCHAR)
8499 create_info->varchar= TRUE;
8500 /* Check if field should be dropped */
8501 drop_it.rewind();
8502 while ((drop=drop_it++))
8503 {
8504 if (drop->type == Alter_drop::COLUMN &&
8505 !my_strcasecmp(system_charset_info,field->field_name.str, drop->name))
8506 break;
8507 }
8508 /*
8509 DROP COLULMN xxx
8510 1. it does not see INVISIBLE_SYSTEM columns
8511 2. otherwise, normally a column is dropped
8512 3. unless it's a system versioning column (but see below).
8513 */
8514 if (drop && field->invisible < INVISIBLE_SYSTEM &&
8515 !(field->flags & VERS_SYSTEM_FIELD &&
8516 !(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)))
8517 {
8518 /* Reset auto_increment value if it was dropped */
8519 if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
8520 !(used_fields & HA_CREATE_USED_AUTO))
8521 {
8522 create_info->auto_increment_value=0;
8523 create_info->used_fields|=HA_CREATE_USED_AUTO;
8524 }
8525 if (table->s->tmp_table == NO_TMP_TABLE)
8526 (void) delete_statistics_for_column(thd, table, field);
8527 dropped_sys_vers_fields|= field->flags;
8528 drop_it.remove();
8529 dropped_fields= &table->tmp_set;
8530 bitmap_set_bit(dropped_fields, field->field_index);
8531 continue;
8532 }
8533 if (field->invisible == INVISIBLE_SYSTEM &&
8534 field->flags & VERS_SYSTEM_FIELD)
8535 {
8536 vers_system_invisible= true;
8537 }
8538 /* invisible versioning column is dropped automatically on DROP SYSTEM VERSIONING */
8539 if (!drop && field->invisible >= INVISIBLE_SYSTEM &&
8540 field->flags & VERS_SYSTEM_FIELD &&
8541 alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING)
8542 {
8543 if (table->s->tmp_table == NO_TMP_TABLE)
8544 (void) delete_statistics_for_column(thd, table, field);
8545 continue;
8546 }
8547
8548 /* Check if field is changed */
8549 def_it.rewind();
8550 while ((def=def_it++))
8551 {
8552 if (def->change.str &&
8553 !lex_string_cmp(system_charset_info, &field->field_name,
8554 &def->change))
8555 break;
8556 }
8557 if (def && field->invisible < INVISIBLE_SYSTEM)
8558 { // Field is changed
8559 def->field=field;
8560 /*
8561 Add column being updated to the list of new columns.
8562 Note that columns with AFTER clauses are added to the end
8563 of the list for now. Their positions will be corrected later.
8564 */
8565 new_create_list.push_back(def, thd->mem_root);
8566 if (field->stored_in_db() != def->stored_in_db())
8567 {
8568 my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0));
8569 goto err;
8570 }
8571 if (!def->after.str)
8572 {
8573 /*
8574 If this ALTER TABLE doesn't have an AFTER clause for the modified
8575 column then remove this column from the list of columns to be
8576 processed. So later we can iterate over the columns remaining
8577 in this list and process modified columns with AFTER clause or
8578 add new columns.
8579 */
8580 def_it.remove();
8581 }
8582 }
8583 else if (alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING &&
8584 field->flags & VERS_SYSTEM_FIELD &&
8585 field->invisible < INVISIBLE_SYSTEM)
8586 {
8587 StringBuffer<NAME_LEN*3> tmp;
8588 append_drop_column(thd, &tmp, field);
8589 my_error(ER_MISSING, MYF(0), table->s->table_name.str, tmp.c_ptr());
8590 goto err;
8591 }
8592 else if (drop && field->invisible < INVISIBLE_SYSTEM &&
8593 field->flags & VERS_SYSTEM_FIELD &&
8594 !(alter_info->flags & ALTER_DROP_SYSTEM_VERSIONING))
8595 {
8596 /* "dropping" a versioning field only hides it from the user */
8597 def= new (thd->mem_root) Create_field(thd, field, field);
8598 def->invisible= INVISIBLE_SYSTEM;
8599 alter_info->flags|= ALTER_CHANGE_COLUMN;
8600 if (field->flags & VERS_ROW_START)
8601 create_info->vers_info.period.start=
8602 create_info->vers_info.as_row.start=
8603 def->field_name= Vers_parse_info::default_start;
8604
8605 else
8606 create_info->vers_info.period.end=
8607 create_info->vers_info.as_row.end=
8608 def->field_name= Vers_parse_info::default_end;
8609 new_create_list.push_back(def, thd->mem_root);
8610 dropped_sys_vers_fields|= field->flags;
8611 drop_it.remove();
8612 }
8613 else
8614 {
8615 /*
8616 This field was not dropped and not changed, add it to the list
8617 for the new table.
8618 */
8619 def= new (thd->mem_root) Create_field(thd, field, field);
8620 new_create_list.push_back(def, thd->mem_root);
8621 alter_it.rewind(); // Change default if ALTER
8622 Alter_column *alter;
8623 while ((alter=alter_it++))
8624 {
8625 if (!my_strcasecmp(system_charset_info,field->field_name.str,
8626 alter->name.str))
8627 break;
8628 }
8629 if (alter && field->invisible < INVISIBLE_SYSTEM)
8630 {
8631 if (alter->is_rename())
8632 {
8633 def->change= alter->name;
8634 def->field_name= alter->new_name;
8635 column_rename_param.fields.push_back(def);
8636 if (field->flags & VERS_ROW_START)
8637 {
8638 create_info->vers_info.as_row.start= alter->new_name;
8639 create_info->vers_info.period.start= alter->new_name;
8640 }
8641 else if (field->flags & VERS_ROW_END)
8642 {
8643 create_info->vers_info.as_row.end= alter->new_name;
8644 create_info->vers_info.period.end= alter->new_name;
8645 }
8646 if (table->s->period.name)
8647 {
8648 if (field == table->period_start_field())
8649 period_start_name= alter->new_name;
8650 else if (field == table->period_end_field())
8651 period_end_name= alter->new_name;
8652 }
8653 }
8654 else
8655 {
8656 if ((def->default_value= alter->default_value))
8657 def->flags&= ~NO_DEFAULT_VALUE_FLAG;
8658 else
8659 def->flags|= NO_DEFAULT_VALUE_FLAG;
8660 }
8661 alter_it.remove();
8662 }
8663 }
8664 }
8665
8666 /*
8667 If we are doing a rename of a column, update all references in virtual
8668 column expressions, constraints and defaults to use the new column name
8669 */
8670 if (alter_info->flags & ALTER_RENAME_COLUMN)
8671 {
8672 alter_it.rewind();
8673 Alter_column *alter;
8674 while ((alter=alter_it++))
8675 {
8676 if (alter->is_rename())
8677 {
8678 my_error(ER_BAD_FIELD_ERROR, MYF(0), alter->name.str,
8679 table->s->table_name.str);
8680 goto err;
8681 }
8682 }
8683 for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
8684 {
8685 if (field->vcol_info)
8686 field->vcol_info->expr->walk(&Item::rename_fields_processor, 1,
8687 &column_rename_param);
8688 if (field->check_constraint)
8689 field->check_constraint->expr->walk(&Item::rename_fields_processor, 1,
8690 &column_rename_param);
8691 if (field->default_value)
8692 field->default_value->expr->walk(&Item::rename_fields_processor, 1,
8693 &column_rename_param);
8694 }
8695 // Force reopen because new column name is on thd->mem_root
8696 table->mark_table_for_reopen();
8697 }
8698
8699 dropped_sys_vers_fields &= VERS_SYSTEM_FIELD;
8700 if ((dropped_sys_vers_fields ||
8701 alter_info->flags & ALTER_DROP_PERIOD) &&
8702 dropped_sys_vers_fields != VERS_SYSTEM_FIELD &&
8703 !vers_system_invisible)
8704 {
8705 StringBuffer<NAME_LEN*3> tmp;
8706 if (!(dropped_sys_vers_fields & VERS_ROW_START))
8707 append_drop_column(thd, &tmp, table->vers_start_field());
8708 if (!(dropped_sys_vers_fields & VERS_ROW_END))
8709 append_drop_column(thd, &tmp, table->vers_end_field());
8710 my_error(ER_MISSING, MYF(0), table->s->table_name.str, tmp.c_ptr());
8711 goto err;
8712 }
8713 else if (alter_info->flags & ALTER_DROP_PERIOD && vers_system_invisible)
8714 {
8715 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), "PERIOD FOR SYSTEM_TIME on", table->s->table_name.str);
8716 goto err;
8717 }
8718 alter_info->flags &= ~(ALTER_DROP_PERIOD | ALTER_ADD_PERIOD);
8719 def_it.rewind();
8720 while ((def=def_it++)) // Add new columns
8721 {
8722 Create_field *find;
8723 if (def->change.str && ! def->field)
8724 {
8725 /*
8726 Check if there is modify for newly added field.
8727 */
8728 find_it.rewind();
8729 while((find=find_it++))
8730 {
8731 if (!my_strcasecmp(system_charset_info,find->field_name.str,
8732 def->field_name.str))
8733 break;
8734 }
8735
8736 if (likely(find && !find->field))
8737 find_it.remove();
8738 else
8739 {
8740 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change.str,
8741 table->s->table_name.str);
8742 goto err;
8743 }
8744 }
8745 /*
8746 Check that the DATE/DATETIME not null field we are going to add is
8747 either has a default value or the '0000-00-00' is allowed by the
8748 set sql mode.
8749 If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
8750 flag to allow ALTER TABLE only if the table to be altered is empty.
8751 */
8752 if (!alter_ctx->implicit_default_value_error_field && !def->field &&
8753 !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
8754 def->type_handler()->validate_implicit_default_value(thd, *def))
8755 {
8756 alter_ctx->implicit_default_value_error_field= def;
8757 alter_ctx->error_if_not_empty= TRUE;
8758 }
8759 if (!def->after.str)
8760 new_create_list.push_back(def, thd->mem_root);
8761 else
8762 {
8763 if (def->change.str)
8764 {
8765 find_it.rewind();
8766 /*
8767 For columns being modified with AFTER clause we should first remove
8768 these columns from the list and then add them back at their correct
8769 positions.
8770 */
8771 while ((find=find_it++))
8772 {
8773 /*
8774 Create_fields representing changed columns are added directly
8775 from Alter_info::create_list to new_create_list. We can therefore
8776 safely use pointer equality rather than name matching here.
8777 This prevents removing the wrong column in case of column rename.
8778 */
8779 if (find == def)
8780 {
8781 find_it.remove();
8782 break;
8783 }
8784 }
8785 }
8786 if (def->after.str == first_keyword)
8787 new_create_list.push_front(def, thd->mem_root);
8788 else
8789 {
8790 find_it.rewind();
8791 while ((find=find_it++))
8792 {
8793 if (!lex_string_cmp(system_charset_info, &def->after,
8794 &find->field_name))
8795 break;
8796 }
8797 if (unlikely(!find))
8798 {
8799 my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after.str,
8800 table->s->table_name.str);
8801 goto err;
8802 }
8803 find_it.after(def); // Put column after this
8804 }
8805 }
8806 /*
8807 Check if there is alter for newly added field.
8808 */
8809 alter_it.rewind();
8810 Alter_column *alter;
8811 while ((alter=alter_it++))
8812 {
8813 if (!my_strcasecmp(system_charset_info,def->field_name.str,
8814 alter->name.str))
8815 break;
8816 }
8817 if (alter)
8818 {
8819 if ((def->default_value= alter->default_value)) // Use new default
8820 def->flags&= ~NO_DEFAULT_VALUE_FLAG;
8821 else
8822 def->flags|= NO_DEFAULT_VALUE_FLAG;
8823 alter_it.remove();
8824 }
8825 }
8826 if (unlikely(alter_info->alter_list.elements))
8827 {
8828 my_error(ER_BAD_FIELD_ERROR, MYF(0),
8829 alter_info->alter_list.head()->name.str, table->s->table_name.str);
8830 goto err;
8831 }
8832 if (unlikely(!new_create_list.elements))
8833 {
8834 my_message(ER_CANT_REMOVE_ALL_FIELDS,
8835 ER_THD(thd, ER_CANT_REMOVE_ALL_FIELDS),
8836 MYF(0));
8837 goto err;
8838 }
8839
8840 /*
8841 Collect all keys which isn't in drop list. Add only those
8842 for which some fields exists.
8843 */
8844 for (uint i=0 ; i < table->s->keys ; i++,key_info++)
8845 {
8846 bool long_hash_key= false;
8847 if (key_info->flags & HA_INVISIBLE_KEY)
8848 continue;
8849 const char *key_name= key_info->name.str;
8850 const bool primary_key= table->s->primary_key == i;
8851 const bool explicit_pk= primary_key &&
8852 !my_strcasecmp(system_charset_info, key_name,
8853 primary_key_name);
8854 const bool implicit_pk= primary_key && !explicit_pk;
8855
8856 Alter_drop *drop;
8857 drop_it.rewind();
8858 while ((drop=drop_it++))
8859 {
8860 if (drop->type == Alter_drop::KEY &&
8861 !my_strcasecmp(system_charset_info,key_name, drop->name))
8862 break;
8863 }
8864 if (drop)
8865 {
8866 if (table->s->tmp_table == NO_TMP_TABLE)
8867 {
8868 (void) delete_statistics_for_index(thd, table, key_info, FALSE);
8869 if (primary_key)
8870 {
8871 KEY *tab_key_info= table->key_info;
8872 for (uint j=0; j < table->s->keys; j++, tab_key_info++)
8873 {
8874 if (tab_key_info->user_defined_key_parts !=
8875 tab_key_info->ext_key_parts)
8876 (void) delete_statistics_for_index(thd, table, tab_key_info,
8877 TRUE);
8878 }
8879 }
8880 }
8881 drop_it.remove();
8882 continue;
8883 }
8884
8885 /* If this index is to stay in the table check if it has to be renamed. */
8886 List_iterator<Alter_rename_key> rename_key_it(rename_key_list);
8887 Alter_rename_key *rename_key;
8888
8889 while ((rename_key= rename_key_it++))
8890 {
8891 if (!my_strcasecmp(system_charset_info, key_name, rename_key->old_name.str))
8892 {
8893 if (!my_strcasecmp(system_charset_info, key_name, primary_key_name))
8894 {
8895 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->old_name.str);
8896 goto err;
8897 }
8898 else if (!my_strcasecmp(system_charset_info, rename_key->new_name.str,
8899 primary_key_name))
8900 {
8901 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->new_name.str);
8902 goto err;
8903 }
8904
8905 key_name= rename_key->new_name.str;
8906 rename_key_it.remove();
8907 /*
8908 If the user has explicitly renamed the key, we should no longer
8909 treat it as generated. Otherwise this key might be automatically
8910 dropped by mysql_prepare_create_table() and this will confuse
8911 code in fill_alter_inplace_info().
8912 */
8913 key_info->flags&= ~HA_GENERATED_KEY;
8914 break;
8915 }
8916 }
8917
8918 if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
8919 {
8920 setup_keyinfo_hash(key_info);
8921 long_hash_key= true;
8922 }
8923 const char *dropped_key_part= NULL;
8924 bool user_keyparts= false; // some user-defined keyparts left
8925 KEY_PART_INFO *key_part= key_info->key_part;
8926 key_parts.empty();
8927 uint key_parts_nr= key_info->user_defined_key_parts;
8928 if (key_info->without_overlaps)
8929 key_parts_nr-= 2;
8930
8931 bool delete_index_stat= FALSE;
8932 for (uint j=0 ; j < key_parts_nr ; j++,key_part++)
8933 {
8934 Field *kfield= key_part->field;
8935 if (!kfield)
8936 continue; // Wrong field (from UNIREG)
8937 const char *key_part_name=kfield->field_name.str;
8938 Create_field *cfield;
8939 uint key_part_length;
8940
8941 field_it.rewind();
8942 while ((cfield=field_it++))
8943 {
8944 if (cfield->change.str)
8945 {
8946 if (!my_strcasecmp(system_charset_info, key_part_name,
8947 cfield->change.str))
8948 break;
8949 }
8950 else if (!my_strcasecmp(system_charset_info,
8951 key_part_name, cfield->field_name.str))
8952 break;
8953 }
8954 if (!cfield)
8955 {
8956 if (primary_key)
8957 alter_ctx->modified_primary_key= true;
8958 delete_index_stat= TRUE;
8959 if (!(kfield->flags & VERS_SYSTEM_FIELD))
8960 dropped_key_part= key_part_name;
8961 continue; // Field is removed
8962 }
8963
8964 DBUG_ASSERT(!primary_key || kfield->flags & NOT_NULL_FLAG);
8965 if (implicit_pk && !alter_ctx->modified_primary_key &&
8966 !(cfield->flags & NOT_NULL_FLAG))
8967 alter_ctx->modified_primary_key= true;
8968
8969 key_part_length= key_part->length;
8970 if (cfield->field) // Not new field
8971 {
8972 /*
8973 If the field can't have only a part used in a key according to its
8974 new type, or should not be used partially according to its
8975 previous type, or the field length is less than the key part
8976 length, unset the key part length.
8977
8978 We also unset the key part length if it is the same as the
8979 old field's length, so the whole new field will be used.
8980
8981 BLOBs may have cfield->length == 0, which is why we test it before
8982 checking whether cfield->length < key_part_length (in chars).
8983
8984 In case of TEXTs we check the data type maximum length *in bytes*
8985 to key part length measured *in characters* (i.e. key_part_length
8986 devided to mbmaxlen). This is because it's OK to have:
8987 CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8);
8988 In case of this example:
8989 - data type maximum length is 255.
8990 - key_part_length is 1016 (=254*4, where 4 is mbmaxlen)
8991 */
8992 if (!cfield->field->type_handler()->type_can_have_key_part() ||
8993 !cfield->type_handler()->type_can_have_key_part() ||
8994 /* spatial keys can't have sub-key length */
8995 (key_info->flags & HA_SPATIAL) ||
8996 (cfield->field->field_length == key_part_length &&
8997 !f_is_blob(key_part->key_type)) ||
8998 (cfield->length &&
8999 (((cfield->real_field_type() >= MYSQL_TYPE_TINY_BLOB &&
9000 cfield->real_field_type() <= MYSQL_TYPE_BLOB) ?
9001 blob_length_by_type(cfield->real_field_type()) :
9002 cfield->length) <
9003 key_part_length / kfield->charset()->mbmaxlen)))
9004 key_part_length= 0; // Use whole field
9005 }
9006 key_part_length /= kfield->charset()->mbmaxlen;
9007 key_parts.push_back(new (thd->mem_root) Key_part_spec(&cfield->field_name,
9008 key_part_length, true),
9009 thd->mem_root);
9010 if (!(cfield->invisible == INVISIBLE_SYSTEM && cfield->vers_sys_field()))
9011 user_keyparts= true;
9012 }
9013 if (table->s->tmp_table == NO_TMP_TABLE)
9014 {
9015 if (delete_index_stat)
9016 (void) delete_statistics_for_index(thd, table, key_info, FALSE);
9017 else if (alter_ctx->modified_primary_key &&
9018 key_info->user_defined_key_parts != key_info->ext_key_parts)
9019 (void) delete_statistics_for_index(thd, table, key_info, TRUE);
9020 }
9021
9022 if (!user_keyparts && key_parts.elements)
9023 {
9024 /*
9025 If we dropped all user key-parts we also drop implicit system fields.
9026 */
9027 key_parts.empty();
9028 }
9029
9030 if (key_parts.elements)
9031 {
9032 KEY_CREATE_INFO key_create_info;
9033 Key *key;
9034 enum Key::Keytype key_type;
9035 LEX_CSTRING tmp_name;
9036 bzero((char*) &key_create_info, sizeof(key_create_info));
9037 if (key_info->algorithm == HA_KEY_ALG_LONG_HASH)
9038 key_info->algorithm= HA_KEY_ALG_UNDEF;
9039 key_create_info.algorithm= key_info->algorithm;
9040 /*
9041 We copy block size directly as some engines, like Area, sets this
9042 automatically
9043 */
9044 key_create_info.block_size= key_info->block_size;
9045 key_create_info.flags= key_info->flags; // HA_USE_BLOCK_SIZE
9046 if (key_info->flags & HA_USES_PARSER)
9047 key_create_info.parser_name= *plugin_name(key_info->parser);
9048 if (key_info->flags & HA_USES_COMMENT)
9049 key_create_info.comment= key_info->comment;
9050
9051 /*
9052 We're refreshing an already existing index. Since the index is not
9053 modified, there is no need to check for duplicate indexes again.
9054 */
9055 key_create_info.check_for_duplicate_indexes= false;
9056
9057 if (key_info->flags & HA_SPATIAL)
9058 key_type= Key::SPATIAL;
9059 else if (key_info->flags & HA_NOSAME)
9060 {
9061 if (explicit_pk)
9062 key_type= Key::PRIMARY;
9063 else
9064 key_type= Key::UNIQUE;
9065 if (dropped_key_part)
9066 {
9067 my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), dropped_key_part);
9068 if (long_hash_key)
9069 {
9070 key_info->algorithm= HA_KEY_ALG_LONG_HASH;
9071 re_setup_keyinfo_hash(key_info);
9072 }
9073 goto err;
9074 }
9075 }
9076 else if (key_info->flags & HA_FULLTEXT)
9077 key_type= Key::FULLTEXT;
9078 else
9079 key_type= Key::MULTIPLE;
9080
9081 tmp_name.str= key_name;
9082 tmp_name.length= strlen(key_name);
9083 /* We dont need LONG_UNIQUE_HASH_FIELD flag because it will be autogenerated */
9084 key= new (thd->mem_root) Key(key_type, &tmp_name, &key_create_info,
9085 MY_TEST(key_info->flags & HA_GENERATED_KEY),
9086 &key_parts, key_info->option_list, DDL_options());
9087 key->without_overlaps= key_info->without_overlaps;
9088 key->period= table->s->period.name;
9089 new_key_list.push_back(key, thd->mem_root);
9090 }
9091 if (long_hash_key)
9092 {
9093 key_info->algorithm= HA_KEY_ALG_LONG_HASH;
9094 re_setup_keyinfo_hash(key_info);
9095 }
9096 }
9097 {
9098 Key *key;
9099 while ((key=key_it++)) // Add new keys
9100 {
9101 if (key->type == Key::FOREIGN_KEY &&
9102 ((Foreign_key *)key)->validate(new_create_list))
9103 goto err;
9104 new_key_list.push_back(key, thd->mem_root);
9105 if (key->name.str &&
9106 !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
9107 {
9108 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
9109 goto err;
9110 }
9111 }
9112 }
9113
9114 if (table->s->period.name)
9115 {
9116 drop_it.rewind();
9117 Alter_drop *drop;
9118 for (bool found= false; !found && (drop= drop_it++); )
9119 {
9120 found= drop->type == Alter_drop::PERIOD &&
9121 table->s->period.name.streq(drop->name);
9122 }
9123
9124 if (drop)
9125 {
9126 drop_period= true;
9127 drop_it.remove();
9128 }
9129 else if (create_info->period_info.is_set() && table->s->period.name)
9130 {
9131 my_error(ER_MORE_THAN_ONE_PERIOD, MYF(0));
9132 goto err;
9133 }
9134 else
9135 {
9136 create_info->period_info.set_period(period_start_name, period_end_name);
9137 create_info->period_info.name= table->s->period.name;
9138 }
9139 }
9140
9141 /* Add all table level constraints which are not in the drop list */
9142 if (table->s->table_check_constraints)
9143 {
9144 TABLE_SHARE *share= table->s;
9145
9146 for (uint i= share->field_check_constraints;
9147 i < share->table_check_constraints ; i++)
9148 {
9149 Virtual_column_info *check= table->check_constraints[i];
9150 Alter_drop *drop;
9151 bool keep= true;
9152 drop_it.rewind();
9153 while ((drop=drop_it++))
9154 {
9155 if (drop->type == Alter_drop::CHECK_CONSTRAINT &&
9156 !my_strcasecmp(system_charset_info, check->name.str, drop->name))
9157 {
9158 drop_it.remove();
9159 keep= false;
9160 break;
9161 }
9162 }
9163
9164 if (share->period.constr_name.streq(check->name.str))
9165 {
9166 if (!drop_period && !keep)
9167 {
9168 my_error(ER_PERIOD_CONSTRAINT_DROP, MYF(0), check->name.str,
9169 share->period.name.str);
9170 goto err;
9171 }
9172 keep= keep && !drop_period;
9173
9174 DBUG_ASSERT(create_info->period_info.constr == NULL || drop_period);
9175
9176 if (keep)
9177 {
9178 Item *expr_copy= check->expr->get_copy(thd);
9179 check= new Virtual_column_info();
9180 check->name= share->period.constr_name;
9181 check->automatic_name= true;
9182 check->expr= expr_copy;
9183 create_info->period_info.constr= check;
9184 }
9185 }
9186 /* see if the constraint depends on *only* on dropped fields */
9187 if (keep && dropped_fields)
9188 {
9189 table->default_column_bitmaps();
9190 bitmap_clear_all(table->read_set);
9191 check->expr->walk(&Item::register_field_in_read_map, 1, 0);
9192 if (bitmap_is_subset(table->read_set, dropped_fields))
9193 keep= false;
9194 else if (bitmap_is_overlapping(dropped_fields, table->read_set))
9195 {
9196 bitmap_intersect(table->read_set, dropped_fields);
9197 uint field_nr= bitmap_get_first_set(table->read_set);
9198 my_error(ER_BAD_FIELD_ERROR, MYF(0),
9199 table->field[field_nr]->field_name.str, "CHECK");
9200 goto err;
9201 }
9202 }
9203 if (keep)
9204 {
9205 if (alter_info->flags & ALTER_RENAME_COLUMN)
9206 {
9207 check->expr->walk(&Item::rename_fields_processor, 1,
9208 &column_rename_param);
9209 // Force reopen because new column name is on thd->mem_root
9210 table->mark_table_for_reopen();
9211 }
9212 new_constraint_list.push_back(check, thd->mem_root);
9213 }
9214 }
9215 }
9216
9217 if (!alter_info->check_constraint_list.is_empty())
9218 {
9219 /* Check the table FOREIGN KEYs for name duplications. */
9220 List <FOREIGN_KEY_INFO> fk_child_key_list;
9221 FOREIGN_KEY_INFO *f_key;
9222 table->file->get_foreign_key_list(thd, &fk_child_key_list);
9223 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
9224 while ((f_key= fk_key_it++))
9225 {
9226 List_iterator_fast<Virtual_column_info>
9227 c_it(alter_info->check_constraint_list);
9228 Virtual_column_info *check;
9229 while ((check= c_it++))
9230 {
9231 if (!check->name.length || check->automatic_name)
9232 continue;
9233
9234 if (check->name.length == f_key->foreign_id->length &&
9235 my_strcasecmp(system_charset_info, f_key->foreign_id->str,
9236 check->name.str) == 0)
9237 {
9238 my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name.str);
9239 goto err;
9240 }
9241 }
9242 }
9243 }
9244
9245 /* Add new constraints */
9246 new_constraint_list.append(&alter_info->check_constraint_list);
9247
9248 if (alter_info->drop_list.elements)
9249 {
9250 Alter_drop *drop;
9251 drop_it.rewind();
9252 while ((drop=drop_it++)) {
9253 switch (drop->type) {
9254 case Alter_drop::KEY:
9255 case Alter_drop::COLUMN:
9256 case Alter_drop::CHECK_CONSTRAINT:
9257 case Alter_drop::PERIOD:
9258 my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
9259 alter_info->drop_list.head()->name);
9260 goto err;
9261 case Alter_drop::FOREIGN_KEY:
9262 // Leave the DROP FOREIGN KEY names in the alter_info->drop_list.
9263 break;
9264 }
9265 }
9266 }
9267
9268 if (rename_key_list.elements)
9269 {
9270 my_error(ER_KEY_DOES_NOT_EXISTS, MYF(0), rename_key_list.head()->old_name.str,
9271 table->s->table_name.str);
9272 goto err;
9273 }
9274
9275 if (!create_info->comment.str)
9276 {
9277 create_info->comment.str= table->s->comment.str;
9278 create_info->comment.length= table->s->comment.length;
9279 }
9280
9281 table->file->update_create_info(create_info);
9282 if ((create_info->table_options &
9283 (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
9284 (used_fields & HA_CREATE_USED_PACK_KEYS))
9285 db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
9286 if ((create_info->table_options &
9287 (HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT)) ||
9288 (used_fields & HA_CREATE_USED_STATS_PERSISTENT))
9289 db_create_options&= ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT);
9290
9291 if (create_info->table_options &
9292 (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
9293 db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
9294 if (create_info->table_options &
9295 (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
9296 db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
9297 HA_OPTION_NO_DELAY_KEY_WRITE);
9298 create_info->table_options|= db_create_options;
9299
9300 if (table->s->tmp_table)
9301 create_info->options|=HA_LEX_CREATE_TMP_TABLE;
9302
9303 rc= FALSE;
9304 alter_info->create_list.swap(new_create_list);
9305 alter_info->key_list.swap(new_key_list);
9306 alter_info->check_constraint_list.swap(new_constraint_list);
9307 err:
9308 DBUG_RETURN(rc);
9309 }
9310
9311
9312 /**
9313 Get Create_field object for newly created table by its name
9314 in the old version of table.
9315
9316 @param alter_info Alter_info describing newly created table.
9317 @param old_name Name of field in old table.
9318
9319 @returns Pointer to Create_field object, NULL - if field is
9320 not present in new version of table.
9321 */
9322
get_field_by_old_name(Alter_info * alter_info,const char * old_name)9323 static Create_field *get_field_by_old_name(Alter_info *alter_info,
9324 const char *old_name)
9325 {
9326 List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
9327 Create_field *new_field;
9328
9329 while ((new_field= new_field_it++))
9330 {
9331 if (new_field->field &&
9332 (my_strcasecmp(system_charset_info,
9333 new_field->field->field_name.str,
9334 old_name) == 0))
9335 break;
9336 }
9337 return new_field;
9338 }
9339
9340
9341 /** Type of change to foreign key column, */
9342
9343 enum fk_column_change_type
9344 {
9345 FK_COLUMN_NO_CHANGE, FK_COLUMN_DATA_CHANGE,
9346 FK_COLUMN_RENAMED, FK_COLUMN_DROPPED
9347 };
9348
9349 /**
9350 Check that ALTER TABLE's changes on columns of a foreign key are allowed.
9351
9352 @param[in] thd Thread context.
9353 @param[in] alter_info Alter_info describing changes to be done
9354 by ALTER TABLE.
9355 @param[in] fk_columns List of columns of the foreign key to check.
9356 @param[out] bad_column_name Name of field on which ALTER TABLE tries to
9357 do prohibited operation.
9358
9359 @note This function takes into account value of @@foreign_key_checks
9360 setting.
9361
9362 @retval FK_COLUMN_NO_CHANGE No significant changes are to be done on
9363 foreign key columns.
9364 @retval FK_COLUMN_DATA_CHANGE ALTER TABLE might result in value
9365 change in foreign key column (and
9366 foreign_key_checks is on).
9367 @retval FK_COLUMN_RENAMED Foreign key column is renamed.
9368 @retval FK_COLUMN_DROPPED Foreign key column is dropped.
9369 */
9370
9371 static enum fk_column_change_type
fk_check_column_changes(THD * thd,Alter_info * alter_info,List<LEX_CSTRING> & fk_columns,const char ** bad_column_name)9372 fk_check_column_changes(THD *thd, Alter_info *alter_info,
9373 List<LEX_CSTRING> &fk_columns,
9374 const char **bad_column_name)
9375 {
9376 List_iterator_fast<LEX_CSTRING> column_it(fk_columns);
9377 LEX_CSTRING *column;
9378
9379 *bad_column_name= NULL;
9380
9381 while ((column= column_it++))
9382 {
9383 Create_field *new_field= get_field_by_old_name(alter_info, column->str);
9384
9385 if (new_field)
9386 {
9387 Field *old_field= new_field->field;
9388
9389 if (lex_string_cmp(system_charset_info, &old_field->field_name,
9390 &new_field->field_name))
9391 {
9392 /*
9393 Copy algorithm doesn't support proper renaming of columns in
9394 the foreign key yet. At the moment we lack API which will tell
9395 SE that foreign keys should be updated to use new name of column
9396 like it happens in case of in-place algorithm.
9397 */
9398 *bad_column_name= column->str;
9399 return FK_COLUMN_RENAMED;
9400 }
9401
9402 if ((old_field->is_equal(*new_field) == IS_EQUAL_NO) ||
9403 ((new_field->flags & NOT_NULL_FLAG) &&
9404 !(old_field->flags & NOT_NULL_FLAG)))
9405 {
9406 if (!(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
9407 {
9408 /*
9409 Column in a FK has changed significantly. Unless
9410 foreign_key_checks are off we prohibit this since this
9411 means values in this column might be changed by ALTER
9412 and thus referential integrity might be broken,
9413 */
9414 *bad_column_name= column->str;
9415 return FK_COLUMN_DATA_CHANGE;
9416 }
9417 }
9418 }
9419 else
9420 {
9421 /*
9422 Column in FK was dropped. Most likely this will break
9423 integrity constraints of InnoDB data-dictionary (and thus
9424 InnoDB will emit an error), so we prohibit this right away
9425 even if foreign_key_checks are off.
9426 This also includes a rare case when another field replaces
9427 field being dropped since it is easy to break referential
9428 integrity in this case.
9429 */
9430 *bad_column_name= column->str;
9431 return FK_COLUMN_DROPPED;
9432 }
9433 }
9434
9435 return FK_COLUMN_NO_CHANGE;
9436 }
9437
9438
9439 /**
9440 Check if ALTER TABLE we are about to execute using COPY algorithm
9441 is not supported as it might break referential integrity.
9442
9443 @note If foreign_key_checks is disabled (=0), we allow to break
9444 referential integrity. But we still disallow some operations
9445 like dropping or renaming columns in foreign key since they
9446 are likely to break consistency of InnoDB data-dictionary
9447 and thus will end-up in error anyway.
9448
9449 @param[in] thd Thread context.
9450 @param[in] table Table to be altered.
9451 @param[in] alter_info Lists of fields, keys to be changed, added
9452 or dropped.
9453 @param[out] alter_ctx ALTER TABLE runtime context.
9454 Alter_table_ctx::fk_error_if_delete flag
9455 is set if deletion during alter can break
9456 foreign key integrity.
9457
9458 @retval false Success.
9459 @retval true Error, ALTER - tries to do change which is not compatible
9460 with foreign key definitions on the table.
9461 */
9462
fk_prepare_copy_alter_table(THD * thd,TABLE * table,Alter_info * alter_info,Alter_table_ctx * alter_ctx)9463 static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
9464 Alter_info *alter_info,
9465 Alter_table_ctx *alter_ctx)
9466 {
9467 List <FOREIGN_KEY_INFO> fk_parent_key_list;
9468 List <FOREIGN_KEY_INFO> fk_child_key_list;
9469 FOREIGN_KEY_INFO *f_key;
9470
9471 DBUG_ENTER("fk_prepare_copy_alter_table");
9472
9473 table->file->get_parent_foreign_key_list(thd, &fk_parent_key_list);
9474
9475 /* OOM when building list. */
9476 if (unlikely(thd->is_error()))
9477 DBUG_RETURN(true);
9478
9479 /*
9480 Remove from the list all foreign keys in which table participates as
9481 parent which are to be dropped by this ALTER TABLE. This is possible
9482 when a foreign key has the same table as child and parent.
9483 */
9484 List_iterator<FOREIGN_KEY_INFO> fk_parent_key_it(fk_parent_key_list);
9485
9486 while ((f_key= fk_parent_key_it++))
9487 {
9488 Alter_drop *drop;
9489 List_iterator_fast<Alter_drop> drop_it(alter_info->drop_list);
9490
9491 while ((drop= drop_it++))
9492 {
9493 /*
9494 InnoDB treats foreign key names in case-insensitive fashion.
9495 So we do it here too. For database and table name type of
9496 comparison used depends on lower-case-table-names setting.
9497 For l_c_t_n = 0 we use case-sensitive comparison, for
9498 l_c_t_n > 0 modes case-insensitive comparison is used.
9499 */
9500 if ((drop->type == Alter_drop::FOREIGN_KEY) &&
9501 (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
9502 drop->name) == 0) &&
9503 (lex_string_cmp(table_alias_charset, f_key->foreign_db,
9504 &table->s->db) == 0) &&
9505 (lex_string_cmp(table_alias_charset, f_key->foreign_table,
9506 &table->s->table_name) == 0))
9507 fk_parent_key_it.remove();
9508 }
9509 }
9510
9511 /*
9512 If there are FKs in which this table is parent which were not
9513 dropped we need to prevent ALTER deleting rows from the table,
9514 as it might break referential integrity. OTOH it is OK to do
9515 so if foreign_key_checks are disabled.
9516 */
9517 if (!fk_parent_key_list.is_empty() &&
9518 !(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))
9519 alter_ctx->set_fk_error_if_delete_row(fk_parent_key_list.head());
9520
9521 fk_parent_key_it.rewind();
9522 while ((f_key= fk_parent_key_it++))
9523 {
9524 enum fk_column_change_type changes;
9525 const char *bad_column_name;
9526
9527 changes= fk_check_column_changes(thd, alter_info,
9528 f_key->referenced_fields,
9529 &bad_column_name);
9530
9531 switch(changes)
9532 {
9533 case FK_COLUMN_NO_CHANGE:
9534 /* No significant changes. We can proceed with ALTER! */
9535 break;
9536 case FK_COLUMN_DATA_CHANGE:
9537 {
9538 char buff[NAME_LEN*2+2];
9539 strxnmov(buff, sizeof(buff)-1, f_key->foreign_db->str, ".",
9540 f_key->foreign_table->str, NullS);
9541 my_error(ER_FK_COLUMN_CANNOT_CHANGE_CHILD, MYF(0), bad_column_name,
9542 f_key->foreign_id->str, buff);
9543 DBUG_RETURN(true);
9544 }
9545 case FK_COLUMN_RENAMED:
9546 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
9547 "ALGORITHM=COPY",
9548 ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME),
9549 "ALGORITHM=INPLACE");
9550 DBUG_RETURN(true);
9551 case FK_COLUMN_DROPPED:
9552 {
9553 StringBuffer<NAME_LEN*2+2> buff(system_charset_info);
9554 LEX_CSTRING *db= f_key->foreign_db, *tbl= f_key->foreign_table;
9555
9556 append_identifier(thd, &buff, db);
9557 buff.append('.');
9558 append_identifier(thd, &buff, tbl);
9559 my_error(ER_FK_COLUMN_CANNOT_DROP_CHILD, MYF(0), bad_column_name,
9560 f_key->foreign_id->str, buff.c_ptr());
9561 DBUG_RETURN(true);
9562 }
9563 default:
9564 DBUG_ASSERT(0);
9565 }
9566 }
9567
9568 table->file->get_foreign_key_list(thd, &fk_child_key_list);
9569
9570 /* OOM when building list. */
9571 if (unlikely(thd->is_error()))
9572 DBUG_RETURN(true);
9573
9574 /*
9575 Remove from the list all foreign keys which are to be dropped
9576 by this ALTER TABLE.
9577 */
9578 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
9579
9580 while ((f_key= fk_key_it++))
9581 {
9582 Alter_drop *drop;
9583 List_iterator_fast<Alter_drop> drop_it(alter_info->drop_list);
9584
9585 while ((drop= drop_it++))
9586 {
9587 /* Names of foreign keys in InnoDB are case-insensitive. */
9588 if ((drop->type == Alter_drop::FOREIGN_KEY) &&
9589 (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
9590 drop->name) == 0))
9591 fk_key_it.remove();
9592 }
9593 }
9594
9595 fk_key_it.rewind();
9596 while ((f_key= fk_key_it++))
9597 {
9598 enum fk_column_change_type changes;
9599 const char *bad_column_name;
9600
9601 changes= fk_check_column_changes(thd, alter_info,
9602 f_key->foreign_fields,
9603 &bad_column_name);
9604
9605 switch(changes)
9606 {
9607 case FK_COLUMN_NO_CHANGE:
9608 /* No significant changes. We can proceed with ALTER! */
9609 break;
9610 case FK_COLUMN_DATA_CHANGE:
9611 my_error(ER_FK_COLUMN_CANNOT_CHANGE, MYF(0), bad_column_name,
9612 f_key->foreign_id->str);
9613 DBUG_RETURN(true);
9614 case FK_COLUMN_RENAMED:
9615 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
9616 "ALGORITHM=COPY",
9617 ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME),
9618 "ALGORITHM=INPLACE");
9619 DBUG_RETURN(true);
9620 case FK_COLUMN_DROPPED:
9621 my_error(ER_FK_COLUMN_CANNOT_DROP, MYF(0), bad_column_name,
9622 f_key->foreign_id->str);
9623 DBUG_RETURN(true);
9624 default:
9625 DBUG_ASSERT(0);
9626 }
9627 }
9628
9629 /*
9630 Normally, an attempt to modify an FK parent table will cause
9631 FK children to be prelocked, so the table-being-altered cannot
9632 be modified by a cascade FK action, because ALTER holds a lock
9633 and prelocking will wait.
9634
9635 But if a new FK is being added by this very ALTER, then the target
9636 table is not locked yet (it's a temporary table). So, we have to
9637 lock FK parents explicitly.
9638 */
9639 if (alter_info->flags & ALTER_ADD_FOREIGN_KEY)
9640 {
9641 List_iterator<Key> fk_list_it(alter_info->key_list);
9642
9643 while (Key *key= fk_list_it++)
9644 {
9645 if (key->type != Key::FOREIGN_KEY)
9646 continue;
9647
9648 Foreign_key *fk= static_cast<Foreign_key*>(key);
9649 char dbuf[NAME_LEN];
9650 char tbuf[NAME_LEN];
9651 const char *ref_db= (fk->ref_db.str ?
9652 fk->ref_db.str :
9653 alter_ctx->new_db.str);
9654 const char *ref_table= fk->ref_table.str;
9655 MDL_request mdl_request;
9656
9657 if (lower_case_table_names)
9658 {
9659 strmake_buf(dbuf, ref_db);
9660 my_casedn_str(system_charset_info, dbuf);
9661 strmake_buf(tbuf, ref_table);
9662 my_casedn_str(system_charset_info, tbuf);
9663 ref_db= dbuf;
9664 ref_table= tbuf;
9665 }
9666
9667 MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, ref_db, ref_table,
9668 MDL_SHARED_NO_WRITE, MDL_TRANSACTION);
9669 if (thd->mdl_context.acquire_lock(&mdl_request,
9670 thd->variables.lock_wait_timeout))
9671 DBUG_RETURN(true);
9672 }
9673 }
9674
9675 DBUG_RETURN(false);
9676 }
9677
9678 /**
9679 Rename temporary table and/or turn indexes on/off without touching .FRM.
9680 Its a variant of simple_rename_or_index_change() to be used exclusively
9681 for temporary tables.
9682
9683 @param thd Thread handler
9684 @param table_list TABLE_LIST for the table to change
9685 @param keys_onoff ENABLE or DISABLE KEYS?
9686 @param alter_ctx ALTER TABLE runtime context.
9687
9688 @return Operation status
9689 @retval false Success
9690 @retval true Failure
9691 */
9692 static bool
simple_tmp_rename_or_index_change(THD * thd,TABLE_LIST * table_list,Alter_info::enum_enable_or_disable keys_onoff,Alter_table_ctx * alter_ctx)9693 simple_tmp_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
9694 Alter_info::enum_enable_or_disable keys_onoff,
9695 Alter_table_ctx *alter_ctx)
9696 {
9697 DBUG_ENTER("simple_tmp_rename_or_index_change");
9698
9699 TABLE *table= table_list->table;
9700 bool error= false;
9701
9702 DBUG_ASSERT(table->s->tmp_table);
9703
9704 if (keys_onoff != Alter_info::LEAVE_AS_IS)
9705 {
9706 THD_STAGE_INFO(thd, stage_manage_keys);
9707 error= alter_table_manage_keys(table, table->file->indexes_are_disabled(),
9708 keys_onoff);
9709 }
9710
9711 if (likely(!error) && alter_ctx->is_table_renamed())
9712 {
9713 THD_STAGE_INFO(thd, stage_rename);
9714
9715 /*
9716 If THD::rename_temporary_table() fails, there is no need to rename it
9717 back to the original name (unlike the case for non-temporary tables),
9718 as it was an allocation error and the table was not renamed.
9719 */
9720 error= thd->rename_temporary_table(table, &alter_ctx->new_db,
9721 &alter_ctx->new_alias);
9722 }
9723
9724 if (likely(!error))
9725 {
9726 /*
9727 We do not replicate alter table statement on temporary tables under
9728 ROW-based replication.
9729 */
9730 if (!thd->is_current_stmt_binlog_format_row())
9731 {
9732 error= write_bin_log(thd, true, thd->query(), thd->query_length()) != 0;
9733 }
9734 if (likely(!error))
9735 my_ok(thd);
9736 }
9737
9738 DBUG_RETURN(error);
9739 }
9740
9741
9742 /**
9743 Rename table and/or turn indexes on/off without touching .FRM
9744
9745 @param thd Thread handler
9746 @param table_list TABLE_LIST for the table to change
9747 @param keys_onoff ENABLE or DISABLE KEYS?
9748 @param alter_ctx ALTER TABLE runtime context.
9749
9750 @return Operation status
9751 @retval false Success
9752 @retval true Failure
9753 */
9754
9755 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)9756 simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
9757 Alter_info::enum_enable_or_disable keys_onoff,
9758 Alter_table_ctx *alter_ctx)
9759 {
9760 TABLE *table= table_list->table;
9761 MDL_ticket *mdl_ticket= table->mdl_ticket;
9762 int error= 0;
9763 enum ha_extra_function extra_func= thd->locked_tables_mode
9764 ? HA_EXTRA_NOT_USED
9765 : HA_EXTRA_FORCE_REOPEN;
9766 DBUG_ENTER("simple_rename_or_index_change");
9767
9768 if (keys_onoff != Alter_info::LEAVE_AS_IS)
9769 {
9770 if (wait_while_table_is_used(thd, table, extra_func))
9771 DBUG_RETURN(true);
9772
9773 // It's now safe to take the table level lock.
9774 if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0))
9775 DBUG_RETURN(true);
9776
9777 THD_STAGE_INFO(thd, stage_manage_keys);
9778 error= alter_table_manage_keys(table,
9779 table->file->indexes_are_disabled(),
9780 keys_onoff);
9781 }
9782
9783 if (likely(!error) && alter_ctx->is_table_renamed())
9784 {
9785 THD_STAGE_INFO(thd, stage_rename);
9786 handlerton *old_db_type= table->s->db_type();
9787 /*
9788 Then do a 'simple' rename of the table. First we need to close all
9789 instances of 'source' table.
9790 Note that if wait_while_table_is_used() returns error here (i.e. if
9791 this thread was killed) then it must be that previous step of
9792 simple rename did nothing and therefore we can safely return
9793 without additional clean-up.
9794 */
9795 if (wait_while_table_is_used(thd, table, extra_func))
9796 DBUG_RETURN(true);
9797 close_all_tables_for_name(thd, table->s, HA_EXTRA_PREPARE_FOR_RENAME,
9798 NULL);
9799
9800 if (mysql_rename_table(old_db_type, &alter_ctx->db, &alter_ctx->table_name,
9801 &alter_ctx->new_db, &alter_ctx->new_alias, 0))
9802 error= -1;
9803 else if (Table_triggers_list::change_table_name(thd,
9804 &alter_ctx->db,
9805 &alter_ctx->alias,
9806 &alter_ctx->table_name,
9807 &alter_ctx->new_db,
9808 &alter_ctx->new_alias))
9809 {
9810 (void) mysql_rename_table(old_db_type,
9811 &alter_ctx->new_db, &alter_ctx->new_alias,
9812 &alter_ctx->db, &alter_ctx->table_name,
9813 NO_FK_CHECKS);
9814 error= -1;
9815 }
9816 /* Update stat tables last. This is to be able to handle rename of a stat table */
9817 if (error == 0)
9818 (void) rename_table_in_stat_tables(thd, &alter_ctx->db,
9819 &alter_ctx->table_name,
9820 &alter_ctx->new_db,
9821 &alter_ctx->new_alias);
9822 }
9823
9824 if (likely(!error))
9825 {
9826 error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
9827
9828 if (likely(!error))
9829 my_ok(thd);
9830 }
9831 table_list->table= NULL; // For query cache
9832 query_cache_invalidate3(thd, table_list, 0);
9833
9834 if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
9835 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
9836 {
9837 /*
9838 Under LOCK TABLES we should adjust meta-data locks before finishing
9839 statement. Otherwise we can rely on them being released
9840 along with the implicit commit.
9841 */
9842 if (alter_ctx->is_table_renamed())
9843 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
9844 else
9845 mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
9846 }
9847 DBUG_RETURN(error != 0);
9848 }
9849
9850
cleanup_table_after_inplace_alter_keep_files(TABLE * table)9851 static void cleanup_table_after_inplace_alter_keep_files(TABLE *table)
9852 {
9853 TABLE_SHARE *share= table->s;
9854 closefrm(table);
9855 free_table_share(share);
9856 }
9857
9858
cleanup_table_after_inplace_alter(TABLE * table)9859 static void cleanup_table_after_inplace_alter(TABLE *table)
9860 {
9861 table->file->ha_create_partitioning_metadata(table->s->normalized_path.str, 0,
9862 CHF_DELETE_FLAG);
9863 deletefrm(table->s->normalized_path.str);
9864 cleanup_table_after_inplace_alter_keep_files(table);
9865 }
9866
9867
create_table_for_inplace_alter(THD * thd,const Alter_table_ctx & alter_ctx,LEX_CUSTRING * frm,TABLE_SHARE * share,TABLE * table)9868 static int create_table_for_inplace_alter(THD *thd,
9869 const Alter_table_ctx &alter_ctx,
9870 LEX_CUSTRING *frm,
9871 TABLE_SHARE *share,
9872 TABLE *table)
9873 {
9874 init_tmp_table_share(thd, share, alter_ctx.new_db.str, 0,
9875 alter_ctx.new_name.str, alter_ctx.get_tmp_path());
9876 if (share->init_from_binary_frm_image(thd, true, frm->str, frm->length) ||
9877 open_table_from_share(thd, share, &alter_ctx.new_name, 0,
9878 EXTRA_RECORD, thd->open_options,
9879 table, false))
9880 {
9881 free_table_share(share);
9882 deletefrm(alter_ctx.get_tmp_path());
9883 return 1;
9884 }
9885 if (table->internal_tables && open_and_lock_internal_tables(table, false))
9886 {
9887 cleanup_table_after_inplace_alter(table);
9888 return 1;
9889 }
9890 return 0;
9891 }
9892
9893
9894 /*
9895 log query if slave thread and send my_ok()
9896
9897 Help function for mysql_alter_table()
9898 */
9899
log_and_ok(THD * thd)9900 static bool log_and_ok(THD *thd)
9901 {
9902 if (thd->slave_thread &&
9903 write_bin_log(thd, true, thd->query(), thd->query_length()))
9904 return(true);
9905 my_ok(thd);
9906 return(0);
9907 }
9908
9909
9910 /**
9911 Alter table
9912
9913 @param thd Thread handle
9914 @param new_db If there is a RENAME clause
9915 @param new_name If there is a RENAME clause
9916 @param create_info Information from the parsing phase about new
9917 table properties.
9918 @param table_list The table to change.
9919 @param alter_info Lists of fields, keys to be changed, added
9920 or dropped.
9921 @param order_num How many ORDER BY fields has been specified.
9922 @param order List of fields to ORDER BY.
9923 @param ignore Whether we have ALTER IGNORE TABLE
9924
9925 @retval true Error
9926 @retval false Success
9927
9928 This is a veery long function and is everything but the kitchen sink :)
9929 It is used to alter a table and not only by ALTER TABLE but also
9930 CREATE|DROP INDEX are mapped on this function.
9931
9932 When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS,
9933 or both, then this function short cuts its operation by renaming
9934 the table and/or enabling/disabling the keys. In this case, the FRM is
9935 not changed, directly by mysql_alter_table. However, if there is a
9936 RENAME + change of a field, or an index, the short cut is not used.
9937 See how `create_list` is used to generate the new FRM regarding the
9938 structure of the fields. The same is done for the indices of the table.
9939
9940 Altering a table can be done in two ways. The table can be modified
9941 directly using an in-place algorithm, or the changes can be done using
9942 an intermediate temporary table (copy). In-place is the preferred
9943 algorithm as it avoids copying table data. The storage engine
9944 selects which algorithm to use in check_if_supported_inplace_alter()
9945 based on information about the table changes from fill_alter_inplace_info().
9946 */
9947
mysql_alter_table(THD * thd,const LEX_CSTRING * new_db,const LEX_CSTRING * new_name,HA_CREATE_INFO * create_info,TABLE_LIST * table_list,Alter_info * alter_info,uint order_num,ORDER * order,bool ignore,bool if_exists)9948 bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
9949 const LEX_CSTRING *new_name,
9950 HA_CREATE_INFO *create_info,
9951 TABLE_LIST *table_list,
9952 Alter_info *alter_info,
9953 uint order_num, ORDER *order, bool ignore,
9954 bool if_exists)
9955 {
9956 bool engine_changed, error;
9957 bool no_ha_table= true; /* We have not created table in storage engine yet */
9958 TABLE *table, *new_table;
9959 #ifdef WITH_PARTITION_STORAGE_ENGINE
9960 bool partition_changed= false;
9961 bool fast_alter_partition= false;
9962 #endif
9963 /*
9964 Create .FRM for new version of table with a temporary name.
9965 We don't log the statement, it will be logged later.
9966
9967 Keep information about keys in newly created table as it
9968 will be used later to construct Alter_inplace_info object
9969 and by fill_alter_inplace_info() call.
9970 */
9971 KEY *key_info;
9972 uint key_count;
9973 /*
9974 Remember if the new definition has new VARCHAR column;
9975 create_info->varchar will be reset in create_table_impl()/
9976 mysql_prepare_create_table().
9977 */
9978 bool varchar= create_info->varchar, table_creation_was_logged= 0;
9979 bool binlog_as_create_select= 0, log_if_exists= 0;
9980 uint tables_opened;
9981 handlerton *new_db_type, *old_db_type;
9982 ha_rows copied=0, deleted=0;
9983 LEX_CUSTRING frm= {0,0};
9984 char index_file[FN_REFLEN], data_file[FN_REFLEN];
9985 MDL_request target_mdl_request;
9986 MDL_ticket *mdl_ticket= 0;
9987 Alter_table_prelocking_strategy alter_prelocking_strategy;
9988 DBUG_ENTER("mysql_alter_table");
9989
9990 /*
9991 Check if we attempt to alter mysql.slow_log or
9992 mysql.general_log table and return an error if
9993 it is the case.
9994 TODO: this design is obsolete and will be removed.
9995 */
9996 int table_kind= check_if_log_table(table_list, FALSE, NullS);
9997
9998 if (table_kind)
9999 {
10000 /* Disable alter of enabled log tables */
10001 if (logger.is_log_table_enabled(table_kind))
10002 {
10003 my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
10004 DBUG_RETURN(true);
10005 }
10006
10007 /* Disable alter of log tables to unsupported engine */
10008 if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
10009 (!create_info->db_type || /* unknown engine */
10010 !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
10011 {
10012 unsupported:
10013 my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0),
10014 hton_name(create_info->db_type)->str);
10015 DBUG_RETURN(true);
10016 }
10017
10018 if (create_info->db_type == maria_hton &&
10019 create_info->transactional != HA_CHOICE_NO)
10020 goto unsupported;
10021
10022 #ifdef WITH_PARTITION_STORAGE_ENGINE
10023 if (alter_info->partition_flags & ALTER_PARTITION_INFO)
10024 {
10025 my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
10026 DBUG_RETURN(true);
10027 }
10028 #endif
10029 }
10030
10031 THD_STAGE_INFO(thd, stage_init_update);
10032
10033 /* Check if the new table type is a shared table */
10034 if (ha_check_if_updates_are_ignored(thd, create_info->db_type, "ALTER"))
10035 {
10036 /*
10037 Remove old local .frm file if it exists. We should use the new
10038 shared one in the future. The drop is not logged, the ALTER table is
10039 logged.
10040 */
10041 table_list->mdl_request.type= MDL_EXCLUSIVE;
10042 /* This will only drop the .frm file and local tables, not shared ones */
10043 error= mysql_rm_table(thd, table_list, 1, 0, 0, 1);
10044 DBUG_RETURN(log_and_ok(thd));
10045 }
10046
10047 /*
10048 Code below can handle only base tables so ensure that we won't open a view.
10049 Note that RENAME TABLE the only ALTER clause which is supported for views
10050 has been already processed.
10051 */
10052 table_list->required_type= TABLE_TYPE_NORMAL;
10053
10054 DEBUG_SYNC(thd, "alter_table_before_open_tables");
10055
10056 thd->open_options|= HA_OPEN_FOR_ALTER;
10057 thd->mdl_backup_ticket= 0;
10058 error= open_tables(thd, &table_list, &tables_opened, 0,
10059 &alter_prelocking_strategy);
10060 thd->open_options&= ~HA_OPEN_FOR_ALTER;
10061
10062 if (unlikely(error))
10063 {
10064 if (if_exists)
10065 {
10066 int tmp_errno= thd->get_stmt_da()->sql_errno();
10067 if (tmp_errno == ER_NO_SUCH_TABLE)
10068 {
10069 /*
10070 ALTER TABLE IF EXISTS was used on not existing table
10071 We have to log the query on a slave as the table may be a shared one
10072 from the master and we need to ensure that the next slave can see
10073 the statement as this slave may not have the table shared
10074 */
10075 thd->clear_error();
10076 DBUG_RETURN(log_and_ok(thd));
10077 }
10078 }
10079 DBUG_RETURN(true);
10080 }
10081
10082 table= table_list->table;
10083
10084 #ifdef WITH_WSREP
10085 if (WSREP(thd) &&
10086 (thd->lex->sql_command == SQLCOM_ALTER_TABLE ||
10087 thd->lex->sql_command == SQLCOM_CREATE_INDEX ||
10088 thd->lex->sql_command == SQLCOM_DROP_INDEX) &&
10089 !wsrep_should_replicate_ddl(thd, table_list->table->s->db_type()->db_type))
10090 DBUG_RETURN(true);
10091 #endif
10092
10093 DEBUG_SYNC(thd, "alter_table_after_open_tables");
10094
10095 if (table->versioned())
10096 {
10097 if (handlerton *hton1= create_info->db_type)
10098 {
10099 handlerton *hton2= table->file->partition_ht();
10100 if (hton1 != hton2 &&
10101 (ha_check_storage_engine_flag(hton1, HTON_NATIVE_SYS_VERSIONING) ||
10102 ha_check_storage_engine_flag(hton2, HTON_NATIVE_SYS_VERSIONING)))
10103 {
10104 my_error(ER_VERS_ALTER_ENGINE_PROHIBITED, MYF(0), table_list->db.str,
10105 table_list->table_name.str);
10106 DBUG_RETURN(true);
10107 }
10108 }
10109 if (alter_info->vers_prohibited(thd))
10110 {
10111 my_error(ER_VERS_ALTER_NOT_ALLOWED, MYF(0),
10112 table_list->db.str, table_list->table_name.str);
10113 DBUG_RETURN(true);
10114 }
10115 }
10116
10117 DEBUG_SYNC(thd, "alter_opened_table");
10118
10119 #ifdef WITH_WSREP
10120 DBUG_EXECUTE_IF("sync.alter_opened_table",
10121 {
10122 const char act[]=
10123 "now "
10124 "wait_for signal.alter_opened_table";
10125 DBUG_ASSERT(!debug_sync_set_action(thd,
10126 STRING_WITH_LEN(act)));
10127 };);
10128 #endif // WITH_WSREP
10129
10130 Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name);
10131 mdl_ticket= table->mdl_ticket;
10132
10133 /*
10134 We have to do a check also after table is opened as there could be no
10135 ENGINE= on the command line or the table could a partitioned S3 table.
10136 */
10137 if (table->file->check_if_updates_are_ignored("ALTER"))
10138 {
10139 /*
10140 Table is a shared table. Remove the .frm file. Discovery will create
10141 a new one if needed.
10142 */
10143 table->s->tdc->flushed= 1; // Force close of all instances
10144 if (thd->mdl_context.upgrade_shared_lock(mdl_ticket,
10145 MDL_EXCLUSIVE,
10146 thd->variables.lock_wait_timeout))
10147 DBUG_RETURN(1);
10148 quick_rm_table(thd, table->file->ht, &table_list->db,
10149 &table_list->table_name,
10150 NO_HA_TABLE, 0);
10151 goto end_inplace;
10152 }
10153 if (!if_exists &&
10154 (table->file->partition_ht()->flags &
10155 HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE))
10156 {
10157 /*
10158 Table is a shared table that may not exist on the slave.
10159 We add 'if_exists' to the query if it was not used
10160 */
10161 log_if_exists= 1;
10162 }
10163 table_creation_was_logged= table->s->table_creation_was_logged;
10164
10165 table->use_all_columns();
10166
10167 /*
10168 Prohibit changing of the UNION list of a non-temporary MERGE table
10169 under LOCK tables. It would be quite difficult to reuse a shrinked
10170 set of tables from the old table or to open a new TABLE object for
10171 an extended list and verify that they belong to locked tables.
10172 */
10173 if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
10174 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
10175 (create_info->used_fields & HA_CREATE_USED_UNION) &&
10176 (table->s->tmp_table == NO_TMP_TABLE))
10177 {
10178 my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
10179 DBUG_RETURN(true);
10180 }
10181
10182 /* Check that we are not trying to rename to an existing table */
10183 if (alter_ctx.is_table_renamed())
10184 {
10185 if (table->s->tmp_table != NO_TMP_TABLE)
10186 {
10187 /*
10188 Check whether a temporary table exists with same requested new name.
10189 If such table exists, there must be a corresponding TABLE_SHARE in
10190 THD::all_temp_tables list.
10191 */
10192 if (thd->find_tmp_table_share(alter_ctx.new_db.str,
10193 alter_ctx.new_name.str))
10194 {
10195 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias.str);
10196 DBUG_RETURN(true);
10197 }
10198 }
10199 else
10200 {
10201 MDL_request_list mdl_requests;
10202 MDL_request target_db_mdl_request;
10203
10204 MDL_REQUEST_INIT(&target_mdl_request, MDL_key::TABLE,
10205 alter_ctx.new_db.str, alter_ctx.new_name.str,
10206 MDL_EXCLUSIVE, MDL_TRANSACTION);
10207 mdl_requests.push_front(&target_mdl_request);
10208
10209 /*
10210 If we are moving the table to a different database, we also
10211 need IX lock on the database name so that the target database
10212 is protected by MDL while the table is moved.
10213 */
10214 if (alter_ctx.is_database_changed())
10215 {
10216 MDL_REQUEST_INIT(&target_db_mdl_request, MDL_key::SCHEMA,
10217 alter_ctx.new_db.str, "", MDL_INTENTION_EXCLUSIVE,
10218 MDL_TRANSACTION);
10219 mdl_requests.push_front(&target_db_mdl_request);
10220 }
10221
10222 /*
10223 Protection against global read lock must have been acquired when table
10224 to be altered was being opened.
10225 */
10226 DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::BACKUP,
10227 "", "",
10228 MDL_BACKUP_DDL));
10229
10230 if (thd->mdl_context.acquire_locks(&mdl_requests,
10231 thd->variables.lock_wait_timeout))
10232 DBUG_RETURN(true);
10233
10234 DEBUG_SYNC(thd, "locked_table_name");
10235 /*
10236 Table maybe does not exist, but we got an exclusive lock
10237 on the name, now we can safely try to find out for sure.
10238 */
10239 if (ha_table_exists(thd, &alter_ctx.new_db, &alter_ctx.new_name))
10240 {
10241 /* Table will be closed in do_command() */
10242 my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias.str);
10243 DBUG_RETURN(true);
10244 }
10245 }
10246 }
10247
10248 if (!create_info->db_type)
10249 {
10250 #ifdef WITH_PARTITION_STORAGE_ENGINE
10251 if (table->part_info &&
10252 create_info->used_fields & HA_CREATE_USED_ENGINE)
10253 {
10254 /*
10255 This case happens when the user specified
10256 ENGINE = x where x is a non-existing storage engine
10257 We set create_info->db_type to default_engine_type
10258 to ensure we don't change underlying engine type
10259 due to a erroneously given engine name.
10260 */
10261 create_info->db_type= table->part_info->default_engine_type;
10262 }
10263 else
10264 #endif
10265 create_info->db_type= table->s->db_type();
10266 }
10267
10268 if (check_engine(thd, alter_ctx.new_db.str, alter_ctx.new_name.str, create_info))
10269 DBUG_RETURN(true);
10270
10271 if (create_info->vers_info.fix_alter_info(thd, alter_info, create_info, table))
10272 {
10273 DBUG_RETURN(true);
10274 }
10275
10276 if ((create_info->db_type != table->s->db_type() ||
10277 (alter_info->partition_flags & ALTER_PARTITION_INFO)) &&
10278 !table->file->can_switch_engines())
10279 {
10280 my_error(ER_ROW_IS_REFERENCED, MYF(0));
10281 DBUG_RETURN(true);
10282 }
10283
10284 /*
10285 If foreign key is added then check permission to access parent table.
10286
10287 In function "check_fk_parent_table_access", create_info->db_type is used
10288 to identify whether engine supports FK constraint or not. Since
10289 create_info->db_type is set here, check to parent table access is delayed
10290 till this point for the alter operation.
10291 */
10292 if ((alter_info->flags & ALTER_ADD_FOREIGN_KEY) &&
10293 check_fk_parent_table_access(thd, create_info, alter_info, new_db->str))
10294 DBUG_RETURN(true);
10295
10296 /*
10297 If this is an ALTER TABLE and no explicit row type specified reuse
10298 the table's row type.
10299 Note: this is the same as if the row type was specified explicitly.
10300 */
10301 if (create_info->row_type == ROW_TYPE_NOT_USED)
10302 {
10303 /* ALTER TABLE without explicit row type */
10304 create_info->row_type= table->s->row_type;
10305 }
10306 else
10307 {
10308 /* ALTER TABLE with specific row type */
10309 create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
10310 }
10311
10312 DBUG_PRINT("info", ("old type: %s new type: %s",
10313 ha_resolve_storage_engine_name(table->s->db_type()),
10314 ha_resolve_storage_engine_name(create_info->db_type)));
10315 if (ha_check_storage_engine_flag(table->s->db_type(), HTON_ALTER_NOT_SUPPORTED))
10316 {
10317 DBUG_PRINT("info", ("doesn't support alter"));
10318 my_error(ER_ILLEGAL_HA, MYF(0), hton_name(table->s->db_type())->str,
10319 alter_ctx.db.str, alter_ctx.table_name.str);
10320 DBUG_RETURN(true);
10321 }
10322
10323 if (ha_check_storage_engine_flag(create_info->db_type,
10324 HTON_ALTER_NOT_SUPPORTED))
10325 {
10326 DBUG_PRINT("info", ("doesn't support alter"));
10327 my_error(ER_ILLEGAL_HA, MYF(0), hton_name(create_info->db_type)->str,
10328 alter_ctx.new_db.str, alter_ctx.new_name.str);
10329 DBUG_RETURN(true);
10330 }
10331
10332 if (table->s->tmp_table == NO_TMP_TABLE)
10333 mysql_audit_alter_table(thd, table_list);
10334 else if (table_creation_was_logged && mysql_bin_log.is_open())
10335 {
10336 /* Protect against MDL error in binary logging */
10337 MDL_request mdl_request;
10338 DBUG_ASSERT(!mdl_ticket);
10339 MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_BACKUP_COMMIT,
10340 MDL_TRANSACTION);
10341 if (thd->mdl_context.acquire_lock(&mdl_request,
10342 thd->variables.lock_wait_timeout))
10343 DBUG_RETURN(true);
10344 }
10345
10346 THD_STAGE_INFO(thd, stage_setup);
10347
10348 if (alter_info->flags & ALTER_DROP_CHECK_CONSTRAINT)
10349 {
10350 /*
10351 ALTER TABLE DROP CONSTRAINT
10352 should be replaced with ... DROP [FOREIGN] KEY
10353 if the constraint is the FOREIGN KEY or UNIQUE one.
10354 */
10355
10356 List_iterator<Alter_drop> drop_it(alter_info->drop_list);
10357 Alter_drop *drop;
10358 List <FOREIGN_KEY_INFO> fk_child_key_list;
10359 table->file->get_foreign_key_list(thd, &fk_child_key_list);
10360
10361 alter_info->flags&= ~ALTER_DROP_CHECK_CONSTRAINT;
10362
10363 while ((drop= drop_it++))
10364 {
10365 if (drop->type == Alter_drop::CHECK_CONSTRAINT)
10366 {
10367 {
10368 /* Test if there is a FOREIGN KEY with this name. */
10369 FOREIGN_KEY_INFO *f_key;
10370 List_iterator<FOREIGN_KEY_INFO> fk_key_it(fk_child_key_list);
10371
10372 while ((f_key= fk_key_it++))
10373 {
10374 if (my_strcasecmp(system_charset_info, f_key->foreign_id->str,
10375 drop->name) == 0)
10376 {
10377 drop->type= Alter_drop::FOREIGN_KEY;
10378 alter_info->flags|= ALTER_DROP_FOREIGN_KEY;
10379 goto do_continue;
10380 }
10381 }
10382 }
10383
10384 {
10385 /* Test if there is an UNIQUE with this name. */
10386 uint n_key;
10387
10388 for (n_key=0; n_key < table->s->keys; n_key++)
10389 {
10390 if ((table->key_info[n_key].flags & HA_NOSAME) &&
10391 my_strcasecmp(system_charset_info,
10392 drop->name, table->key_info[n_key].name.str) == 0)
10393 {
10394 drop->type= Alter_drop::KEY;
10395 alter_info->flags|= ALTER_DROP_INDEX;
10396 goto do_continue;
10397 }
10398 }
10399 }
10400 }
10401 alter_info->flags|= ALTER_DROP_CHECK_CONSTRAINT;
10402 do_continue:;
10403 }
10404 }
10405
10406 if (handle_if_exists_options(thd, table, alter_info,
10407 &create_info->period_info) ||
10408 fix_constraints_names(thd, &alter_info->check_constraint_list,
10409 create_info))
10410 DBUG_RETURN(true);
10411
10412 /*
10413 Look if we have to do anything at all.
10414 ALTER can become NOOP after handling
10415 the IF (NOT) EXISTS options.
10416 */
10417 if (alter_info->flags == 0 && alter_info->partition_flags == 0)
10418 {
10419 my_snprintf(alter_ctx.tmp_buff, sizeof(alter_ctx.tmp_buff),
10420 ER_THD(thd, ER_INSERT_INFO), 0L, 0L,
10421 thd->get_stmt_da()->current_statement_warn_count());
10422 my_ok(thd, 0L, 0L, alter_ctx.tmp_buff);
10423
10424 /* We don't replicate alter table statement on temporary tables */
10425 if (table_creation_was_logged)
10426 {
10427 if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
10428 DBUG_RETURN(true);
10429 }
10430
10431 DBUG_RETURN(false);
10432 }
10433
10434 /*
10435 Test if we are only doing RENAME or KEYS ON/OFF. This works
10436 as we are testing if flags == 0 above.
10437 */
10438 if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
10439 alter_info->partition_flags == 0 &&
10440 alter_info->algorithm(thd) !=
10441 Alter_info::ALTER_TABLE_ALGORITHM_COPY) // No need to touch frm.
10442 {
10443 bool res;
10444
10445 if (!table->s->tmp_table)
10446 {
10447 // This requires X-lock, no other lock levels supported.
10448 if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT &&
10449 alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
10450 {
10451 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
10452 "LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
10453 DBUG_RETURN(true);
10454 }
10455 res= simple_rename_or_index_change(thd, table_list,
10456 alter_info->keys_onoff,
10457 &alter_ctx);
10458 }
10459 else
10460 {
10461 res= simple_tmp_rename_or_index_change(thd, table_list,
10462 alter_info->keys_onoff,
10463 &alter_ctx);
10464 }
10465 DBUG_RETURN(res);
10466 }
10467
10468 /* We have to do full alter table. */
10469
10470 #ifdef WITH_PARTITION_STORAGE_ENGINE
10471 {
10472 if (prep_alter_part_table(thd, table, alter_info, create_info,
10473 &partition_changed, &fast_alter_partition))
10474 {
10475 DBUG_RETURN(true);
10476 }
10477 }
10478 #endif
10479
10480 if (mysql_prepare_alter_table(thd, table, create_info, alter_info,
10481 &alter_ctx))
10482 {
10483 DBUG_RETURN(true);
10484 }
10485
10486 set_table_default_charset(thd, create_info, alter_ctx.db);
10487
10488 if (create_info->check_fields(thd, alter_info,
10489 table_list->table_name, table_list->db) ||
10490 create_info->fix_period_fields(thd, alter_info))
10491 DBUG_RETURN(true);
10492
10493 if (!opt_explicit_defaults_for_timestamp)
10494 promote_first_timestamp_column(&alter_info->create_list);
10495
10496 #ifdef WITH_PARTITION_STORAGE_ENGINE
10497 if (fast_alter_partition)
10498 {
10499 /*
10500 ALGORITHM and LOCK clauses are generally not allowed by the
10501 parser for operations related to partitioning.
10502 The exceptions are ALTER_PARTITION_INFO and ALTER_PARTITION_REMOVE.
10503 For consistency, we report ER_ALTER_OPERATION_NOT_SUPPORTED here.
10504 */
10505 if (alter_info->requested_lock !=
10506 Alter_info::ALTER_TABLE_LOCK_DEFAULT)
10507 {
10508 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
10509 "LOCK=NONE/SHARED/EXCLUSIVE",
10510 ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION),
10511 "LOCK=DEFAULT");
10512 DBUG_RETURN(true);
10513 }
10514 else if (alter_info->algorithm(thd) !=
10515 Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
10516 {
10517 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
10518 "ALGORITHM=COPY/INPLACE",
10519 ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION),
10520 "ALGORITHM=DEFAULT");
10521 DBUG_RETURN(true);
10522 }
10523
10524 /*
10525 Upgrade from MDL_SHARED_UPGRADABLE to MDL_SHARED_NO_WRITE.
10526 Afterwards it's safe to take the table level lock.
10527 */
10528 if ((thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE,
10529 thd->variables.lock_wait_timeout)) ||
10530 lock_tables(thd, table_list, alter_ctx.tables_opened, 0))
10531 {
10532 DBUG_RETURN(true);
10533 }
10534
10535 // In-place execution of ALTER TABLE for partitioning.
10536 DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
10537 create_info, table_list,
10538 &alter_ctx.db,
10539 &alter_ctx.table_name));
10540 }
10541 #endif
10542
10543 /*
10544 Use copy algorithm if:
10545 - old_alter_table system variable is set without in-place requested using
10546 the ALGORITHM clause.
10547 - Or if in-place is impossible for given operation.
10548 - Changes to partitioning which were not handled by fast_alter_part_table()
10549 needs to be handled using table copying algorithm unless the engine
10550 supports auto-partitioning as such engines can do some changes
10551 using in-place API.
10552 */
10553 if ((thd->variables.alter_algorithm == Alter_info::ALTER_TABLE_ALGORITHM_COPY &&
10554 alter_info->algorithm(thd) !=
10555 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
10556 || is_inplace_alter_impossible(table, create_info, alter_info)
10557 || IF_PARTITIONING((partition_changed &&
10558 !(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)), 0))
10559 {
10560 if (alter_info->algorithm(thd) ==
10561 Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
10562 {
10563 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
10564 "ALGORITHM=INPLACE", "ALGORITHM=COPY");
10565 DBUG_RETURN(true);
10566 }
10567 alter_info->set_requested_algorithm(
10568 Alter_info::ALTER_TABLE_ALGORITHM_COPY);
10569 }
10570
10571 /*
10572 ALTER TABLE ... ENGINE to the same engine is a common way to
10573 request table rebuild. Set ALTER_RECREATE flag to force table
10574 rebuild.
10575 */
10576 if (create_info->db_type == table->s->db_type() &&
10577 create_info->used_fields & HA_CREATE_USED_ENGINE)
10578 alter_info->flags|= ALTER_RECREATE;
10579
10580 /*
10581 If the old table had partitions and we are doing ALTER TABLE ...
10582 engine= <new_engine>, the new table must preserve the original
10583 partitioning. This means that the new engine is still the
10584 partitioning engine, not the engine specified in the parser.
10585 This is discovered in prep_alter_part_table, which in such case
10586 updates create_info->db_type.
10587 It's therefore important that the assignment below is done
10588 after prep_alter_part_table.
10589 */
10590 new_db_type= create_info->db_type;
10591 old_db_type= table->s->db_type();
10592 new_table= NULL;
10593
10594 /*
10595 Handling of symlinked tables:
10596 If no rename:
10597 Create new data file and index file on the same disk as the
10598 old data and index files.
10599 Copy data.
10600 Rename new data file over old data file and new index file over
10601 old index file.
10602 Symlinks are not changed.
10603
10604 If rename:
10605 Create new data file and index file on the same disk as the
10606 old data and index files. Create also symlinks to point at
10607 the new tables.
10608 Copy data.
10609 At end, rename intermediate tables, and symlinks to intermediate
10610 table, to final table name.
10611 Remove old table and old symlinks
10612
10613 If rename is made to another database:
10614 Create new tables in new database.
10615 Copy data.
10616 Remove old table and symlinks.
10617 */
10618 if (!alter_ctx.is_database_changed())
10619 {
10620 if (create_info->index_file_name)
10621 {
10622 /* Fix index_file_name to have 'tmp_name' as basename */
10623 strmov(index_file, alter_ctx.tmp_name.str);
10624 create_info->index_file_name=fn_same(index_file,
10625 create_info->index_file_name,
10626 1);
10627 }
10628 if (create_info->data_file_name)
10629 {
10630 /* Fix data_file_name to have 'tmp_name' as basename */
10631 strmov(data_file, alter_ctx.tmp_name.str);
10632 create_info->data_file_name=fn_same(data_file,
10633 create_info->data_file_name,
10634 1);
10635 }
10636 }
10637 else
10638 {
10639 /* Ignore symlink if db is changed. */
10640 create_info->data_file_name=create_info->index_file_name=0;
10641 }
10642
10643 DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
10644
10645 tmp_disable_binlog(thd);
10646 create_info->options|=HA_CREATE_TMP_ALTER;
10647 if (!(alter_info->flags & ALTER_ADD_INDEX) && !alter_ctx.modified_primary_key)
10648 create_info->options|= HA_SKIP_KEY_SORT;
10649 else
10650 alter_info->flags|= ALTER_INDEX_ORDER;
10651 create_info->alias= alter_ctx.table_name;
10652 error= create_table_impl(thd, alter_ctx.db, alter_ctx.table_name,
10653 alter_ctx.new_db, alter_ctx.tmp_name,
10654 alter_ctx.get_tmp_path(),
10655 thd->lex->create_info, create_info, alter_info,
10656 C_ALTER_TABLE_FRM_ONLY, NULL,
10657 &key_info, &key_count, &frm);
10658 reenable_binlog(thd);
10659 if (unlikely(error))
10660 {
10661 my_free(const_cast<uchar*>(frm.str));
10662 DBUG_RETURN(true);
10663 }
10664
10665 if (alter_info->algorithm(thd) != Alter_info::ALTER_TABLE_ALGORITHM_COPY)
10666 {
10667 Alter_inplace_info ha_alter_info(create_info, alter_info,
10668 key_info, key_count,
10669 IF_PARTITIONING(thd->work_part_info, NULL),
10670 ignore, alter_ctx.error_if_not_empty);
10671 TABLE_SHARE altered_share;
10672 TABLE altered_table;
10673 bool use_inplace= true;
10674
10675 /* Fill the Alter_inplace_info structure. */
10676 if (fill_alter_inplace_info(thd, table, varchar, &ha_alter_info))
10677 goto err_new_table_cleanup;
10678
10679 /*
10680 We can ignore ALTER_COLUMN_ORDER and instead check
10681 ALTER_STORED_COLUMN_ORDER & ALTER_VIRTUAL_COLUMN_ORDER. This
10682 is ok as ALTER_COLUMN_ORDER may be wrong if we use AFTER last_field
10683 ALTER_COLUMN_NAME is set if field really was renamed.
10684 */
10685
10686 if (!(ha_alter_info.handler_flags &
10687 ~(ALTER_COLUMN_ORDER | ALTER_RENAME_COLUMN | ALTER_INDEX_ORDER)))
10688 {
10689 /*
10690 No-op ALTER, no need to call handler API functions.
10691
10692 If this code path is entered for an ALTER statement that
10693 should not be a real no-op, new handler flags should be added
10694 and fill_alter_inplace_info() adjusted.
10695
10696 Note that we can end up here if an ALTER statement has clauses
10697 that cancel each other out (e.g. ADD/DROP identically index).
10698
10699 Also note that we ignore the LOCK clause here.
10700
10701 TODO don't create partitioning metadata in the first place
10702
10703 TODO: Now case-change index name is treated as noop which is not quite
10704 correct.
10705 */
10706 table->file->ha_create_partitioning_metadata(alter_ctx.get_tmp_path(),
10707 NULL, CHF_DELETE_FLAG);
10708 my_free(const_cast<uchar*>(frm.str));
10709 goto end_inplace;
10710 }
10711
10712 // We assume that the table is non-temporary.
10713 DBUG_ASSERT(!table->s->tmp_table);
10714
10715 if (create_table_for_inplace_alter(thd, alter_ctx, &frm, &altered_share,
10716 &altered_table))
10717 goto err_new_table_cleanup;
10718
10719 /* Set markers for fields in TABLE object for altered table. */
10720 update_altered_table(ha_alter_info, &altered_table);
10721
10722 /*
10723 Mark all columns in 'altered_table' as used to allow usage
10724 of its record[0] buffer and Field objects during in-place
10725 ALTER TABLE.
10726 */
10727 altered_table.column_bitmaps_set_no_signal(&altered_table.s->all_set,
10728 &altered_table.s->all_set);
10729 restore_record(&altered_table, s->default_values); // Create empty record
10730 /* Check that we can call default functions with default field values */
10731 thd->count_cuted_fields= CHECK_FIELD_EXPRESSION;
10732 altered_table.reset_default_fields();
10733 if (altered_table.default_field &&
10734 altered_table.update_default_fields(true))
10735 {
10736 cleanup_table_after_inplace_alter(&altered_table);
10737 goto err_new_table_cleanup;
10738 }
10739 thd->count_cuted_fields= CHECK_FIELD_IGNORE;
10740
10741 if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
10742 ha_alter_info.online= true;
10743 // Ask storage engine whether to use copy or in-place
10744 {
10745 Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN);
10746 ha_alter_info.inplace_supported=
10747 table->file->check_if_supported_inplace_alter(&altered_table,
10748 &ha_alter_info);
10749 }
10750
10751 if (ha_alter_info.inplace_supported != HA_ALTER_INPLACE_NOT_SUPPORTED)
10752 {
10753 List_iterator<Key> it(alter_info->key_list);
10754 while (Key *k= it++)
10755 {
10756 if (k->without_overlaps)
10757 {
10758 ha_alter_info.inplace_supported= HA_ALTER_INPLACE_NOT_SUPPORTED;
10759 break;
10760 }
10761 }
10762 }
10763
10764 if (alter_info->supports_algorithm(thd, &ha_alter_info) ||
10765 alter_info->supports_lock(thd, &ha_alter_info))
10766 {
10767 cleanup_table_after_inplace_alter(&altered_table);
10768 goto err_new_table_cleanup;
10769 }
10770
10771 // If SHARED lock and no particular algorithm was requested, use COPY.
10772 if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK &&
10773 alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED &&
10774 alter_info->algorithm(thd) ==
10775 Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT &&
10776 thd->variables.alter_algorithm ==
10777 Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
10778 use_inplace= false;
10779
10780 if (ha_alter_info.inplace_supported == HA_ALTER_INPLACE_NOT_SUPPORTED)
10781 use_inplace= false;
10782
10783 if (use_inplace)
10784 {
10785 table->s->frm_image= &frm;
10786 /*
10787 Set the truncated column values of thd as warning
10788 for alter table.
10789 */
10790 Check_level_instant_set check_level_save(thd, CHECK_FIELD_WARN);
10791 int res= mysql_inplace_alter_table(thd, table_list, table, &altered_table,
10792 &ha_alter_info,
10793 &target_mdl_request, &alter_ctx);
10794 my_free(const_cast<uchar*>(frm.str));
10795
10796 if (res)
10797 {
10798 cleanup_table_after_inplace_alter(&altered_table);
10799 DBUG_RETURN(true);
10800 }
10801 cleanup_table_after_inplace_alter_keep_files(&altered_table);
10802
10803 goto end_inplace;
10804 }
10805 else
10806 cleanup_table_after_inplace_alter_keep_files(&altered_table);
10807 }
10808
10809 /* ALTER TABLE using copy algorithm. */
10810
10811 /* Check if ALTER TABLE is compatible with foreign key definitions. */
10812 if (fk_prepare_copy_alter_table(thd, table, alter_info, &alter_ctx))
10813 goto err_new_table_cleanup;
10814
10815 if (!table->s->tmp_table)
10816 {
10817 // COPY algorithm doesn't work with concurrent writes.
10818 if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
10819 {
10820 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0),
10821 "LOCK=NONE",
10822 ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY),
10823 "LOCK=SHARED");
10824 goto err_new_table_cleanup;
10825 }
10826
10827 // If EXCLUSIVE lock is requested, upgrade already.
10828 if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE &&
10829 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
10830 goto err_new_table_cleanup;
10831
10832 /*
10833 Otherwise upgrade to SHARED_NO_WRITE.
10834 Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE.
10835 */
10836 if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE &&
10837 thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE,
10838 thd->variables.lock_wait_timeout))
10839 goto err_new_table_cleanup;
10840
10841 DEBUG_SYNC(thd, "alter_table_copy_after_lock_upgrade");
10842 }
10843 else
10844 thd->close_unused_temporary_table_instances(table_list);
10845
10846 // It's now safe to take the table level lock.
10847 if (lock_tables(thd, table_list, alter_ctx.tables_opened,
10848 MYSQL_LOCK_USE_MALLOC))
10849 goto err_new_table_cleanup;
10850
10851 if (ha_create_table(thd, alter_ctx.get_tmp_path(),
10852 alter_ctx.new_db.str, alter_ctx.new_name.str,
10853 create_info, &frm))
10854 goto err_new_table_cleanup;
10855
10856 /* Mark that we have created table in storage engine. */
10857 no_ha_table= false;
10858 DEBUG_SYNC(thd, "alter_table_intermediate_table_created");
10859
10860 /* Open the table since we need to copy the data. */
10861 new_table= thd->create_and_open_tmp_table(&frm,
10862 alter_ctx.get_tmp_path(),
10863 alter_ctx.new_db.str,
10864 alter_ctx.new_name.str,
10865 true);
10866 if (!new_table)
10867 goto err_new_table_cleanup;
10868
10869 if (table->s->tmp_table != NO_TMP_TABLE)
10870 {
10871 /* in case of alter temp table send the tracker in OK packet */
10872 thd->session_tracker.state_change.mark_as_changed(thd);
10873 }
10874
10875 /*
10876 Note: In case of MERGE table, we do not attach children. We do not
10877 copy data for MERGE tables. Only the children have data.
10878 */
10879
10880 /* Copy the data if necessary. */
10881 thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
10882 thd->cuted_fields=0L;
10883
10884 /*
10885 We do not copy data for MERGE tables. Only the children have data.
10886 MERGE tables have HA_NO_COPY_ON_ALTER set.
10887 */
10888 if (!(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
10889 {
10890 new_table->next_number_field=new_table->found_next_number_field;
10891 THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
10892 DBUG_EXECUTE_IF("abort_copy_table", {
10893 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
10894 goto err_new_table_cleanup;
10895 });
10896
10897 /*
10898 If old table was a shared table and new table is not same type,
10899 the slaves will not be able to recreate the data. In this case we
10900 write the CREATE TABLE statement for the new table to the log and
10901 log all inserted rows to the table.
10902 */
10903 if ((table->file->partition_ht()->flags &
10904 HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE) &&
10905 (table->file->partition_ht() != new_table->file->partition_ht()) &&
10906 thd->binlog_table_should_be_logged(&new_table->s->db))
10907 {
10908 /*
10909 'new_table' is marked as internal temp table, but we want to have
10910 the logging based on the original table type
10911 */
10912 bool res;
10913 tmp_table_type org_tmp_table= new_table->s->tmp_table;
10914 new_table->s->tmp_table= table->s->tmp_table;
10915
10916 /* Force row logging, even if the table was created as 'temporary' */
10917 new_table->s->can_do_row_logging= 1;
10918 thd->binlog_start_trans_and_stmt();
10919 thd->variables.option_bits|= OPTION_BIN_COMMIT_OFF;
10920 res= (binlog_drop_table(thd, table) ||
10921 binlog_create_table(thd, new_table, 1));
10922 new_table->s->tmp_table= org_tmp_table;
10923 if (res)
10924 goto err_new_table_cleanup;
10925 /*
10926 ha_write_row() will log inserted rows in copy_data_between_tables().
10927 No additional logging of query is needed
10928 */
10929 binlog_as_create_select= 1;
10930 DBUG_ASSERT(new_table->file->row_logging);
10931 new_table->mark_columns_needed_for_insert();
10932 thd->binlog_write_table_map(new_table, 1);
10933 }
10934 if (copy_data_between_tables(thd, table, new_table,
10935 alter_info->create_list, ignore,
10936 order_num, order, &copied, &deleted,
10937 alter_info->keys_onoff,
10938 &alter_ctx))
10939 goto err_new_table_cleanup;
10940 }
10941 else
10942 {
10943 if (!table->s->tmp_table &&
10944 wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
10945 goto err_new_table_cleanup;
10946 THD_STAGE_INFO(thd, stage_manage_keys);
10947 alter_table_manage_keys(table, table->file->indexes_are_disabled(),
10948 alter_info->keys_onoff);
10949 if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
10950 goto err_new_table_cleanup;
10951 }
10952 thd->count_cuted_fields= CHECK_FIELD_IGNORE;
10953
10954 if (table->s->tmp_table != NO_TMP_TABLE)
10955 {
10956 /* Close lock if this is a transactional table */
10957 if (thd->lock)
10958 {
10959 if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
10960 thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
10961 {
10962 int tmp_error= mysql_unlock_tables(thd, thd->lock);
10963 thd->lock= NULL;
10964 if (tmp_error)
10965 goto err_new_table_cleanup;
10966 }
10967 else
10968 {
10969 /*
10970 If LOCK TABLES list is not empty and contains this table,
10971 unlock the table and remove the table from this list.
10972 */
10973 if (mysql_lock_remove(thd, thd->lock, table))
10974 goto err_new_table_cleanup;
10975 }
10976 }
10977 new_table->s->table_creation_was_logged=
10978 table->s->table_creation_was_logged;
10979 /* Remove link to old table and rename the new one */
10980 thd->drop_temporary_table(table, NULL, true);
10981 /* Should pass the 'new_name' as we store table name in the cache */
10982 if (thd->rename_temporary_table(new_table, &alter_ctx.new_db,
10983 &alter_ctx.new_name))
10984 goto err_new_table_cleanup;
10985
10986 if (binlog_as_create_select)
10987 {
10988 /*
10989 The original table is now deleted. Copy the
10990 DROP + CREATE + data statement to the binary log
10991 */
10992 thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
10993 (binlog_hton->commit)(binlog_hton, thd, 1);
10994 }
10995
10996 /* We don't replicate alter table statement on temporary tables */
10997 if (!thd->is_current_stmt_binlog_format_row() &&
10998 table_creation_was_logged &&
10999 !binlog_as_create_select &&
11000 write_bin_log_with_if_exists(thd, true, false, log_if_exists))
11001 DBUG_RETURN(true);
11002 my_free(const_cast<uchar*>(frm.str));
11003 goto end_temporary;
11004 }
11005
11006 /*
11007 Check if file names for the engine are unique. If we change engine
11008 and file names are unique then we don't need to rename the original
11009 table to a temporary name during the rename phase
11010
11011 File names are unique if engine changed and
11012 - Either new or old engine does not store the table in files
11013 - Neither old or new engine uses files from another engine
11014 The above is mainly true for the sequence and the partition engine.
11015 */
11016 engine_changed= ((new_table->file->ht != table->file->ht) &&
11017 ((!(new_table->file->ha_table_flags() & HA_FILE_BASED) ||
11018 !(table->file->ha_table_flags() & HA_FILE_BASED))) &&
11019 !(table->file->ha_table_flags() & HA_REUSES_FILE_NAMES) &&
11020 !(new_table->file->ha_table_flags() &
11021 HA_REUSES_FILE_NAMES));
11022 /*
11023 Close the intermediate table that will be the new table, but do
11024 not delete it! Even though MERGE tables do not have their children
11025 attached here it is safe to call THD::drop_temporary_table().
11026 */
11027 thd->drop_temporary_table(new_table, NULL, false);
11028 new_table= NULL;
11029
11030 DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
11031
11032 /*
11033 Data is copied. Now we:
11034 1) Wait until all other threads will stop using old version of table
11035 by upgrading shared metadata lock to exclusive one.
11036 2) Close instances of table open by this thread and replace them
11037 with placeholders to simplify reopen process.
11038 3) Rename the old table to a temp name, rename the new one to the
11039 old name.
11040 4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
11041 we reopen new version of table.
11042 5) Write statement to the binary log.
11043 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
11044 remove placeholders and release metadata locks.
11045 7) If we are not not under LOCK TABLES we rely on the caller
11046 (mysql_execute_command()) to release metadata locks.
11047 */
11048
11049 THD_STAGE_INFO(thd, stage_rename_result_table);
11050
11051 if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
11052 goto err_new_table_cleanup;
11053
11054 close_all_tables_for_name(thd, table->s,
11055 alter_ctx.is_table_renamed() ?
11056 HA_EXTRA_PREPARE_FOR_RENAME:
11057 HA_EXTRA_NOT_USED,
11058 NULL);
11059 table_list->table= table= NULL; /* Safety */
11060 my_free(const_cast<uchar*>(frm.str));
11061
11062 /*
11063 Rename the old table to temporary name to have a backup in case
11064 anything goes wrong while renaming the new table.
11065 We only have to do this if name of the table is not changed.
11066 If we are changing to use another table handler, we don't
11067 have to do the rename as the table names will not interfer.
11068 */
11069 char backup_name_buff[FN_LEN];
11070 LEX_CSTRING backup_name;
11071 backup_name.str= backup_name_buff;
11072
11073 DBUG_PRINT("info", ("is_table_renamed: %d engine_changed: %d",
11074 alter_ctx.is_table_renamed(), engine_changed));
11075
11076 /*
11077 InnoDB cannot use the rename optimization when foreign key
11078 constraint is involved because InnoDB fails to drop the
11079 parent table due to foreign key constraint
11080 */
11081 if (!alter_ctx.is_table_renamed() || alter_ctx.fk_error_if_delete_row)
11082 {
11083 backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff),
11084 "%s-backup-%lx-%llx", tmp_file_prefix,
11085 current_pid, thd->thread_id);
11086 if (lower_case_table_names)
11087 my_casedn_str(files_charset_info, backup_name_buff);
11088 if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name,
11089 &alter_ctx.db, &backup_name,
11090 FN_TO_IS_TMP |
11091 (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0)))
11092 {
11093 // Rename to temporary name failed, delete the new table, abort ALTER.
11094 (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
11095 &alter_ctx.tmp_name, FN_IS_TMP);
11096 goto err_with_mdl;
11097 }
11098 }
11099 else
11100 {
11101 /* The original table is the backup */
11102 backup_name= alter_ctx.table_name;
11103 PSI_CALL_drop_table_share(0, alter_ctx.db.str, (int) alter_ctx.db.length,
11104 alter_ctx.table_name.str, (int) alter_ctx.table_name.length);
11105 }
11106
11107 // Rename the new table to the correct name.
11108 if (mysql_rename_table(new_db_type, &alter_ctx.new_db, &alter_ctx.tmp_name,
11109 &alter_ctx.new_db, &alter_ctx.new_alias,
11110 FN_FROM_IS_TMP))
11111 {
11112 // Rename failed, delete the temporary table.
11113 (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
11114 &alter_ctx.tmp_name, FN_IS_TMP);
11115
11116 if (!alter_ctx.is_table_renamed() || alter_ctx.fk_error_if_delete_row)
11117 {
11118 // Restore the backup of the original table to the old name.
11119 (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
11120 &alter_ctx.db, &alter_ctx.alias,
11121 FN_FROM_IS_TMP | NO_FK_CHECKS |
11122 (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
11123 0));
11124 }
11125 goto err_with_mdl;
11126 }
11127
11128 // Check if we renamed the table and if so update trigger files.
11129 if (alter_ctx.is_table_renamed())
11130 {
11131 if (Table_triggers_list::change_table_name(thd,
11132 &alter_ctx.db,
11133 &alter_ctx.alias,
11134 &alter_ctx.table_name,
11135 &alter_ctx.new_db,
11136 &alter_ctx.new_alias))
11137 {
11138 // Rename succeeded, delete the new table.
11139 (void) quick_rm_table(thd, new_db_type,
11140 &alter_ctx.new_db, &alter_ctx.new_alias, 0);
11141 // Restore the backup of the original table to the old name.
11142 (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
11143 &alter_ctx.db, &alter_ctx.alias,
11144 FN_FROM_IS_TMP | NO_FK_CHECKS |
11145 (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
11146 0));
11147 goto err_with_mdl;
11148 }
11149 rename_table_in_stat_tables(thd, &alter_ctx.db, &alter_ctx.alias,
11150 &alter_ctx.new_db, &alter_ctx.new_alias);
11151 }
11152
11153 // ALTER TABLE succeeded, delete the backup of the old table.
11154 error= quick_rm_table(thd, old_db_type, &alter_ctx.db, &backup_name,
11155 FN_IS_TMP |
11156 (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE: 0));
11157 if (engine_changed)
11158 {
11159 /* the .frm file was removed but not the original table */
11160 error|= quick_rm_table(thd, old_db_type, &alter_ctx.db,
11161 &alter_ctx.table_name,
11162 NO_FRM_RENAME |
11163 (engine_changed ? 0 : FN_IS_TMP));
11164 }
11165 if (binlog_as_create_select)
11166 {
11167 /*
11168 The original table is now deleted. Copy the
11169 DROP + CREATE + data statement to the binary log
11170 */
11171 thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
11172 binlog_hton->commit(binlog_hton, thd, 1);
11173 }
11174
11175 if (error)
11176 {
11177 /*
11178 The fact that deletion of the backup failed is not critical
11179 error, but still worth reporting as it might indicate serious
11180 problem with server.
11181 */
11182 goto err_with_mdl_after_alter;
11183 }
11184
11185 end_inplace:
11186 thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
11187
11188 if (thd->locked_tables_list.reopen_tables(thd, false))
11189 goto err_with_mdl_after_alter;
11190
11191 THD_STAGE_INFO(thd, stage_end);
11192
11193 DEBUG_SYNC(thd, "alter_table_before_main_binlog");
11194
11195 DBUG_ASSERT(!(mysql_bin_log.is_open() &&
11196 thd->is_current_stmt_binlog_format_row() &&
11197 (create_info->tmp_table())));
11198 if (!binlog_as_create_select)
11199 {
11200 if (write_bin_log_with_if_exists(thd, true, false, log_if_exists))
11201 DBUG_RETURN(true);
11202 }
11203 table_list->table= NULL; // For query cache
11204 query_cache_invalidate3(thd, table_list, false);
11205
11206 if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
11207 thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
11208 {
11209 if (alter_ctx.is_table_renamed())
11210 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
11211 else
11212 mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
11213 }
11214
11215 end_temporary:
11216 thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
11217
11218 my_snprintf(alter_ctx.tmp_buff, sizeof(alter_ctx.tmp_buff),
11219 ER_THD(thd, ER_INSERT_INFO),
11220 (ulong) (copied + deleted), (ulong) deleted,
11221 (ulong) thd->get_stmt_da()->current_statement_warn_count());
11222 my_ok(thd, copied + deleted, 0L, alter_ctx.tmp_buff);
11223 DEBUG_SYNC(thd, "alter_table_inplace_trans_commit");
11224 DBUG_RETURN(false);
11225
11226 err_new_table_cleanup:
11227 DBUG_PRINT("error", ("err_new_table_cleanup"));
11228 thd->variables.option_bits&= ~OPTION_BIN_COMMIT_OFF;
11229
11230 my_free(const_cast<uchar*>(frm.str));
11231 /*
11232 No default value was provided for a DATE/DATETIME field, the
11233 current sql_mode doesn't allow the '0000-00-00' value and
11234 the table to be altered isn't empty.
11235 Report error here.
11236 */
11237 if (unlikely(alter_ctx.error_if_not_empty &&
11238 thd->get_stmt_da()->current_row_for_warning()))
11239 {
11240 Abort_on_warning_instant_set aws(thd, true);
11241 alter_ctx.report_implicit_default_value_error(thd, new_table
11242 ? new_table->s : table->s);
11243 }
11244
11245 if (new_table)
11246 {
11247 thd->drop_temporary_table(new_table, NULL, true);
11248 }
11249 else
11250 (void) quick_rm_table(thd, new_db_type,
11251 &alter_ctx.new_db, &alter_ctx.tmp_name,
11252 (FN_IS_TMP | (no_ha_table ? NO_HA_TABLE : 0)),
11253 alter_ctx.get_tmp_path());
11254
11255 DBUG_RETURN(true);
11256
11257 err_with_mdl_after_alter:
11258 DBUG_PRINT("error", ("err_with_mdl_after_alter"));
11259 /* the table was altered. binlog the operation */
11260 DBUG_ASSERT(!(mysql_bin_log.is_open() &&
11261 thd->is_current_stmt_binlog_format_row() &&
11262 (create_info->tmp_table())));
11263 /*
11264 We can't reset error as we will return 'true' below and the server
11265 expects that error is set
11266 */
11267 if (!binlog_as_create_select)
11268 write_bin_log_with_if_exists(thd, FALSE, FALSE, log_if_exists);
11269
11270 err_with_mdl:
11271 /*
11272 An error happened while we were holding exclusive name metadata lock
11273 on table being altered. To be safe under LOCK TABLES we should
11274 remove all references to the altered table from the list of locked
11275 tables and release the exclusive metadata lock.
11276 */
11277 thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
11278 if (!table_list->table)
11279 thd->mdl_context.release_all_locks_for_name(mdl_ticket);
11280 DBUG_RETURN(true);
11281 }
11282
11283
11284
11285 /**
11286 Prepare the transaction for the alter table's copy phase.
11287 */
11288
mysql_trans_prepare_alter_copy_data(THD * thd)11289 bool mysql_trans_prepare_alter_copy_data(THD *thd)
11290 {
11291 DBUG_ENTER("mysql_trans_prepare_alter_copy_data");
11292 /*
11293 Turn off recovery logging since rollback of an alter table is to
11294 delete the new table so there is no need to log the changes to it.
11295
11296 This needs to be done before external_lock.
11297 */
11298 DBUG_RETURN(ha_enable_transaction(thd, FALSE) != 0);
11299 }
11300
11301
11302 /**
11303 Commit the copy phase of the alter table.
11304 */
11305
mysql_trans_commit_alter_copy_data(THD * thd)11306 bool mysql_trans_commit_alter_copy_data(THD *thd)
11307 {
11308 bool error= FALSE;
11309 uint save_unsafe_rollback_flags;
11310 DBUG_ENTER("mysql_trans_commit_alter_copy_data");
11311
11312 /* Save flags as trans_commit_implicit are deleting them */
11313 save_unsafe_rollback_flags= thd->transaction->stmt.m_unsafe_rollback_flags;
11314
11315 DEBUG_SYNC(thd, "alter_table_copy_trans_commit");
11316
11317 if (ha_enable_transaction(thd, TRUE))
11318 DBUG_RETURN(TRUE);
11319
11320 /*
11321 Ensure that the new table is saved properly to disk before installing
11322 the new .frm.
11323 And that InnoDB's internal latches are released, to avoid deadlock
11324 when waiting on other instances of the table before rename (Bug#54747).
11325 */
11326 if (trans_commit_stmt(thd))
11327 error= TRUE;
11328 if (trans_commit_implicit(thd))
11329 error= TRUE;
11330
11331 thd->transaction->stmt.m_unsafe_rollback_flags= save_unsafe_rollback_flags;
11332 DBUG_RETURN(error);
11333 }
11334
11335
11336 static int
copy_data_between_tables(THD * thd,TABLE * from,TABLE * to,List<Create_field> & create,bool ignore,uint order_num,ORDER * order,ha_rows * copied,ha_rows * deleted,Alter_info::enum_enable_or_disable keys_onoff,Alter_table_ctx * alter_ctx)11337 copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
11338 List<Create_field> &create, bool ignore,
11339 uint order_num, ORDER *order,
11340 ha_rows *copied, ha_rows *deleted,
11341 Alter_info::enum_enable_or_disable keys_onoff,
11342 Alter_table_ctx *alter_ctx)
11343 {
11344 int error= 1;
11345 Copy_field *copy= NULL, *copy_end;
11346 ha_rows found_count= 0, delete_count= 0;
11347 SORT_INFO *file_sort= 0;
11348 READ_RECORD info;
11349 TABLE_LIST tables;
11350 List<Item> fields;
11351 List<Item> all_fields;
11352 bool auto_increment_field_copied= 0;
11353 bool cleanup_done= 0;
11354 bool init_read_record_done= 0;
11355 sql_mode_t save_sql_mode= thd->variables.sql_mode;
11356 ulonglong prev_insert_id, time_to_report_progress;
11357 Field **dfield_ptr= to->default_field;
11358 uint save_to_s_default_fields= to->s->default_fields;
11359 bool make_versioned= !from->versioned() && to->versioned();
11360 bool make_unversioned= from->versioned() && !to->versioned();
11361 bool keep_versioned= from->versioned() && to->versioned();
11362 bool bulk_insert_started= 0;
11363 Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL;
11364 MYSQL_TIME query_start;
11365 DBUG_ENTER("copy_data_between_tables");
11366
11367 /* Two or 3 stages; Sorting, copying data and update indexes */
11368 thd_progress_init(thd, 2 + MY_TEST(order));
11369
11370 if (!(copy= new (thd->mem_root) Copy_field[to->s->fields]))
11371 DBUG_RETURN(-1);
11372
11373 if (mysql_trans_prepare_alter_copy_data(thd))
11374 {
11375 delete [] copy;
11376 DBUG_RETURN(-1);
11377 }
11378
11379 /* We need external lock before we can disable/enable keys */
11380 if (to->file->ha_external_lock(thd, F_WRLCK))
11381 {
11382 /* Undo call to mysql_trans_prepare_alter_copy_data() */
11383 ha_enable_transaction(thd, TRUE);
11384 delete [] copy;
11385 DBUG_RETURN(-1);
11386 }
11387
11388 backup_set_alter_copy_lock(thd, from);
11389
11390 alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
11391
11392 from->default_column_bitmaps();
11393
11394 /* We can abort alter table for any table type */
11395 thd->abort_on_warning= !ignore && thd->is_strict_mode();
11396
11397 from->file->info(HA_STATUS_VARIABLE);
11398 to->file->extra(HA_EXTRA_PREPARE_FOR_ALTER_TABLE);
11399 to->file->ha_start_bulk_insert(from->file->stats.records,
11400 ignore ? 0 : HA_CREATE_UNIQUE_INDEX_BY_SORT);
11401 bulk_insert_started= 1;
11402 mysql_stage_set_work_estimated(thd->m_stage_progress_psi, from->file->stats.records);
11403
11404 List_iterator<Create_field> it(create);
11405 Create_field *def;
11406 copy_end=copy;
11407 to->s->default_fields= 0;
11408 for (Field **ptr=to->field ; *ptr ; ptr++)
11409 {
11410 def=it++;
11411 if (def->field)
11412 {
11413 if (*ptr == to->next_number_field)
11414 {
11415 auto_increment_field_copied= TRUE;
11416 /*
11417 If we are going to copy contents of one auto_increment column to
11418 another auto_increment column it is sensible to preserve zeroes.
11419 This condition also covers case when we are don't actually alter
11420 auto_increment column.
11421 */
11422 if (def->field == from->found_next_number_field)
11423 thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
11424 }
11425 if (!(*ptr)->vcol_info)
11426 {
11427 bitmap_set_bit(from->read_set, def->field->field_index);
11428 (copy_end++)->set(*ptr,def->field,0);
11429 }
11430 }
11431 else
11432 {
11433 /*
11434 Update the set of auto-update fields to contain only the new fields
11435 added to the table. Only these fields should be updated automatically.
11436 Old fields keep their current values, and therefore should not be
11437 present in the set of autoupdate fields.
11438 */
11439 if ((*ptr)->default_value)
11440 {
11441 *(dfield_ptr++)= *ptr;
11442 ++to->s->default_fields;
11443 }
11444 }
11445 }
11446 if (dfield_ptr)
11447 *dfield_ptr= NULL;
11448
11449 if (order)
11450 {
11451 if (to->s->primary_key != MAX_KEY &&
11452 to->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX)
11453 {
11454 char warn_buff[MYSQL_ERRMSG_SIZE];
11455 Abort_on_warning_instant_set aws(thd, false);
11456 my_snprintf(warn_buff, sizeof(warn_buff),
11457 "ORDER BY ignored as there is a user-defined clustered index"
11458 " in the table '%-.192s'", from->s->table_name.str);
11459 push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
11460 warn_buff);
11461 }
11462 else
11463 {
11464 bzero((char *) &tables, sizeof(tables));
11465 tables.table= from;
11466 tables.alias= tables.table_name= from->s->table_name;
11467 tables.db= from->s->db;
11468
11469 THD_STAGE_INFO(thd, stage_sorting);
11470 Filesort_tracker dummy_tracker(false);
11471 Filesort fsort(order, HA_POS_ERROR, true, NULL);
11472
11473 if (thd->lex->first_select_lex()->setup_ref_array(thd, order_num) ||
11474 setup_order(thd, thd->lex->first_select_lex()->ref_pointer_array,
11475 &tables, fields, all_fields, order))
11476 goto err;
11477
11478 if (!(file_sort= filesort(thd, from, &fsort, &dummy_tracker)))
11479 goto err;
11480 }
11481 thd_progress_next_stage(thd);
11482 }
11483
11484 if (make_versioned)
11485 {
11486 query_start= thd->query_start_TIME();
11487 to_row_start= to->vers_start_field();
11488 to_row_end= to->vers_end_field();
11489 }
11490 else if (make_unversioned)
11491 {
11492 from_row_end= from->vers_end_field();
11493 }
11494
11495 if (from_row_end)
11496 bitmap_set_bit(from->read_set, from_row_end->field_index);
11497
11498 from->file->column_bitmaps_signal();
11499
11500 to->file->prepare_for_insert(0);
11501 DBUG_ASSERT(to->file->inited == handler::NONE);
11502
11503 /* Tell handler that we have values for all columns in the to table */
11504 to->use_all_columns();
11505 /* Add virtual columns to vcol_set to ensure they are updated */
11506 if (to->vfield)
11507 to->mark_virtual_columns_for_write(TRUE);
11508 if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, file_sort, 1, 1,
11509 FALSE))
11510 goto err;
11511 init_read_record_done= 1;
11512
11513 if (ignore && !alter_ctx->fk_error_if_delete_row)
11514 to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
11515 thd->get_stmt_da()->reset_current_row_for_warning();
11516 restore_record(to, s->default_values); // Create empty record
11517 to->reset_default_fields();
11518
11519 thd->progress.max_counter= from->file->records();
11520 time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10;
11521 if (!ignore) /* for now, InnoDB needs the undo log for ALTER IGNORE */
11522 to->file->extra(HA_EXTRA_BEGIN_ALTER_COPY);
11523
11524 while (likely(!(error= info.read_record())))
11525 {
11526 if (unlikely(thd->killed))
11527 {
11528 thd->send_kill_message();
11529 error= 1;
11530 break;
11531 }
11532
11533 if (make_unversioned)
11534 {
11535 if (!from_row_end->is_max())
11536 continue; // Drop history rows.
11537 }
11538
11539 if (unlikely(++thd->progress.counter >= time_to_report_progress))
11540 {
11541 time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10;
11542 thd_progress_report(thd, thd->progress.counter,
11543 thd->progress.max_counter);
11544 }
11545
11546 /* Return error if source table isn't empty. */
11547 if (unlikely(alter_ctx->error_if_not_empty))
11548 {
11549 error= 1;
11550 break;
11551 }
11552
11553 for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
11554 {
11555 copy_ptr->do_copy(copy_ptr);
11556 }
11557
11558 if (make_versioned)
11559 {
11560 to_row_start->set_notnull();
11561 to_row_start->store_time(&query_start);
11562 to_row_end->set_max();
11563 }
11564
11565 prev_insert_id= to->file->next_insert_id;
11566 if (to->default_field)
11567 to->update_default_fields(ignore);
11568 if (to->vfield)
11569 to->update_virtual_fields(to->file, VCOL_UPDATE_FOR_WRITE);
11570
11571 /* This will set thd->is_error() if fatal failure */
11572 if (to->verify_constraints(ignore) == VIEW_CHECK_SKIP)
11573 continue;
11574 if (unlikely(thd->is_error()))
11575 {
11576 error= 1;
11577 break;
11578 }
11579 if (keep_versioned && to->versioned(VERS_TRX_ID))
11580 to->vers_write= false;
11581
11582 if (to->next_number_field)
11583 {
11584 if (auto_increment_field_copied)
11585 to->auto_increment_field_not_null= TRUE;
11586 else
11587 to->next_number_field->reset();
11588 }
11589 error= to->file->ha_write_row(to->record[0]);
11590 to->auto_increment_field_not_null= FALSE;
11591 if (unlikely(error))
11592 {
11593 if (to->file->is_fatal_error(error, HA_CHECK_DUP))
11594 {
11595 /* Not a duplicate key error. */
11596 to->file->print_error(error, MYF(0));
11597 error= 1;
11598 break;
11599 }
11600 else
11601 {
11602 /* Duplicate key error. */
11603 if (unlikely(alter_ctx->fk_error_if_delete_row))
11604 {
11605 /*
11606 We are trying to omit a row from the table which serves as parent
11607 in a foreign key. This might have broken referential integrity so
11608 emit an error. Note that we can't ignore this error even if we are
11609 executing ALTER IGNORE TABLE. IGNORE allows to skip rows, but
11610 doesn't allow to break unique or foreign key constraints,
11611 */
11612 my_error(ER_FK_CANNOT_DELETE_PARENT, MYF(0),
11613 alter_ctx->fk_error_id,
11614 alter_ctx->fk_error_table);
11615 break;
11616 }
11617
11618 if (ignore)
11619 {
11620 /* This ALTER IGNORE TABLE. Simply skip row and continue. */
11621 to->file->restore_auto_increment(prev_insert_id);
11622 delete_count++;
11623 }
11624 else
11625 {
11626 /* Ordinary ALTER TABLE. Report duplicate key error. */
11627 uint key_nr= to->file->get_dup_key(error);
11628 if ((int) key_nr >= 0)
11629 {
11630 const char *err_msg= ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME);
11631 if (key_nr == 0 && to->s->keys > 0 &&
11632 (to->key_info[0].key_part[0].field->flags &
11633 AUTO_INCREMENT_FLAG))
11634 err_msg= ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE);
11635 print_keydup_error(to,
11636 key_nr >= to->s->keys ? NULL :
11637 &to->key_info[key_nr],
11638 err_msg, MYF(0));
11639 }
11640 else
11641 to->file->print_error(error, MYF(0));
11642 break;
11643 }
11644 }
11645 }
11646 else
11647 {
11648 DEBUG_SYNC(thd, "copy_data_between_tables_before");
11649 found_count++;
11650 mysql_stage_set_work_completed(thd->m_stage_progress_psi, found_count);
11651 }
11652 thd->get_stmt_da()->inc_current_row_for_warning();
11653 }
11654
11655 THD_STAGE_INFO(thd, stage_enabling_keys);
11656 thd_progress_next_stage(thd);
11657
11658 if (error > 0 && !from->s->tmp_table)
11659 {
11660 /* We are going to drop the temporary table */
11661 to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
11662 }
11663 if (unlikely(to->file->ha_end_bulk_insert()) && error <= 0)
11664 {
11665 /* Give error, if not already given */
11666 if (!thd->is_error())
11667 to->file->print_error(my_errno,MYF(0));
11668 error= 1;
11669 }
11670 bulk_insert_started= 0;
11671 if (!ignore)
11672 to->file->extra(HA_EXTRA_END_ALTER_COPY);
11673
11674 cleanup_done= 1;
11675 to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
11676
11677 if (backup_reset_alter_copy_lock(thd))
11678 error= 1;
11679
11680 if (unlikely(mysql_trans_commit_alter_copy_data(thd)))
11681 error= 1;
11682
11683 err:
11684 if (bulk_insert_started)
11685 (void) to->file->ha_end_bulk_insert();
11686
11687 /* Free resources */
11688 if (init_read_record_done)
11689 end_read_record(&info);
11690 delete [] copy;
11691 delete file_sort;
11692
11693 thd->variables.sql_mode= save_sql_mode;
11694 thd->abort_on_warning= 0;
11695 *copied= found_count;
11696 *deleted=delete_count;
11697 to->file->ha_release_auto_increment();
11698 to->s->default_fields= save_to_s_default_fields;
11699
11700 if (!cleanup_done)
11701 {
11702 /* This happens if we get an error during initialization of data */
11703 DBUG_ASSERT(error);
11704 to->file->ha_end_bulk_insert();
11705 ha_enable_transaction(thd, TRUE);
11706 }
11707
11708 if (to->file->ha_external_unlock(thd))
11709 error=1;
11710 if (error < 0 && !from->s->tmp_table &&
11711 to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
11712 error= 1;
11713 thd_progress_end(thd);
11714 DBUG_RETURN(error > 0 ? -1 : 0);
11715 }
11716
11717
11718 /*
11719 Recreates one table by calling mysql_alter_table().
11720
11721 SYNOPSIS
11722 mysql_recreate_table()
11723 thd Thread handler
11724 table_list Table to recreate
11725 table_copy Recreate the table by using
11726 ALTER TABLE COPY algorithm
11727
11728 RETURN
11729 Like mysql_alter_table().
11730 */
11731
mysql_recreate_table(THD * thd,TABLE_LIST * table_list,bool table_copy)11732 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
11733 {
11734 HA_CREATE_INFO create_info;
11735 Alter_info alter_info;
11736 TABLE_LIST *next_table= table_list->next_global;
11737 DBUG_ENTER("mysql_recreate_table");
11738
11739 /* Set lock type which is appropriate for ALTER TABLE. */
11740 table_list->lock_type= TL_READ_NO_INSERT;
11741 /* Same applies to MDL request. */
11742 table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
11743 /* hide following tables from open_tables() */
11744 table_list->next_global= NULL;
11745
11746 bzero((char*) &create_info, sizeof(create_info));
11747 create_info.row_type=ROW_TYPE_NOT_USED;
11748 create_info.default_table_charset=default_charset_info;
11749 create_info.alter_info= &alter_info;
11750 /* Force alter table to recreate table */
11751 alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
11752
11753 if (table_copy)
11754 alter_info.set_requested_algorithm(
11755 Alter_info::ALTER_TABLE_ALGORITHM_COPY);
11756
11757 bool res= mysql_alter_table(thd, &null_clex_str, &null_clex_str, &create_info,
11758 table_list, &alter_info, 0,
11759 (ORDER *) 0, 0, 0);
11760 table_list->next_global= next_table;
11761 DBUG_RETURN(res);
11762 }
11763
11764
mysql_checksum_table(THD * thd,TABLE_LIST * tables,HA_CHECK_OPT * check_opt)11765 bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
11766 HA_CHECK_OPT *check_opt)
11767 {
11768 TABLE_LIST *table;
11769 List<Item> field_list;
11770 Item *item;
11771 Protocol *protocol= thd->protocol;
11772 DBUG_ENTER("mysql_checksum_table");
11773
11774 /*
11775 CHECKSUM TABLE returns results and rollbacks statement transaction,
11776 so it should not be used in stored function or trigger.
11777 */
11778 DBUG_ASSERT(! thd->in_sub_stmt);
11779
11780 field_list.push_back(item= new (thd->mem_root)
11781 Item_empty_string(thd, "Table", NAME_LEN*2),
11782 thd->mem_root);
11783 item->maybe_null= 1;
11784 field_list.push_back(item= new (thd->mem_root)
11785 Item_int(thd, "Checksum", (longlong) 1,
11786 MY_INT64_NUM_DECIMAL_DIGITS),
11787 thd->mem_root);
11788 item->maybe_null= 1;
11789 if (protocol->send_result_set_metadata(&field_list,
11790 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
11791 DBUG_RETURN(TRUE);
11792
11793 /*
11794 Close all temporary tables which were pre-open to simplify
11795 privilege checking. Clear all references to closed tables.
11796 */
11797 close_thread_tables(thd);
11798 for (table= tables; table; table= table->next_local)
11799 table->table= NULL;
11800
11801 /* Open one table after the other to keep lock time as short as possible. */
11802 for (table= tables; table; table= table->next_local)
11803 {
11804 char table_name[SAFE_NAME_LEN*2+2];
11805 TABLE *t;
11806 TABLE_LIST *save_next_global;
11807
11808 strxmov(table_name, table->db.str ,".", table->table_name.str, NullS);
11809
11810 /* Remember old 'next' pointer and break the list. */
11811 save_next_global= table->next_global;
11812 table->next_global= NULL;
11813 table->lock_type= TL_READ;
11814 /* Allow to open real tables only. */
11815 table->required_type= TABLE_TYPE_NORMAL;
11816
11817 if (thd->open_temporary_tables(table) ||
11818 open_and_lock_tables(thd, table, FALSE, 0))
11819 {
11820 t= NULL;
11821 }
11822 else
11823 t= table->table;
11824
11825 table->next_global= save_next_global;
11826
11827 protocol->prepare_for_resend();
11828 protocol->store(table_name, system_charset_info);
11829
11830 if (!t)
11831 {
11832 /* Table didn't exist */
11833 protocol->store_null();
11834 }
11835 else
11836 {
11837 /* Call ->checksum() if the table checksum matches 'old_mode' settings */
11838 if (!(check_opt->flags & T_EXTEND) &&
11839 (((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) && thd->variables.old_mode) ||
11840 ((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) && !thd->variables.old_mode)))
11841 {
11842 if (t->file->info(HA_STATUS_VARIABLE) || t->file->stats.checksum_null)
11843 protocol->store_null();
11844 else
11845 protocol->store((longlong)t->file->stats.checksum);
11846 }
11847 else if (check_opt->flags & T_QUICK)
11848 protocol->store_null();
11849 else
11850 {
11851 int error= t->file->calculate_checksum();
11852 if (thd->killed)
11853 {
11854 /*
11855 we've been killed; let handler clean up, and remove the
11856 partial current row from the recordset (embedded lib)
11857 */
11858 t->file->ha_rnd_end();
11859 thd->protocol->remove_last_row();
11860 goto err;
11861 }
11862 if (error || t->file->stats.checksum_null)
11863 protocol->store_null();
11864 else
11865 protocol->store((longlong)t->file->stats.checksum);
11866 }
11867 trans_rollback_stmt(thd);
11868 close_thread_tables(thd);
11869 }
11870
11871 if (thd->transaction_rollback_request)
11872 {
11873 /*
11874 If transaction rollback was requested we honor it. To do this we
11875 abort statement and return error as not only CHECKSUM TABLE is
11876 rolled back but the whole transaction in which it was used.
11877 */
11878 thd->protocol->remove_last_row();
11879 goto err;
11880 }
11881
11882 /* Hide errors from client. Return NULL for problematic tables instead. */
11883 thd->clear_error();
11884
11885 if (protocol->write())
11886 goto err;
11887 }
11888
11889 my_eof(thd);
11890 DBUG_RETURN(FALSE);
11891
11892 err:
11893 DBUG_RETURN(TRUE);
11894 }
11895
11896 /**
11897 @brief Check if the table can be created in the specified storage engine.
11898
11899 Checks if the storage engine is enabled and supports the given table
11900 type (e.g. normal, temporary, system). May do engine substitution
11901 if the requested engine is disabled.
11902
11903 @param thd Thread descriptor.
11904 @param db_name Database name.
11905 @param table_name Name of table to be created.
11906 @param create_info Create info from parser, including engine.
11907
11908 @retval true Engine not available/supported, error has been reported.
11909 @retval false Engine available/supported.
11910 */
11911
check_engine(THD * thd,const char * db_name,const char * table_name,HA_CREATE_INFO * create_info)11912 bool check_engine(THD *thd, const char *db_name,
11913 const char *table_name, HA_CREATE_INFO *create_info)
11914 {
11915 DBUG_ENTER("check_engine");
11916 handlerton **new_engine= &create_info->db_type;
11917 handlerton *req_engine= *new_engine;
11918 handlerton *enf_engine= NULL;
11919 bool no_substitution= thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION;
11920 *new_engine= ha_checktype(thd, req_engine, no_substitution);
11921 DBUG_ASSERT(*new_engine);
11922 if (!*new_engine)
11923 DBUG_RETURN(true);
11924
11925 /* Enforced storage engine should not be used in
11926 ALTER TABLE that does not use explicit ENGINE = x to
11927 avoid unwanted unrelated changes.*/
11928 if (!(thd->lex->sql_command == SQLCOM_ALTER_TABLE &&
11929 !(create_info->used_fields & HA_CREATE_USED_ENGINE)))
11930 enf_engine= thd->variables.enforced_table_plugin ?
11931 plugin_hton(thd->variables.enforced_table_plugin) : NULL;
11932
11933 if (enf_engine && enf_engine != *new_engine)
11934 {
11935 if (no_substitution)
11936 {
11937 const char *engine_name= ha_resolve_storage_engine_name(req_engine);
11938 my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), engine_name);
11939 DBUG_RETURN(TRUE);
11940 }
11941 *new_engine= enf_engine;
11942 }
11943
11944 if (req_engine && req_engine != *new_engine)
11945 {
11946 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
11947 ER_WARN_USING_OTHER_HANDLER,
11948 ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
11949 ha_resolve_storage_engine_name(*new_engine),
11950 table_name);
11951 }
11952 if (create_info->tmp_table() &&
11953 ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
11954 {
11955 if (create_info->used_fields & HA_CREATE_USED_ENGINE)
11956 {
11957 my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
11958 hton_name(*new_engine)->str, "TEMPORARY");
11959 *new_engine= 0;
11960 DBUG_RETURN(true);
11961 }
11962 *new_engine= myisam_hton;
11963 }
11964
11965 DBUG_RETURN(false);
11966 }
11967
11968
execute(THD * thd)11969 bool Sql_cmd_create_table_like::execute(THD *thd)
11970 {
11971 DBUG_ENTER("Sql_cmd_create_table::execute");
11972 LEX *lex= thd->lex;
11973 SELECT_LEX *select_lex= lex->first_select_lex();
11974 TABLE_LIST *first_table= select_lex->table_list.first;
11975 DBUG_ASSERT(first_table == lex->query_tables);
11976 DBUG_ASSERT(first_table != 0);
11977 bool link_to_local;
11978 TABLE_LIST *create_table= first_table;
11979 TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
11980 /* most outer SELECT_LEX_UNIT of query */
11981 SELECT_LEX_UNIT *unit= &lex->unit;
11982 int res= 0;
11983
11984 const bool used_engine= lex->create_info.used_fields & HA_CREATE_USED_ENGINE;
11985 DBUG_ASSERT((m_storage_engine_name.str != NULL) == used_engine);
11986 if (used_engine)
11987 {
11988 if (resolve_storage_engine_with_error(thd, &lex->create_info.db_type,
11989 lex->create_info.tmp_table()))
11990 DBUG_RETURN(true); // Engine not found, substitution is not allowed
11991
11992 if (!lex->create_info.db_type) // Not found, but substitution is allowed
11993 {
11994 lex->create_info.use_default_db_type(thd);
11995 push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
11996 ER_WARN_USING_OTHER_HANDLER,
11997 ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
11998 hton_name(lex->create_info.db_type)->str,
11999 create_table->table_name.str);
12000 }
12001 }
12002
12003 if (lex->tmp_table())
12004 {
12005 status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]);
12006 status_var_increment(thd->status_var.com_create_tmp_table);
12007 }
12008
12009 /*
12010 Code below (especially in mysql_create_table() and select_create
12011 methods) may modify HA_CREATE_INFO structure in LEX, so we have to
12012 use a copy of this structure to make execution prepared statement-
12013 safe. A shallow copy is enough as this code won't modify any memory
12014 referenced from this structure.
12015 */
12016 Table_specification_st create_info(lex->create_info);
12017 /*
12018 We need to copy alter_info for the same reasons of re-execution
12019 safety, only in case of Alter_info we have to do (almost) a deep
12020 copy.
12021 */
12022 Alter_info alter_info(lex->alter_info, thd->mem_root);
12023
12024 if (unlikely(thd->is_fatal_error))
12025 {
12026 /* If out of memory when creating a copy of alter_info. */
12027 res= 1;
12028 goto end_with_restore_list;
12029 }
12030
12031 /*
12032 Since CREATE_INFO is not full without Alter_info, it is better to pass them
12033 as a signle parameter. TODO: remove alter_info argument where create_info is
12034 passed.
12035 */
12036 create_info.alter_info= &alter_info;
12037
12038 /* Check privileges */
12039 if ((res= create_table_precheck(thd, select_tables, create_table)))
12040 goto end_with_restore_list;
12041
12042 /* Might have been updated in create_table_precheck */
12043 create_info.alias= create_table->alias;
12044
12045 /* Fix names if symlinked or relocated tables */
12046 if (append_file_to_dir(thd, &create_info.data_file_name,
12047 &create_table->table_name) ||
12048 append_file_to_dir(thd, &create_info.index_file_name,
12049 &create_table->table_name))
12050 goto end_with_restore_list;
12051
12052 /*
12053 If no engine type was given, work out the default now
12054 rather than at parse-time.
12055 */
12056 if (!(create_info.used_fields & HA_CREATE_USED_ENGINE))
12057 create_info.use_default_db_type(thd);
12058 /*
12059 If we are using SET CHARSET without DEFAULT, add an implicit
12060 DEFAULT to not confuse old users. (This may change).
12061 */
12062 if ((create_info.used_fields &
12063 (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) ==
12064 HA_CREATE_USED_CHARSET)
12065 {
12066 create_info.used_fields&= ~HA_CREATE_USED_CHARSET;
12067 create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET;
12068 create_info.default_table_charset= create_info.alter_table_convert_to_charset;
12069 create_info.alter_table_convert_to_charset= 0;
12070 }
12071
12072 /*
12073 If we are a slave, we should add OR REPLACE if we don't have
12074 IF EXISTS. This will help a slave to recover from
12075 CREATE TABLE OR EXISTS failures by dropping the table and
12076 retrying the create.
12077 */
12078 if (thd->slave_thread &&
12079 slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT &&
12080 !lex->create_info.if_not_exists())
12081 {
12082 create_info.add(DDL_options_st::OPT_OR_REPLACE);
12083 create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED);
12084 }
12085
12086 #ifdef WITH_PARTITION_STORAGE_ENGINE
12087 thd->work_part_info= 0;
12088 {
12089 partition_info *part_info= thd->lex->part_info;
12090 if (part_info && !(part_info= part_info->get_clone(thd)))
12091 {
12092 res= -1;
12093 goto end_with_restore_list;
12094 }
12095 thd->work_part_info= part_info;
12096 }
12097 #endif
12098
12099 if (select_lex->item_list.elements || select_lex->tvc) // With select or TVC
12100 {
12101 select_result *result;
12102
12103 /*
12104 CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless
12105 ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore
12106 use row based logging if mixed or row based logging is available.
12107 TODO: Check if the order of the output of the select statement is
12108 deterministic. Waiting for BUG#42415
12109 */
12110 if(lex->ignore)
12111 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT);
12112
12113 if(lex->duplicates == DUP_REPLACE)
12114 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT);
12115
12116 /*
12117 If:
12118 a) we inside an SP and there was NAME_CONST substitution,
12119 b) binlogging is on (STMT mode),
12120 c) we log the SP as separate statements
12121 raise a warning, as it may cause problems
12122 (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs')
12123 */
12124 if (thd->query_name_consts && mysql_bin_log.is_open() &&
12125 thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
12126 !mysql_bin_log.is_query_in_union(thd, thd->query_id))
12127 {
12128 List_iterator_fast<Item> it(select_lex->item_list);
12129 Item *item;
12130 uint splocal_refs= 0;
12131 /* Count SP local vars in the top-level SELECT list */
12132 while ((item= it++))
12133 {
12134 if (item->get_item_splocal())
12135 splocal_refs++;
12136 }
12137 /*
12138 If it differs from number of NAME_CONST substitution applied,
12139 we may have a SOME_FUNC(NAME_CONST()) in the SELECT list,
12140 that may cause a problem with binary log (see BUG#35383),
12141 raise a warning.
12142 */
12143 if (splocal_refs != thd->query_name_consts)
12144 push_warning(thd,
12145 Sql_condition::WARN_LEVEL_WARN,
12146 ER_UNKNOWN_ERROR,
12147 "Invoked routine ran a statement that may cause problems with "
12148 "binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' "
12149 "section of the manual.");
12150 }
12151
12152 select_lex->options|= SELECT_NO_UNLOCK;
12153 unit->set_limit(select_lex);
12154
12155 /*
12156 Disable non-empty MERGE tables with CREATE...SELECT. Too
12157 complicated. See Bug #26379. Empty MERGE tables are read-only
12158 and don't allow CREATE...SELECT anyway.
12159 */
12160 if (create_info.used_fields & HA_CREATE_USED_UNION)
12161 {
12162 my_error(ER_WRONG_OBJECT, MYF(0), create_table->db.str,
12163 create_table->table_name.str, "BASE TABLE");
12164 res= 1;
12165 goto end_with_restore_list;
12166 }
12167
12168 res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0);
12169 if (unlikely(res))
12170 {
12171 /* Got error or warning. Set res to 1 if error */
12172 if (!(res= thd->is_error()))
12173 my_ok(thd); // CREATE ... IF NOT EXISTS
12174 goto end_with_restore_list;
12175 }
12176
12177 /* Ensure we don't try to create something from which we select from */
12178 if (create_info.or_replace() && !create_info.tmp_table())
12179 {
12180 if (TABLE_LIST *duplicate= unique_table(thd, lex->query_tables,
12181 lex->query_tables->next_global,
12182 CHECK_DUP_FOR_CREATE |
12183 CHECK_DUP_SKIP_TEMP_TABLE))
12184 {
12185 update_non_unique_table_error(lex->query_tables, "CREATE",
12186 duplicate);
12187 res= TRUE;
12188 goto end_with_restore_list;
12189 }
12190 }
12191 {
12192 /*
12193 Remove target table from main select and name resolution
12194 context. This can't be done earlier as it will break view merging in
12195 statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
12196 */
12197 lex->unlink_first_table(&link_to_local);
12198
12199 /* Store reference to table in case of LOCK TABLES */
12200 create_info.table= create_table->table;
12201
12202 /*
12203 select_create is currently not re-execution friendly and
12204 needs to be created for every execution of a PS/SP.
12205 Note: In wsrep-patch, CTAS is handled like a regular transaction.
12206 */
12207 if ((result= new (thd->mem_root) select_create(thd, create_table,
12208 &create_info,
12209 &alter_info,
12210 select_lex->item_list,
12211 lex->duplicates,
12212 lex->ignore,
12213 select_tables)))
12214 {
12215 /*
12216 CREATE from SELECT give its SELECT_LEX for SELECT,
12217 and item_list belong to SELECT
12218 */
12219 if (!(res= handle_select(thd, lex, result, 0)))
12220 {
12221 if (create_info.tmp_table())
12222 thd->variables.option_bits|= OPTION_KEEP_LOG;
12223 }
12224 delete result;
12225 }
12226 lex->link_first_table_back(create_table, link_to_local);
12227 }
12228 }
12229 else
12230 {
12231 /* regular create */
12232 if (create_info.like())
12233 {
12234 /* CREATE TABLE ... LIKE ... */
12235 res= mysql_create_like_table(thd, create_table, select_tables,
12236 &create_info);
12237 }
12238 else
12239 {
12240 if (create_info.fix_create_fields(thd, &alter_info, *create_table) ||
12241 create_info.check_fields(thd, &alter_info,
12242 create_table->table_name, create_table->db))
12243 goto end_with_restore_list;
12244
12245 /*
12246 In STATEMENT format, we probably have to replicate also temporary
12247 tables, like mysql replication does. Also check if the requested
12248 engine is allowed/supported.
12249 */
12250 if (WSREP(thd))
12251 {
12252 handlerton *orig_ht= create_info.db_type;
12253 if (!check_engine(thd, create_table->db.str,
12254 create_table->table_name.str,
12255 &create_info) &&
12256 (!thd->is_current_stmt_binlog_format_row() ||
12257 !create_info.tmp_table()))
12258 {
12259 #ifdef WITH_WSREP
12260 WSREP_TO_ISOLATION_BEGIN_ALTER(create_table->db.str,
12261 create_table->table_name.str,
12262 first_table, &alter_info, NULL,
12263 &create_info)
12264 {
12265 WSREP_WARN("CREATE TABLE isolation failure");
12266 DBUG_RETURN(true);
12267 }
12268 #endif /* WITH_WSREP */
12269 }
12270 // check_engine will set db_type to NULL if e.g. TEMPORARY is
12271 // not supported by the storage engine, this case is checked
12272 // again in mysql_create_table
12273 create_info.db_type= orig_ht;
12274 }
12275 /* Regular CREATE TABLE */
12276 res= mysql_create_table(thd, create_table, &create_info, &alter_info);
12277 }
12278 if (!res)
12279 {
12280 /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
12281 if (create_info.tmp_table())
12282 thd->variables.option_bits|= OPTION_KEEP_LOG;
12283 /* in case of create temp tables if @@session_track_state_change is
12284 ON then send session state notification in OK packet */
12285 if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
12286 {
12287 thd->session_tracker.state_change.mark_as_changed(thd);
12288 }
12289 my_ok(thd);
12290 }
12291 }
12292
12293 end_with_restore_list:
12294 DBUG_RETURN(res);
12295 }
12296