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