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