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