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