1 /*
2    Copyright (c) 2000, 2018, 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 as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
16 */
17 
18 /* drop and alter of tables */
19 
20 #include "sql_priv.h"
21 #include "unireg.h"
22 #include "debug_sync.h"
23 #include "sql_table.h"
24 #include "sql_rename.h" // do_rename
25 #include "sql_parse.h"                        // test_if_data_home_dir
26 #include "sql_cache.h"                          // query_cache_*
27 #include "sql_base.h"   // open_table_uncached, lock_table_names
28 #include "lock.h"       // mysql_unlock_tables
29 #include "strfunc.h"    // find_type2, find_set
30 #include "sql_view.h" // view_checksum
31 #include "sql_truncate.h"                       // regenerate_locked_table
32 #include "sql_partition.h"                      // mem_alloc_error,
33                                                 // generate_partition_syntax,
34                                                 // partition_info
35 #include "sql_db.h"                             // load_db_opt_by_name
36 #include "sql_time.h"                  // make_truncated_value_warning
37 #include "records.h"             // init_read_record, end_read_record
38 #include "filesort.h"            // filesort_free_buffers
39 #include "sql_select.h"                // setup_order,
40                                        // make_unireg_sortorder
41 #include "sql_handler.h"               // mysql_ha_rm_tables
42 #include "discover.h"                  // readfrm
43 #include "my_pthread.h"                // pthread_mutex_t
44 #include "log_event.h"                 // Query_log_event
45 #include <hash.h>
46 #include <myisam.h>
47 #include <my_dir.h>
48 #include "sp_head.h"
49 #include "sp.h"
50 #include "sql_trigger.h"
51 #include "sql_parse.h"
52 #include "sql_show.h"
53 #include "transaction.h"
54 #include "datadict.h"  // dd_frm_type()
55 
56 #ifdef __WIN__
57 #include <io.h>
58 #endif
59 
60 const char *primary_key_name="PRIMARY";
61 
62 static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
63 static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
64 static int copy_data_between_tables(TABLE *from,TABLE *to,
65                                     List<Create_field> &create, bool ignore,
66 				    uint order_num, ORDER *order,
67 				    ha_rows *copied,ha_rows *deleted,
68                                     enum enum_enable_or_disable keys_onoff,
69                                     bool error_if_not_empty);
70 
71 static bool prepare_blob_field(THD *thd, Create_field *sql_field);
72 static bool check_engine(THD *thd, const char *db_name,
73                          const char *table_name,
74                          HA_CREATE_INFO *create_info);
75 
76 static int
77 mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
78                            Alter_info *alter_info,
79                            bool tmp_table,
80                            uint *db_options,
81                            handler *file, KEY **key_info_buffer,
82                            uint *key_count, int select_field_count);
83 
84 
85 /**
86   @brief Helper function for explain_filename
87   @param thd          Thread handle
88   @param to_p         Explained name in system_charset_info
89   @param end_p        End of the to_p buffer
90   @param name         Name to be converted
91   @param name_len     Length of the name, in bytes
92 */
add_identifier(THD * thd,char * to_p,const char * end_p,const char * name,uint name_len)93 static char* add_identifier(THD* thd, char *to_p, const char * end_p,
94                             const char* name, uint name_len)
95 {
96   uint res;
97   uint errors;
98   const char *conv_name;
99   char tmp_name[FN_REFLEN];
100   char conv_string[FN_REFLEN];
101   int quote;
102 
103   DBUG_ENTER("add_identifier");
104   if (!name[name_len])
105     conv_name= name;
106   else
107   {
108     strnmov(tmp_name, name, name_len);
109     tmp_name[name_len]= 0;
110     conv_name= tmp_name;
111   }
112   res= strconvert(&my_charset_filename, conv_name, system_charset_info,
113                   conv_string, FN_REFLEN, &errors);
114   if (!res || errors)
115   {
116     DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors));
117     conv_name= name;
118   }
119   else
120   {
121     DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
122     conv_name= conv_string;
123   }
124 
125   quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"';
126 
127   if (quote != EOF && (end_p - to_p > 2))
128   {
129     *(to_p++)= (char) quote;
130     while (*conv_name && (end_p - to_p - 1) > 0)
131     {
132       uint length= my_mbcharlen(system_charset_info, *conv_name);
133       if (!length)
134         length= 1;
135       if (length == 1 && *conv_name == (char) quote)
136       {
137         if ((end_p - to_p) < 3)
138           break;
139         *(to_p++)= (char) quote;
140         *(to_p++)= *(conv_name++);
141       }
142       else if (((long) length) < (end_p - to_p))
143       {
144         to_p= strnmov(to_p, conv_name, length);
145         conv_name+= length;
146       }
147       else
148         break;                               /* string already filled */
149     }
150     if (end_p > to_p) {
151       *(to_p++)= (char) quote;
152       if (end_p > to_p)
153 	*to_p= 0; /* terminate by NUL, but do not include it in the count */
154     }
155   }
156   else
157     to_p= strnmov(to_p, conv_name, end_p - to_p);
158   DBUG_RETURN(to_p);
159 }
160 
161 
162 /**
163   @brief Explain a path name by split it to database, table etc.
164 
165   @details Break down the path name to its logic parts
166   (database, table, partition, subpartition).
167   filename_to_tablename cannot be used on partitions, due to the #P# part.
168   There can be up to 6 '#', #P# for partition, #SP# for subpartition
169   and #TMP# or #REN# for temporary or renamed partitions.
170   This should be used when something should be presented to a user in a
171   diagnostic, error etc. when it would be useful to know what a particular
172   file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc.
173 
174    @param      thd          Thread handle
175    @param      from         Path name in my_charset_filename
176                             Null terminated in my_charset_filename, normalized
177                             to use '/' as directory separation character.
178    @param      to           Explained name in system_charset_info
179    @param      to_length    Size of to buffer
180    @param      explain_mode Requested output format.
181                             EXPLAIN_ALL_VERBOSE ->
182                             [Database `db`, ]Table `tbl`[,[ Temporary| Renamed]
183                             Partition `p` [, Subpartition `sp`]]
184                             EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl`
185                             [[ Temporary| Renamed] Partition `p`
186                             [, Subpartition `sp`]]
187                             EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |*
188                             [,[ Temporary| Renamed] Partition `p`
189                             [, Subpartition `sp`]] *|
190                             (| is really a /, and it is all in one line)
191 
192    @retval     Length of returned string
193 */
194 
explain_filename(THD * thd,const char * from,char * to,uint to_length,enum_explain_filename_mode explain_mode)195 uint explain_filename(THD* thd,
196 		      const char *from,
197                       char *to,
198                       uint to_length,
199                       enum_explain_filename_mode explain_mode)
200 {
201   char *to_p= to;
202   char *end_p= to_p + to_length;
203   const char *db_name= NULL;
204   int  db_name_len= 0;
205   const char *table_name;
206   int  table_name_len= 0;
207   const char *part_name= NULL;
208   int  part_name_len= 0;
209   const char *subpart_name= NULL;
210   int  subpart_name_len= 0;
211   enum enum_part_name_type {NORMAL, TEMP, RENAMED} part_type= NORMAL;
212 
213   const char *tmp_p;
214   DBUG_ENTER("explain_filename");
215   DBUG_PRINT("enter", ("from '%s'", from));
216   tmp_p= from;
217   table_name= from;
218   /*
219     If '/' then take last directory part as database.
220     '/' is the directory separator, not FN_LIB_CHAR
221   */
222   while ((tmp_p= strchr(tmp_p, '/')))
223   {
224     db_name= table_name;
225     /* calculate the length */
226     db_name_len= tmp_p - db_name;
227     tmp_p++;
228     table_name= tmp_p;
229   }
230   tmp_p= table_name;
231   /* Look if there are partition tokens in the table name. */
232   while ((tmp_p= strchr(tmp_p, '#')))
233   {
234     tmp_p++;
235     switch (tmp_p[0]) {
236     case 'P':
237     case 'p':
238       if (tmp_p[1] == '#')
239       {
240         part_name= tmp_p + 2;
241         tmp_p+= 2;
242       }
243       break;
244     case 'S':
245     case 's':
246       if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#')
247       {
248         part_name_len= tmp_p - part_name - 1;
249         subpart_name= tmp_p + 3;
250 	tmp_p+= 3;
251       }
252       break;
253     case 'T':
254     case 't':
255       if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
256           (tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
257           tmp_p[3] == '#' && !tmp_p[4])
258       {
259         part_type= TEMP;
260         tmp_p+= 4;
261       }
262       break;
263     case 'R':
264     case 'r':
265       if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
266           (tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
267           tmp_p[3] == '#' && !tmp_p[4])
268       {
269         part_type= RENAMED;
270         tmp_p+= 4;
271       }
272       break;
273     default:
274       /* Not partition name part. */
275       ;
276     }
277   }
278   if (part_name)
279   {
280     table_name_len= part_name - table_name - 3;
281     if (subpart_name)
282       subpart_name_len= strlen(subpart_name);
283     else
284       part_name_len= strlen(part_name);
285     if (part_type != NORMAL)
286     {
287       if (subpart_name)
288         subpart_name_len-= 5;
289       else
290         part_name_len-= 5;
291     }
292   }
293   else
294     table_name_len= strlen(table_name);
295   if (db_name)
296   {
297     if (explain_mode == EXPLAIN_ALL_VERBOSE)
298     {
299       to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME),
300                                             end_p - to_p);
301       *(to_p++)= ' ';
302       to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
303       to_p= strnmov(to_p, ", ", end_p - to_p);
304     }
305     else
306     {
307       to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len);
308       to_p= strnmov(to_p, ".", end_p - to_p);
309     }
310   }
311   if (explain_mode == EXPLAIN_ALL_VERBOSE)
312   {
313     to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p);
314     *(to_p++)= ' ';
315     to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
316   }
317   else
318     to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len);
319   if (part_name)
320   {
321     if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
322       to_p= strnmov(to_p, " /* ", end_p - to_p);
323     else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE)
324       to_p= strnmov(to_p, " ", end_p - to_p);
325     else
326       to_p= strnmov(to_p, ", ", end_p - to_p);
327     if (part_type != NORMAL)
328     {
329       if (part_type == TEMP)
330         to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
331                       end_p - to_p);
332       else
333         to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME),
334                       end_p - to_p);
335       to_p= strnmov(to_p, " ", end_p - to_p);
336     }
337     to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME),
338                   end_p - to_p);
339     *(to_p++)= ' ';
340     to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len);
341     if (subpart_name)
342     {
343       to_p= strnmov(to_p, ", ", end_p - to_p);
344       to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME),
345                     end_p - to_p);
346       *(to_p++)= ' ';
347       to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len);
348     }
349     if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
350       to_p= strnmov(to_p, " */", end_p - to_p);
351   }
352   DBUG_PRINT("exit", ("to '%s'", to));
353   DBUG_RETURN(to_p - to);
354 }
355 
356 
357 /*
358   Translate a file name to a table name (WL #1324).
359 
360   SYNOPSIS
361     filename_to_tablename()
362       from                      The file name in my_charset_filename.
363       to                OUT     The table name in system_charset_info.
364       to_length                 The size of the table name buffer.
365 
366   RETURN
367     Table name length.
368 */
369 
filename_to_tablename(const char * from,char * to,uint to_length,bool stay_quiet)370 uint filename_to_tablename(const char *from, char *to, uint to_length
371 #ifndef DBUG_OFF
372                            , bool stay_quiet
373 #endif /* DBUG_OFF */
374                            )
375 {
376   uint errors;
377   size_t res;
378   DBUG_ENTER("filename_to_tablename");
379   DBUG_PRINT("enter", ("from '%s'", from));
380 
381   if (strlen(from) >= tmp_file_prefix_length &&
382       !memcmp(from, tmp_file_prefix, tmp_file_prefix_length))
383   {
384     /* Temporary table name. */
385     res= (strnmov(to, from, to_length) - to);
386   }
387   else
388   {
389     res= strconvert(&my_charset_filename, from,
390                     system_charset_info,  to, to_length, &errors);
391     if (errors) // Old 5.0 name
392     {
393       res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX,  from, NullS) -
394             to);
395 #ifndef DBUG_OFF
396       if (!stay_quiet) {
397 #endif /* DBUG_OFF */
398         sql_print_error("Invalid (old?) table or database name '%s'", from);
399 #ifndef DBUG_OFF
400       }
401 #endif /* DBUG_OFF */
402       /*
403         TODO: add a stored procedure for fix table and database names,
404         and mention its name in error log.
405       */
406     }
407   }
408 
409   DBUG_PRINT("exit", ("to '%s'", to));
410   DBUG_RETURN(res);
411 }
412 
413 
414 /**
415   Check if given string begins with "#mysql50#" prefix
416 
417   @param   name          string to check cut
418 
419   @retval
420     FALSE  no prefix found
421   @retval
422     TRUE   prefix found
423 */
424 
check_mysql50_prefix(const char * name)425 bool check_mysql50_prefix(const char *name)
426 {
427   return (name[0] == '#' &&
428          !strncmp(name, MYSQL50_TABLE_NAME_PREFIX,
429                   MYSQL50_TABLE_NAME_PREFIX_LENGTH));
430 }
431 
432 
433 /**
434   Check if given string begins with "#mysql50#" prefix, cut it if so.
435 
436   @param   from          string to check and cut
437   @param   to[out]       buffer for result string
438   @param   to_length     its size
439 
440   @retval
441     0      no prefix found
442   @retval
443     non-0  result string length
444 */
445 
check_n_cut_mysql50_prefix(const char * from,char * to,uint to_length)446 uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length)
447 {
448   if (check_mysql50_prefix(from))
449     return (uint) (strmake(to, from + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
450                            to_length - 1) - to);
451   return 0;
452 }
453 
454 
455 /*
456   Translate a table name to a file name (WL #1324).
457 
458   SYNOPSIS
459     tablename_to_filename()
460       from                      The table name in system_charset_info.
461       to                OUT     The file name in my_charset_filename.
462       to_length                 The size of the file name buffer.
463 
464   RETURN
465     File name length.
466 */
467 
tablename_to_filename(const char * from,char * to,uint to_length)468 uint tablename_to_filename(const char *from, char *to, uint to_length)
469 {
470   uint errors, length;
471   DBUG_ENTER("tablename_to_filename");
472   DBUG_PRINT("enter", ("from '%s'", from));
473 
474   if ((length= check_n_cut_mysql50_prefix(from, to, to_length)))
475   {
476     /*
477       Check if the name supplied is a valid mysql 5.0 name and
478       make the name a zero length string if it's not.
479       Note that just returning zero length is not enough :
480       a lot of places don't check the return value and expect
481       a zero terminated string.
482     */
483     if (check_table_name(to, length, TRUE))
484     {
485       to[0]= 0;
486       length= 0;
487     }
488     DBUG_RETURN(length);
489   }
490   length= strconvert(system_charset_info, from,
491                      &my_charset_filename, to, to_length, &errors);
492   if (check_if_legal_tablename(to) &&
493       length + 4 < to_length)
494   {
495     memcpy(to + length, "@@@", 4);
496     length+= 3;
497   }
498   DBUG_PRINT("exit", ("to '%s'", to));
499   DBUG_RETURN(length);
500 }
501 
502 
503 /*
504   Creates path to a file: mysql_data_dir/db/table.ext
505 
506   SYNOPSIS
507    build_table_filename()
508      buff                       Where to write result in my_charset_filename.
509                                 This may be the same as table_name.
510      bufflen                    buff size
511      db                         Database name in system_charset_info.
512      table_name                 Table name in system_charset_info.
513      ext                        File extension.
514      flags                      FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP
515                                 table_name is temporary, do not change.
516 
517   NOTES
518 
519     Uses database and table name, and extension to create
520     a file name in mysql_data_dir. Database and table
521     names are converted from system_charset_info into "fscs".
522     Unless flags indicate a temporary table name.
523     'db' is always converted.
524     'ext' is not converted.
525 
526     The conversion suppression is required for ALTER TABLE. This
527     statement creates intermediate tables. These are regular
528     (non-temporary) tables with a temporary name. Their path names must
529     be derivable from the table name. So we cannot use
530     build_tmptable_filename() for them.
531 
532   RETURN
533     path length
534 */
535 
build_table_filename(char * buff,size_t bufflen,const char * db,const char * table_name,const char * ext,uint flags)536 uint build_table_filename(char *buff, size_t bufflen, const char *db,
537                           const char *table_name, const char *ext, uint flags)
538 {
539   char dbbuff[FN_REFLEN];
540   char tbbuff[FN_REFLEN];
541   DBUG_ENTER("build_table_filename");
542   DBUG_PRINT("enter", ("db: '%s'  table_name: '%s'  ext: '%s'  flags: %x",
543                        db, table_name, ext, flags));
544 
545   if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP
546     strnmov(tbbuff, table_name, sizeof(tbbuff));
547   else
548     (void) tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
549 
550   (void) tablename_to_filename(db, dbbuff, sizeof(dbbuff));
551 
552   char *end = buff + bufflen;
553   /* Don't add FN_ROOTDIR if mysql_data_home already includes it */
554   char *pos = strnmov(buff, mysql_data_home, bufflen);
555   size_t rootdir_len= strlen(FN_ROOTDIR);
556   if (pos - rootdir_len >= buff &&
557       memcmp(pos - rootdir_len, FN_ROOTDIR, rootdir_len) != 0)
558     pos= strnmov(pos, FN_ROOTDIR, end - pos);
559   pos= strxnmov(pos, end - pos, dbbuff, FN_ROOTDIR, NullS);
560 #ifdef USE_SYMDIR
561   unpack_dirname(buff, buff);
562   pos= strend(buff);
563 #endif
564   pos= strxnmov(pos, end - pos, tbbuff, ext, NullS);
565 
566   DBUG_PRINT("exit", ("buff: '%s'", buff));
567   DBUG_RETURN(pos - buff);
568 }
569 
570 
571 /*
572   Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext
573 
574   SYNOPSIS
575    build_tmptable_filename()
576      thd                        The thread handle.
577      buff                       Where to write result in my_charset_filename.
578      bufflen                    buff size
579 
580   NOTES
581 
582     Uses current_pid, thread_id, and tmp_table counter to create
583     a file name in mysql_tmpdir.
584 
585   RETURN
586     path length
587 */
588 
build_tmptable_filename(THD * thd,char * buff,size_t bufflen)589 uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
590 {
591   DBUG_ENTER("build_tmptable_filename");
592 
593   char *p= strnmov(buff, mysql_tmpdir, bufflen);
594   my_snprintf(p, bufflen - (p - buff), "/%s%lx_%lx_%x%s",
595               tmp_file_prefix, current_pid,
596               thd->thread_id, thd->tmp_table++, reg_ext);
597 
598   if (lower_case_table_names)
599   {
600     /* Convert all except tmpdir to lower case */
601     my_casedn_str(files_charset_info, p);
602   }
603 
604   size_t length= unpack_filename(buff, buff);
605   DBUG_PRINT("exit", ("buff: '%s'", buff));
606   DBUG_RETURN(length);
607 }
608 
609 /*
610 --------------------------------------------------------------------------
611 
612    MODULE: DDL log
613    -----------------
614 
615    This module is used to ensure that we can recover from crashes that occur
616    in the middle of a meta-data operation in MySQL. E.g. DROP TABLE t1, t2;
617    We need to ensure that both t1 and t2 are dropped and not only t1 and
618    also that each table drop is entirely done and not "half-baked".
619 
620    To support this we create log entries for each meta-data statement in the
621    ddl log while we are executing. These entries are dropped when the
622    operation is completed.
623 
624    At recovery those entries that were not completed will be executed.
625 
626    There is only one ddl log in the system and it is protected by a mutex
627    and there is a global struct that contains information about its current
628    state.
629 
630    History:
631    First version written in 2006 by Mikael Ronstrom
632 --------------------------------------------------------------------------
633 */
634 
635 
636 struct st_global_ddl_log
637 {
638   char file_name_str[FN_REFLEN];
639   char *file_name;
640   DDL_LOG_MEMORY_ENTRY *first_free;
641   DDL_LOG_MEMORY_ENTRY *first_used;
642   uint num_entries;
643   File file_id;
644   uint name_len;
645   uint io_size;
646   bool inited;
647   bool do_release;
648   bool recovery_phase;
st_global_ddl_logst_global_ddl_log649   st_global_ddl_log() : inited(false), do_release(false) {}
650 };
651 
652 st_global_ddl_log global_ddl_log;
653 
654 mysql_mutex_t LOCK_gdl;
655 
656 #define DDL_LOG_ENTRY_TYPE_POS 0
657 #define DDL_LOG_ACTION_TYPE_POS 1
658 #define DDL_LOG_PHASE_POS 2
659 #define DDL_LOG_NEXT_ENTRY_POS 4
660 #define DDL_LOG_NAME_POS 8
661 
662 #define DDL_LOG_NUM_ENTRY_POS 0
663 #define DDL_LOG_NAME_LEN_POS 4
664 #define DDL_LOG_IO_SIZE_POS 8
665 #define DDL_LOG_HEADER_SIZE 12
666 
667 /**
668   Read one entry from ddl log file.
669   @param[out]  file_entry_buf  Buffer to read into
670   @param       entry_no        Entry number to read
671   @param       size            Number of bytes of the entry to read
672 
673   @return Operation status
674     @retval true   Error
675     @retval false  Success
676 */
677 
read_ddl_log_file_entry(uchar * file_entry_buf,uint entry_no,uint size)678 static bool read_ddl_log_file_entry(uchar *file_entry_buf,
679                                     uint entry_no,
680                                     uint size)
681 {
682   bool error= FALSE;
683   File file_id= global_ddl_log.file_id;
684   uint io_size= global_ddl_log.io_size;
685   DBUG_ENTER("read_ddl_log_file_entry");
686   DBUG_ASSERT(io_size >= size);
687 
688   if (mysql_file_pread(file_id, file_entry_buf, size, io_size * entry_no,
689                        MYF(MY_WME)) != size)
690     error= TRUE;
691   DBUG_RETURN(error);
692 }
693 
694 
695 /**
696   Write one entry to ddl log file.
697 
698   @param  file_entry_buf  Buffer to write
699   @param  entry_no        Entry number to write
700   @param  size            Number of bytes of the entry to write
701 
702   @return Operation status
703     @retval true   Error
704     @retval false  Success
705 */
706 
write_ddl_log_file_entry(uchar * file_entry_buf,uint entry_no,uint size)707 static bool write_ddl_log_file_entry(uchar *file_entry_buf,
708                                      uint entry_no,
709                                      uint size)
710 {
711   bool error= FALSE;
712   File file_id= global_ddl_log.file_id;
713   uint io_size= global_ddl_log.io_size;
714   DBUG_ENTER("write_ddl_log_file_entry");
715   DBUG_ASSERT(io_size >= size);
716 
717   if (mysql_file_pwrite(file_id, file_entry_buf, size,
718                         io_size * entry_no, MYF(MY_WME)) != size)
719     error= TRUE;
720   DBUG_RETURN(error);
721 }
722 
723 
724 /*
725   Write ddl log header
726   SYNOPSIS
727     write_ddl_log_header()
728   RETURN VALUES
729     TRUE                      Error
730     FALSE                     Success
731 */
732 
write_ddl_log_header()733 static bool write_ddl_log_header()
734 {
735   uint16 const_var;
736   bool error= FALSE;
737   uchar file_entry_buf[DDL_LOG_HEADER_SIZE];
738   DBUG_ENTER("write_ddl_log_header");
739   DBUG_ASSERT((DDL_LOG_NAME_POS + 3 * global_ddl_log.name_len)
740                 <= global_ddl_log.io_size);
741 
742   int4store(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
743             global_ddl_log.num_entries);
744   const_var= global_ddl_log.name_len;
745   int4store(&file_entry_buf[DDL_LOG_NAME_LEN_POS],
746             (ulong) const_var);
747   const_var= global_ddl_log.io_size;
748   int4store(&file_entry_buf[DDL_LOG_IO_SIZE_POS],
749             (ulong) const_var);
750   if (write_ddl_log_file_entry(file_entry_buf, 0UL, DDL_LOG_HEADER_SIZE))
751   {
752     sql_print_error("Error writing ddl log header");
753     DBUG_RETURN(TRUE);
754   }
755   (void) sync_ddl_log();
756   DBUG_RETURN(error);
757 }
758 
759 
760 /*
761   Create ddl log file name
762   SYNOPSIS
763     create_ddl_log_file_name()
764     file_name                   Filename setup
765   RETURN VALUES
766     NONE
767 */
768 
create_ddl_log_file_name(char * file_name)769 static inline void create_ddl_log_file_name(char *file_name)
770 {
771   strxmov(file_name, mysql_data_home, "/", "ddl_log.log", NullS);
772 }
773 
774 
775 /*
776   Read header of ddl log file
777   SYNOPSIS
778     read_ddl_log_header()
779   RETURN VALUES
780     > 0                  Last entry in ddl log
781     0                    No entries in ddl log
782   DESCRIPTION
783     When we read the ddl log header we get information about maximum sizes
784     of names in the ddl log and we also get information about the number
785     of entries in the ddl log.
786 */
787 
read_ddl_log_header()788 static uint read_ddl_log_header()
789 {
790   char file_entry_buf[DDL_LOG_HEADER_SIZE];
791   char file_name[FN_REFLEN];
792   uint entry_no;
793   bool successful_open= FALSE;
794   DBUG_ENTER("read_ddl_log_header");
795   DBUG_ASSERT(global_ddl_log.io_size <= IO_SIZE);
796 
797   create_ddl_log_file_name(file_name);
798   if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
799                                                file_name,
800                                                O_RDWR | O_BINARY, MYF(0))) >= 0)
801   {
802     if (read_ddl_log_file_entry((uchar *) file_entry_buf, 0UL,
803                                 DDL_LOG_HEADER_SIZE))
804     {
805       /* Write message into error log */
806       sql_print_error("Failed to read ddl log file in recovery");
807     }
808     else
809       successful_open= TRUE;
810   }
811   if (successful_open)
812   {
813     entry_no= uint4korr(&file_entry_buf[DDL_LOG_NUM_ENTRY_POS]);
814     global_ddl_log.name_len= uint4korr(&file_entry_buf[DDL_LOG_NAME_LEN_POS]);
815     global_ddl_log.io_size= uint4korr(&file_entry_buf[DDL_LOG_IO_SIZE_POS]);
816   }
817   else
818   {
819     entry_no= 0;
820   }
821   global_ddl_log.first_free= NULL;
822   global_ddl_log.first_used= NULL;
823   global_ddl_log.num_entries= 0;
824   mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_FAST);
825   global_ddl_log.do_release= true;
826   DBUG_RETURN(entry_no);
827 }
828 
829 
830 /**
831   Set ddl log entry struct from buffer
832   @param read_entry      Entry number
833   @param file_entry_buf  Buffer to use
834   @param ddl_log_entry   Entry to be set
835 
836   @note Pointers in ddl_log_entry will point into file_entry_buf!
837 */
838 
set_ddl_log_entry_from_buf(uint read_entry,uchar * file_entry_buf,DDL_LOG_ENTRY * ddl_log_entry)839 static void set_ddl_log_entry_from_buf(uint read_entry,
840                                        uchar *file_entry_buf,
841                                        DDL_LOG_ENTRY *ddl_log_entry)
842 {
843   uint inx;
844   uchar single_char;
845   DBUG_ENTER("set_ddl_log_entry_from_buf");
846   ddl_log_entry->entry_pos= read_entry;
847   single_char= file_entry_buf[DDL_LOG_ENTRY_TYPE_POS];
848   ddl_log_entry->entry_type= (enum ddl_log_entry_code)single_char;
849   single_char= file_entry_buf[DDL_LOG_ACTION_TYPE_POS];
850   ddl_log_entry->action_type= (enum ddl_log_action_code)single_char;
851   ddl_log_entry->phase= file_entry_buf[DDL_LOG_PHASE_POS];
852   ddl_log_entry->next_entry= uint4korr(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS]);
853   ddl_log_entry->name= (char*) &file_entry_buf[DDL_LOG_NAME_POS];
854   inx= DDL_LOG_NAME_POS + global_ddl_log.name_len;
855   ddl_log_entry->from_name= (char*) &file_entry_buf[inx];
856   inx+= global_ddl_log.name_len;
857   ddl_log_entry->handler_name= (char*) &file_entry_buf[inx];
858   DBUG_VOID_RETURN;
859 }
860 
861 
862 /*
863   Initialise ddl log
864   SYNOPSIS
865     init_ddl_log()
866 
867   DESCRIPTION
868     Write the header of the ddl log file and length of names. Also set
869     number of entries to zero.
870 
871   RETURN VALUES
872     TRUE                     Error
873     FALSE                    Success
874 */
875 
init_ddl_log()876 static bool init_ddl_log()
877 {
878   char file_name[FN_REFLEN];
879   DBUG_ENTER("init_ddl_log");
880 
881   if (global_ddl_log.inited)
882     goto end;
883 
884   global_ddl_log.io_size= IO_SIZE;
885   global_ddl_log.name_len= FN_LEN;
886   create_ddl_log_file_name(file_name);
887   if ((global_ddl_log.file_id= mysql_file_create(key_file_global_ddl_log,
888                                                  file_name, CREATE_MODE,
889                                                  O_RDWR | O_TRUNC | O_BINARY,
890                                                  MYF(MY_WME))) < 0)
891   {
892     /* Couldn't create ddl log file, this is serious error */
893     sql_print_error("Failed to open ddl log file");
894     DBUG_RETURN(TRUE);
895   }
896   global_ddl_log.inited= TRUE;
897   if (write_ddl_log_header())
898   {
899     (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
900     global_ddl_log.inited= FALSE;
901     DBUG_RETURN(TRUE);
902   }
903 
904 end:
905   DBUG_RETURN(FALSE);
906 }
907 
908 
909 /*
910   Execute one action in a ddl log entry
911   SYNOPSIS
912     execute_ddl_log_action()
913     ddl_log_entry              Information in action entry to execute
914   RETURN VALUES
915     TRUE                       Error
916     FALSE                      Success
917 */
918 
execute_ddl_log_action(THD * thd,DDL_LOG_ENTRY * ddl_log_entry)919 static int execute_ddl_log_action(THD *thd, DDL_LOG_ENTRY *ddl_log_entry)
920 {
921   bool frm_action= FALSE;
922   LEX_STRING handler_name;
923   handler *file= NULL;
924   MEM_ROOT mem_root;
925   int error= TRUE;
926   char to_path[FN_REFLEN];
927   char from_path[FN_REFLEN];
928 #ifdef WITH_PARTITION_STORAGE_ENGINE
929   char *par_ext= (char*)".par";
930 #endif
931   handlerton *hton;
932   DBUG_ENTER("execute_ddl_log_action");
933 
934   if (ddl_log_entry->entry_type == DDL_IGNORE_LOG_ENTRY_CODE)
935   {
936     DBUG_RETURN(FALSE);
937   }
938   DBUG_PRINT("ddl_log",
939              ("execute type %c next %u name '%s' from_name '%s' handler '%s'",
940              ddl_log_entry->action_type,
941              ddl_log_entry->next_entry,
942              ddl_log_entry->name,
943              ddl_log_entry->from_name,
944              ddl_log_entry->handler_name));
945   handler_name.str= (char*)ddl_log_entry->handler_name;
946   handler_name.length= strlen(ddl_log_entry->handler_name);
947   init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
948   if (!strcmp(ddl_log_entry->handler_name, reg_ext))
949     frm_action= TRUE;
950   else
951   {
952     plugin_ref plugin= ha_resolve_by_name(thd, &handler_name);
953     if (!plugin)
954     {
955       my_error(ER_ILLEGAL_HA, MYF(0), ddl_log_entry->handler_name);
956       goto error;
957     }
958     hton= plugin_data(plugin, handlerton*);
959     file= get_new_handler((TABLE_SHARE*)0, &mem_root, hton);
960     if (!file)
961     {
962       mem_alloc_error(sizeof(handler));
963       goto error;
964     }
965   }
966   switch (ddl_log_entry->action_type)
967   {
968     case DDL_LOG_REPLACE_ACTION:
969     case DDL_LOG_DELETE_ACTION:
970     {
971       if (ddl_log_entry->phase == 0)
972       {
973         if (frm_action)
974         {
975           strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
976           if ((error= mysql_file_delete(key_file_frm, to_path, MYF(MY_WME))))
977           {
978             if (my_errno != ENOENT)
979               break;
980           }
981 #ifdef WITH_PARTITION_STORAGE_ENGINE
982           strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
983           (void) mysql_file_delete(key_file_partition, to_path, MYF(MY_WME));
984 #endif
985         }
986         else
987         {
988           if ((error= file->ha_delete_table(ddl_log_entry->name)))
989           {
990             if (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE)
991               break;
992           }
993         }
994         if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
995           break;
996         (void) sync_ddl_log();
997         error= FALSE;
998         if (ddl_log_entry->action_type == DDL_LOG_DELETE_ACTION)
999           break;
1000       }
1001       DBUG_ASSERT(ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION);
1002       /*
1003         Fall through and perform the rename action of the replace
1004         action. We have already indicated the success of the delete
1005         action in the log entry by stepping up the phase.
1006       */
1007     }
1008     case DDL_LOG_RENAME_ACTION:
1009     {
1010       error= TRUE;
1011       if (frm_action)
1012       {
1013         strxmov(to_path, ddl_log_entry->name, reg_ext, NullS);
1014         strxmov(from_path, ddl_log_entry->from_name, reg_ext, NullS);
1015         if (mysql_file_rename(key_file_frm, from_path, to_path, MYF(MY_WME)))
1016           break;
1017 #ifdef WITH_PARTITION_STORAGE_ENGINE
1018         strxmov(to_path, ddl_log_entry->name, par_ext, NullS);
1019         strxmov(from_path, ddl_log_entry->from_name, par_ext, NullS);
1020         (void) mysql_file_rename(key_file_partition, from_path, to_path, MYF(MY_WME));
1021 #endif
1022       }
1023       else
1024       {
1025         if (file->ha_rename_table(ddl_log_entry->from_name,
1026                                   ddl_log_entry->name))
1027           break;
1028       }
1029       if ((deactivate_ddl_log_entry(ddl_log_entry->entry_pos)))
1030         break;
1031       (void) sync_ddl_log();
1032       error= FALSE;
1033       break;
1034     }
1035     default:
1036       DBUG_ASSERT(0);
1037       break;
1038   }
1039   delete file;
1040 error:
1041   free_root(&mem_root, MYF(0));
1042   DBUG_RETURN(error);
1043 }
1044 
1045 
1046 /*
1047   Get a free entry in the ddl log
1048   SYNOPSIS
1049     get_free_ddl_log_entry()
1050     out:active_entry                A ddl log memory entry returned
1051   RETURN VALUES
1052     TRUE                       Error
1053     FALSE                      Success
1054 */
1055 
get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY ** active_entry,bool * write_header)1056 static bool get_free_ddl_log_entry(DDL_LOG_MEMORY_ENTRY **active_entry,
1057                                    bool *write_header)
1058 {
1059   DDL_LOG_MEMORY_ENTRY *used_entry;
1060   DDL_LOG_MEMORY_ENTRY *first_used= global_ddl_log.first_used;
1061   DBUG_ENTER("get_free_ddl_log_entry");
1062 
1063   mysql_mutex_assert_owner(&LOCK_gdl);
1064   if (global_ddl_log.first_free == NULL)
1065   {
1066     if (!(used_entry= (DDL_LOG_MEMORY_ENTRY*)my_malloc(
1067                               sizeof(DDL_LOG_MEMORY_ENTRY), MYF(MY_WME))))
1068     {
1069       sql_print_error("Failed to allocate memory for ddl log free list");
1070       DBUG_RETURN(TRUE);
1071     }
1072     global_ddl_log.num_entries++;
1073     used_entry->entry_pos= global_ddl_log.num_entries;
1074     *write_header= TRUE;
1075   }
1076   else
1077   {
1078     used_entry= global_ddl_log.first_free;
1079     global_ddl_log.first_free= used_entry->next_log_entry;
1080     *write_header= FALSE;
1081   }
1082   /*
1083     Move from free list to used list
1084   */
1085   used_entry->next_log_entry= first_used;
1086   used_entry->prev_log_entry= NULL;
1087   used_entry->next_active_log_entry= NULL;
1088   global_ddl_log.first_used= used_entry;
1089   if (first_used)
1090     first_used->prev_log_entry= used_entry;
1091 
1092   *active_entry= used_entry;
1093   DBUG_RETURN(FALSE);
1094 }
1095 
1096 
1097 /*
1098   External interface methods for the DDL log Module
1099   ---------------------------------------------------
1100 */
1101 
1102 /*
1103   SYNOPSIS
1104     write_ddl_log_entry()
1105     ddl_log_entry         Information about log entry
1106     out:entry_written     Entry information written into
1107 
1108   RETURN VALUES
1109     TRUE                      Error
1110     FALSE                     Success
1111 
1112   DESCRIPTION
1113     A careful write of the ddl log is performed to ensure that we can
1114     handle crashes occurring during CREATE and ALTER TABLE processing.
1115 */
1116 
write_ddl_log_entry(DDL_LOG_ENTRY * ddl_log_entry,DDL_LOG_MEMORY_ENTRY ** active_entry)1117 bool write_ddl_log_entry(DDL_LOG_ENTRY *ddl_log_entry,
1118                          DDL_LOG_MEMORY_ENTRY **active_entry)
1119 {
1120   bool error, write_header;
1121   char file_entry_buf[IO_SIZE];
1122   DBUG_ENTER("write_ddl_log_entry");
1123 
1124   if (init_ddl_log())
1125   {
1126     DBUG_RETURN(TRUE);
1127   }
1128   memset(file_entry_buf, 0, sizeof(file_entry_buf));
1129   file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]=
1130                                     (char)DDL_LOG_ENTRY_CODE;
1131   file_entry_buf[DDL_LOG_ACTION_TYPE_POS]=
1132                                     (char)ddl_log_entry->action_type;
1133   file_entry_buf[DDL_LOG_PHASE_POS]= 0;
1134   int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS],
1135             ddl_log_entry->next_entry);
1136   DBUG_ASSERT(strlen(ddl_log_entry->name) < global_ddl_log.name_len);
1137   strmake(&file_entry_buf[DDL_LOG_NAME_POS], ddl_log_entry->name,
1138           global_ddl_log.name_len - 1);
1139   if (ddl_log_entry->action_type == DDL_LOG_RENAME_ACTION ||
1140       ddl_log_entry->action_type == DDL_LOG_REPLACE_ACTION)
1141   {
1142     DBUG_ASSERT(strlen(ddl_log_entry->from_name) < global_ddl_log.name_len);
1143     strmake(&file_entry_buf[DDL_LOG_NAME_POS + global_ddl_log.name_len],
1144             ddl_log_entry->from_name, global_ddl_log.name_len - 1);
1145   }
1146   else
1147     file_entry_buf[DDL_LOG_NAME_POS + global_ddl_log.name_len]= 0;
1148   DBUG_ASSERT(strlen(ddl_log_entry->handler_name) < global_ddl_log.name_len);
1149   strmake(&file_entry_buf[DDL_LOG_NAME_POS + (2*global_ddl_log.name_len)],
1150           ddl_log_entry->handler_name, global_ddl_log.name_len - 1);
1151   if (get_free_ddl_log_entry(active_entry, &write_header))
1152   {
1153     DBUG_RETURN(TRUE);
1154   }
1155   error= FALSE;
1156   DBUG_PRINT("ddl_log",
1157              ("write type %c next %u name '%s' from_name '%s' handler '%s'",
1158              (char) file_entry_buf[DDL_LOG_ACTION_TYPE_POS],
1159              ddl_log_entry->next_entry,
1160              (char*) &file_entry_buf[DDL_LOG_NAME_POS],
1161              (char*) &file_entry_buf[DDL_LOG_NAME_POS +
1162                                      global_ddl_log.name_len],
1163              (char*) &file_entry_buf[DDL_LOG_NAME_POS +
1164                                      (2*global_ddl_log.name_len)]));
1165   if (write_ddl_log_file_entry((uchar*) file_entry_buf,
1166                                (*active_entry)->entry_pos, IO_SIZE))
1167   {
1168     error= TRUE;
1169     sql_print_error("Failed to write entry_no = %u",
1170                     (*active_entry)->entry_pos);
1171   }
1172   if (write_header && !error)
1173   {
1174     (void) sync_ddl_log();
1175     if (write_ddl_log_header())
1176       error= TRUE;
1177   }
1178   if (error)
1179     release_ddl_log_memory_entry(*active_entry);
1180   DBUG_RETURN(error);
1181 }
1182 
1183 
1184 /*
1185   Write final entry in the ddl log
1186   SYNOPSIS
1187     write_execute_ddl_log_entry()
1188     first_entry                    First entry in linked list of entries
1189                                    to execute, if 0 = NULL it means that
1190                                    the entry is removed and the entries
1191                                    are put into the free list.
1192     complete                       Flag indicating we are simply writing
1193                                    info about that entry has been completed
1194     in:out:active_entry            Entry to execute, 0 = NULL if the entry
1195                                    is written first time and needs to be
1196                                    returned. In this case the entry written
1197                                    is returned in this parameter
1198   RETURN VALUES
1199     TRUE                           Error
1200     FALSE                          Success
1201 
1202   DESCRIPTION
1203     This is the last write in the ddl log. The previous log entries have
1204     already been written but not yet synched to disk.
1205     We write a couple of log entries that describes action to perform.
1206     This entries are set-up in a linked list, however only when a first
1207     execute entry is put as the first entry these will be executed.
1208     This routine writes this first
1209 */
1210 
write_execute_ddl_log_entry(uint first_entry,bool complete,DDL_LOG_MEMORY_ENTRY ** active_entry)1211 bool write_execute_ddl_log_entry(uint first_entry,
1212                                  bool complete,
1213                                  DDL_LOG_MEMORY_ENTRY **active_entry)
1214 {
1215   bool write_header= FALSE;
1216   char file_entry_buf[IO_SIZE];
1217   DBUG_ENTER("write_execute_ddl_log_entry");
1218 
1219   if (init_ddl_log())
1220   {
1221     DBUG_RETURN(TRUE);
1222   }
1223   memset(file_entry_buf, 0, sizeof(file_entry_buf));
1224   if (!complete)
1225   {
1226     /*
1227       We haven't synched the log entries yet, we synch them now before
1228       writing the execute entry. If complete is true we haven't written
1229       any log entries before, we are only here to write the execute
1230       entry to indicate it is done.
1231     */
1232     (void) sync_ddl_log();
1233     file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_LOG_EXECUTE_CODE;
1234   }
1235   else
1236     file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= (char)DDL_IGNORE_LOG_ENTRY_CODE;
1237   int4store(&file_entry_buf[DDL_LOG_NEXT_ENTRY_POS], first_entry);
1238   if (!(*active_entry))
1239   {
1240     if (get_free_ddl_log_entry(active_entry, &write_header))
1241     {
1242       DBUG_RETURN(TRUE);
1243     }
1244   }
1245   if (write_ddl_log_file_entry((uchar*) file_entry_buf,
1246                                (*active_entry)->entry_pos,
1247                                IO_SIZE))
1248   {
1249     sql_print_error("Error writing execute entry in ddl log");
1250     release_ddl_log_memory_entry(*active_entry);
1251     DBUG_RETURN(TRUE);
1252   }
1253   (void) sync_ddl_log();
1254   if (write_header)
1255   {
1256     if (write_ddl_log_header())
1257     {
1258       release_ddl_log_memory_entry(*active_entry);
1259       DBUG_RETURN(TRUE);
1260     }
1261   }
1262   DBUG_RETURN(FALSE);
1263 }
1264 
1265 
1266 /*
1267   For complex rename operations we need to deactivate individual entries.
1268   SYNOPSIS
1269     deactivate_ddl_log_entry()
1270     entry_no                      Entry position of record to change
1271   RETURN VALUES
1272     TRUE                         Error
1273     FALSE                        Success
1274   DESCRIPTION
1275     During replace operations where we start with an existing table called
1276     t1 and a replacement table called t1#temp or something else and where
1277     we want to delete t1 and rename t1#temp to t1 this is not possible to
1278     do in a safe manner unless the ddl log is informed of the phases in
1279     the change.
1280 
1281     Delete actions are 1-phase actions that can be ignored immediately after
1282     being executed.
1283     Rename actions from x to y is also a 1-phase action since there is no
1284     interaction with any other handlers named x and y.
1285     Replace action where drop y and x -> y happens needs to be a two-phase
1286     action. Thus the first phase will drop y and the second phase will
1287     rename x -> y.
1288 */
1289 
deactivate_ddl_log_entry(uint entry_no)1290 bool deactivate_ddl_log_entry(uint entry_no)
1291 {
1292   uchar file_entry_buf[DDL_LOG_NAME_POS];
1293   DBUG_ENTER("deactivate_ddl_log_entry");
1294 
1295 
1296   /*
1297     Only need to read and write the first bytes of the entry, where
1298     ENTRY_TYPE, ACTION_TYPE and PHASE reside. Using DDL_LOG_NAME_POS
1299     to include all info except for the names.
1300   */
1301   if (!read_ddl_log_file_entry(file_entry_buf, entry_no, DDL_LOG_NAME_POS))
1302   {
1303     if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
1304     {
1305       if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
1306           file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
1307           (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
1308            file_entry_buf[DDL_LOG_PHASE_POS] == 1))
1309         file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
1310       else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
1311       {
1312         DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] == 0);
1313         file_entry_buf[DDL_LOG_PHASE_POS]= 1;
1314       }
1315       else
1316       {
1317         DBUG_ASSERT(0);
1318       }
1319       if (write_ddl_log_file_entry(file_entry_buf, entry_no, DDL_LOG_NAME_POS))
1320       {
1321         sql_print_error("Error in deactivating log entry. Position = %u",
1322                         entry_no);
1323         DBUG_RETURN(TRUE);
1324       }
1325     }
1326   }
1327   else
1328   {
1329     sql_print_error("Failed in reading entry before deactivating it");
1330     DBUG_RETURN(TRUE);
1331   }
1332   DBUG_RETURN(FALSE);
1333 }
1334 
1335 
1336 /*
1337   Sync ddl log file
1338   SYNOPSIS
1339     sync_ddl_log()
1340   RETURN VALUES
1341     TRUE                      Error
1342     FALSE                     Success
1343 */
1344 
sync_ddl_log()1345 bool sync_ddl_log()
1346 {
1347   bool error= FALSE;
1348   DBUG_ENTER("sync_ddl_log");
1349 
1350   if ((!global_ddl_log.recovery_phase) &&
1351       init_ddl_log())
1352   {
1353     DBUG_RETURN(TRUE);
1354   }
1355   if (mysql_file_sync(global_ddl_log.file_id, MYF(0)))
1356   {
1357     /* Write to error log */
1358     sql_print_error("Failed to sync ddl log");
1359     error= TRUE;
1360   }
1361   DBUG_RETURN(error);
1362 }
1363 
1364 
1365 /*
1366   Release a log memory entry
1367   SYNOPSIS
1368     release_ddl_log_memory_entry()
1369     log_memory_entry                Log memory entry to release
1370   RETURN VALUES
1371     NONE
1372 */
1373 
release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY * log_entry)1374 void release_ddl_log_memory_entry(DDL_LOG_MEMORY_ENTRY *log_entry)
1375 {
1376   DDL_LOG_MEMORY_ENTRY *first_free= global_ddl_log.first_free;
1377   DDL_LOG_MEMORY_ENTRY *next_log_entry= log_entry->next_log_entry;
1378   DDL_LOG_MEMORY_ENTRY *prev_log_entry= log_entry->prev_log_entry;
1379   DBUG_ENTER("release_ddl_log_memory_entry");
1380   mysql_mutex_assert_owner(&LOCK_gdl);
1381 
1382   global_ddl_log.first_free= log_entry;
1383   log_entry->next_log_entry= first_free;
1384 
1385   if (prev_log_entry)
1386     prev_log_entry->next_log_entry= next_log_entry;
1387   else
1388     global_ddl_log.first_used= next_log_entry;
1389   if (next_log_entry)
1390     next_log_entry->prev_log_entry= prev_log_entry;
1391   DBUG_VOID_RETURN;
1392 }
1393 
1394 
1395 /*
1396   Execute one entry in the ddl log. Executing an entry means executing
1397   a linked list of actions.
1398   SYNOPSIS
1399     execute_ddl_log_entry()
1400     first_entry                Reference to first action in entry
1401   RETURN VALUES
1402     TRUE                       Error
1403     FALSE                      Success
1404 */
1405 
execute_ddl_log_entry(THD * thd,uint first_entry)1406 bool execute_ddl_log_entry(THD *thd, uint first_entry)
1407 {
1408   DDL_LOG_ENTRY ddl_log_entry;
1409   uint read_entry= first_entry;
1410   uchar file_entry_buf[IO_SIZE];
1411   DBUG_ENTER("execute_ddl_log_entry");
1412 
1413   mysql_mutex_lock(&LOCK_gdl);
1414   do
1415   {
1416     if (read_ddl_log_file_entry(file_entry_buf, read_entry, IO_SIZE))
1417     {
1418       /* Print the error to the log and continue with next log entry */
1419       sql_print_error("Failed to read entry = %u from ddl log",
1420                       read_entry);
1421       break;
1422     }
1423     set_ddl_log_entry_from_buf(read_entry, file_entry_buf, &ddl_log_entry);
1424     DBUG_ASSERT(ddl_log_entry.entry_type == DDL_LOG_ENTRY_CODE ||
1425                 ddl_log_entry.entry_type == DDL_IGNORE_LOG_ENTRY_CODE);
1426 
1427     if (execute_ddl_log_action(thd, &ddl_log_entry))
1428     {
1429       /* Print the error to the log and continue with next log entry */
1430       sql_print_error("Failed to execute action for entry = %u from ddl log",
1431                       read_entry);
1432       break;
1433     }
1434     read_entry= ddl_log_entry.next_entry;
1435   } while (read_entry);
1436   mysql_mutex_unlock(&LOCK_gdl);
1437   DBUG_RETURN(FALSE);
1438 }
1439 
1440 
1441 /*
1442   Close the ddl log
1443   SYNOPSIS
1444     close_ddl_log()
1445   RETURN VALUES
1446     NONE
1447 */
1448 
close_ddl_log()1449 static void close_ddl_log()
1450 {
1451   DBUG_ENTER("close_ddl_log");
1452   if (global_ddl_log.file_id >= 0)
1453   {
1454     (void) mysql_file_close(global_ddl_log.file_id, MYF(MY_WME));
1455     global_ddl_log.file_id= (File) -1;
1456   }
1457   DBUG_VOID_RETURN;
1458 }
1459 
1460 
1461 /*
1462   Execute the ddl log at recovery of MySQL Server
1463   SYNOPSIS
1464     execute_ddl_log_recovery()
1465   RETURN VALUES
1466     NONE
1467 */
1468 
execute_ddl_log_recovery()1469 void execute_ddl_log_recovery()
1470 {
1471   uint num_entries, i;
1472   THD *thd;
1473   DDL_LOG_ENTRY ddl_log_entry;
1474   uchar *file_entry_buf;
1475   uint io_size;
1476   char file_name[FN_REFLEN];
1477   DBUG_ENTER("execute_ddl_log_recovery");
1478 
1479   /*
1480     Initialise global_ddl_log struct
1481   */
1482   global_ddl_log.inited= FALSE;
1483   global_ddl_log.recovery_phase= TRUE;
1484   global_ddl_log.io_size= IO_SIZE;
1485   global_ddl_log.file_id= (File) -1;
1486 
1487   /*
1488     To be able to run this from boot, we allocate a temporary THD
1489   */
1490   if (!(thd=new THD))
1491     DBUG_VOID_RETURN;
1492   thd->thread_stack= (char*) &thd;
1493   thd->store_globals();
1494 
1495   num_entries= read_ddl_log_header();
1496   io_size= global_ddl_log.io_size;
1497   file_entry_buf= (uchar*) my_malloc(io_size, MYF(0));
1498   if (!file_entry_buf)
1499   {
1500     sql_print_error("Failed to allocate buffer for recover ddl log");
1501     DBUG_VOID_RETURN;
1502   }
1503   for (i= 1; i < num_entries + 1; i++)
1504   {
1505     if (read_ddl_log_file_entry(file_entry_buf, i, io_size))
1506     {
1507       sql_print_error("Failed to read entry no = %u from ddl log",
1508                        i);
1509       continue;
1510     }
1511 
1512     set_ddl_log_entry_from_buf(i, file_entry_buf, &ddl_log_entry);
1513     if (ddl_log_entry.entry_type == DDL_LOG_EXECUTE_CODE)
1514     {
1515       if (execute_ddl_log_entry(thd, ddl_log_entry.next_entry))
1516       {
1517         /* Real unpleasant scenario but we continue anyways.  */
1518         continue;
1519       }
1520     }
1521   }
1522   close_ddl_log();
1523   create_ddl_log_file_name(file_name);
1524   (void) mysql_file_delete(key_file_global_ddl_log, file_name, MYF(0));
1525   global_ddl_log.recovery_phase= FALSE;
1526   delete thd;
1527   my_free(file_entry_buf);
1528   /* Remember that we don't have a THD */
1529   my_pthread_setspecific_ptr(THR_THD,  0);
1530   DBUG_VOID_RETURN;
1531 }
1532 
1533 
1534 /*
1535   Release all memory allocated to the ddl log
1536   SYNOPSIS
1537     release_ddl_log()
1538   RETURN VALUES
1539     NONE
1540 */
1541 
release_ddl_log()1542 void release_ddl_log()
1543 {
1544   DDL_LOG_MEMORY_ENTRY *free_list;
1545   DDL_LOG_MEMORY_ENTRY *used_list;
1546   DBUG_ENTER("release_ddl_log");
1547 
1548   if (!global_ddl_log.do_release)
1549     DBUG_VOID_RETURN;
1550 
1551   mysql_mutex_lock(&LOCK_gdl);
1552   free_list= global_ddl_log.first_free;
1553   used_list= global_ddl_log.first_used;
1554   while (used_list)
1555   {
1556     DDL_LOG_MEMORY_ENTRY *tmp= used_list->next_log_entry;
1557     my_free(used_list);
1558     used_list= tmp;
1559   }
1560   while (free_list)
1561   {
1562     DDL_LOG_MEMORY_ENTRY *tmp= free_list->next_log_entry;
1563     my_free(free_list);
1564     free_list= tmp;
1565   }
1566   close_ddl_log();
1567   global_ddl_log.inited= 0;
1568   mysql_mutex_unlock(&LOCK_gdl);
1569   mysql_mutex_destroy(&LOCK_gdl);
1570   global_ddl_log.do_release= false;
1571   DBUG_VOID_RETURN;
1572 }
1573 
1574 
1575 /*
1576 ---------------------------------------------------------------------------
1577 
1578   END MODULE DDL log
1579   --------------------
1580 
1581 ---------------------------------------------------------------------------
1582 */
1583 
1584 
1585 /**
1586    @brief construct a temporary shadow file name.
1587 
1588    @details Make a shadow file name used by ALTER TABLE to construct the
1589    modified table (with keeping the original). The modified table is then
1590    moved back as original table. The name must start with the temp file
1591    prefix so it gets filtered out by table files listing routines.
1592 
1593    @param[out] buff      buffer to receive the constructed name
1594    @param      bufflen   size of buff
1595    @param      lpt       alter table data structure
1596 
1597    @retval     path length
1598 */
1599 
build_table_shadow_filename(char * buff,size_t bufflen,ALTER_PARTITION_PARAM_TYPE * lpt)1600 uint build_table_shadow_filename(char *buff, size_t bufflen,
1601                                  ALTER_PARTITION_PARAM_TYPE *lpt)
1602 {
1603   char tmp_name[FN_REFLEN];
1604   my_snprintf (tmp_name, sizeof (tmp_name), "%s-%s", tmp_file_prefix,
1605                lpt->table_name);
1606   return build_table_filename(buff, bufflen, lpt->db, tmp_name, "", FN_IS_TMP);
1607 }
1608 
1609 
1610 /*
1611   SYNOPSIS
1612     mysql_write_frm()
1613     lpt                    Struct carrying many parameters needed for this
1614                            method
1615     flags                  Flags as defined below
1616       WFRM_INITIAL_WRITE        If set we need to prepare table before
1617                                 creating the frm file
1618       WFRM_INSTALL_SHADOW       If set we should install the new frm
1619       WFRM_KEEP_SHARE           If set we know that the share is to be
1620                                 retained and thus we should ensure share
1621                                 object is correct, if not set we don't
1622                                 set the new partition syntax string since
1623                                 we know the share object is destroyed.
1624       WFRM_PACK_FRM             If set we should pack the frm file and delete
1625                                 the frm file
1626 
1627   RETURN VALUES
1628     TRUE                   Error
1629     FALSE                  Success
1630 
1631   DESCRIPTION
1632     A support method that creates a new frm file and in this process it
1633     regenerates the partition data. It works fine also for non-partitioned
1634     tables since it only handles partitioned data if it exists.
1635 */
1636 
mysql_write_frm(ALTER_PARTITION_PARAM_TYPE * lpt,uint flags)1637 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
1638 {
1639   /*
1640     Prepare table to prepare for writing a new frm file where the
1641     partitions in add/drop state have temporarily changed their state
1642     We set tmp_table to avoid get errors on naming of primary key index.
1643   */
1644   int error= 0;
1645   char path[FN_REFLEN+1];
1646   char shadow_path[FN_REFLEN+1];
1647   char shadow_frm_name[FN_REFLEN+1];
1648   char frm_name[FN_REFLEN+1];
1649 #ifdef WITH_PARTITION_STORAGE_ENGINE
1650   char *part_syntax_buf;
1651   uint syntax_len;
1652 #endif
1653   DBUG_ENTER("mysql_write_frm");
1654 
1655   /*
1656     Build shadow frm file name
1657   */
1658   build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
1659   strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
1660   if (flags & WFRM_WRITE_SHADOW)
1661   {
1662     if (mysql_prepare_create_table(lpt->thd, lpt->create_info,
1663                                    lpt->alter_info,
1664                                    /*tmp_table*/ 1,
1665                                    &lpt->db_options,
1666                                    lpt->table->file,
1667                                    &lpt->key_info_buffer,
1668                                    &lpt->key_count,
1669                                    /*select_field_count*/ 0))
1670     {
1671       DBUG_RETURN(TRUE);
1672     }
1673 #ifdef WITH_PARTITION_STORAGE_ENGINE
1674     {
1675       partition_info *part_info= lpt->table->part_info;
1676       if (part_info)
1677       {
1678         if (!(part_syntax_buf= generate_partition_syntax(part_info,
1679                                                          &syntax_len,
1680                                                          TRUE, TRUE,
1681                                                          lpt->create_info,
1682                                                          lpt->alter_info,
1683                                                          NULL)))
1684         {
1685           DBUG_RETURN(TRUE);
1686         }
1687         part_info->part_info_string= part_syntax_buf;
1688         part_info->part_info_len= syntax_len;
1689       }
1690     }
1691 #endif
1692     /* Write shadow frm file */
1693     lpt->create_info->table_options= lpt->db_options;
1694     if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
1695                           lpt->table_name, lpt->create_info,
1696                           lpt->alter_info->create_list, lpt->key_count,
1697                           lpt->key_info_buffer, lpt->table->file)) ||
1698         lpt->table->file->ha_create_handler_files(shadow_path, NULL,
1699                                                   CHF_CREATE_FLAG,
1700                                                   lpt->create_info))
1701     {
1702       mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
1703       error= 1;
1704       goto end;
1705     }
1706   }
1707   if (flags & WFRM_PACK_FRM)
1708   {
1709     /*
1710       We need to pack the frm file and after packing it we delete the
1711       frm file to ensure it doesn't get used. This is only used for
1712       handlers that have the main version of the frm file stored in the
1713       handler.
1714     */
1715     uchar *data;
1716     size_t length;
1717     if (readfrm(shadow_path, &data, &length) ||
1718         packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
1719     {
1720       my_free(data);
1721       my_free(lpt->pack_frm_data);
1722       mem_alloc_error(length);
1723       error= 1;
1724       goto end;
1725     }
1726     error= mysql_file_delete(key_file_frm, shadow_frm_name, MYF(MY_WME));
1727   }
1728   if (flags & WFRM_INSTALL_SHADOW)
1729   {
1730 #ifdef WITH_PARTITION_STORAGE_ENGINE
1731     partition_info *part_info= lpt->part_info;
1732 #endif
1733     /*
1734       Build frm file name
1735     */
1736     build_table_filename(path, sizeof(path) - 1, lpt->db,
1737                          lpt->table_name, "", 0);
1738     strxmov(frm_name, path, reg_ext, NullS);
1739     /*
1740       When we are changing to use new frm file we need to ensure that we
1741       don't collide with another thread in process to open the frm file.
1742       We start by deleting the .frm file and possible .par file. Then we
1743       write to the DDL log that we have completed the delete phase by
1744       increasing the phase of the log entry. Next step is to rename the
1745       new .frm file and the new .par file to the real name. After
1746       completing this we write a new phase to the log entry that will
1747       deactivate it.
1748     */
1749     if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
1750 #ifdef WITH_PARTITION_STORAGE_ENGINE
1751         lpt->table->file->ha_create_handler_files(path, shadow_path,
1752                                                   CHF_DELETE_FLAG, NULL) ||
1753         deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
1754         (sync_ddl_log(), FALSE) ||
1755         mysql_file_rename(key_file_frm,
1756                           shadow_frm_name, frm_name, MYF(MY_WME)) ||
1757         lpt->table->file->ha_create_handler_files(path, shadow_path,
1758                                                   CHF_RENAME_FLAG, NULL))
1759 #else
1760         mysql_file_rename(key_file_frm,
1761                           shadow_frm_name, frm_name, MYF(MY_WME)))
1762 #endif
1763     {
1764       error= 1;
1765       goto err;
1766     }
1767 #ifdef WITH_PARTITION_STORAGE_ENGINE
1768     if (part_info && (flags & WFRM_KEEP_SHARE))
1769     {
1770       TABLE_SHARE *share= lpt->table->s;
1771       char *tmp_part_syntax_str;
1772       if (!(part_syntax_buf= generate_partition_syntax(part_info,
1773                                                        &syntax_len,
1774                                                        TRUE, TRUE,
1775                                                        lpt->create_info,
1776                                                        lpt->alter_info,
1777                                                        NULL)))
1778       {
1779         error= 1;
1780         goto err;
1781       }
1782       if (share->partition_info_buffer_size < syntax_len + 1)
1783       {
1784         share->partition_info_buffer_size= syntax_len+1;
1785         if (!(tmp_part_syntax_str= (char*) strmake_root(&share->mem_root,
1786                                                         part_syntax_buf,
1787                                                         syntax_len)))
1788         {
1789           error= 1;
1790           goto err;
1791         }
1792         share->partition_info_str= tmp_part_syntax_str;
1793       }
1794       else
1795         memcpy((char*) share->partition_info_str, part_syntax_buf,
1796                syntax_len + 1);
1797       share->partition_info_str_len= part_info->part_info_len= syntax_len;
1798       part_info->part_info_string= part_syntax_buf;
1799     }
1800 #endif
1801 
1802 err:
1803 #ifdef WITH_PARTITION_STORAGE_ENGINE
1804     deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos);
1805     part_info->frm_log_entry= NULL;
1806     (void) sync_ddl_log();
1807 #endif
1808     ;
1809   }
1810 
1811 end:
1812   DBUG_RETURN(error);
1813 }
1814 
1815 
1816 /*
1817   SYNOPSIS
1818     write_bin_log()
1819     thd                           Thread object
1820     clear_error                   is clear_error to be called
1821     query                         Query to log
1822     query_length                  Length of query
1823     is_trans                      if the event changes either
1824                                   a trans or non-trans engine.
1825 
1826   RETURN VALUES
1827     NONE
1828 
1829   DESCRIPTION
1830     Write the binlog if open, routine used in multiple places in this
1831     file
1832 */
1833 
write_bin_log(THD * thd,bool clear_error,char const * query,ulong query_length,bool is_trans)1834 int write_bin_log(THD *thd, bool clear_error,
1835                   char const *query, ulong query_length, bool is_trans)
1836 {
1837   int error= 0;
1838   if (mysql_bin_log.is_open())
1839   {
1840     int errcode= 0;
1841     if (clear_error)
1842       thd->clear_error();
1843     else
1844       errcode= query_error_code(thd, TRUE);
1845     error= thd->binlog_query(THD::STMT_QUERY_TYPE,
1846                              query, query_length, is_trans, FALSE, FALSE,
1847                              errcode);
1848   }
1849   return error;
1850 }
1851 
1852 
1853 /*
1854  delete (drop) tables.
1855 
1856   SYNOPSIS
1857    mysql_rm_table()
1858    thd			Thread handle
1859    tables		List of tables to delete
1860    if_exists		If 1, don't give error if one table doesn't exists
1861 
1862   NOTES
1863     Will delete all tables that can be deleted and give a compact error
1864     messages for tables that could not be deleted.
1865     If a table is in use, we will wait for all users to free the table
1866     before dropping it
1867 
1868     Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but
1869     not if under LOCK TABLES.
1870 
1871   RETURN
1872     FALSE OK.  In this case ok packet is sent to user
1873     TRUE  Error
1874 
1875 */
1876 
mysql_rm_table(THD * thd,TABLE_LIST * tables,my_bool if_exists,my_bool drop_temporary)1877 bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
1878                     my_bool drop_temporary)
1879 {
1880   bool error;
1881   Drop_table_error_handler err_handler;
1882   TABLE_LIST *table;
1883 
1884   DBUG_ENTER("mysql_rm_table");
1885 
1886   /* Disable drop of enabled log tables, must be done before name locking */
1887   for (table= tables; table; table= table->next_local)
1888   {
1889     if (check_if_log_table(table->db_length, table->db,
1890                            table->table_name_length, table->table_name, true))
1891     {
1892       my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
1893       DBUG_RETURN(true);
1894     }
1895   }
1896 
1897   mysql_ha_rm_tables(thd, tables);
1898 
1899   if (!drop_temporary)
1900   {
1901     if (!thd->locked_tables_mode)
1902     {
1903       if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout,
1904                            MYSQL_OPEN_SKIP_TEMPORARY))
1905         DBUG_RETURN(true);
1906       for (table= tables; table; table= table->next_local)
1907         tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
1908                          false);
1909     }
1910     else
1911     {
1912       for (table= tables; table; table= table->next_local)
1913         if (table->open_type != OT_BASE_ONLY &&
1914 	    find_temporary_table(thd, table))
1915         {
1916           /*
1917             A temporary table.
1918 
1919             Don't try to find a corresponding MDL lock or assign it
1920             to table->mdl_request.ticket. There can't be metadata
1921             locks for temporary tables: they are local to the session.
1922 
1923             Later in this function we release the MDL lock only if
1924             table->mdl_requeset.ticket is not NULL. Thus here we
1925             ensure that we won't release the metadata lock on the base
1926             table locked with LOCK TABLES as a side effect of temporary
1927             table drop.
1928           */
1929           DBUG_ASSERT(table->mdl_request.ticket == NULL);
1930         }
1931         else
1932         {
1933           /*
1934             Not a temporary table.
1935 
1936             Since 'tables' list can't contain duplicates (this is ensured
1937             by parser) it is safe to cache pointer to the TABLE instances
1938             in its elements.
1939           */
1940           table->table= find_table_for_mdl_upgrade(thd, table->db,
1941                                                    table->table_name, false);
1942           if (!table->table)
1943             DBUG_RETURN(true);
1944           table->mdl_request.ticket= table->table->mdl_ticket;
1945         }
1946     }
1947   }
1948 
1949   /* mark for close and remove all cached entries */
1950   thd->push_internal_handler(&err_handler);
1951   error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary,
1952                                  false, false);
1953   thd->pop_internal_handler();
1954 
1955   if (error)
1956     DBUG_RETURN(TRUE);
1957   my_ok(thd);
1958   DBUG_RETURN(FALSE);
1959 }
1960 
1961 
1962 /**
1963   Execute the drop of a normal or temporary table.
1964 
1965   @param  thd             Thread handler
1966   @param  tables          Tables to drop
1967   @param  if_exists       If set, don't give an error if table doesn't exists.
1968                           In this case we give an warning of level 'NOTE'
1969   @param  drop_temporary  Only drop temporary tables
1970   @param  drop_view       Allow to delete VIEW .frm
1971   @param  dont_log_query  Don't write query to log files. This will also not
1972                           generate warnings if the handler files doesn't exists
1973 
1974   @retval  0  ok
1975   @retval  1  Error
1976   @retval -1  Thread was killed
1977 
1978   @note This function assumes that metadata locks have already been taken.
1979         It is also assumed that the tables have been removed from TDC.
1980 
1981   @todo When logging to the binary log, we should log
1982         tmp_tables and transactional tables as separate statements if we
1983         are in a transaction;  This is needed to get these tables into the
1984         cached binary log that is only written on COMMIT.
1985         The current code only writes DROP statements that only uses temporary
1986         tables to the cache binary log.  This should be ok on most cases, but
1987         not all.
1988 */
1989 
mysql_rm_table_no_locks(THD * thd,TABLE_LIST * tables,bool if_exists,bool drop_temporary,bool drop_view,bool dont_log_query)1990 int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
1991                             bool drop_temporary, bool drop_view,
1992                             bool dont_log_query)
1993 {
1994   TABLE_LIST *table;
1995   char path[FN_REFLEN + 1], *alias= NULL;
1996   uint path_length= 0;
1997   String wrong_tables;
1998   int error= 0;
1999   int non_temp_tables_count= 0;
2000   bool foreign_key_error=0;
2001   bool non_tmp_error= 0;
2002   bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
2003   bool non_tmp_table_deleted= 0;
2004   bool is_drop_tmp_if_exists_added= 0;
2005   String built_query;
2006   String built_trans_tmp_query, built_non_trans_tmp_query;
2007   DBUG_ENTER("mysql_rm_table_no_locks");
2008 
2009   /*
2010     Prepares the drop statements that will be written into the binary
2011     log as follows:
2012 
2013     1 - If we are not processing a "DROP TEMPORARY" it prepares a
2014     "DROP".
2015 
2016     2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
2017     not true.
2018 
2019     3 - If the current format is row, the IF EXISTS token needs to be
2020     appended because one does not know if CREATE TEMPORARY was previously
2021     written to the binary log.
2022 
2023     4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
2024 
2025     5 - For temporary tables, there is a need to differentiate tables
2026     in transactional and non-transactional storage engines. For that,
2027     reason, two types of drop statements are prepared.
2028 
2029     The need to different the type of tables when dropping a temporary
2030     table stems from the fact that such drop does not commit an ongoing
2031     transaction and changes to non-transactional tables must be written
2032     ahead of the transaction in some circumstances.
2033 
2034     6- Slave SQL thread ignores all replicate-* filter rules
2035     for temporary tables with 'IF EXISTS' clause. (See sql/sql_parse.cc:
2036     mysql_execute_command() for details). These commands will be binlogged
2037     as they are, even if the default database (from USE `db`) is not present
2038     on the Slave. This can cause point in time recovery failures later
2039     when user uses the slave's binlog to re-apply. Hence at the time of binary
2040     logging, these commands will be written with fully qualified table names
2041     and use `db` will be suppressed.
2042   */
2043   if (!dont_log_query)
2044   {
2045     if (!drop_temporary)
2046     {
2047       built_query.set_charset(system_charset_info);
2048       if (if_exists)
2049         built_query.append("DROP TABLE IF EXISTS ");
2050       else
2051         built_query.append("DROP TABLE ");
2052     }
2053 
2054     if (thd->is_current_stmt_binlog_format_row() || if_exists)
2055     {
2056       is_drop_tmp_if_exists_added= true;
2057       built_trans_tmp_query.set_charset(system_charset_info);
2058       built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
2059       built_non_trans_tmp_query.set_charset(system_charset_info);
2060       built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
2061     }
2062     else
2063     {
2064       built_trans_tmp_query.set_charset(system_charset_info);
2065       built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
2066       built_non_trans_tmp_query.set_charset(system_charset_info);
2067       built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
2068     }
2069   }
2070 
2071   for (table= tables; table; table= table->next_local)
2072   {
2073     bool is_trans;
2074     char *db=table->db;
2075     int db_len= table->db_length;
2076     handlerton *table_type;
2077     enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
2078 
2079     DBUG_PRINT("table", ("table_l: '%s'.'%s'  table: 0x%lx  s: 0x%lx",
2080                          table->db, table->table_name, (long) table->table,
2081                          table->table ? (long) table->table->s : (long) -1));
2082 
2083     /*
2084       If we are in locked tables mode and are dropping a temporary table,
2085       the ticket should be NULL to ensure that we don't release a lock
2086       on a base table later.
2087     */
2088     DBUG_ASSERT(!(thd->locked_tables_mode &&
2089                   table->open_type != OT_BASE_ONLY &&
2090                   find_temporary_table(thd, table) &&
2091                   table->mdl_request.ticket != NULL));
2092 
2093     /*
2094       drop_temporary_table may return one of the following error codes:
2095       .  0 - a temporary table was successfully dropped.
2096       .  1 - a temporary table was not found.
2097       . -1 - a temporary table is used by an outer statement.
2098     */
2099     if (table->open_type == OT_BASE_ONLY)
2100       error= 1;
2101     else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
2102     {
2103       DBUG_ASSERT(thd->in_sub_stmt);
2104       goto err;
2105     }
2106 
2107     if ((drop_temporary && if_exists) || !error)
2108     {
2109       /*
2110         This handles the case of temporary tables. We have the following cases:
2111 
2112           . "DROP TEMPORARY" was executed and a temporary table was affected
2113           (i.e. drop_temporary && !error) or the if_exists was specified (i.e.
2114           drop_temporary && if_exists).
2115 
2116           . "DROP" was executed but a temporary table was affected (.i.e
2117           !error).
2118       */
2119       if (!dont_log_query)
2120       {
2121         /*
2122           If there is an error, we don't know the type of the engine
2123           at this point. So, we keep it in the trx-cache.
2124         */
2125         is_trans= error ? TRUE : is_trans;
2126         if (is_trans)
2127           trans_tmp_table_deleted= TRUE;
2128         else
2129           non_trans_tmp_table_deleted= TRUE;
2130 
2131         String *built_ptr_query=
2132           (is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
2133         /*
2134           Write the database name if it is not the current one or if
2135           thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY'
2136           query.
2137         */
2138         if (thd->db == NULL || strcmp(db,thd->db) != 0
2139             || is_drop_tmp_if_exists_added )
2140         {
2141           append_identifier(thd, built_ptr_query, db, db_len,
2142                             system_charset_info, thd->charset());
2143           built_ptr_query->append(".");
2144         }
2145         append_identifier(thd, built_ptr_query, table->table_name,
2146                           strlen(table->table_name), system_charset_info,
2147                           thd->charset());
2148         built_ptr_query->append(",");
2149       }
2150       /*
2151         This means that a temporary table was droped and as such there
2152         is no need to proceed with the code that tries to drop a regular
2153         table.
2154       */
2155       if (!error) continue;
2156     }
2157     else if (!drop_temporary)
2158     {
2159       non_temp_tables_count++;
2160 
2161       if (thd->locked_tables_mode)
2162       {
2163         if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
2164         {
2165           error= -1;
2166           goto err;
2167         }
2168         close_all_tables_for_name(thd, table->table->s, TRUE, NULL);
2169         table->table= 0;
2170       }
2171 
2172       /* Check that we have an exclusive lock on the table to be dropped. */
2173       DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
2174                                                  table->table_name,
2175                                                  MDL_EXCLUSIVE));
2176       if (thd->killed)
2177       {
2178         error= -1;
2179         goto err;
2180       }
2181       alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
2182       /* remove .frm file and engine files */
2183       path_length= build_table_filename(path, sizeof(path) - 1, db, alias,
2184                                         reg_ext,
2185                                         table->internal_tmp_table ?
2186                                         FN_IS_TMP : 0);
2187 
2188       /*
2189         This handles the case where a "DROP" was executed and a regular
2190         table "may be" dropped as drop_temporary is FALSE and error is
2191         TRUE. If the error was FALSE a temporary table was dropped and
2192         regardless of the status of drop_tempoary a "DROP TEMPORARY"
2193         must be used.
2194       */
2195       if (!dont_log_query)
2196       {
2197         /*
2198           Note that unless if_exists is TRUE or a temporary table was deleted,
2199           there is no means to know if the statement should be written to the
2200           binary log. See further information on this variable in what follows.
2201         */
2202         non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted);
2203         /*
2204           Don't write the database name if it is the current one (or if
2205           thd->db is NULL).
2206         */
2207         if (thd->db == NULL || strcmp(db,thd->db) != 0)
2208         {
2209           append_identifier(thd, &built_query, db, db_len,
2210                             system_charset_info, thd->charset());
2211           built_query.append(".");
2212         }
2213 
2214         append_identifier(thd, &built_query, table->table_name,
2215                           strlen(table->table_name), system_charset_info,
2216                           thd->charset());
2217         built_query.append(",");
2218       }
2219     }
2220     DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
2221     DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table",
2222                     my_sleep(100000););
2223     error= 0;
2224     if (drop_temporary ||
2225         ((access(path, F_OK) &&
2226           ha_create_table_from_engine(thd, db, alias)) ||
2227          (!drop_view &&
2228           dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
2229     {
2230       /*
2231         One of the following cases happened:
2232           . "DROP TEMPORARY" but a temporary table was not found.
2233           . "DROP" but table was not found on disk and table can't be
2234             created from engine.
2235           . ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
2236       */
2237       if (if_exists)
2238 	push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
2239 			    ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
2240 			    table->table_name);
2241       else
2242       {
2243         non_tmp_error = (drop_temporary ? non_tmp_error : TRUE);
2244         error= 1;
2245       }
2246     }
2247     else
2248     {
2249       char *end;
2250       /*
2251         Cannot use the db_type from the table, since that might have changed
2252         while waiting for the exclusive name lock.
2253       */
2254       if (frm_db_type == DB_TYPE_UNKNOWN)
2255       {
2256         dd_frm_type(thd, path, &frm_db_type);
2257         DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
2258       }
2259       table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
2260       // Remove extension for delete
2261       *(end= path + path_length - reg_ext_length)= '\0';
2262       DBUG_PRINT("info", ("deleting table of type %d",
2263                           (table_type ? table_type->db_type : 0)));
2264       error= ha_delete_table(thd, table_type, path, db, table->table_name,
2265                              !dont_log_query);
2266 
2267       /* No error if non existent table and 'IF EXIST' clause or view */
2268       if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
2269 	  (if_exists || table_type == NULL))
2270       {
2271 	error= 0;
2272         thd->clear_error();
2273       }
2274       if (error == HA_ERR_ROW_IS_REFERENCED)
2275       {
2276 	/* the table is referenced by a foreign key constraint */
2277 	foreign_key_error= 1;
2278       }
2279       if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
2280       {
2281         int new_error;
2282 	/* Delete the table definition file */
2283 	strmov(end,reg_ext);
2284         if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
2285         {
2286           non_tmp_table_deleted= TRUE;
2287           new_error= Table_triggers_list::drop_all_triggers(thd, db,
2288                                                             table->table_name);
2289         }
2290         error|= new_error;
2291       }
2292        non_tmp_error= error ? TRUE : non_tmp_error;
2293     }
2294     if (error)
2295     {
2296       if (wrong_tables.length())
2297 	wrong_tables.append(',');
2298       wrong_tables.append(String(table->table_name,system_charset_info));
2299     }
2300     DBUG_PRINT("table", ("table: 0x%lx  s: 0x%lx", (long) table->table,
2301                          table->table ? (long) table->table->s : (long) -1));
2302 
2303     DBUG_EXECUTE_IF("bug43138",
2304                     my_printf_error(ER_BAD_TABLE_ERROR,
2305                                     ER(ER_BAD_TABLE_ERROR), MYF(0),
2306                                     table->table_name););
2307   }
2308   DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
2309   thd->thread_specific_used|= (trans_tmp_table_deleted ||
2310                                non_trans_tmp_table_deleted);
2311   error= 0;
2312 err:
2313   if (wrong_tables.length())
2314   {
2315     if (!foreign_key_error)
2316       my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
2317                       wrong_tables.c_ptr());
2318     else
2319       my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
2320     error= 1;
2321   }
2322 
2323   if (non_trans_tmp_table_deleted ||
2324       trans_tmp_table_deleted || non_tmp_table_deleted)
2325   {
2326     query_cache_invalidate3(thd, tables, 0);
2327     if (!dont_log_query && mysql_bin_log.is_open())
2328     {
2329       if (non_trans_tmp_table_deleted)
2330       {
2331           /* Chop of the last comma */
2332           built_non_trans_tmp_query.chop();
2333           built_non_trans_tmp_query.append(" /* generated by server */");
2334           error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2335                                      built_non_trans_tmp_query.ptr(),
2336                                      built_non_trans_tmp_query.length(),
2337                                      FALSE, FALSE,
2338                                      is_drop_tmp_if_exists_added,
2339                                      0);
2340       }
2341       if (trans_tmp_table_deleted)
2342       {
2343           /* Chop of the last comma */
2344           built_trans_tmp_query.chop();
2345           built_trans_tmp_query.append(" /* generated by server */");
2346           error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2347                                      built_trans_tmp_query.ptr(),
2348                                      built_trans_tmp_query.length(),
2349                                      TRUE, FALSE,
2350                                      is_drop_tmp_if_exists_added,
2351                                      0);
2352       }
2353       if (non_tmp_table_deleted)
2354       {
2355           /* Chop of the last comma */
2356           built_query.chop();
2357           built_query.append(" /* generated by server */");
2358           int error_code = (non_tmp_error ?
2359             (foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
2360           error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
2361                                      built_query.ptr(),
2362                                      built_query.length(),
2363                                      TRUE, FALSE, FALSE,
2364                                      error_code);
2365       }
2366     }
2367   }
2368 
2369   if (!drop_temporary)
2370   {
2371     /*
2372       Under LOCK TABLES we should release meta-data locks on the tables
2373       which were dropped.
2374 
2375       Leave LOCK TABLES mode if we managed to drop all tables which were
2376       locked. Additional check for 'non_temp_tables_count' is to avoid
2377       leaving LOCK TABLES mode if we have dropped only temporary tables.
2378     */
2379     if (thd->locked_tables_mode)
2380     {
2381       if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
2382       {
2383         thd->locked_tables_list.unlock_locked_tables(thd);
2384         goto end;
2385       }
2386       for (table= tables; table; table= table->next_local)
2387       {
2388         /* Drop locks for all successfully dropped tables. */
2389         if (table->table == NULL && table->mdl_request.ticket)
2390         {
2391           /*
2392             Under LOCK TABLES we may have several instances of table open
2393             and locked and therefore have to remove several metadata lock
2394             requests associated with them.
2395           */
2396           thd->mdl_context.release_all_locks_for_name(table->mdl_request.ticket);
2397         }
2398       }
2399     }
2400     /*
2401       Rely on the caller to implicitly commit the transaction
2402       and release metadata locks.
2403     */
2404   }
2405 
2406 end:
2407   DBUG_RETURN(error);
2408 }
2409 
2410 
2411 /*
2412   Quickly remove a table.
2413 
2414   SYNOPSIS
2415     quick_rm_table()
2416       base                      The handlerton handle.
2417       db                        The database name.
2418       table_name                The table name.
2419       flags                     flags for build_table_filename().
2420 
2421   RETURN
2422     0           OK
2423     != 0        Error
2424 */
2425 
quick_rm_table(handlerton * base,const char * db,const char * table_name,uint flags)2426 bool quick_rm_table(handlerton *base,const char *db,
2427                     const char *table_name, uint flags)
2428 {
2429   char path[FN_REFLEN + 1];
2430   bool error= 0;
2431   DBUG_ENTER("quick_rm_table");
2432 
2433   uint path_length= build_table_filename(path, sizeof(path) - 1,
2434                                          db, table_name, reg_ext, flags);
2435   if (mysql_file_delete(key_file_frm, path, MYF(0)))
2436     error= 1; /* purecov: inspected */
2437   path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
2438   if (!(flags & FRM_ONLY))
2439     error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
2440   DBUG_RETURN(error);
2441 }
2442 
2443 /*
2444   Sort keys in the following order:
2445   - PRIMARY KEY
2446   - UNIQUE keys where all column are NOT NULL
2447   - UNIQUE keys that don't contain partial segments
2448   - Other UNIQUE keys
2449   - Normal keys
2450   - Fulltext keys
2451 
2452   This will make checking for duplicated keys faster and ensure that
2453   PRIMARY keys are prioritized.
2454 */
2455 
sort_keys(KEY * a,KEY * b)2456 static int sort_keys(KEY *a, KEY *b)
2457 {
2458   ulong a_flags= a->flags, b_flags= b->flags;
2459 
2460   if (a_flags & HA_NOSAME)
2461   {
2462     if (!(b_flags & HA_NOSAME))
2463       return -1;
2464     if ((a_flags ^ b_flags) & HA_NULL_PART_KEY)
2465     {
2466       /* Sort NOT NULL keys before other keys */
2467       return (a_flags & HA_NULL_PART_KEY) ? 1 : -1;
2468     }
2469     if (a->name == primary_key_name)
2470       return -1;
2471     if (b->name == primary_key_name)
2472       return 1;
2473     /* Sort keys don't containing partial segments before others */
2474     if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG)
2475       return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1;
2476   }
2477   else if (b_flags & HA_NOSAME)
2478     return 1;					// Prefer b
2479 
2480   if ((a_flags ^ b_flags) & HA_FULLTEXT)
2481   {
2482     return (a_flags & HA_FULLTEXT) ? 1 : -1;
2483   }
2484   /*
2485     Prefer original key order.	usable_key_parts contains here
2486     the original key position.
2487   */
2488   return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
2489 	  (a->usable_key_parts > b->usable_key_parts) ? 1 :
2490 	  0);
2491 }
2492 
2493 /*
2494   Check TYPELIB (set or enum) for duplicates
2495 
2496   SYNOPSIS
2497     check_duplicates_in_interval()
2498     set_or_name   "SET" or "ENUM" string for warning message
2499     name	  name of the checked column
2500     typelib	  list of values for the column
2501     dup_val_count  returns count of duplicate elements
2502 
2503   DESCRIPTION
2504     This function prints an warning for each value in list
2505     which has some duplicates on its right
2506 
2507   RETURN VALUES
2508     0             ok
2509     1             Error
2510 */
2511 
check_duplicates_in_interval(const char * set_or_name,const char * name,TYPELIB * typelib,CHARSET_INFO * cs,unsigned int * dup_val_count)2512 bool check_duplicates_in_interval(const char *set_or_name,
2513                                   const char *name, TYPELIB *typelib,
2514                                   CHARSET_INFO *cs, unsigned int *dup_val_count)
2515 {
2516   TYPELIB tmp= *typelib;
2517   const char **cur_value= typelib->type_names;
2518   unsigned int *cur_length= typelib->type_lengths;
2519   *dup_val_count= 0;
2520 
2521   for ( ; tmp.count > 1; cur_value++, cur_length++)
2522   {
2523     tmp.type_names++;
2524     tmp.type_lengths++;
2525     tmp.count--;
2526     if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
2527     {
2528       THD *thd= current_thd;
2529       ErrConvString err(*cur_value, *cur_length, cs);
2530       if ((current_thd->variables.sql_mode &
2531          (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
2532       {
2533         my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
2534                  name, err.ptr(), set_or_name);
2535         return 1;
2536       }
2537       push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_NOTE,
2538                           ER_DUPLICATED_VALUE_IN_TYPE,
2539                           ER(ER_DUPLICATED_VALUE_IN_TYPE),
2540                           name, err.ptr(), set_or_name);
2541       (*dup_val_count)++;
2542     }
2543   }
2544   return 0;
2545 }
2546 
2547 
2548 /*
2549   Check TYPELIB (set or enum) max and total lengths
2550 
2551   SYNOPSIS
2552     calculate_interval_lengths()
2553     cs            charset+collation pair of the interval
2554     typelib       list of values for the column
2555     max_length    length of the longest item
2556     tot_length    sum of the item lengths
2557 
2558   DESCRIPTION
2559     After this function call:
2560     - ENUM uses max_length
2561     - SET uses tot_length.
2562 
2563   RETURN VALUES
2564     void
2565 */
calculate_interval_lengths(CHARSET_INFO * cs,TYPELIB * interval,uint32 * max_length,uint32 * tot_length)2566 void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
2567                                 uint32 *max_length, uint32 *tot_length)
2568 {
2569   const char **pos;
2570   uint *len;
2571   *max_length= *tot_length= 0;
2572   for (pos= interval->type_names, len= interval->type_lengths;
2573        *pos ; pos++, len++)
2574   {
2575     size_t length= cs->cset->numchars(cs, *pos, *pos + *len);
2576     *tot_length+= length;
2577     set_if_bigger(*max_length, (uint32)length);
2578   }
2579 }
2580 
2581 
2582 /*
2583   Prepare a create_table instance for packing
2584 
2585   SYNOPSIS
2586     prepare_create_field()
2587     sql_field     field to prepare for packing
2588     blob_columns  count for BLOBs
2589     timestamps    count for timestamps
2590     table_flags   table flags
2591 
2592   DESCRIPTION
2593     This function prepares a Create_field instance.
2594     Fields such as pack_flag are valid after this call.
2595 
2596   RETURN VALUES
2597    0	ok
2598    1	Error
2599 */
2600 
prepare_create_field(Create_field * sql_field,uint * blob_columns,int * timestamps,int * timestamps_with_niladic,longlong table_flags)2601 int prepare_create_field(Create_field *sql_field,
2602 			 uint *blob_columns,
2603 			 int *timestamps, int *timestamps_with_niladic,
2604 			 longlong table_flags)
2605 {
2606   unsigned int dup_val_count;
2607   DBUG_ENTER("prepare_field");
2608 
2609   /*
2610     This code came from mysql_prepare_create_table.
2611     Indent preserved to make patching easier
2612   */
2613   DBUG_ASSERT(sql_field->charset);
2614 
2615   switch (sql_field->sql_type) {
2616   case MYSQL_TYPE_BLOB:
2617   case MYSQL_TYPE_MEDIUM_BLOB:
2618   case MYSQL_TYPE_TINY_BLOB:
2619   case MYSQL_TYPE_LONG_BLOB:
2620     sql_field->pack_flag=FIELDFLAG_BLOB |
2621       pack_length_to_packflag(sql_field->pack_length -
2622                               portable_sizeof_char_ptr);
2623     if (sql_field->charset->state & MY_CS_BINSORT)
2624       sql_field->pack_flag|=FIELDFLAG_BINARY;
2625     sql_field->length=8;			// Unireg field length
2626     sql_field->unireg_check=Field::BLOB_FIELD;
2627     (*blob_columns)++;
2628     break;
2629   case MYSQL_TYPE_GEOMETRY:
2630 #ifdef HAVE_SPATIAL
2631     if (!(table_flags & HA_CAN_GEOMETRY))
2632     {
2633       my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
2634                       MYF(0), "GEOMETRY");
2635       DBUG_RETURN(1);
2636     }
2637     sql_field->pack_flag=FIELDFLAG_GEOM |
2638       pack_length_to_packflag(sql_field->pack_length -
2639                               portable_sizeof_char_ptr);
2640     if (sql_field->charset->state & MY_CS_BINSORT)
2641       sql_field->pack_flag|=FIELDFLAG_BINARY;
2642     sql_field->length=8;			// Unireg field length
2643     sql_field->unireg_check=Field::BLOB_FIELD;
2644     (*blob_columns)++;
2645     break;
2646 #else
2647     my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
2648                     sym_group_geom.name, sym_group_geom.needed_define);
2649     DBUG_RETURN(1);
2650 #endif /*HAVE_SPATIAL*/
2651   case MYSQL_TYPE_VARCHAR:
2652 #ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
2653     if (table_flags & HA_NO_VARCHAR)
2654     {
2655       /* convert VARCHAR to CHAR because handler is not yet up to date */
2656       sql_field->sql_type=    MYSQL_TYPE_VAR_STRING;
2657       sql_field->pack_length= calc_pack_length(sql_field->sql_type,
2658                                                (uint) sql_field->length);
2659       if ((sql_field->length / sql_field->charset->mbmaxlen) >
2660           MAX_FIELD_CHARLENGTH)
2661       {
2662         my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
2663                         MYF(0), sql_field->field_name,
2664                         static_cast<ulong>(MAX_FIELD_CHARLENGTH));
2665         DBUG_RETURN(1);
2666       }
2667     }
2668 #endif
2669     /* fall through */
2670   case MYSQL_TYPE_STRING:
2671     sql_field->pack_flag=0;
2672     if (sql_field->charset->state & MY_CS_BINSORT)
2673       sql_field->pack_flag|=FIELDFLAG_BINARY;
2674     break;
2675   case MYSQL_TYPE_ENUM:
2676     sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
2677       FIELDFLAG_INTERVAL;
2678     if (sql_field->charset->state & MY_CS_BINSORT)
2679       sql_field->pack_flag|=FIELDFLAG_BINARY;
2680     sql_field->unireg_check=Field::INTERVAL_FIELD;
2681     if (check_duplicates_in_interval("ENUM",sql_field->field_name,
2682                                      sql_field->interval,
2683                                      sql_field->charset, &dup_val_count))
2684       DBUG_RETURN(1);
2685     break;
2686   case MYSQL_TYPE_SET:
2687     sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
2688       FIELDFLAG_BITFIELD;
2689     if (sql_field->charset->state & MY_CS_BINSORT)
2690       sql_field->pack_flag|=FIELDFLAG_BINARY;
2691     sql_field->unireg_check=Field::BIT_FIELD;
2692     if (check_duplicates_in_interval("SET",sql_field->field_name,
2693                                      sql_field->interval,
2694                                      sql_field->charset, &dup_val_count))
2695       DBUG_RETURN(1);
2696     /* Check that count of unique members is not more then 64 */
2697     if (sql_field->interval->count -  dup_val_count > sizeof(longlong)*8)
2698     {
2699        my_error(ER_TOO_BIG_SET, MYF(0), sql_field->field_name);
2700        DBUG_RETURN(1);
2701     }
2702     break;
2703   case MYSQL_TYPE_DATE:			// Rest of string types
2704   case MYSQL_TYPE_NEWDATE:
2705   case MYSQL_TYPE_TIME:
2706   case MYSQL_TYPE_DATETIME:
2707   case MYSQL_TYPE_NULL:
2708     sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
2709     break;
2710   case MYSQL_TYPE_BIT:
2711     /*
2712       We have sql_field->pack_flag already set here, see
2713       mysql_prepare_create_table().
2714     */
2715     break;
2716   case MYSQL_TYPE_NEWDECIMAL:
2717     sql_field->pack_flag=(FIELDFLAG_NUMBER |
2718                           (sql_field->flags & UNSIGNED_FLAG ? 0 :
2719                            FIELDFLAG_DECIMAL) |
2720                           (sql_field->flags & ZEROFILL_FLAG ?
2721                            FIELDFLAG_ZEROFILL : 0) |
2722                           (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
2723     break;
2724   case MYSQL_TYPE_TIMESTAMP:
2725     /* We should replace old TIMESTAMP fields with their newer analogs */
2726     if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
2727     {
2728       if (!*timestamps)
2729       {
2730         sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
2731         (*timestamps_with_niladic)++;
2732       }
2733       else
2734         sql_field->unireg_check= Field::NONE;
2735     }
2736     else if (sql_field->unireg_check != Field::NONE)
2737       (*timestamps_with_niladic)++;
2738 
2739     (*timestamps)++;
2740     /* fall-through */
2741   default:
2742     sql_field->pack_flag=(FIELDFLAG_NUMBER |
2743                           (sql_field->flags & UNSIGNED_FLAG ? 0 :
2744                            FIELDFLAG_DECIMAL) |
2745                           (sql_field->flags & ZEROFILL_FLAG ?
2746                            FIELDFLAG_ZEROFILL : 0) |
2747                           f_settype((uint) sql_field->sql_type) |
2748                           (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
2749     break;
2750   }
2751   if (!(sql_field->flags & NOT_NULL_FLAG))
2752     sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
2753   if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
2754     sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
2755   DBUG_RETURN(0);
2756 }
2757 
2758 
2759 /*
2760   Get character set from field object generated by parser using
2761   default values when not set.
2762 
2763   SYNOPSIS
2764     get_sql_field_charset()
2765     sql_field                 The sql_field object
2766     create_info               Info generated by parser
2767 
2768   RETURN VALUES
2769     cs                        Character set
2770 */
2771 
get_sql_field_charset(Create_field * sql_field,HA_CREATE_INFO * create_info)2772 CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
2773                                     HA_CREATE_INFO *create_info)
2774 {
2775   CHARSET_INFO *cs= sql_field->charset;
2776 
2777   if (!cs)
2778     cs= create_info->default_table_charset;
2779   /*
2780     table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname
2781     if we want change character set for all varchar/char columns.
2782     But the table charset must not affect the BLOB fields, so don't
2783     allow to change my_charset_bin to somethig else.
2784   */
2785   if (create_info->table_charset && cs != &my_charset_bin)
2786     cs= create_info->table_charset;
2787   return cs;
2788 }
2789 
2790 
check_duplicate_warning(THD * thd,char * msg,ulong length)2791 bool check_duplicate_warning(THD *thd, char *msg, ulong length)
2792 {
2793   List_iterator_fast<MYSQL_ERROR> it(thd->warning_info->warn_list());
2794   MYSQL_ERROR *err;
2795   while ((err= it++))
2796   {
2797     if (strncmp(msg, err->get_message_text(), length) == 0)
2798     {
2799       return true;
2800     }
2801   }
2802   return false;
2803 }
2804 
2805 
2806 /*
2807   Preparation for table creation
2808 
2809   SYNOPSIS
2810     mysql_prepare_create_table()
2811       thd                       Thread object.
2812       create_info               Create information (like MAX_ROWS).
2813       alter_info                List of columns and indexes to create
2814       tmp_table                 If a temporary table is to be created.
2815       db_options          INOUT Table options (like HA_OPTION_PACK_RECORD).
2816       file                      The handler for the new table.
2817       key_info_buffer     OUT   An array of KEY structs for the indexes.
2818       key_count           OUT   The number of elements in the array.
2819       select_field_count        The number of fields coming from a select table.
2820 
2821   DESCRIPTION
2822     Prepares the table and key structures for table creation.
2823 
2824   NOTES
2825     sets create_info->varchar if the table has a varchar
2826 
2827   RETURN VALUES
2828     FALSE    OK
2829     TRUE     error
2830 */
2831 
2832 static int
mysql_prepare_create_table(THD * thd,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)2833 mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
2834                            Alter_info *alter_info,
2835                            bool tmp_table,
2836                            uint *db_options,
2837                            handler *file, KEY **key_info_buffer,
2838                            uint *key_count, int select_field_count)
2839 {
2840   const char	*key_name;
2841   Create_field	*sql_field,*dup_field;
2842   uint		field,null_fields,blob_columns,max_key_length;
2843   ulong		record_offset= 0;
2844   KEY		*key_info;
2845   KEY_PART_INFO *key_part_info;
2846   int		timestamps= 0, timestamps_with_niladic= 0;
2847   int		field_no,dup_no;
2848   int		select_field_pos,auto_increment=0;
2849   List_iterator<Create_field> it(alter_info->create_list);
2850   List_iterator<Create_field> it2(alter_info->create_list);
2851   uint total_uneven_bit_length= 0;
2852   DBUG_ENTER("mysql_prepare_create_table");
2853 
2854   LEX_STRING* connect_string = &create_info->connect_string;
2855   if (connect_string->length != 0 &&
2856       connect_string->length > CONNECT_STRING_MAXLEN &&
2857       (system_charset_info->cset->charpos(system_charset_info,
2858                                           connect_string->str,
2859                                           (connect_string->str +
2860                                            connect_string->length),
2861                                           CONNECT_STRING_MAXLEN)
2862       < connect_string->length))
2863   {
2864     my_error(ER_WRONG_STRING_LENGTH, MYF(0),
2865              connect_string->str, "CONNECTION", CONNECT_STRING_MAXLEN);
2866     DBUG_RETURN(TRUE);
2867   }
2868 
2869   select_field_pos= alter_info->create_list.elements - select_field_count;
2870   null_fields=blob_columns=0;
2871   create_info->varchar= 0;
2872   max_key_length= file->max_key_length();
2873 
2874   for (field_no=0; (sql_field=it++) ; field_no++)
2875   {
2876     CHARSET_INFO *save_cs;
2877 
2878     /*
2879       Initialize length from its original value (number of characters),
2880       which was set in the parser. This is necessary if we're
2881       executing a prepared statement for the second time.
2882     */
2883     sql_field->length= sql_field->char_length;
2884     save_cs= sql_field->charset= get_sql_field_charset(sql_field,
2885                                                        create_info);
2886     if ((sql_field->flags & BINCMP_FLAG) &&
2887 	!(sql_field->charset= get_charset_by_csname(sql_field->charset->csname,
2888 						    MY_CS_BINSORT,MYF(0))))
2889     {
2890       char tmp[65];
2891       strmake(strmake(tmp, save_cs->csname, sizeof(tmp)-4),
2892               STRING_WITH_LEN("_bin"));
2893       my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
2894       DBUG_RETURN(TRUE);
2895     }
2896 
2897     /*
2898       Convert the default value from client character
2899       set into the column character set if necessary.
2900     */
2901     if (sql_field->def &&
2902         save_cs != sql_field->def->collation.collation &&
2903         (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
2904          sql_field->sql_type == MYSQL_TYPE_STRING ||
2905          sql_field->sql_type == MYSQL_TYPE_SET ||
2906          sql_field->sql_type == MYSQL_TYPE_ENUM))
2907     {
2908       /*
2909         Starting from 5.1 we work here with a copy of Create_field
2910         created by the caller, not with the instance that was
2911         originally created during parsing. It's OK to create
2912         a temporary item and initialize with it a member of the
2913         copy -- this item will be thrown away along with the copy
2914         at the end of execution, and thus not introduce a dangling
2915         pointer in the parsed tree of a prepared statement or a
2916         stored procedure statement.
2917       */
2918       sql_field->def= sql_field->def->safe_charset_converter(save_cs);
2919 
2920       if (sql_field->def == NULL)
2921       {
2922         /* Could not convert */
2923         my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
2924         DBUG_RETURN(TRUE);
2925       }
2926     }
2927 
2928     if (sql_field->sql_type == MYSQL_TYPE_SET ||
2929         sql_field->sql_type == MYSQL_TYPE_ENUM)
2930     {
2931       uint32 dummy;
2932       CHARSET_INFO *cs= sql_field->charset;
2933       TYPELIB *interval= sql_field->interval;
2934 
2935       /*
2936         Create typelib from interval_list, and if necessary
2937         convert strings from client character set to the
2938         column character set.
2939       */
2940       if (!interval)
2941       {
2942         /*
2943           Create the typelib in runtime memory - we will free the
2944           occupied memory at the same time when we free this
2945           sql_field -- at the end of execution.
2946         */
2947         interval= sql_field->interval= typelib(thd->mem_root,
2948                                                sql_field->interval_list);
2949         List_iterator<String> int_it(sql_field->interval_list);
2950         String conv, *tmp;
2951         char comma_buf[4]; /* 4 bytes for utf32 */
2952         int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf,
2953                                           (uchar*) comma_buf +
2954                                           sizeof(comma_buf));
2955         DBUG_ASSERT(comma_length > 0);
2956         for (uint i= 0; (tmp= int_it++); i++)
2957         {
2958           size_t lengthsp;
2959           if (String::needs_conversion(tmp->length(), tmp->charset(),
2960                                        cs, &dummy))
2961           {
2962             uint cnv_errs;
2963             conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
2964             interval->type_names[i]= strmake_root(thd->mem_root, conv.ptr(),
2965                                                   conv.length());
2966             interval->type_lengths[i]= conv.length();
2967           }
2968 
2969           // Strip trailing spaces.
2970           lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
2971                                        interval->type_lengths[i]);
2972           interval->type_lengths[i]= lengthsp;
2973           ((uchar *)interval->type_names[i])[lengthsp]= '\0';
2974           if (sql_field->sql_type == MYSQL_TYPE_SET)
2975           {
2976             if (cs->coll->instr(cs, interval->type_names[i],
2977                                 interval->type_lengths[i],
2978                                 comma_buf, comma_length, NULL, 0))
2979             {
2980               ErrConvString err(tmp->ptr(), tmp->length(), cs);
2981               my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr());
2982               DBUG_RETURN(TRUE);
2983             }
2984           }
2985         }
2986         sql_field->interval_list.empty(); // Don't need interval_list anymore
2987       }
2988 
2989       if (sql_field->sql_type == MYSQL_TYPE_SET)
2990       {
2991         uint32 field_length;
2992         if (sql_field->def != NULL)
2993         {
2994           char *not_used;
2995           uint not_used2;
2996           bool not_found= 0;
2997           String str, *def= sql_field->def->val_str(&str);
2998           if (def == NULL) /* SQL "NULL" maps to NULL */
2999           {
3000             if ((sql_field->flags & NOT_NULL_FLAG) != 0)
3001             {
3002               my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3003               DBUG_RETURN(TRUE);
3004             }
3005 
3006             /* else, NULL is an allowed value */
3007             (void) find_set(interval, NULL, 0,
3008                             cs, &not_used, &not_used2, &not_found);
3009           }
3010           else /* not NULL */
3011           {
3012             (void) find_set(interval, def->ptr(), def->length(),
3013                             cs, &not_used, &not_used2, &not_found);
3014           }
3015 
3016           if (not_found)
3017           {
3018             my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3019             DBUG_RETURN(TRUE);
3020           }
3021         }
3022         calculate_interval_lengths(cs, interval, &dummy, &field_length);
3023         sql_field->length= field_length + (interval->count - 1);
3024       }
3025       else  /* MYSQL_TYPE_ENUM */
3026       {
3027         uint32 field_length;
3028         DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
3029         if (sql_field->def != NULL)
3030         {
3031           String str, *def= sql_field->def->val_str(&str);
3032           if (def == NULL) /* SQL "NULL" maps to NULL */
3033           {
3034             if ((sql_field->flags & NOT_NULL_FLAG) != 0)
3035             {
3036               my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3037               DBUG_RETURN(TRUE);
3038             }
3039 
3040             /* else, the defaults yield the correct length for NULLs. */
3041           }
3042           else /* not NULL */
3043           {
3044             def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
3045             if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
3046             {
3047               my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3048               DBUG_RETURN(TRUE);
3049             }
3050           }
3051         }
3052         calculate_interval_lengths(cs, interval, &field_length, &dummy);
3053         sql_field->length= field_length;
3054       }
3055       set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
3056     }
3057 
3058     if (sql_field->sql_type == MYSQL_TYPE_BIT)
3059     {
3060       sql_field->pack_flag= FIELDFLAG_NUMBER;
3061       if (file->ha_table_flags() & HA_CAN_BIT_FIELD)
3062         total_uneven_bit_length+= sql_field->length & 7;
3063       else
3064         sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
3065     }
3066 
3067     sql_field->create_length_to_internal_length();
3068     if (prepare_blob_field(thd, sql_field))
3069       DBUG_RETURN(TRUE);
3070 
3071     if (!(sql_field->flags & NOT_NULL_FLAG))
3072       null_fields++;
3073 
3074     if (check_column_name(sql_field->field_name))
3075     {
3076       my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
3077       DBUG_RETURN(TRUE);
3078     }
3079 
3080     /* Check if we have used the same field name before */
3081     for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
3082     {
3083       if (my_strcasecmp(system_charset_info,
3084 			sql_field->field_name,
3085 			dup_field->field_name) == 0)
3086       {
3087 	/*
3088 	  If this was a CREATE ... SELECT statement, accept a field
3089 	  redefinition if we are changing a field in the SELECT part
3090 	*/
3091 	if (field_no < select_field_pos || dup_no >= select_field_pos)
3092 	{
3093 	  my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name);
3094 	  DBUG_RETURN(TRUE);
3095 	}
3096 	else
3097 	{
3098 	  /* Field redefined */
3099 
3100           /*
3101             If we are replacing a BIT field, revert the increment
3102             of total_uneven_bit_length that was done above.
3103           */
3104           if (sql_field->sql_type == MYSQL_TYPE_BIT &&
3105               file->ha_table_flags() & HA_CAN_BIT_FIELD)
3106             total_uneven_bit_length-= sql_field->length & 7;
3107 
3108 	  sql_field->def=		dup_field->def;
3109 	  sql_field->sql_type=		dup_field->sql_type;
3110 
3111           /*
3112             If we are replacing a field with a BIT field, we need
3113             to initialize pack_flag. Note that we do not need to
3114             increment total_uneven_bit_length here as this dup_field
3115             has already been processed.
3116           */
3117           if (sql_field->sql_type == MYSQL_TYPE_BIT)
3118           {
3119             sql_field->pack_flag= FIELDFLAG_NUMBER;
3120             if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD))
3121               sql_field->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
3122           }
3123 
3124 	  sql_field->charset=		(dup_field->charset ?
3125 					 dup_field->charset :
3126 					 create_info->default_table_charset);
3127 	  sql_field->length=		dup_field->char_length;
3128           sql_field->pack_length=	dup_field->pack_length;
3129           sql_field->key_length=	dup_field->key_length;
3130 	  sql_field->decimals=		dup_field->decimals;
3131 	  sql_field->create_length_to_internal_length();
3132 	  sql_field->unireg_check=	dup_field->unireg_check;
3133           /*
3134             We're making one field from two, the result field will have
3135             dup_field->flags as flags. If we've incremented null_fields
3136             because of sql_field->flags, decrement it back.
3137           */
3138           if (!(sql_field->flags & NOT_NULL_FLAG))
3139             null_fields--;
3140 	  sql_field->flags=		dup_field->flags;
3141           sql_field->interval=          dup_field->interval;
3142 	  it2.remove();			// Remove first (create) definition
3143 	  select_field_pos--;
3144 	  break;
3145 	}
3146       }
3147     }
3148     /* Don't pack rows in old tables if the user has requested this */
3149     if ((sql_field->flags & BLOB_FLAG) ||
3150 	(sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
3151 	create_info->row_type != ROW_TYPE_FIXED))
3152       (*db_options)|= HA_OPTION_PACK_RECORD;
3153     it2.rewind();
3154   }
3155 
3156   /* record_offset will be increased with 'length-of-null-bits' later */
3157   record_offset= 0;
3158   null_fields+= total_uneven_bit_length;
3159 
3160   it.rewind();
3161   while ((sql_field=it++))
3162   {
3163     DBUG_ASSERT(sql_field->charset != 0);
3164 
3165     if (prepare_create_field(sql_field, &blob_columns,
3166 			     &timestamps, &timestamps_with_niladic,
3167 			     file->ha_table_flags()))
3168       DBUG_RETURN(TRUE);
3169     if (sql_field->sql_type == MYSQL_TYPE_VARCHAR)
3170       create_info->varchar= TRUE;
3171     sql_field->offset= record_offset;
3172     if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
3173       auto_increment++;
3174     record_offset+= sql_field->pack_length;
3175   }
3176   if (timestamps_with_niladic > 1)
3177   {
3178     my_message(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS,
3179                ER(ER_TOO_MUCH_AUTO_TIMESTAMP_COLS), MYF(0));
3180     DBUG_RETURN(TRUE);
3181   }
3182   if (auto_increment > 1)
3183   {
3184     my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
3185     DBUG_RETURN(TRUE);
3186   }
3187   if (auto_increment &&
3188       (file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
3189   {
3190     my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
3191                ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
3192     DBUG_RETURN(TRUE);
3193   }
3194 
3195   if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
3196   {
3197     my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
3198                MYF(0));
3199     DBUG_RETURN(TRUE);
3200   }
3201 
3202   /*
3203    CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows
3204    inserted in the created table depends on the order of the rows fetched
3205    from the select tables. This order may differ on master and slave. We
3206    therefore mark it as unsafe.
3207   */
3208   if (select_field_count > 0 && auto_increment)
3209   thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
3210 
3211   /* Create keys */
3212 
3213   List_iterator<Key> key_iterator(alter_info->key_list);
3214   List_iterator<Key> key_iterator2(alter_info->key_list);
3215   uint key_parts=0, fk_key_count=0;
3216   bool primary_key=0,unique_key=0;
3217   Key *key, *key2;
3218   uint tmp, key_number;
3219   /* special marker for keys to be ignored */
3220   static char ignore_key[1];
3221 
3222   /* Calculate number of key segements */
3223   *key_count= 0;
3224 
3225   while ((key=key_iterator++))
3226   {
3227     DBUG_PRINT("info", ("key name: '%s'  type: %d", key->name.str ? key->name.str :
3228                         "(none)" , key->type));
3229     if (key->type == Key::FOREIGN_KEY)
3230     {
3231       fk_key_count++;
3232       Foreign_key *fk_key= (Foreign_key*) key;
3233       if (fk_key->ref_columns.elements &&
3234 	  fk_key->ref_columns.elements != fk_key->columns.elements)
3235       {
3236         my_error(ER_WRONG_FK_DEF, MYF(0),
3237                  (fk_key->name.str ? fk_key->name.str :
3238                                      "foreign key without name"),
3239                  ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
3240 	DBUG_RETURN(TRUE);
3241       }
3242       continue;
3243     }
3244     (*key_count)++;
3245     tmp=file->max_key_parts();
3246     if (key->columns.elements > tmp)
3247     {
3248       my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
3249       DBUG_RETURN(TRUE);
3250     }
3251     if (check_string_char_length(&key->name, "", NAME_CHAR_LEN,
3252                                  system_charset_info, 1))
3253     {
3254       my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
3255       DBUG_RETURN(TRUE);
3256     }
3257     key_iterator2.rewind ();
3258     if (key->type != Key::FOREIGN_KEY)
3259     {
3260       while ((key2 = key_iterator2++) != key)
3261       {
3262 	/*
3263           foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is
3264           'generated', and a generated key is a prefix of the other key.
3265           Then we do not need the generated shorter key.
3266         */
3267         if ((key2->type != Key::FOREIGN_KEY &&
3268              key2->name.str != ignore_key &&
3269              !foreign_key_prefix(key, key2)))
3270         {
3271           /* TODO: issue warning message */
3272           /* mark that the generated key should be ignored */
3273           if (!key2->generated ||
3274               (key->generated && key->columns.elements <
3275                key2->columns.elements))
3276             key->name.str= ignore_key;
3277           else
3278           {
3279             key2->name.str= ignore_key;
3280             key_parts-= key2->columns.elements;
3281             (*key_count)--;
3282           }
3283           break;
3284         }
3285       }
3286     }
3287     if (key->name.str != ignore_key)
3288       key_parts+=key->columns.elements;
3289     else
3290       (*key_count)--;
3291     if (key->name.str && !tmp_table && (key->type != Key::PRIMARY) &&
3292 	!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
3293     {
3294       my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
3295       DBUG_RETURN(TRUE);
3296     }
3297   }
3298   tmp=file->max_keys();
3299   if (*key_count > tmp)
3300   {
3301     my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
3302     DBUG_RETURN(TRUE);
3303   }
3304 
3305   (*key_info_buffer)= key_info= (KEY*) sql_calloc(sizeof(KEY) * (*key_count));
3306   key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
3307   if (!*key_info_buffer || ! key_part_info)
3308     DBUG_RETURN(TRUE);				// Out of memory
3309 
3310   key_iterator.rewind();
3311   key_number=0;
3312   for (; (key=key_iterator++) ; key_number++)
3313   {
3314     uint key_length=0;
3315     Key_part_spec *column;
3316 
3317     if (key->name.str == ignore_key)
3318     {
3319       /* ignore redundant keys */
3320       do
3321 	key=key_iterator++;
3322       while (key && key->name.str == ignore_key);
3323       if (!key)
3324 	break;
3325     }
3326 
3327     switch (key->type) {
3328     case Key::MULTIPLE:
3329 	key_info->flags= 0;
3330 	break;
3331     case Key::FULLTEXT:
3332 	key_info->flags= HA_FULLTEXT;
3333 	if ((key_info->parser_name= &key->key_create_info.parser_name)->str)
3334           key_info->flags|= HA_USES_PARSER;
3335         else
3336           key_info->parser_name= 0;
3337 	break;
3338     case Key::SPATIAL:
3339 #ifdef HAVE_SPATIAL
3340 	key_info->flags= HA_SPATIAL;
3341 	break;
3342 #else
3343 	my_error(ER_FEATURE_DISABLED, MYF(0),
3344                  sym_group_geom.name, sym_group_geom.needed_define);
3345 	DBUG_RETURN(TRUE);
3346 #endif
3347     case Key::FOREIGN_KEY:
3348       key_number--;				// Skip this key
3349       continue;
3350     default:
3351       key_info->flags = HA_NOSAME;
3352       break;
3353     }
3354     if (key->generated)
3355       key_info->flags|= HA_GENERATED_KEY;
3356 
3357     key_info->key_parts=(uint8) key->columns.elements;
3358     key_info->key_part=key_part_info;
3359     key_info->usable_key_parts= key_number;
3360     key_info->algorithm= key->key_create_info.algorithm;
3361 
3362     if (key->type == Key::FULLTEXT)
3363     {
3364       if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
3365       {
3366 	my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
3367                    MYF(0));
3368 	DBUG_RETURN(TRUE);
3369       }
3370     }
3371     /*
3372        Make SPATIAL to be RTREE by default
3373        SPATIAL only on BLOB or at least BINARY, this
3374        actually should be replaced by special GEOM type
3375        in near future when new frm file is ready
3376        checking for proper key parts number:
3377     */
3378 
3379     /* TODO: Add proper checks if handler supports key_type and algorithm */
3380     if (key_info->flags & HA_SPATIAL)
3381     {
3382       if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
3383       {
3384         my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
3385                    MYF(0));
3386         DBUG_RETURN(TRUE);
3387       }
3388       if (key_info->key_parts != 1)
3389       {
3390 	my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
3391 	DBUG_RETURN(TRUE);
3392       }
3393     }
3394     else if (key_info->algorithm == HA_KEY_ALG_RTREE)
3395     {
3396 #ifdef HAVE_RTREE_KEYS
3397       if ((key_info->key_parts & 1) == 1)
3398       {
3399 	my_error(ER_WRONG_ARGUMENTS, MYF(0), "RTREE INDEX");
3400 	DBUG_RETURN(TRUE);
3401       }
3402       /* TODO: To be deleted */
3403       my_error(ER_NOT_SUPPORTED_YET, MYF(0), "RTREE INDEX");
3404       DBUG_RETURN(TRUE);
3405 #else
3406       my_error(ER_FEATURE_DISABLED, MYF(0),
3407                sym_group_rtree.name, sym_group_rtree.needed_define);
3408       DBUG_RETURN(TRUE);
3409 #endif
3410     }
3411 
3412     /* Take block size from key part or table part */
3413     /*
3414       TODO: Add warning if block size changes. We can't do it here, as
3415       this may depend on the size of the key
3416     */
3417     key_info->block_size= (key->key_create_info.block_size ?
3418                            key->key_create_info.block_size :
3419                            create_info->key_block_size);
3420 
3421     if (key_info->block_size)
3422       key_info->flags|= HA_USES_BLOCK_SIZE;
3423 
3424     List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
3425     CHARSET_INFO *ft_key_charset=0;  // for FULLTEXT
3426     for (uint column_nr=0 ; (column=cols++) ; column_nr++)
3427     {
3428       Key_part_spec *dup_column;
3429 
3430       it.rewind();
3431       field=0;
3432       while ((sql_field=it++) &&
3433 	     my_strcasecmp(system_charset_info,
3434 			   column->field_name.str,
3435 			   sql_field->field_name))
3436 	field++;
3437       if (!sql_field)
3438       {
3439 	my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name.str);
3440 	DBUG_RETURN(TRUE);
3441       }
3442       while ((dup_column= cols2++) != column)
3443       {
3444         if (!my_strcasecmp(system_charset_info,
3445 	     	           column->field_name.str, dup_column->field_name.str))
3446 	{
3447 	  my_printf_error(ER_DUP_FIELDNAME,
3448 			  ER(ER_DUP_FIELDNAME),MYF(0),
3449 			  column->field_name.str);
3450 	  DBUG_RETURN(TRUE);
3451 	}
3452       }
3453       cols2.rewind();
3454       if (key->type == Key::FULLTEXT)
3455       {
3456 	if ((sql_field->sql_type != MYSQL_TYPE_STRING &&
3457 	     sql_field->sql_type != MYSQL_TYPE_VARCHAR &&
3458 	     !f_is_blob(sql_field->pack_flag)) ||
3459 	    sql_field->charset == &my_charset_bin ||
3460 	    sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
3461 	    (ft_key_charset && sql_field->charset != ft_key_charset))
3462 	{
3463 	    my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
3464 	    DBUG_RETURN(-1);
3465 	}
3466 	ft_key_charset=sql_field->charset;
3467 	/*
3468 	  for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
3469 	  code anyway, and 0 (set to column width later) for char's. it has
3470 	  to be correct col width for char's, as char data are not prefixed
3471 	  with length (unlike blobs, where ft code takes data length from a
3472 	  data prefix, ignoring column->length).
3473 	*/
3474 	column->length=test(f_is_blob(sql_field->pack_flag));
3475       }
3476       else
3477       {
3478 	column->length*= sql_field->charset->mbmaxlen;
3479 
3480         if (key->type == Key::SPATIAL)
3481         {
3482           if (column->length)
3483           {
3484             my_error(ER_WRONG_SUB_KEY, MYF(0));
3485             DBUG_RETURN(TRUE);
3486           }
3487           if (!f_is_geom(sql_field->pack_flag))
3488           {
3489             my_error(ER_SPATIAL_MUST_HAVE_GEOM_COL, MYF(0));
3490             DBUG_RETURN(TRUE);
3491           }
3492         }
3493 
3494 	if (f_is_blob(sql_field->pack_flag) ||
3495             (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
3496 	{
3497 	  if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
3498 	  {
3499 	    my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
3500 	    DBUG_RETURN(TRUE);
3501 	  }
3502           if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
3503               Field::GEOM_POINT)
3504             column->length= MAX_LEN_GEOM_POINT_FIELD;
3505 	  if (!column->length)
3506 	  {
3507 	    my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
3508 	    DBUG_RETURN(TRUE);
3509 	  }
3510 	}
3511 #ifdef HAVE_SPATIAL
3512 	if (key->type == Key::SPATIAL)
3513 	{
3514 	  if (!column->length)
3515 	  {
3516 	    /*
3517               4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
3518               Lately we'll extend this code to support more dimensions
3519 	    */
3520 	    column->length= 4*sizeof(double);
3521 	  }
3522 	}
3523 #endif
3524 	if (!(sql_field->flags & NOT_NULL_FLAG))
3525 	{
3526 	  if (key->type == Key::PRIMARY)
3527 	  {
3528 	    /* Implicitly set primary key fields to NOT NULL for ISO conf. */
3529 	    sql_field->flags|= NOT_NULL_FLAG;
3530 	    sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
3531             null_fields--;
3532 	  }
3533 	  else
3534           {
3535             key_info->flags|= HA_NULL_PART_KEY;
3536             if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
3537             {
3538               my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
3539               DBUG_RETURN(TRUE);
3540             }
3541             if (key->type == Key::SPATIAL)
3542             {
3543               my_message(ER_SPATIAL_CANT_HAVE_NULL,
3544                          ER(ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
3545               DBUG_RETURN(TRUE);
3546             }
3547           }
3548 	}
3549 	if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
3550 	{
3551 	  if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
3552 	    auto_increment--;			// Field is used
3553 	}
3554       }
3555 
3556       key_part_info->fieldnr= field;
3557       key_part_info->offset=  (uint16) sql_field->offset;
3558       key_part_info->key_type=sql_field->pack_flag;
3559       uint key_part_length= sql_field->key_length;
3560 
3561       if (column->length)
3562       {
3563 	if (f_is_blob(sql_field->pack_flag))
3564 	{
3565           key_part_length= column->length;
3566           /*
3567             There is a possibility that the given prefix length is less
3568             than the engine max key part length, but still greater
3569             than the BLOB field max size. We handle this case
3570             using the max_field_size variable below.
3571           */
3572           uint max_field_size= sql_field->key_length * sql_field->charset->mbmaxlen;
3573 	  if ((max_field_size && key_part_length > max_field_size) ||
3574               key_part_length > max_key_length ||
3575 	      key_part_length > file->max_key_part_length())
3576 	  {
3577             // Given prefix length is too large, adjust it.
3578 	    key_part_length= min(max_key_length, file->max_key_part_length());
3579 	    if (max_field_size)
3580               key_part_length= min(key_part_length, max_field_size);
3581 	    if (key->type == Key::MULTIPLE)
3582 	    {
3583 	      /* not a critical problem */
3584 	      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
3585 		           ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
3586                            key_part_length);
3587               /* Align key length to multibyte char boundary */
3588               key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
3589 	    }
3590 	    else
3591 	    {
3592 	      my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
3593 	      DBUG_RETURN(TRUE);
3594 	    }
3595 	  }
3596 	}
3597         // Catch invalid use of partial keys
3598 	else if (!f_is_geom(sql_field->pack_flag) &&
3599                  // is the key partial?
3600                  column->length != key_part_length &&
3601                  // is prefix length bigger than field length?
3602                  (column->length > key_part_length ||
3603                   // can the field have a partial key?
3604                   !Field::type_can_have_key_part (sql_field->sql_type) ||
3605                   // a packed field can't be used in a partial key
3606                   f_is_packed(sql_field->pack_flag) ||
3607                   // does the storage engine allow prefixed search?
3608                   ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
3609                    // and is this a 'unique' key?
3610                    (key_info->flags & HA_NOSAME))))
3611         {
3612 	  my_message(ER_WRONG_SUB_KEY, ER(ER_WRONG_SUB_KEY), MYF(0));
3613 	  DBUG_RETURN(TRUE);
3614 	}
3615 	else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
3616 	  key_part_length= column->length;
3617       }
3618       else if (key_part_length == 0)
3619       {
3620 	my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
3621 	  DBUG_RETURN(TRUE);
3622       }
3623       if (key_part_length > file->max_key_part_length() &&
3624           key->type != Key::FULLTEXT)
3625       {
3626         key_part_length= file->max_key_part_length();
3627 	if (key->type == Key::MULTIPLE)
3628 	{
3629 	  /* not a critical problem */
3630 	  push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
3631 		       ER_TOO_LONG_KEY, ER(ER_TOO_LONG_KEY),
3632                        key_part_length);
3633           /* Align key length to multibyte char boundary */
3634           key_part_length-= key_part_length % sql_field->charset->mbmaxlen;
3635 	}
3636 	else
3637 	{
3638 	  my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
3639 	  DBUG_RETURN(TRUE);
3640 	}
3641       }
3642       key_part_info->length= (uint16) key_part_length;
3643       /* Use packed keys for long strings on the first column */
3644       if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
3645           !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) &&
3646 	  (key_part_length >= KEY_DEFAULT_PACK_LENGTH &&
3647 	   (sql_field->sql_type == MYSQL_TYPE_STRING ||
3648 	    sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
3649 	    sql_field->pack_flag & FIELDFLAG_BLOB)))
3650       {
3651 	if ((column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB)) ||
3652             sql_field->sql_type == MYSQL_TYPE_VARCHAR)
3653 	  key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
3654 	else
3655 	  key_info->flags|= HA_PACK_KEY;
3656       }
3657       /* Check if the key segment is partial, set the key flag accordingly */
3658       if (key_part_length != sql_field->key_length)
3659         key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
3660 
3661       key_length+= key_part_length;
3662       key_part_info++;
3663 
3664       /* Create the key name based on the first column (if not given) */
3665       if (column_nr == 0)
3666       {
3667 	if (key->type == Key::PRIMARY)
3668 	{
3669 	  if (primary_key)
3670 	  {
3671 	    my_message(ER_MULTIPLE_PRI_KEY, ER(ER_MULTIPLE_PRI_KEY),
3672                        MYF(0));
3673 	    DBUG_RETURN(TRUE);
3674 	  }
3675 	  key_name=primary_key_name;
3676 	  primary_key=1;
3677 	}
3678 	else if (!(key_name= key->name.str))
3679 	  key_name=make_unique_key_name(sql_field->field_name,
3680 					*key_info_buffer, key_info);
3681 	if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
3682 	{
3683 	  my_error(ER_DUP_KEYNAME, MYF(0), key_name);
3684 	  DBUG_RETURN(TRUE);
3685 	}
3686 	key_info->name=(char*) key_name;
3687       }
3688     }
3689     if (!key_info->name || check_column_name(key_info->name))
3690     {
3691       my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name);
3692       DBUG_RETURN(TRUE);
3693     }
3694     if (!(key_info->flags & HA_NULL_PART_KEY))
3695       unique_key=1;
3696     key_info->key_length=(uint16) key_length;
3697     if (key_length > max_key_length && key->type != Key::FULLTEXT)
3698     {
3699       my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
3700       DBUG_RETURN(TRUE);
3701     }
3702 
3703     uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
3704                                            key->key_create_info.comment.str,
3705                                            key->key_create_info.comment.str +
3706                                            key->key_create_info.comment.length,
3707                                            INDEX_COMMENT_MAXLEN);
3708 
3709     if (tmp_len < key->key_create_info.comment.length)
3710     {
3711       if ((thd->variables.sql_mode &
3712            (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
3713       {
3714         my_error(ER_TOO_LONG_INDEX_COMMENT, MYF(0),
3715                  key_info->name, static_cast<ulong>(INDEX_COMMENT_MAXLEN));
3716         DBUG_RETURN(-1);
3717       }
3718       char warn_buff[MYSQL_ERRMSG_SIZE];
3719       my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_INDEX_COMMENT),
3720                   key_info->name, static_cast<ulong>(INDEX_COMMENT_MAXLEN));
3721       /* do not push duplicate warnings */
3722       if (!check_duplicate_warning(thd, warn_buff, strlen(warn_buff)))
3723         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
3724                      ER_TOO_LONG_INDEX_COMMENT, warn_buff);
3725 
3726       key->key_create_info.comment.length= tmp_len;
3727     }
3728 
3729     key_info->comment.length= key->key_create_info.comment.length;
3730     if (key_info->comment.length > 0)
3731     {
3732       key_info->flags|= HA_USES_COMMENT;
3733       key_info->comment.str= key->key_create_info.comment.str;
3734     }
3735 
3736     key_info++;
3737   }
3738   if (!unique_key && !primary_key &&
3739       (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY))
3740   {
3741     my_message(ER_REQUIRES_PRIMARY_KEY, ER(ER_REQUIRES_PRIMARY_KEY), MYF(0));
3742     DBUG_RETURN(TRUE);
3743   }
3744   if (auto_increment > 0)
3745   {
3746     my_message(ER_WRONG_AUTO_KEY, ER(ER_WRONG_AUTO_KEY), MYF(0));
3747     DBUG_RETURN(TRUE);
3748   }
3749   /* Sort keys in optimized order */
3750   my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
3751 	   (qsort_cmp) sort_keys);
3752   create_info->null_bits= null_fields;
3753 
3754   /* Check fields. */
3755   it.rewind();
3756   while ((sql_field=it++))
3757   {
3758     Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
3759 
3760     if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
3761         !sql_field->def &&
3762         sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
3763         (sql_field->flags & NOT_NULL_FLAG) &&
3764         (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
3765     {
3766       /*
3767         An error should be reported if:
3768           - NO_ZERO_DATE SQL mode is active;
3769           - there is no explicit DEFAULT clause (default column value);
3770           - this is a TIMESTAMP column;
3771           - the column is not NULL;
3772           - this is not the DEFAULT CURRENT_TIMESTAMP column.
3773 
3774         In other words, an error should be reported if
3775           - NO_ZERO_DATE SQL mode is active;
3776           - the column definition is equivalent to
3777             'column_name TIMESTAMP DEFAULT 0'.
3778       */
3779 
3780       my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
3781       DBUG_RETURN(TRUE);
3782     }
3783   }
3784 
3785   DBUG_RETURN(FALSE);
3786 }
3787 
3788 
3789 /*
3790   Set table default charset, if not set
3791 
3792   SYNOPSIS
3793     set_table_default_charset()
3794     create_info        Table create information
3795 
3796   DESCRIPTION
3797     If the table character set was not given explicitely,
3798     let's fetch the database default character set and
3799     apply it to the table.
3800 */
3801 
set_table_default_charset(THD * thd,HA_CREATE_INFO * create_info,char * db)3802 static void set_table_default_charset(THD *thd,
3803 				      HA_CREATE_INFO *create_info, char *db)
3804 {
3805   /*
3806     If the table character set was not given explicitly,
3807     let's fetch the database default character set and
3808     apply it to the table.
3809   */
3810   if (!create_info->default_table_charset)
3811   {
3812     HA_CREATE_INFO db_info;
3813 
3814     load_db_opt_by_name(thd, db, &db_info);
3815 
3816     create_info->default_table_charset= db_info.default_table_charset;
3817   }
3818 }
3819 
3820 
3821 /*
3822   Extend long VARCHAR fields to blob & prepare field if it's a blob
3823 
3824   SYNOPSIS
3825     prepare_blob_field()
3826     sql_field		Field to check
3827 
3828   RETURN
3829     0	ok
3830     1	Error (sql_field can't be converted to blob)
3831         In this case the error is given
3832 */
3833 
prepare_blob_field(THD * thd,Create_field * sql_field)3834 static bool prepare_blob_field(THD *thd, Create_field *sql_field)
3835 {
3836   DBUG_ENTER("prepare_blob_field");
3837 
3838   if (sql_field->length > MAX_FIELD_VARCHARLENGTH &&
3839       !(sql_field->flags & BLOB_FLAG))
3840   {
3841     /* Convert long VARCHAR columns to TEXT or BLOB */
3842     char warn_buff[MYSQL_ERRMSG_SIZE];
3843 
3844     if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
3845                                                       MODE_STRICT_ALL_TABLES)))
3846     {
3847       my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
3848                static_cast<ulong>(MAX_FIELD_VARCHARLENGTH /
3849                                   sql_field->charset->mbmaxlen));
3850       DBUG_RETURN(1);
3851     }
3852     sql_field->sql_type= MYSQL_TYPE_BLOB;
3853     sql_field->flags|= BLOB_FLAG;
3854     my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_AUTO_CONVERT), sql_field->field_name,
3855             (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
3856             (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
3857     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
3858                  warn_buff);
3859   }
3860 
3861   if ((sql_field->flags & BLOB_FLAG) && sql_field->length)
3862   {
3863     if (sql_field->sql_type == FIELD_TYPE_BLOB ||
3864         sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
3865         sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB)
3866     {
3867       /* The user has given a length to the blob column */
3868       sql_field->sql_type= get_blob_type_from_length(sql_field->length);
3869       sql_field->pack_length= calc_pack_length(sql_field->sql_type, 0);
3870     }
3871     sql_field->length= 0;
3872   }
3873   DBUG_RETURN(0);
3874 }
3875 
3876 
3877 /*
3878   Preparation of Create_field for SP function return values.
3879   Based on code used in the inner loop of mysql_prepare_create_table()
3880   above.
3881 
3882   SYNOPSIS
3883     sp_prepare_create_field()
3884     thd			Thread object
3885     sql_field		Field to prepare
3886 
3887   DESCRIPTION
3888     Prepares the field structures for field creation.
3889 
3890 */
3891 
sp_prepare_create_field(THD * thd,Create_field * sql_field)3892 void sp_prepare_create_field(THD *thd, Create_field *sql_field)
3893 {
3894   if (sql_field->sql_type == MYSQL_TYPE_SET ||
3895       sql_field->sql_type == MYSQL_TYPE_ENUM)
3896   {
3897     uint32 field_length, dummy;
3898     if (sql_field->sql_type == MYSQL_TYPE_SET)
3899     {
3900       calculate_interval_lengths(sql_field->charset,
3901                                  sql_field->interval, &dummy,
3902                                  &field_length);
3903       sql_field->length= field_length +
3904                          (sql_field->interval->count - 1);
3905     }
3906     else /* MYSQL_TYPE_ENUM */
3907     {
3908       calculate_interval_lengths(sql_field->charset,
3909                                  sql_field->interval,
3910                                  &field_length, &dummy);
3911       sql_field->length= field_length;
3912     }
3913     set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
3914   }
3915 
3916   if (sql_field->sql_type == MYSQL_TYPE_BIT)
3917   {
3918     sql_field->pack_flag= FIELDFLAG_NUMBER |
3919                           FIELDFLAG_TREAT_BIT_AS_CHAR;
3920   }
3921   sql_field->create_length_to_internal_length();
3922   DBUG_ASSERT(sql_field->def == 0);
3923   /* Can't go wrong as sql_field->def is not defined */
3924   (void) prepare_blob_field(thd, sql_field);
3925 }
3926 
3927 
3928 /**
3929   Auxiliary function which allows to check if freshly created .FRM
3930   file for table can be opened.
3931 
3932   @retval FALSE - Success.
3933   @retval TRUE  - Failure.
3934 */
3935 
check_if_created_table_can_be_opened(THD * thd,const char * path,const char * db,const char * table_name,HA_CREATE_INFO * create_info,handler * file)3936 static bool check_if_created_table_can_be_opened(THD *thd,
3937                                                  const char *path,
3938                                                  const char *db,
3939                                                  const char *table_name,
3940                                                  HA_CREATE_INFO *create_info,
3941                                                  handler *file)
3942 {
3943   TABLE table;
3944   TABLE_SHARE share;
3945   bool result;
3946 
3947   /*
3948     It is impossible to open definition of partitioned table without .par file.
3949   */
3950   if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
3951     return TRUE;
3952 
3953   init_tmp_table_share(thd, &share, db, 0, table_name, path);
3954 
3955   result= (open_table_def(thd, &share, 0) ||
3956            open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
3957                                  0, &table, TRUE));
3958   /*
3959     Assert that the change list is empty as no partition function currently
3960     needs to modify item tree. May need call THD::rollback_item_tree_changes
3961     later before calling closefrm if the change list is not empty.
3962   */
3963   DBUG_ASSERT(thd->change_list.is_empty());
3964   if (! result)
3965     (void) closefrm(&table, 0);
3966 
3967   free_table_share(&share);
3968   (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
3969   return result;
3970 }
3971 
3972 
3973 /*
3974   Create a table
3975 
3976   SYNOPSIS
3977     mysql_create_table_no_lock()
3978     thd			Thread object
3979     db			Database
3980     table_name		Table name
3981     create_info	        Create information (like MAX_ROWS)
3982     fields		List of fields to create
3983     keys		List of keys to create
3984     internal_tmp_table  Set to 1 if this is an internal temporary table
3985 			(From ALTER TABLE)
3986     select_field_count
3987     is_trans            identifies the type of engine where the table
3988                         was created: either trans or non-trans.
3989 
3990   DESCRIPTION
3991     If one creates a temporary table, this is automatically opened
3992 
3993     Note that this function assumes that caller already have taken
3994     exclusive metadata lock on table being created or used some other
3995     way to ensure that concurrent operations won't intervene.
3996     mysql_create_table() is a wrapper that can be used for this.
3997 
3998     no_log is needed for the case of CREATE ... SELECT,
3999     as the logging will be done later in sql_insert.cc
4000     select_field_count is also used for CREATE ... SELECT,
4001     and must be zero for standard create of table.
4002 
4003   RETURN VALUES
4004     FALSE OK
4005     TRUE  error
4006 */
4007 
mysql_create_table_no_lock(THD * thd,const char * db,const char * table_name,HA_CREATE_INFO * create_info,Alter_info * alter_info,bool internal_tmp_table,uint select_field_count,bool * is_trans)4008 bool mysql_create_table_no_lock(THD *thd,
4009                                 const char *db, const char *table_name,
4010                                 HA_CREATE_INFO *create_info,
4011                                 Alter_info *alter_info,
4012                                 bool internal_tmp_table,
4013                                 uint select_field_count,
4014                                 bool *is_trans)
4015 {
4016   char		path[FN_REFLEN + 1];
4017   uint          path_length;
4018   const char	*alias;
4019   uint		db_options, key_count;
4020   KEY		*key_info_buffer;
4021   handler	*file;
4022   bool		error= TRUE;
4023   DBUG_ENTER("mysql_create_table_no_lock");
4024   DBUG_PRINT("enter", ("db: '%s'  table: '%s'  tmp: %d",
4025                        db, table_name, internal_tmp_table));
4026 
4027 
4028   /* Check for duplicate fields and check type of table to create */
4029   if (!alter_info->create_list.elements)
4030   {
4031     my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
4032                MYF(0));
4033     DBUG_RETURN(TRUE);
4034   }
4035   if (check_engine(thd, db, table_name, create_info))
4036     DBUG_RETURN(TRUE);
4037 
4038   set_table_default_charset(thd, create_info, (char*) db);
4039 
4040   db_options= create_info->table_options;
4041   if (create_info->row_type == ROW_TYPE_DYNAMIC)
4042     db_options|=HA_OPTION_PACK_RECORD;
4043   alias= table_case_name(create_info, table_name);
4044   if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
4045                               create_info->db_type)))
4046   {
4047     mem_alloc_error(sizeof(handler));
4048     DBUG_RETURN(TRUE);
4049   }
4050 #ifdef WITH_PARTITION_STORAGE_ENGINE
4051   partition_info *part_info= thd->work_part_info;
4052 
4053   if (!part_info && create_info->db_type->partition_flags &&
4054       (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION))
4055   {
4056     /*
4057       Table is not defined as a partitioned table but the engine handles
4058       all tables as partitioned. The handler will set up the partition info
4059       object with the default settings.
4060     */
4061     thd->work_part_info= part_info= new partition_info();
4062     if (!part_info)
4063     {
4064       mem_alloc_error(sizeof(partition_info));
4065       DBUG_RETURN(TRUE);
4066     }
4067     file->set_auto_partitions(part_info);
4068     part_info->default_engine_type= create_info->db_type;
4069     part_info->is_auto_partitioned= TRUE;
4070   }
4071   if (part_info)
4072   {
4073     /*
4074       The table has been specified as a partitioned table.
4075       If this is part of an ALTER TABLE the handler will be the partition
4076       handler but we need to specify the default handler to use for
4077       partitions also in the call to check_partition_info. We transport
4078       this information in the default_db_type variable, it is either
4079       DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command.
4080 
4081       Check that we don't use foreign keys in the table since it won't
4082       work even with InnoDB beneath it.
4083     */
4084     List_iterator<Key> key_iterator(alter_info->key_list);
4085     Key *key;
4086     handlerton *part_engine_type= create_info->db_type;
4087     char *part_syntax_buf;
4088     uint syntax_len;
4089     handlerton *engine_type;
4090     if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4091     {
4092       my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
4093       goto err;
4094     }
4095     while ((key= key_iterator++))
4096     {
4097       if (key->type == Key::FOREIGN_KEY &&
4098           !part_info->is_auto_partitioned)
4099       {
4100         my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
4101         goto err;
4102       }
4103     }
4104     if ((part_engine_type == partition_hton) &&
4105         part_info->default_engine_type)
4106     {
4107       /*
4108         This only happens at ALTER TABLE.
4109         default_engine_type was assigned from the engine set in the ALTER
4110         TABLE command.
4111       */
4112       ;
4113     }
4114     else
4115     {
4116       if (create_info->used_fields & HA_CREATE_USED_ENGINE)
4117       {
4118         part_info->default_engine_type= create_info->db_type;
4119       }
4120       else
4121       {
4122         if (part_info->default_engine_type == NULL)
4123         {
4124           part_info->default_engine_type= ha_checktype(thd,
4125                                           DB_TYPE_DEFAULT, 0, 0);
4126         }
4127       }
4128     }
4129     DBUG_PRINT("info", ("db_type = %s create_info->db_type = %s",
4130              ha_resolve_storage_engine_name(part_info->default_engine_type),
4131              ha_resolve_storage_engine_name(create_info->db_type)));
4132     if (part_info->check_partition_info(thd, &engine_type, file,
4133                                         create_info, FALSE))
4134       goto err;
4135     part_info->default_engine_type= engine_type;
4136 
4137     /*
4138       We reverse the partitioning parser and generate a standard format
4139       for syntax stored in frm file.
4140     */
4141     if (!(part_syntax_buf= generate_partition_syntax(part_info,
4142                                                      &syntax_len,
4143                                                      TRUE, TRUE,
4144                                                      create_info,
4145                                                      alter_info,
4146                                                      NULL)))
4147       goto err;
4148     part_info->part_info_string= part_syntax_buf;
4149     part_info->part_info_len= syntax_len;
4150     if ((!(engine_type->partition_flags &&
4151            engine_type->partition_flags() & HA_CAN_PARTITION)) ||
4152         create_info->db_type == partition_hton)
4153     {
4154       /*
4155         The handler assigned to the table cannot handle partitioning.
4156         Assign the partition handler as the handler of the table.
4157       */
4158       DBUG_PRINT("info", ("db_type: %s",
4159                         ha_resolve_storage_engine_name(create_info->db_type)));
4160       delete file;
4161       create_info->db_type= partition_hton;
4162       if (!(file= get_ha_partition(part_info)))
4163       {
4164         DBUG_RETURN(TRUE);
4165       }
4166       /*
4167         If we have default number of partitions or subpartitions we
4168         might require to set-up the part_info object such that it
4169         creates a proper .par file. The current part_info object is
4170         only used to create the frm-file and .par-file.
4171       */
4172       if (part_info->use_default_num_partitions &&
4173           part_info->num_parts &&
4174           (int)part_info->num_parts !=
4175           file->get_default_no_partitions(create_info))
4176       {
4177         uint i;
4178         List_iterator<partition_element> part_it(part_info->partitions);
4179         part_it++;
4180         DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
4181         for (i= 1; i < part_info->partitions.elements; i++)
4182           (part_it++)->part_state= PART_TO_BE_DROPPED;
4183       }
4184       else if (part_info->is_sub_partitioned() &&
4185                part_info->use_default_num_subpartitions &&
4186                part_info->num_subparts &&
4187                (int)part_info->num_subparts !=
4188                  file->get_default_no_partitions(create_info))
4189       {
4190         DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE);
4191         part_info->num_subparts= file->get_default_no_partitions(create_info);
4192       }
4193     }
4194     else if (create_info->db_type != engine_type)
4195     {
4196       /*
4197         We come here when we don't use a partitioned handler.
4198         Since we use a partitioned table it must be "native partitioned".
4199         We have switched engine from defaults, most likely only specified
4200         engines in partition clauses.
4201       */
4202       delete file;
4203       if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
4204                                   engine_type)))
4205       {
4206         mem_alloc_error(sizeof(handler));
4207         DBUG_RETURN(TRUE);
4208       }
4209     }
4210   }
4211 #endif
4212 
4213   if (mysql_prepare_create_table(thd, create_info, alter_info,
4214                                  internal_tmp_table,
4215                                  &db_options, file,
4216                                  &key_info_buffer, &key_count,
4217                                  select_field_count))
4218     goto err;
4219 
4220       /* Check if table exists */
4221   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4222   {
4223     path_length= build_tmptable_filename(thd, path, sizeof(path));
4224     create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
4225   }
4226   else
4227   {
4228     path_length= build_table_filename(path, sizeof(path) - 1, db, alias, reg_ext,
4229                                       internal_tmp_table ? FN_IS_TMP : 0);
4230   }
4231 
4232   /* Check if table already exists */
4233   if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
4234       find_temporary_table(thd, db, table_name))
4235   {
4236     if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
4237     {
4238       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4239                           ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
4240                           alias);
4241       error= 0;
4242       goto err;
4243     }
4244     my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
4245     goto err;
4246   }
4247 
4248   if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
4249   {
4250     if (!access(path,F_OK))
4251     {
4252       if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
4253         goto warn;
4254       my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
4255       goto err;
4256     }
4257     /*
4258       We don't assert here, but check the result, because the table could be
4259       in the table definition cache and in the same time the .frm could be
4260       missing from the disk, in case of manual intervention which deletes
4261       the .frm file. The user has to use FLUSH TABLES; to clear the cache.
4262       Then she could create the table. This case is pretty obscure and
4263       therefore we don't introduce a new error message only for it.
4264     */
4265     mysql_mutex_lock(&LOCK_open);
4266     if (get_cached_table_share(db, table_name))
4267     {
4268       mysql_mutex_unlock(&LOCK_open);
4269       my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
4270       goto err;
4271     }
4272     mysql_mutex_unlock(&LOCK_open);
4273   }
4274 
4275   /*
4276     Check that table with given name does not already
4277     exist in any storage engine. In such a case it should
4278     be discovered and the error ER_TABLE_EXISTS_ERROR be returned
4279     unless user specified CREATE TABLE IF EXISTS
4280     An exclusive metadata lock ensures that no
4281     one else is attempting to discover the table. Since
4282     it's not on disk as a frm file, no one could be using it!
4283   */
4284   if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
4285   {
4286     bool create_if_not_exists =
4287       create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
4288     int retcode = ha_table_exists_in_engine(thd, db, table_name);
4289     DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
4290     switch (retcode)
4291     {
4292       case HA_ERR_NO_SUCH_TABLE:
4293         /* Normal case, no table exists. we can go and create it */
4294         break;
4295       case HA_ERR_TABLE_EXIST:
4296         DBUG_PRINT("info", ("Table existed in handler"));
4297 
4298         if (create_if_not_exists)
4299           goto warn;
4300         my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
4301         goto err;
4302         break;
4303       default:
4304         DBUG_PRINT("info", ("error: %u from storage engine", retcode));
4305         my_error(retcode, MYF(0),table_name);
4306         goto err;
4307     }
4308   }
4309 
4310   thd_proc_info(thd, "creating table");
4311 
4312 #ifdef HAVE_READLINK
4313   {
4314     size_t dirlen;
4315     char   dirpath[FN_REFLEN];
4316 
4317     /*
4318       data_file_name and index_file_name include the table name without
4319       extension. Mostly this does not refer to an existing file. When
4320       comparing data_file_name or index_file_name against the data
4321       directory, we try to resolve all symbolic links. On some systems,
4322       we use realpath(3) for the resolution. This returns ENOENT if the
4323       resolved path does not refer to an existing file. my_realpath()
4324       does then copy the requested path verbatim, without symlink
4325       resolution. Thereafter the comparison can fail even if the
4326       requested path is within the data directory. E.g. if symlinks to
4327       another file system are used. To make realpath(3) return the
4328       resolved path, we strip the table name and compare the directory
4329       path only. If the directory doesn't exist either, table creation
4330       will fail anyway.
4331     */
4332     if (create_info->data_file_name)
4333     {
4334       dirname_part(dirpath, create_info->data_file_name, &dirlen);
4335       if (test_if_data_home_dir(dirpath))
4336       {
4337         my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
4338         goto err;
4339       }
4340     }
4341     if (create_info->index_file_name)
4342     {
4343       dirname_part(dirpath, create_info->index_file_name, &dirlen);
4344       if (test_if_data_home_dir(dirpath))
4345       {
4346         my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
4347         goto err;
4348       }
4349     }
4350   }
4351 
4352 #ifdef WITH_PARTITION_STORAGE_ENGINE
4353   if (check_partition_dirs(thd->lex->part_info))
4354   {
4355     goto err;
4356   }
4357 #endif /* WITH_PARTITION_STORAGE_ENGINE */
4358 
4359   if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
4360 #endif /* HAVE_READLINK */
4361   {
4362     if (create_info->data_file_name)
4363       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
4364                           WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
4365                           "DATA DIRECTORY");
4366     if (create_info->index_file_name)
4367       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
4368                           WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
4369                           "INDEX DIRECTORY");
4370     create_info->data_file_name= create_info->index_file_name= 0;
4371   }
4372   create_info->table_options=db_options;
4373 
4374   path[path_length - reg_ext_length]= '\0'; // Remove .frm extension
4375   if (rea_create_table(thd, path, db, table_name,
4376                        create_info, alter_info->create_list,
4377                        key_count, key_info_buffer, file))
4378     goto err;
4379 
4380   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
4381   {
4382     /*
4383       Open a table (skipping table cache) and add it into
4384       THD::temporary_tables list.
4385     */
4386 
4387     TABLE *table= open_table_uncached(thd, path, db, table_name, TRUE);
4388 
4389     if (!table)
4390     {
4391       (void) rm_temporary_table(create_info->db_type, path);
4392       goto err;
4393     }
4394 
4395     if (is_trans != NULL)
4396       *is_trans= table->file->has_transactions();
4397 
4398     thd->thread_specific_used= TRUE;
4399   }
4400 #ifdef WITH_PARTITION_STORAGE_ENGINE
4401   else if (part_info && create_info->frm_only)
4402   {
4403     /*
4404       For partitioned tables we can't find some problems with table
4405       until table is opened. Therefore in order to disallow creation
4406       of corrupted tables we have to try to open table as the part
4407       of its creation process.
4408       In cases when both .FRM and SE part of table are created table
4409       is implicitly open in ha_create_table() call.
4410       In cases when we create .FRM without SE part we have to open
4411       table explicitly.
4412     */
4413     if (check_if_created_table_can_be_opened(thd, path, db, table_name,
4414                                              create_info, file))
4415     {
4416       char frm_name[FN_REFLEN];
4417       strxmov(frm_name, path, reg_ext, NullS);
4418       (void) mysql_file_delete(key_file_frm, frm_name, MYF(0));
4419       goto err;
4420     }
4421   }
4422 #endif
4423 
4424   error= FALSE;
4425 err:
4426   thd_proc_info(thd, "After create");
4427   delete file;
4428   DBUG_RETURN(error);
4429 
4430 warn:
4431   error= FALSE;
4432   push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4433                       ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
4434                       alias);
4435   goto err;
4436 }
4437 
4438 
4439 /**
4440   Implementation of SQLCOM_CREATE_TABLE.
4441 
4442   Take the metadata locks (including a shared lock on the affected
4443   schema) and create the table. Is written to be called from
4444   mysql_execute_command(), to which it delegates the common parts
4445   with other commands (i.e. implicit commit before and after,
4446   close of thread tables.
4447 */
4448 
mysql_create_table(THD * thd,TABLE_LIST * create_table,HA_CREATE_INFO * create_info,Alter_info * alter_info)4449 bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
4450                         HA_CREATE_INFO *create_info,
4451                         Alter_info *alter_info)
4452 {
4453   bool result;
4454   bool is_trans= FALSE;
4455   DBUG_ENTER("mysql_create_table");
4456 
4457   /*
4458     Open or obtain an exclusive metadata lock on table being created.
4459   */
4460   if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
4461   {
4462     result= TRUE;
4463     goto end;
4464   }
4465 
4466   /* Got lock. */
4467   DEBUG_SYNC(thd, "locked_table_name");
4468 
4469   result= mysql_create_table_no_lock(thd, create_table->db,
4470                                      create_table->table_name, create_info,
4471                                      alter_info, FALSE, 0, &is_trans);
4472 
4473   /*
4474     Don't write statement if:
4475     - Table creation has failed
4476     - Row-based logging is used and we are creating a temporary table
4477     Otherwise, the statement shall be binlogged.
4478   */
4479   if (!result &&
4480       (!thd->is_current_stmt_binlog_format_row() ||
4481        (thd->is_current_stmt_binlog_format_row() &&
4482         !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
4483     result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
4484 
4485 end:
4486   DBUG_RETURN(result);
4487 }
4488 
4489 
4490 /*
4491 ** Give the key name after the first field with an optional '_#' after
4492 **/
4493 
4494 static bool
check_if_keyname_exists(const char * name,KEY * start,KEY * end)4495 check_if_keyname_exists(const char *name, KEY *start, KEY *end)
4496 {
4497   for (KEY *key=start ; key != end ; key++)
4498     if (!my_strcasecmp(system_charset_info,name,key->name))
4499       return 1;
4500   return 0;
4501 }
4502 
4503 
4504 static char *
make_unique_key_name(const char * field_name,KEY * start,KEY * end)4505 make_unique_key_name(const char *field_name,KEY *start,KEY *end)
4506 {
4507   char buff[MAX_FIELD_NAME],*buff_end;
4508 
4509   if (!check_if_keyname_exists(field_name,start,end) &&
4510       my_strcasecmp(system_charset_info,field_name,primary_key_name))
4511     return (char*) field_name;			// Use fieldname
4512   buff_end=strmake(buff,field_name, sizeof(buff)-4);
4513 
4514   /*
4515     Only 3 chars + '\0' left, so need to limit to 2 digit
4516     This is ok as we can't have more than 100 keys anyway
4517   */
4518   for (uint i=2 ; i< 100; i++)
4519   {
4520     *buff_end= '_';
4521     int10_to_str(i, buff_end+1, 10);
4522     if (!check_if_keyname_exists(buff,start,end))
4523       return sql_strdup(buff);
4524   }
4525   return (char*) "not_specified";		// Should never happen
4526 }
4527 
4528 
4529 /****************************************************************************
4530 ** Alter a table definition
4531 ****************************************************************************/
4532 
4533 
4534 /*
4535   Rename a table.
4536 
4537   SYNOPSIS
4538     mysql_rename_table()
4539       base                      The handlerton handle.
4540       old_db                    The old database name.
4541       old_name                  The old table name.
4542       new_db                    The new database name.
4543       new_name                  The new table name.
4544       flags                     flags for build_table_filename().
4545                                 FN_FROM_IS_TMP old_name is temporary.
4546                                 FN_TO_IS_TMP   new_name is temporary.
4547                                 NO_FRM_RENAME  Don't rename the FRM file
4548                                 but only the table in the storage engine.
4549                                 NO_FK_CHECKS   Don't check FK constraints
4550                                 during rename.
4551 
4552   RETURN
4553     FALSE   OK
4554     TRUE    Error
4555 */
4556 
4557 bool
mysql_rename_table(handlerton * base,const char * old_db,const char * old_name,const char * new_db,const char * new_name,uint flags)4558 mysql_rename_table(handlerton *base, const char *old_db,
4559                    const char *old_name, const char *new_db,
4560                    const char *new_name, uint flags)
4561 {
4562   THD *thd= current_thd;
4563   char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
4564     lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
4565   char *from_base= from, *to_base= to;
4566   char tmp_name[NAME_LEN+1];
4567   handler *file;
4568   int error=0;
4569   ulonglong save_bits= thd->variables.option_bits;
4570   DBUG_ENTER("mysql_rename_table");
4571   DBUG_PRINT("enter", ("old: '%s'.'%s'  new: '%s'.'%s'",
4572                        old_db, old_name, new_db, new_name));
4573 
4574   // Temporarily disable foreign key checks
4575   if (flags & NO_FK_CHECKS)
4576     thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
4577 
4578   file= (base == NULL ? 0 :
4579          get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
4580 
4581   build_table_filename(from, sizeof(from) - 1, old_db, old_name, "",
4582                        flags & FN_FROM_IS_TMP);
4583   build_table_filename(to, sizeof(to) - 1, new_db, new_name, "",
4584                        flags & FN_TO_IS_TMP);
4585 
4586   /*
4587     If lower_case_table_names == 2 (case-preserving but case-insensitive
4588     file system) and the storage is not HA_FILE_BASED, we need to provide
4589     a lowercase file name, but we leave the .frm in mixed case.
4590    */
4591   if (lower_case_table_names == 2 && file &&
4592       !(file->ha_table_flags() & HA_FILE_BASED))
4593   {
4594     strmov(tmp_name, old_name);
4595     my_casedn_str(files_charset_info, tmp_name);
4596     build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "",
4597                          flags & FN_FROM_IS_TMP);
4598     from_base= lc_from;
4599 
4600     strmov(tmp_name, new_name);
4601     my_casedn_str(files_charset_info, tmp_name);
4602     build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "",
4603                          flags & FN_TO_IS_TMP);
4604     to_base= lc_to;
4605   }
4606 
4607   if (!file || !(error=file->ha_rename_table(from_base, to_base)))
4608   {
4609     if (!(flags & NO_FRM_RENAME) && rename_file_ext(from,to,reg_ext))
4610     {
4611       error=my_errno;
4612       /* Restore old file name */
4613       if (file)
4614         file->ha_rename_table(to_base, from_base);
4615     }
4616   }
4617   delete file;
4618   if (error == HA_ERR_WRONG_COMMAND)
4619     my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
4620   else if (error)
4621     my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
4622 
4623   // Restore options bits to the original value
4624   thd->variables.option_bits= save_bits;
4625 
4626   DBUG_RETURN(error != 0);
4627 }
4628 
4629 
4630 /*
4631   Create a table identical to the specified table
4632 
4633   SYNOPSIS
4634     mysql_create_like_table()
4635     thd		Thread object
4636     table       Table list element for target table
4637     src_table   Table list element for source table
4638     create_info Create info
4639 
4640   RETURN VALUES
4641     FALSE OK
4642     TRUE  error
4643 */
4644 
mysql_create_like_table(THD * thd,TABLE_LIST * table,TABLE_LIST * src_table,HA_CREATE_INFO * create_info)4645 bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
4646                              HA_CREATE_INFO *create_info)
4647 {
4648   HA_CREATE_INFO local_create_info;
4649   Alter_info local_alter_info;
4650   bool res= TRUE;
4651   bool is_trans= FALSE;
4652   uint not_used;
4653   DBUG_ENTER("mysql_create_like_table");
4654 
4655 
4656   /*
4657     We the open source table to get its description in HA_CREATE_INFO
4658     and Alter_info objects. This also acquires a shared metadata lock
4659     on this table which ensures that no concurrent DDL operation will
4660     mess with it.
4661     Also in case when we create non-temporary table open_tables()
4662     call obtains an exclusive metadata lock on target table ensuring
4663     that we can safely perform table creation.
4664     Thus by holding both these locks we ensure that our statement is
4665     properly isolated from all concurrent operations which matter.
4666   */
4667   if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
4668     goto err;
4669   src_table->table->use_all_columns();
4670 
4671   DEBUG_SYNC(thd, "create_table_like_after_open");
4672 
4673   /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
4674   bzero((char*) &local_create_info, sizeof(local_create_info));
4675   local_create_info.db_type= src_table->table->s->db_type();
4676   local_create_info.row_type= src_table->table->s->row_type;
4677   if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
4678                                 &local_alter_info))
4679     goto err;
4680 #ifdef WITH_PARTITION_STORAGE_ENGINE
4681   /* Partition info is not handled by mysql_prepare_alter_table() call. */
4682   if (src_table->table->part_info)
4683     thd->work_part_info= src_table->table->part_info->get_clone();
4684 #endif
4685 
4686   /*
4687     Adjust description of source table before using it for creation of
4688     target table.
4689 
4690     Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
4691     temporary table which represents I_S table.
4692   */
4693   if (src_table->schema_table)
4694     local_create_info.max_rows= 0;
4695   /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
4696   local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
4697   /* Replace type of source table with one specified in the statement. */
4698   local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
4699   local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
4700   /* Reset auto-increment counter for the new table. */
4701   local_create_info.auto_increment_value= 0;
4702   /*
4703     Do not inherit values of DATA and INDEX DIRECTORY options from
4704     the original table. This is documented behavior.
4705   */
4706   local_create_info.data_file_name= local_create_info.index_file_name= NULL;
4707 
4708   if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
4709                                        &local_create_info, &local_alter_info,
4710                                        FALSE, 0, &is_trans)))
4711     goto err;
4712 
4713   /*
4714     Ensure that we have an exclusive lock on target table if we are creating
4715     non-temporary table.
4716   */
4717   DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
4718               thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
4719                                              table->table_name,
4720                                              MDL_EXCLUSIVE));
4721 
4722   DEBUG_SYNC(thd, "create_table_like_before_binlog");
4723 
4724   /*
4725     We have to write the query before we unlock the tables.
4726   */
4727   if (!thd->is_current_stmt_binlog_disabled() &&
4728       thd->is_current_stmt_binlog_format_row())
4729   {
4730     /*
4731        Since temporary tables are not replicated under row-based
4732        replication, CREATE TABLE ... LIKE ... needs special
4733        treatement.  We have four cases to consider, according to the
4734        following decision table:
4735 
4736            ==== ========= ========= ==============================
4737            Case    Target    Source Write to binary log
4738            ==== ========= ========= ==============================
4739            1       normal    normal Original statement
4740            2       normal temporary Generated statement
4741            3    temporary    normal Nothing
4742            4    temporary temporary Nothing
4743            ==== ========= ========= ==============================
4744     */
4745     if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
4746     {
4747       if (src_table->table->s->tmp_table)               // Case 2
4748       {
4749         char buf[2048];
4750         String query(buf, sizeof(buf), system_charset_info);
4751         query.length(0);  // Have to zero it since constructor doesn't
4752         Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
4753 
4754         /*
4755           The condition avoids a crash as described in BUG#48506. Other
4756           binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE
4757           when the existing object is a view will be solved by BUG 47442.
4758         */
4759         if (!table->view)
4760         {
4761           /*
4762             Here we open the destination table, on which we already have
4763             exclusive metadata lock. This is needed for store_create_info()
4764             to work. The table will be closed by close_thread_table() at
4765             the end of this branch.
4766           */
4767           if (open_table(thd, table, thd->mem_root, &ot_ctx))
4768             goto err;
4769 
4770           /*
4771             After opening a MERGE table add the children to the query list of
4772             tables, so that children tables info can be used on "CREATE TABLE"
4773             statement generation by the binary log.
4774             Note that placeholders don't have the handler open.
4775           */
4776           if (table->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
4777             goto err;
4778 
4779           /*
4780             As the reference table is temporary and may not exist on slave, we must
4781             force the ENGINE to be present into CREATE TABLE.
4782           */
4783           create_info->used_fields|= HA_CREATE_USED_ENGINE;
4784 
4785           int result __attribute__((unused))=
4786             store_create_info(thd, table, &query,
4787                               create_info, TRUE /* show_database */);
4788 
4789           DBUG_ASSERT(result == 0); // store_create_info() always return 0
4790           if (write_bin_log(thd, TRUE, query.ptr(), query.length()))
4791             goto err;
4792 
4793           DBUG_ASSERT(thd->open_tables == table->table);
4794           /*
4795             When opening the table, we ignored the locked tables
4796             (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
4797             risking to close some locked table.
4798           */
4799           close_thread_table(thd, &thd->open_tables);
4800         }
4801       }
4802       else                                      // Case 1
4803         if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
4804           goto err;
4805     }
4806     /*
4807       Case 3 and 4 does nothing under RBR
4808     */
4809   }
4810   else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
4811     goto err;
4812 
4813 err:
4814   DBUG_RETURN(res);
4815 }
4816 
4817 
4818 /* table_list should contain just one table */
4819 static int
mysql_discard_or_import_tablespace(THD * thd,TABLE_LIST * table_list,enum tablespace_op_type tablespace_op)4820 mysql_discard_or_import_tablespace(THD *thd,
4821                                    TABLE_LIST *table_list,
4822                                    enum tablespace_op_type tablespace_op)
4823 {
4824   TABLE *table;
4825   my_bool discard;
4826   int error;
4827   DBUG_ENTER("mysql_discard_or_import_tablespace");
4828 
4829   /*
4830     Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
4831     ALTER TABLE
4832   */
4833 
4834   thd_proc_info(thd, "discard_or_import_tablespace");
4835 
4836   discard= test(tablespace_op == DISCARD_TABLESPACE);
4837 
4838  /*
4839    We set this flag so that ha_innobase::open and ::external_lock() do
4840    not complain when we lock the table
4841  */
4842   thd->tablespace_op= TRUE;
4843   table_list->mdl_request.set_type(MDL_SHARED_WRITE);
4844   if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
4845   {
4846     thd->tablespace_op=FALSE;
4847     DBUG_RETURN(-1);
4848   }
4849 
4850   error= table->file->ha_discard_or_import_tablespace(discard);
4851 
4852   thd_proc_info(thd, "end");
4853 
4854   if (error)
4855     goto err;
4856 
4857   /*
4858     The 0 in the call below means 'not in a transaction', which means
4859     immediate invalidation; that is probably what we wish here
4860   */
4861   query_cache_invalidate3(thd, table_list, 0);
4862 
4863   /* The ALTER TABLE is always in its own transaction */
4864   error= trans_commit_stmt(thd);
4865   if (trans_commit_implicit(thd))
4866     error=1;
4867   if (error)
4868     goto err;
4869   error= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
4870 
4871 err:
4872   thd->tablespace_op=FALSE;
4873 
4874   if (error == 0)
4875   {
4876     my_ok(thd);
4877     DBUG_RETURN(0);
4878   }
4879 
4880   table->file->print_error(error, MYF(0));
4881 
4882   DBUG_RETURN(-1);
4883 }
4884 
4885 /**
4886   @brief Check if both DROP and CREATE are present for an index in ALTER TABLE
4887 
4888   @details Checks if any index is being modified (present as both DROP INDEX
4889     and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling
4890     in-place ALTER TABLE.
4891 
4892   @param table       The table being altered
4893   @param alter_info  The ALTER TABLE structure
4894   @return presence of index being altered
4895   @retval FALSE  No such index
4896   @retval TRUE   Have at least 1 index modified
4897 */
4898 
4899 static bool
is_index_maintenance_unique(TABLE * table,Alter_info * alter_info)4900 is_index_maintenance_unique (TABLE *table, Alter_info *alter_info)
4901 {
4902   List_iterator<Key> key_it(alter_info->key_list);
4903   List_iterator<Alter_drop> drop_it(alter_info->drop_list);
4904   Key *key;
4905 
4906   while ((key= key_it++))
4907   {
4908     if (key->name.str)
4909     {
4910       Alter_drop *drop;
4911 
4912       drop_it.rewind();
4913       while ((drop= drop_it++))
4914       {
4915         if (drop->type == Alter_drop::KEY &&
4916             !my_strcasecmp(system_charset_info, key->name.str, drop->name))
4917           return TRUE;
4918       }
4919     }
4920   }
4921   return FALSE;
4922 }
4923 
4924 
4925 /*
4926   SYNOPSIS
4927     mysql_compare_tables()
4928       table                     The original table.
4929       alter_info                Alter options, fields and keys for the new
4930                                 table.
4931       create_info               Create options for the new table.
4932       order_num                 Number of order list elements.
4933       need_copy_table     OUT   Result of the comparison. Undefined if error.
4934                                 Otherwise is one of:
4935                                 ALTER_TABLE_METADATA_ONLY  No copy needed
4936                                 ALTER_TABLE_DATA_CHANGED   Data changes,
4937                                                            copy needed
4938                                 ALTER_TABLE_INDEX_CHANGED  Index changes,
4939                                                            copy might be needed
4940       key_info_buffer     OUT   An array of KEY structs for new indexes
4941       index_drop_buffer   OUT   An array of offsets into table->key_info.
4942       index_drop_count    OUT   The number of elements in the array.
4943       index_add_buffer    OUT   An array of offsets into key_info_buffer.
4944       index_add_count     OUT   The number of elements in the array.
4945       candidate_key_count OUT   The number of candidate keys in original table.
4946 
4947   DESCRIPTION
4948     'table' (first argument) contains information of the original
4949     table, which includes all corresponding parts that the new
4950     table has in arguments create_list, key_list and create_info.
4951 
4952     By comparing the changes between the original and new table
4953     we can determine how much it has changed after ALTER TABLE
4954     and whether we need to make a copy of the table, or just change
4955     the .frm file.
4956 
4957     If there are no data changes, but index changes, 'index_drop_buffer'
4958     and/or 'index_add_buffer' are populated with offsets into
4959     table->key_info or key_info_buffer respectively for the indexes
4960     that need to be dropped and/or (re-)created.
4961 
4962   RETURN VALUES
4963     TRUE   error
4964     FALSE  success
4965 */
4966 
4967 bool
mysql_compare_tables(TABLE * table,Alter_info * alter_info,HA_CREATE_INFO * create_info,uint order_num,enum_alter_table_change_level * need_copy_table,KEY ** key_info_buffer,uint ** index_drop_buffer,uint * index_drop_count,uint ** index_add_buffer,uint * index_add_count,uint * candidate_key_count)4968 mysql_compare_tables(TABLE *table,
4969                      Alter_info *alter_info,
4970                      HA_CREATE_INFO *create_info,
4971                      uint order_num,
4972                      enum_alter_table_change_level *need_copy_table,
4973                      KEY **key_info_buffer,
4974                      uint **index_drop_buffer, uint *index_drop_count,
4975                      uint **index_add_buffer, uint *index_add_count,
4976                      uint *candidate_key_count)
4977 {
4978   Field **f_ptr, *field;
4979   uint changes= 0, tmp;
4980   uint key_count;
4981   List_iterator_fast<Create_field> new_field_it, tmp_new_field_it;
4982   Create_field *new_field, *tmp_new_field;
4983   KEY_PART_INFO *key_part;
4984   KEY_PART_INFO *end;
4985   THD *thd= table->in_use;
4986   /*
4987     Remember if the new definition has new VARCHAR column;
4988     create_info->varchar will be reset in mysql_prepare_create_table.
4989   */
4990   bool varchar= create_info->varchar;
4991   bool not_nullable= true;
4992   DBUG_ENTER("mysql_compare_tables");
4993 
4994   /*
4995     Create a copy of alter_info.
4996     To compare the new and old table definitions, we need to "prepare"
4997     the new definition - transform it from parser output to a format
4998     that describes the final table layout (all column defaults are
4999     initialized, duplicate columns are removed). This is done by
5000     mysql_prepare_create_table.  Unfortunately,
5001     mysql_prepare_create_table performs its transformations
5002     "in-place", that is, modifies the argument.  Since we would
5003     like to keep mysql_compare_tables() idempotent (not altering any
5004     of the arguments) we create a copy of alter_info here and
5005     pass it to mysql_prepare_create_table, then use the result
5006     to evaluate possibility of in-place ALTER TABLE, and then
5007     destroy the copy.
5008   */
5009   Alter_info tmp_alter_info(*alter_info, thd->mem_root);
5010   uint db_options= 0; /* not used */
5011 
5012   /* Create the prepared information. */
5013   if (mysql_prepare_create_table(thd, create_info,
5014                                  &tmp_alter_info,
5015                                  (table->s->tmp_table != NO_TMP_TABLE),
5016                                  &db_options,
5017                                  table->file, key_info_buffer,
5018                                  &key_count, 0))
5019     DBUG_RETURN(1);
5020   /* Allocate result buffers. */
5021   if (! (*index_drop_buffer=
5022          (uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
5023       ! (*index_add_buffer=
5024          (uint*) thd->alloc(sizeof(uint) * tmp_alter_info.key_list.elements)))
5025     DBUG_RETURN(1);
5026 
5027   /*
5028     Some very basic checks. If number of fields changes, or the
5029     handler, we need to run full ALTER TABLE. In the future
5030     new fields can be added and old dropped without copy, but
5031     not yet.
5032 
5033     Test also that engine was not given during ALTER TABLE, or
5034     we are force to run regular alter table (copy).
5035     E.g. ALTER TABLE tbl_name ENGINE=MyISAM.
5036 
5037     For the following ones we also want to run regular alter table:
5038     ALTER TABLE tbl_name ORDER BY ..
5039     ALTER TABLE tbl_name CONVERT TO CHARACTER SET ..
5040 
5041     At the moment we can't handle altering temporary tables without a copy.
5042     We also test if OPTIMIZE TABLE was given and was mapped to alter table.
5043     In that case we always do full copy.
5044 
5045     There was a bug prior to mysql-4.0.25. Number of null fields was
5046     calculated incorrectly. As a result frm and data files gets out of
5047     sync after in-place alter table. There is no way to determine by which
5048     mysql version (in 4.0 and 4.1 branches) table was created, thus we
5049     disable in-place alter table for all tables created by mysql versions
5050     prior to 5.0 branch.
5051     See BUG#6236.
5052   */
5053   if (table->s->fields != alter_info->create_list.elements ||
5054       table->s->db_type() != create_info->db_type ||
5055       table->s->tmp_table ||
5056       create_info->used_fields & HA_CREATE_USED_ENGINE ||
5057       create_info->used_fields & HA_CREATE_USED_CHARSET ||
5058       create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
5059       (table->s->row_type != create_info->row_type) ||
5060       create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
5061       create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
5062       (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
5063       order_num ||
5064       !table->s->mysql_version ||
5065       (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
5066   {
5067     *need_copy_table= ALTER_TABLE_DATA_CHANGED;
5068     DBUG_RETURN(0);
5069   }
5070 
5071   /*
5072     Use transformed info to evaluate possibility of in-place ALTER TABLE
5073     but use the preserved field to persist modifications.
5074   */
5075   new_field_it.init(alter_info->create_list);
5076   tmp_new_field_it.init(tmp_alter_info.create_list);
5077 
5078   /*
5079     Go through fields and check if the original ones are compatible
5080     with new table.
5081   */
5082   for (f_ptr= table->field, new_field= new_field_it++,
5083        tmp_new_field= tmp_new_field_it++;
5084        (field= *f_ptr);
5085        f_ptr++, new_field= new_field_it++,
5086        tmp_new_field= tmp_new_field_it++)
5087   {
5088     /* Make sure we have at least the default charset in use. */
5089     if (!new_field->charset)
5090       new_field->charset= create_info->default_table_charset;
5091 
5092     /* Check that NULL behavior is same for old and new fields */
5093     if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
5094 	(uint) (field->flags & NOT_NULL_FLAG))
5095     {
5096       *need_copy_table= ALTER_TABLE_DATA_CHANGED;
5097       DBUG_RETURN(0);
5098     }
5099 
5100     /* Don't pack rows in old tables if the user has requested this. */
5101     if (create_info->row_type == ROW_TYPE_DYNAMIC ||
5102 	(tmp_new_field->flags & BLOB_FLAG) ||
5103 	(tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
5104 	create_info->row_type != ROW_TYPE_FIXED))
5105       create_info->table_options|= HA_OPTION_PACK_RECORD;
5106 
5107     /* Check if field was renamed */
5108     field->flags&= ~FIELD_IS_RENAMED;
5109 
5110     /*
5111       InnoDB data dictionary is case sensitive so we should use string case
5112       sensitive comparison between fields. Note: strcmp branch is to be
5113       removed in future when we fix it in InnoDB.
5114     */
5115     if ((table->s->db_type())->db_type == DB_TYPE_INNODB &&
5116          strcmp(field->field_name,tmp_new_field->field_name))
5117       field->flags|= FIELD_IS_RENAMED;
5118     else
5119     {
5120       if (my_strcasecmp(system_charset_info,
5121                         field->field_name,
5122                         tmp_new_field->field_name))
5123         field->flags|= FIELD_IS_RENAMED;
5124     }
5125 
5126     /* Evaluate changes bitmap and send to check_if_incompatible_data() */
5127     if (!(tmp= field->is_equal(tmp_new_field)))
5128     {
5129       *need_copy_table= ALTER_TABLE_DATA_CHANGED;
5130       DBUG_RETURN(0);
5131     }
5132     // Clear indexed marker
5133     field->flags&= ~FIELD_IN_ADD_INDEX;
5134     changes|= tmp;
5135   }
5136 
5137   /*
5138     Go through keys and check if the original ones are compatible
5139     with new table.
5140   */
5141   KEY *table_key;
5142   KEY *table_key_end= table->key_info + table->s->keys;
5143   KEY *new_key;
5144   KEY *new_key_end= *key_info_buffer + key_count;
5145 
5146   DBUG_PRINT("info", ("index count old: %d  new: %d",
5147                       table->s->keys, key_count));
5148   /*
5149     Step through all keys of the old table and search matching new keys.
5150   */
5151   *index_drop_count= 0;
5152   *index_add_count= 0;
5153   *candidate_key_count= 0;
5154   for (table_key= table->key_info; table_key < table_key_end; table_key++)
5155   {
5156     KEY_PART_INFO *table_part;
5157     KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
5158     KEY_PART_INFO *new_part;
5159 
5160    /*
5161       Check if key is a candidate key, i.e. a unique index with no index
5162       fields nullable, then key is either already primary key or could
5163       be promoted to primary key if the original primary key is dropped.
5164       Count all candidate keys.
5165     */
5166     not_nullable= true;
5167     for (table_part= table_key->key_part;
5168          table_part < table_part_end;
5169          table_part++)
5170     {
5171       not_nullable= not_nullable && (! table_part->field->maybe_null());
5172     }
5173     if ((table_key->flags & HA_NOSAME) && not_nullable)
5174       (*candidate_key_count)++;
5175 
5176     /* Search a new key with the same name. */
5177     for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
5178     {
5179       if (! strcmp(table_key->name, new_key->name))
5180         break;
5181     }
5182     if (new_key >= new_key_end)
5183     {
5184       /* Key not found. Add the offset of the key to the drop buffer. */
5185       (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
5186       DBUG_PRINT("info", ("index dropped: '%s'", table_key->name));
5187       continue;
5188     }
5189 
5190     /* Check that the key types are compatible between old and new tables. */
5191     if ((table_key->algorithm != new_key->algorithm) ||
5192 	((table_key->flags & HA_KEYFLAG_MASK) !=
5193          (new_key->flags & HA_KEYFLAG_MASK)) ||
5194         (table_key->key_parts != new_key->key_parts))
5195       goto index_changed;
5196 
5197     /*
5198       Check that the key parts remain compatible between the old and
5199       new tables.
5200     */
5201     for (table_part= table_key->key_part, new_part= new_key->key_part;
5202          table_part < table_part_end;
5203          table_part++, new_part++)
5204     {
5205       /*
5206 	Key definition has changed if we are using a different field or
5207 	if the used key part length is different. We know that the fields
5208         did not change. Comparing field numbers is sufficient.
5209       */
5210       if ((table_part->length != new_part->length) ||
5211           (table_part->fieldnr - 1 != new_part->fieldnr))
5212 	goto index_changed;
5213     }
5214     continue;
5215 
5216   index_changed:
5217     /* Key modified. Add the offset of the key to both buffers. */
5218     (*index_drop_buffer)[(*index_drop_count)++]= table_key - table->key_info;
5219     (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
5220     key_part= new_key->key_part;
5221     end= key_part + new_key->key_parts;
5222     for(; key_part != end; key_part++)
5223     {
5224       // Mark field to be part of new key
5225       field= table->field[key_part->fieldnr];
5226       field->flags|= FIELD_IN_ADD_INDEX;
5227     }
5228     DBUG_PRINT("info", ("index changed: '%s'", table_key->name));
5229   }
5230   /*end of for (; table_key < table_key_end;) */
5231 
5232   /*
5233     Step through all keys of the new table and find matching old keys.
5234   */
5235   for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
5236   {
5237     /* Search an old key with the same name. */
5238     for (table_key= table->key_info; table_key < table_key_end; table_key++)
5239     {
5240       if (! strcmp(table_key->name, new_key->name))
5241         break;
5242     }
5243     if (table_key >= table_key_end)
5244     {
5245       /* Key not found. Add the offset of the key to the add buffer. */
5246       (*index_add_buffer)[(*index_add_count)++]= new_key - *key_info_buffer;
5247       key_part= new_key->key_part;
5248       end= key_part + new_key->key_parts;
5249       for(; key_part != end; key_part++)
5250       {
5251         // Mark field to be part of new key
5252         field= table->field[key_part->fieldnr];
5253         field->flags|= FIELD_IN_ADD_INDEX;
5254       }
5255       DBUG_PRINT("info", ("index added: '%s'", new_key->name));
5256     }
5257   }
5258 
5259   /* Check if changes are compatible with current handler without a copy */
5260   if (table->file->check_if_incompatible_data(create_info, changes))
5261   {
5262     *need_copy_table= ALTER_TABLE_DATA_CHANGED;
5263     DBUG_RETURN(0);
5264   }
5265 
5266   if (*index_drop_count || *index_add_count)
5267   {
5268     *need_copy_table= ALTER_TABLE_INDEX_CHANGED;
5269     DBUG_RETURN(0);
5270   }
5271 
5272   *need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible
5273   DBUG_RETURN(0);
5274 }
5275 
5276 
5277 /*
5278   Manages enabling/disabling of indexes for ALTER TABLE
5279 
5280   SYNOPSIS
5281     alter_table_manage_keys()
5282       table                  Target table
5283       indexes_were_disabled  Whether the indexes of the from table
5284                              were disabled
5285       keys_onoff             ENABLE | DISABLE | LEAVE_AS_IS
5286 
5287   RETURN VALUES
5288     FALSE  OK
5289     TRUE   Error
5290 */
5291 
5292 static
alter_table_manage_keys(TABLE * table,int indexes_were_disabled,enum enum_enable_or_disable keys_onoff)5293 bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
5294                              enum enum_enable_or_disable keys_onoff)
5295 {
5296   int error= 0;
5297   DBUG_ENTER("alter_table_manage_keys");
5298   DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d",
5299              table, indexes_were_disabled, keys_onoff));
5300 
5301   switch (keys_onoff) {
5302   case ENABLE:
5303     error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
5304     break;
5305   case LEAVE_AS_IS:
5306     if (!indexes_were_disabled)
5307       break;
5308     /* fall-through: disabled indexes */
5309   case DISABLE:
5310     error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
5311   }
5312 
5313   if (error == HA_ERR_WRONG_COMMAND)
5314   {
5315     push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
5316                         ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
5317                         table->s->table_name.str);
5318     error= 0;
5319   } else if (error)
5320     table->file->print_error(error, MYF(0));
5321 
5322   DBUG_RETURN(error);
5323 }
5324 
5325 /**
5326   maximum possible length for certain blob types.
5327 
5328   @param[in]      type        Blob type (e.g. MYSQL_TYPE_TINY_BLOB)
5329 
5330   @return
5331     length
5332 */
5333 
5334 static uint
blob_length_by_type(enum_field_types type)5335 blob_length_by_type(enum_field_types type)
5336 {
5337   switch (type)
5338   {
5339   case MYSQL_TYPE_TINY_BLOB:
5340     return 255;
5341   case MYSQL_TYPE_BLOB:
5342     return 65535;
5343   case MYSQL_TYPE_MEDIUM_BLOB:
5344     return 16777215;
5345   case MYSQL_TYPE_LONG_BLOB:
5346     return 4294967295U;
5347   default:
5348     DBUG_ASSERT(0); // we should never go here
5349     return 0;
5350   }
5351 }
5352 
5353 
5354 /**
5355   Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
5356 
5357   This function transforms parse output of ALTER TABLE - lists of
5358   columns and keys to add, drop or modify into, essentially,
5359   CREATE TABLE definition - a list of columns and keys of the new
5360   table. While doing so, it also performs some (bug not all)
5361   semantic checks.
5362 
5363   This function is invoked when we know that we're going to
5364   perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE
5365   is not possible, perhaps because the ALTER statement contains
5366   instructions that require change in table data, not only in
5367   table definition or indexes.
5368 
5369   @param[in,out]  thd         thread handle. Used as a memory pool
5370                               and source of environment information.
5371   @param[in]      table       the source table, open and locked
5372                               Used as an interface to the storage engine
5373                               to acquire additional information about
5374                               the original table.
5375   @param[in,out]  create_info A blob with CREATE/ALTER TABLE
5376                               parameters
5377   @param[in,out]  alter_info  Another blob with ALTER/CREATE parameters.
5378                               Originally create_info was used only in
5379                               CREATE TABLE and alter_info only in ALTER TABLE.
5380                               But since ALTER might end-up doing CREATE,
5381                               this distinction is gone and we just carry
5382                               around two structures.
5383 
5384   @return
5385     Fills various create_info members based on information retrieved
5386     from the storage engine.
5387     Sets create_info->varchar if the table has a VARCHAR column.
5388     Prepares alter_info->create_list and alter_info->key_list with
5389     columns and keys of the new table.
5390   @retval TRUE   error, out of memory or a semantical error in ALTER
5391                  TABLE instructions
5392   @retval FALSE  success
5393 */
5394 
5395 bool
mysql_prepare_alter_table(THD * thd,TABLE * table,HA_CREATE_INFO * create_info,Alter_info * alter_info)5396 mysql_prepare_alter_table(THD *thd, TABLE *table,
5397                           HA_CREATE_INFO *create_info,
5398                           Alter_info *alter_info)
5399 {
5400   /* New column definitions are added here */
5401   List<Create_field> new_create_list;
5402   /* New key definitions are added here */
5403   List<Key> new_key_list;
5404   List_iterator<Alter_drop> drop_it(alter_info->drop_list);
5405   List_iterator<Create_field> def_it(alter_info->create_list);
5406   List_iterator<Alter_column> alter_it(alter_info->alter_list);
5407   List_iterator<Key> key_it(alter_info->key_list);
5408   List_iterator<Create_field> find_it(new_create_list);
5409   List_iterator<Create_field> field_it(new_create_list);
5410   List<Key_part_spec> key_parts;
5411   uint db_create_options= (table->s->db_create_options
5412                            & ~(HA_OPTION_PACK_RECORD));
5413   uint used_fields= create_info->used_fields;
5414   KEY *key_info=table->key_info;
5415   bool rc= TRUE;
5416 
5417   DBUG_ENTER("mysql_prepare_alter_table");
5418 
5419   create_info->varchar= FALSE;
5420   /* Let new create options override the old ones */
5421   if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
5422     create_info->min_rows= table->s->min_rows;
5423   if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
5424     create_info->max_rows= table->s->max_rows;
5425   if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
5426     create_info->avg_row_length= table->s->avg_row_length;
5427   if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
5428     create_info->default_table_charset= table->s->table_charset;
5429   if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
5430   {
5431     /* Table has an autoincrement, copy value to new table */
5432     table->file->info(HA_STATUS_AUTO);
5433     create_info->auto_increment_value= table->file->stats.auto_increment_value;
5434   }
5435   if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
5436     create_info->key_block_size= table->s->key_block_size;
5437 
5438   if (!create_info->tablespace)
5439     create_info->tablespace= table->s->tablespace;
5440 
5441   if (create_info->storage_media == HA_SM_DEFAULT)
5442     create_info->storage_media= table->s->default_storage_media;
5443 
5444   /* Creation of federated table with LIKE clause needs connection string */
5445   if (!(used_fields & HA_CREATE_USED_CONNECTION))
5446     create_info->connect_string= table->s->connect_string;
5447 
5448   restore_record(table, s->default_values);     // Empty record for DEFAULT
5449   Create_field *def;
5450 
5451   /*
5452     First collect all fields from table which isn't in drop_list
5453   */
5454   Field **f_ptr,*field;
5455   for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
5456   {
5457     if (field->type() == MYSQL_TYPE_STRING)
5458       create_info->varchar= TRUE;
5459     /* Check if field should be dropped */
5460     Alter_drop *drop;
5461     drop_it.rewind();
5462     while ((drop=drop_it++))
5463     {
5464       if (drop->type == Alter_drop::COLUMN &&
5465 	  !my_strcasecmp(system_charset_info,field->field_name, drop->name))
5466       {
5467 	/* Reset auto_increment value if it was dropped */
5468 	if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
5469 	    !(used_fields & HA_CREATE_USED_AUTO))
5470 	{
5471 	  create_info->auto_increment_value=0;
5472 	  create_info->used_fields|=HA_CREATE_USED_AUTO;
5473 	}
5474 	break;
5475       }
5476     }
5477     if (drop)
5478     {
5479       drop_it.remove();
5480       /*
5481         ALTER TABLE DROP COLUMN always changes table data even in cases
5482         when new version of the table has the same structure as the old
5483         one.
5484       */
5485       alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
5486       continue;
5487     }
5488     /* Check if field is changed */
5489     def_it.rewind();
5490     while ((def=def_it++))
5491     {
5492       if (def->change &&
5493 	  !my_strcasecmp(system_charset_info,field->field_name, def->change))
5494 	break;
5495     }
5496     if (def)
5497     {						// Field is changed
5498       def->field=field;
5499       if (!def->after)
5500       {
5501 	new_create_list.push_back(def);
5502 	def_it.remove();
5503       }
5504     }
5505     else
5506     {
5507       /*
5508         This field was not dropped and not changed, add it to the list
5509         for the new table.
5510       */
5511       def= new Create_field(field, field);
5512       new_create_list.push_back(def);
5513       alter_it.rewind();			// Change default if ALTER
5514       Alter_column *alter;
5515       while ((alter=alter_it++))
5516       {
5517 	if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
5518 	  break;
5519       }
5520       if (alter)
5521       {
5522 	if (def->sql_type == MYSQL_TYPE_BLOB)
5523 	{
5524 	  my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
5525           goto err;
5526 	}
5527 	if ((def->def=alter->def))              // Use new default
5528           def->flags&= ~NO_DEFAULT_VALUE_FLAG;
5529         else
5530           def->flags|= NO_DEFAULT_VALUE_FLAG;
5531 	alter_it.remove();
5532       }
5533     }
5534   }
5535   def_it.rewind();
5536   while ((def=def_it++))			// Add new columns
5537   {
5538     if (def->change && ! def->field)
5539     {
5540       my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
5541       goto err;
5542     }
5543     /*
5544       Check that the DATE/DATETIME not null field we are going to add is
5545       either has a default value or the '0000-00-00' is allowed by the
5546       set sql mode.
5547       If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
5548       flag to allow ALTER TABLE only if the table to be altered is empty.
5549     */
5550     if ((def->sql_type == MYSQL_TYPE_DATE ||
5551          def->sql_type == MYSQL_TYPE_NEWDATE ||
5552          def->sql_type == MYSQL_TYPE_DATETIME) &&
5553          !alter_info->datetime_field &&
5554          !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
5555          thd->variables.sql_mode & MODE_NO_ZERO_DATE)
5556     {
5557         alter_info->datetime_field= def;
5558         alter_info->error_if_not_empty= TRUE;
5559     }
5560     if (!def->after)
5561       new_create_list.push_back(def);
5562     else if (def->after == first_keyword)
5563     {
5564       new_create_list.push_front(def);
5565       /*
5566         Re-ordering columns in table can't be done using in-place algorithm
5567         as it always changes table data.
5568       */
5569       alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
5570     }
5571     else
5572     {
5573       Create_field *find;
5574       find_it.rewind();
5575       while ((find=find_it++))			// Add new columns
5576       {
5577 	if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
5578 	  break;
5579       }
5580       if (!find)
5581       {
5582 	my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
5583         goto err;
5584       }
5585       find_it.after(def);			// Put element after this
5586       /*
5587         Re-ordering columns in table can't be done using in-place algorithm
5588         as it always changes table data.
5589       */
5590       alter_info->change_level= ALTER_TABLE_DATA_CHANGED;
5591     }
5592   }
5593   if (alter_info->alter_list.elements)
5594   {
5595     my_error(ER_BAD_FIELD_ERROR, MYF(0),
5596              alter_info->alter_list.head()->name, table->s->table_name.str);
5597     goto err;
5598   }
5599   if (!new_create_list.elements)
5600   {
5601     my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
5602                MYF(0));
5603     goto err;
5604   }
5605 
5606   /*
5607     Collect all keys which isn't in drop list. Add only those
5608     for which some fields exists.
5609   */
5610 
5611   for (uint i=0 ; i < table->s->keys ; i++,key_info++)
5612   {
5613     char *key_name= key_info->name;
5614     Alter_drop *drop;
5615     drop_it.rewind();
5616     while ((drop=drop_it++))
5617     {
5618       if (drop->type == Alter_drop::KEY &&
5619 	  !my_strcasecmp(system_charset_info,key_name, drop->name))
5620 	break;
5621     }
5622     if (drop)
5623     {
5624       drop_it.remove();
5625       continue;
5626     }
5627 
5628     KEY_PART_INFO *key_part= key_info->key_part;
5629     key_parts.empty();
5630     for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
5631     {
5632       if (!key_part->field)
5633 	continue;				// Wrong field (from UNIREG)
5634       const char *key_part_name=key_part->field->field_name;
5635       Create_field *cfield;
5636       field_it.rewind();
5637       while ((cfield=field_it++))
5638       {
5639 	if (cfield->change)
5640 	{
5641 	  if (!my_strcasecmp(system_charset_info, key_part_name,
5642 			     cfield->change))
5643 	    break;
5644 	}
5645 	else if (!my_strcasecmp(system_charset_info,
5646 				key_part_name, cfield->field_name))
5647 	  break;
5648       }
5649       if (!cfield)
5650 	continue;				// Field is removed
5651       uint key_part_length=key_part->length;
5652       if (cfield->field)			// Not new field
5653       {
5654         /*
5655           If the field can't have only a part used in a key according to its
5656           new type, or should not be used partially according to its
5657           previous type, or the field length is less than the key part
5658           length, unset the key part length.
5659 
5660           We also unset the key part length if it is the same as the
5661           old field's length, so the whole new field will be used.
5662 
5663           BLOBs may have cfield->length == 0, which is why we test it before
5664           checking whether cfield->length < key_part_length (in chars).
5665 
5666           In case of TEXTs we check the data type maximum length *in bytes*
5667           to key part length measured *in characters* (i.e. key_part_length
5668           devided to mbmaxlen). This is because it's OK to have:
5669           CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8);
5670           In case of this example:
5671           - data type maximum length is 255.
5672           - key_part_length is 1016 (=254*4, where 4 is mbmaxlen)
5673          */
5674         if (!Field::type_can_have_key_part(cfield->field->type()) ||
5675             !Field::type_can_have_key_part(cfield->sql_type) ||
5676             /* spatial keys can't have sub-key length */
5677             (key_info->flags & HA_SPATIAL) ||
5678             (cfield->field->field_length == key_part_length &&
5679              !f_is_blob(key_part->key_type)) ||
5680             (cfield->length && (((cfield->sql_type >= MYSQL_TYPE_TINY_BLOB &&
5681                                   cfield->sql_type <= MYSQL_TYPE_BLOB) ?
5682                                 blob_length_by_type(cfield->sql_type) :
5683                                 cfield->length) <
5684 	     key_part_length / key_part->field->charset()->mbmaxlen)))
5685 	  key_part_length= 0;			// Use whole field
5686       }
5687       key_part_length /= key_part->field->charset()->mbmaxlen;
5688       key_parts.push_back(new Key_part_spec(cfield->field_name,
5689                                             strlen(cfield->field_name),
5690 					    key_part_length));
5691     }
5692     if (key_parts.elements)
5693     {
5694       KEY_CREATE_INFO key_create_info;
5695       Key *key;
5696       enum Key::Keytype key_type;
5697       bzero((char*) &key_create_info, sizeof(key_create_info));
5698 
5699       key_create_info.algorithm= key_info->algorithm;
5700       if (key_info->flags & HA_USES_BLOCK_SIZE)
5701         key_create_info.block_size= key_info->block_size;
5702       if (key_info->flags & HA_USES_PARSER)
5703         key_create_info.parser_name= *plugin_name(key_info->parser);
5704       if (key_info->flags & HA_USES_COMMENT)
5705         key_create_info.comment= key_info->comment;
5706 
5707       if (key_info->flags & HA_SPATIAL)
5708         key_type= Key::SPATIAL;
5709       else if (key_info->flags & HA_NOSAME)
5710       {
5711         if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
5712           key_type= Key::PRIMARY;
5713         else
5714           key_type= Key::UNIQUE;
5715       }
5716       else if (key_info->flags & HA_FULLTEXT)
5717         key_type= Key::FULLTEXT;
5718       else
5719         key_type= Key::MULTIPLE;
5720 
5721       key= new Key(key_type, key_name, strlen(key_name),
5722                    &key_create_info,
5723                    test(key_info->flags & HA_GENERATED_KEY),
5724                    key_parts);
5725       new_key_list.push_back(key);
5726     }
5727   }
5728   {
5729     Key *key;
5730     while ((key=key_it++))			// Add new keys
5731     {
5732       if (key->type != Key::FOREIGN_KEY)
5733         new_key_list.push_back(key);
5734       if (key->name.str &&
5735 	  !my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
5736       {
5737 	my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
5738         goto err;
5739       }
5740     }
5741   }
5742 
5743   if (alter_info->drop_list.elements)
5744   {
5745     my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
5746              alter_info->drop_list.head()->name);
5747     goto err;
5748   }
5749   if (alter_info->alter_list.elements)
5750   {
5751     my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
5752              alter_info->alter_list.head()->name);
5753     goto err;
5754   }
5755 
5756   if (!create_info->comment.str)
5757   {
5758     create_info->comment.str= table->s->comment.str;
5759     create_info->comment.length= table->s->comment.length;
5760   }
5761 
5762   table->file->update_create_info(create_info);
5763   if ((create_info->table_options &
5764        (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
5765       (used_fields & HA_CREATE_USED_PACK_KEYS))
5766     db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
5767   if (create_info->table_options &
5768       (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
5769     db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
5770   if (create_info->table_options &
5771       (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
5772     db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
5773 			  HA_OPTION_NO_DELAY_KEY_WRITE);
5774   create_info->table_options|= db_create_options;
5775 
5776   if (table->s->tmp_table)
5777     create_info->options|=HA_LEX_CREATE_TMP_TABLE;
5778 
5779   rc= FALSE;
5780   alter_info->create_list.swap(new_create_list);
5781   alter_info->key_list.swap(new_key_list);
5782 err:
5783   DBUG_RETURN(rc);
5784 }
5785 
5786 
5787 /*
5788   Alter table
5789 
5790   SYNOPSIS
5791     mysql_alter_table()
5792       thd              Thread handle
5793       new_db           If there is a RENAME clause
5794       new_name         If there is a RENAME clause
5795       create_info      Information from the parsing phase about new
5796                        table properties.
5797       table_list       The table to change.
5798       alter_info       Lists of fields, keys to be changed, added
5799                        or dropped.
5800       order_num        How many ORDER BY fields has been specified.
5801       order            List of fields to ORDER BY.
5802       ignore           Whether we have ALTER IGNORE TABLE
5803 
5804   DESCRIPTION
5805     This is a veery long function and is everything but the kitchen sink :)
5806     It is used to alter a table and not only by ALTER TABLE but also
5807     CREATE|DROP INDEX are mapped on this function.
5808 
5809     When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS,
5810     or both, then this function short cuts its operation by renaming
5811     the table and/or enabling/disabling the keys. In this case, the FRM is
5812     not changed, directly by mysql_alter_table. However, if there is a
5813     RENAME + change of a field, or an index, the short cut is not used.
5814     See how `create_list` is used to generate the new FRM regarding the
5815     structure of the fields. The same is done for the indices of the table.
5816 
5817     Important is the fact, that this function tries to do as little work as
5818     possible, by finding out whether a intermediate table is needed to copy
5819     data into and when finishing the altering to use it as the original table.
5820     For this reason the function mysql_compare_tables() is called, which decides
5821     based on all kind of data how similar are the new and the original
5822     tables.
5823 
5824   RETURN VALUES
5825     FALSE  OK
5826     TRUE   Error
5827 */
5828 
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)5829 bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
5830                        HA_CREATE_INFO *create_info,
5831                        TABLE_LIST *table_list,
5832                        Alter_info *alter_info,
5833                        uint order_num, ORDER *order, bool ignore)
5834 {
5835   TABLE *table, *new_table= 0;
5836   MDL_ticket *mdl_ticket;
5837   MDL_request target_mdl_request;
5838   int error= 0;
5839   char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
5840   char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
5841   char index_file[FN_REFLEN], data_file[FN_REFLEN];
5842   char path[FN_REFLEN + 1];
5843   char reg_path[FN_REFLEN+1];
5844   ha_rows copied,deleted;
5845   handlerton *old_db_type, *new_db_type, *save_old_db_type;
5846   enum_alter_table_change_level need_copy_table= ALTER_TABLE_METADATA_ONLY;
5847 #ifdef WITH_PARTITION_STORAGE_ENGINE
5848   TABLE *table_for_fast_alter_partition= NULL;
5849   bool partition_changed= FALSE;
5850 #endif
5851   bool need_lock_for_indexes= TRUE;
5852   KEY  *key_info_buffer;
5853   uint index_drop_count= 0;
5854   uint *index_drop_buffer= NULL;
5855   uint index_add_count= 0;
5856   handler_add_index *add= NULL;
5857   bool pending_inplace_add_index= false;
5858   uint *index_add_buffer= NULL;
5859   uint candidate_key_count= 0;
5860   bool no_pk;
5861   DBUG_ENTER("mysql_alter_table");
5862 
5863   /*
5864     Check if we attempt to alter mysql.slow_log or
5865     mysql.general_log table and return an error if
5866     it is the case.
5867     TODO: this design is obsolete and will be removed.
5868   */
5869   if (table_list && table_list->db && table_list->table_name)
5870   {
5871     int table_kind= 0;
5872 
5873     table_kind= check_if_log_table(table_list->db_length, table_list->db,
5874                                    table_list->table_name_length,
5875                                    table_list->table_name, 0);
5876 
5877     if (table_kind)
5878     {
5879       /* Disable alter of enabled log tables */
5880       if (logger.is_log_table_enabled(table_kind))
5881       {
5882         my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
5883         DBUG_RETURN(TRUE);
5884       }
5885 
5886       /* Disable alter of log tables to unsupported engine */
5887       if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
5888           (!create_info->db_type || /* unknown engine */
5889            !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
5890       {
5891         my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
5892         DBUG_RETURN(TRUE);
5893       }
5894 
5895 #ifdef WITH_PARTITION_STORAGE_ENGINE
5896       if (alter_info->flags & ALTER_PARTITION)
5897       {
5898         my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
5899         DBUG_RETURN(TRUE);
5900       }
5901 #endif
5902     }
5903   }
5904 
5905   /*
5906     Assign variables table_name, new_name, db, new_db, path, reg_path
5907     to simplify further comparisions: we want to see if it's a RENAME
5908     later just by comparing the pointers, avoiding the need for strcmp.
5909   */
5910   thd_proc_info(thd, "init");
5911   table_name=table_list->table_name;
5912   alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
5913   db=table_list->db;
5914   if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
5915     new_db= db;
5916   build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0);
5917   build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
5918 
5919   mysql_ha_rm_tables(thd, table_list);
5920 
5921   /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
5922   if (alter_info->tablespace_op != NO_TABLESPACE_OP)
5923     /* Conditionally writes to binlog. */
5924     DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
5925 						   alter_info->tablespace_op));
5926 
5927   /*
5928     Code below can handle only base tables so ensure that we won't open a view.
5929     Note that RENAME TABLE the only ALTER clause which is supported for views
5930     has been already processed.
5931   */
5932   table_list->required_type= FRMTYPE_TABLE;
5933 
5934   Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
5935 
5936   DEBUG_SYNC(thd, "alter_table_before_open_tables");
5937   error= open_and_lock_tables(thd, table_list, FALSE, 0,
5938                               &alter_prelocking_strategy);
5939 
5940   if (error)
5941   {
5942     DBUG_RETURN(TRUE);
5943   }
5944 
5945   table= table_list->table;
5946   table->use_all_columns();
5947   mdl_ticket= table->mdl_ticket;
5948 
5949   /*
5950     Prohibit changing of the UNION list of a non-temporary MERGE table
5951     under LOCK tables. It would be quite difficult to reuse a shrinked
5952     set of tables from the old table or to open a new TABLE object for
5953     an extended list and verify that they belong to locked tables.
5954   */
5955   if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
5956        thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) &&
5957       (create_info->used_fields & HA_CREATE_USED_UNION) &&
5958       (table->s->tmp_table == NO_TMP_TABLE))
5959   {
5960     my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
5961     DBUG_RETURN(TRUE);
5962   }
5963 
5964   /* Check that we are not trying to rename to an existing table */
5965   if (new_name)
5966   {
5967     DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name));
5968     strmov(new_name_buff,new_name);
5969     strmov(new_alias= new_alias_buff, new_name);
5970     if (lower_case_table_names)
5971     {
5972       if (lower_case_table_names != 2)
5973       {
5974 	my_casedn_str(files_charset_info, new_name_buff);
5975 	new_alias= new_name;			// Create lower case table name
5976       }
5977       my_casedn_str(files_charset_info, new_name);
5978     }
5979     if (new_db == db &&
5980 	!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
5981     {
5982       /*
5983 	Source and destination table names are equal: make later check
5984 	easier.
5985       */
5986       new_alias= new_name= table_name;
5987     }
5988     else
5989     {
5990       if (table->s->tmp_table != NO_TMP_TABLE)
5991       {
5992 	if (find_temporary_table(thd,new_db,new_name_buff))
5993 	{
5994 	  my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
5995 	  DBUG_RETURN(TRUE);
5996 	}
5997       }
5998       else
5999       {
6000         MDL_request_list mdl_requests;
6001         MDL_request target_db_mdl_request;
6002 
6003         target_mdl_request.init(MDL_key::TABLE, new_db, new_name,
6004                                 MDL_EXCLUSIVE, MDL_TRANSACTION);
6005         mdl_requests.push_front(&target_mdl_request);
6006 
6007         /*
6008           If we are moving the table to a different database, we also
6009           need IX lock on the database name so that the target database
6010           is protected by MDL while the table is moved.
6011         */
6012         if (new_db != db)
6013         {
6014           target_db_mdl_request.init(MDL_key::SCHEMA, new_db, "",
6015                                      MDL_INTENTION_EXCLUSIVE,
6016                                      MDL_TRANSACTION);
6017           mdl_requests.push_front(&target_db_mdl_request);
6018         }
6019 
6020         /*
6021           Global intention exclusive lock must have been already acquired when
6022           table to be altered was open, so there is no need to do it here.
6023         */
6024         DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::GLOBAL,
6025                                                    "", "",
6026                                                    MDL_INTENTION_EXCLUSIVE));
6027 
6028         if (thd->mdl_context.acquire_locks(&mdl_requests,
6029                                            thd->variables.lock_wait_timeout))
6030           DBUG_RETURN(TRUE);
6031 
6032         DEBUG_SYNC(thd, "locked_table_name");
6033         /*
6034           Table maybe does not exist, but we got an exclusive lock
6035           on the name, now we can safely try to find out for sure.
6036         */
6037         build_table_filename(new_name_buff, sizeof(new_name_buff) - 1,
6038                              new_db, new_name_buff, reg_ext, 0);
6039         if (!access(new_name_buff, F_OK))
6040 	{
6041 	  /* Table will be closed in do_command() */
6042 	  my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
6043           goto err;
6044 	}
6045       }
6046     }
6047   }
6048   else
6049   {
6050     new_alias= (lower_case_table_names == 2) ? alias : table_name;
6051     new_name= table_name;
6052   }
6053 
6054   old_db_type= table->s->db_type();
6055   if (!create_info->db_type)
6056   {
6057 #ifdef WITH_PARTITION_STORAGE_ENGINE
6058     if (table->part_info &&
6059         create_info->used_fields & HA_CREATE_USED_ENGINE)
6060     {
6061       /*
6062         This case happens when the user specified
6063         ENGINE = x where x is a non-existing storage engine
6064         We set create_info->db_type to default_engine_type
6065         to ensure we don't change underlying engine type
6066         due to a erroneously given engine name.
6067       */
6068       create_info->db_type= table->part_info->default_engine_type;
6069     }
6070     else
6071 #endif
6072       create_info->db_type= old_db_type;
6073   }
6074 
6075   if (check_engine(thd, new_db, new_name, create_info))
6076     goto err;
6077   new_db_type= create_info->db_type;
6078 
6079   if ((new_db_type != old_db_type ||
6080        alter_info->flags & ALTER_PARTITION) &&
6081       !table->file->can_switch_engines())
6082   {
6083     my_error(ER_ROW_IS_REFERENCED, MYF(0));
6084     goto err;
6085   }
6086 
6087   /*
6088    If foreign key is added then check permission to access parent table.
6089 
6090    In function "check_fk_parent_table_access", create_info->db_type is used
6091    to identify whether engine supports FK constraint or not. Since
6092    create_info->db_type is set here, check to parent table access is delayed
6093    till this point for the alter operation.
6094   */
6095   if ((alter_info->flags & ALTER_FOREIGN_KEY) &&
6096       check_fk_parent_table_access(thd, create_info, alter_info))
6097     goto err;
6098 
6099   /*
6100    If this is an ALTER TABLE and no explicit row type specified reuse
6101    the table's row type.
6102    Note : this is the same as if the row type was specified explicitly.
6103   */
6104   if (create_info->row_type == ROW_TYPE_NOT_USED)
6105   {
6106     /* ALTER TABLE without explicit row type */
6107     create_info->row_type= table->s->row_type;
6108   }
6109   else
6110   {
6111     /* ALTER TABLE with specific row type */
6112     create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
6113   }
6114 
6115   DBUG_PRINT("info", ("old type: %s  new type: %s",
6116              ha_resolve_storage_engine_name(old_db_type),
6117              ha_resolve_storage_engine_name(new_db_type)));
6118   if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
6119       ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
6120   {
6121     DBUG_PRINT("info", ("doesn't support alter"));
6122     my_error(ER_ILLEGAL_HA, MYF(0), table_name);
6123     goto err;
6124   }
6125 
6126   thd_proc_info(thd, "setup");
6127   if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
6128       !table->s->tmp_table) // no need to touch frm
6129   {
6130     switch (alter_info->keys_onoff) {
6131     case LEAVE_AS_IS:
6132       break;
6133     case ENABLE:
6134       if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6135         goto err;
6136       DEBUG_SYNC(thd,"alter_table_enable_indexes");
6137       DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
6138       error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
6139       break;
6140     case DISABLE:
6141       if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6142         goto err;
6143       error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
6144       break;
6145     default:
6146       DBUG_ASSERT(FALSE);
6147       error= 0;
6148       break;
6149     }
6150     if (error == HA_ERR_WRONG_COMMAND)
6151     {
6152       error= 0;
6153       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
6154                           ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
6155                           table->alias);
6156     }
6157 
6158     if (!error && (new_name != table_name || new_db != db))
6159     {
6160       thd_proc_info(thd, "rename");
6161       /*
6162         Then do a 'simple' rename of the table. First we need to close all
6163         instances of 'source' table.
6164         Note that if wait_while_table_is_used() returns error here (i.e. if
6165         this thread was killed) then it must be that previous step of
6166         simple rename did nothing and therefore we can safely return
6167         without additional clean-up.
6168       */
6169       if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6170         goto err;
6171       close_all_tables_for_name(thd, table->s, TRUE, NULL);
6172       /*
6173         Then, we want check once again that target table does not exist.
6174         Actually the order of these two steps does not matter since
6175         earlier we took exclusive metadata lock on the target table, so
6176         we do them in this particular order only to be consistent with 5.0,
6177         in which we don't take this lock and where this order really matters.
6178         TODO: Investigate if we need this access() check at all.
6179       */
6180       if (!access(new_name_buff,F_OK))
6181       {
6182         my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
6183         error= -1;
6184       }
6185       else
6186       {
6187         *fn_ext(new_name)=0;
6188         if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
6189           error= -1;
6190         else if (Table_triggers_list::change_table_name(thd, db,
6191                                                         alias, table_name,
6192                                                         new_db, new_alias))
6193         {
6194           (void) mysql_rename_table(old_db_type, new_db, new_alias, db,
6195                                     table_name, NO_FK_CHECKS);
6196           error= -1;
6197         }
6198       }
6199     }
6200 
6201     if (error == HA_ERR_WRONG_COMMAND)
6202     {
6203       error= 0;
6204       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
6205                           ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
6206                           table->alias);
6207     }
6208 
6209     if (!error)
6210     {
6211       error= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
6212       if (!error)
6213         my_ok(thd);
6214     }
6215     else if (error > 0)
6216     {
6217       table->file->print_error(error, MYF(0));
6218       error= -1;
6219     }
6220     table_list->table= NULL;                    // For query cache
6221     query_cache_invalidate3(thd, table_list, 0);
6222 
6223     if ((thd->locked_tables_mode == LTM_LOCK_TABLES ||
6224          thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES))
6225     {
6226       /*
6227         Under LOCK TABLES we should adjust meta-data locks before finishing
6228         statement. Otherwise we can rely on them being released
6229         along with the implicit commit.
6230       */
6231       if (new_name != table_name || new_db != db)
6232         thd->mdl_context.release_all_locks_for_name(mdl_ticket);
6233       else
6234         mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
6235     }
6236     DBUG_RETURN(error);
6237   }
6238 
6239   /* We have to do full alter table. */
6240 
6241 #ifdef WITH_PARTITION_STORAGE_ENGINE
6242   if (prep_alter_part_table(thd, table, alter_info, create_info, old_db_type,
6243                             &partition_changed,
6244                             db, table_name, path,
6245                             &table_for_fast_alter_partition))
6246     goto err;
6247 #endif
6248   /*
6249     If the old table had partitions and we are doing ALTER TABLE ...
6250     engine= <new_engine>, the new table must preserve the original
6251     partitioning. That means that the new engine is still the
6252     partitioning engine, not the engine specified in the parser.
6253     This is discovered  in prep_alter_part_table, which in such case
6254     updates create_info->db_type.
6255     Now we need to update the stack copy of create_info->db_type,
6256     as otherwise we won't be able to correctly move the files of the
6257     temporary table to the result table files.
6258   */
6259   new_db_type= create_info->db_type;
6260 
6261   if (is_index_maintenance_unique (table, alter_info))
6262     need_copy_table= ALTER_TABLE_DATA_CHANGED;
6263 
6264   if (mysql_prepare_alter_table(thd, table, create_info, alter_info))
6265     goto err;
6266 
6267   if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6268     need_copy_table= alter_info->change_level;
6269 
6270   set_table_default_charset(thd, create_info, db);
6271 
6272   if (thd->variables.old_alter_table
6273       || (table->s->db_type() != create_info->db_type)
6274 #ifdef WITH_PARTITION_STORAGE_ENGINE
6275       || partition_changed
6276 #endif
6277      )
6278     need_copy_table= ALTER_TABLE_DATA_CHANGED;
6279   else
6280   {
6281     enum_alter_table_change_level need_copy_table_res;
6282     /* Check how much the tables differ. */
6283     if (mysql_compare_tables(table, alter_info,
6284                              create_info, order_num,
6285                              &need_copy_table_res,
6286                              &key_info_buffer,
6287                              &index_drop_buffer, &index_drop_count,
6288                              &index_add_buffer, &index_add_count,
6289                              &candidate_key_count))
6290       goto err;
6291 
6292     DBUG_EXECUTE_IF("alter_table_only_metadata_change", {
6293       if (need_copy_table_res != ALTER_TABLE_METADATA_ONLY)
6294         goto err; });
6295     DBUG_EXECUTE_IF("alter_table_only_index_change", {
6296       if (need_copy_table_res != ALTER_TABLE_INDEX_CHANGED)
6297         goto err; });
6298 
6299     if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6300       need_copy_table= need_copy_table_res;
6301   }
6302 
6303   /*
6304     If there are index changes only, try to do them in-place. "Index
6305     changes only" means also that the handler for the table does not
6306     change. The table is open and locked. The handler can be accessed.
6307   */
6308 
6309   if (need_copy_table == ALTER_TABLE_INDEX_CHANGED)
6310   {
6311     int   pk_changed= 0;
6312     ulong alter_flags= 0;
6313     ulong needed_inplace_with_read_flags= 0;
6314     ulong needed_inplace_flags= 0;
6315     KEY   *key;
6316     uint  *idx_p;
6317     uint  *idx_end_p;
6318 
6319     alter_flags= table->file->alter_table_flags(alter_info->flags);
6320     DBUG_PRINT("info", ("alter_flags: %lu", alter_flags));
6321     /* Check dropped indexes. */
6322     for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count;
6323          idx_p < idx_end_p;
6324          idx_p++)
6325     {
6326       key= table->key_info + *idx_p;
6327       DBUG_PRINT("info", ("index dropped: '%s'", key->name));
6328       if (key->flags & HA_NOSAME)
6329       {
6330         /*
6331            Unique key. Check for "PRIMARY".
6332            or if dropping last unique key
6333         */
6334         if ((uint) (key - table->key_info) == table->s->primary_key)
6335         {
6336           DBUG_PRINT("info", ("Dropping primary key"));
6337           /* Primary key. */
6338           needed_inplace_with_read_flags|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE;
6339           needed_inplace_flags|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE;
6340           pk_changed++;
6341           candidate_key_count--;
6342         }
6343         else
6344         {
6345           KEY_PART_INFO *part_end= key->key_part + key->key_parts;
6346           bool is_candidate_key= true;
6347 
6348           /* Non-primary unique key. */
6349           needed_inplace_with_read_flags|=
6350             HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
6351           needed_inplace_flags|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE;
6352 
6353           /*
6354             Check if all fields in key are declared
6355             NOT NULL and adjust candidate_key_count
6356           */
6357           for (KEY_PART_INFO *key_part= key->key_part;
6358                key_part < part_end;
6359                key_part++)
6360             is_candidate_key=
6361               (is_candidate_key &&
6362                (! table->field[key_part->fieldnr-1]->maybe_null()));
6363           if (is_candidate_key)
6364             candidate_key_count--;
6365         }
6366       }
6367       else
6368       {
6369         /* Non-unique key. */
6370         needed_inplace_with_read_flags|= HA_INPLACE_DROP_INDEX_NO_WRITE;
6371         needed_inplace_flags|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE;
6372       }
6373     }
6374     no_pk= ((table->s->primary_key == MAX_KEY) ||
6375             (needed_inplace_with_read_flags &
6376              HA_INPLACE_DROP_PK_INDEX_NO_WRITE));
6377     /* Check added indexes. */
6378     for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count;
6379          idx_p < idx_end_p;
6380          idx_p++)
6381     {
6382       key= key_info_buffer + *idx_p;
6383       DBUG_PRINT("info", ("index added: '%s'", key->name));
6384       if (key->flags & HA_NOSAME)
6385       {
6386         /* Unique key */
6387 
6388         KEY_PART_INFO *part_end= key->key_part + key->key_parts;
6389         bool is_candidate_key= true;
6390 
6391         /*
6392           Check if all fields in key are declared
6393           NOT NULL
6394          */
6395         for (KEY_PART_INFO *key_part= key->key_part;
6396              key_part < part_end;
6397              key_part++)
6398           is_candidate_key=
6399             (is_candidate_key &&
6400              (! table->field[key_part->fieldnr]->maybe_null()));
6401 
6402         /*
6403            Check for "PRIMARY"
6404            or if adding first unique key
6405            defined on non-nullable fields
6406         */
6407 
6408         if ((!my_strcasecmp(system_charset_info,
6409                             key->name, primary_key_name)) ||
6410             (no_pk && candidate_key_count == 0 && is_candidate_key))
6411         {
6412           DBUG_PRINT("info", ("Adding primary key"));
6413           /* Primary key. */
6414           needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE;
6415           needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE;
6416           pk_changed++;
6417           no_pk= false;
6418         }
6419         else
6420         {
6421           /* Non-primary unique key. */
6422           needed_inplace_with_read_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE;
6423           needed_inplace_flags|= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE;
6424         }
6425       }
6426       else
6427       {
6428         /* Non-unique key. */
6429         needed_inplace_with_read_flags|= HA_INPLACE_ADD_INDEX_NO_WRITE;
6430         needed_inplace_flags|= HA_INPLACE_ADD_INDEX_NO_READ_WRITE;
6431       }
6432     }
6433 
6434     if ((candidate_key_count > 0) &&
6435         (needed_inplace_with_read_flags & HA_INPLACE_DROP_PK_INDEX_NO_WRITE))
6436     {
6437       /*
6438         Dropped primary key when there is some other unique
6439         not null key that should be converted to primary key
6440       */
6441       needed_inplace_with_read_flags|= HA_INPLACE_ADD_PK_INDEX_NO_WRITE;
6442       needed_inplace_flags|= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE;
6443       pk_changed= 2;
6444     }
6445 
6446     DBUG_PRINT("info",
6447           ("needed_inplace_with_read_flags: 0x%lx, needed_inplace_flags: 0x%lx",
6448            needed_inplace_with_read_flags, needed_inplace_flags));
6449     /*
6450       In-place add/drop index is possible only if
6451       the primary key is not added and dropped in the same statement.
6452       Otherwise we have to recreate the table.
6453       need_copy_table is no-zero at this place.
6454 
6455       Also, in-place is not possible if we add a primary key
6456       and drop another key in the same statement. If the drop fails,
6457       we will not be able to revert adding of primary key.
6458     */
6459     if ( pk_changed < 2 )
6460     {
6461       if ((needed_inplace_with_read_flags & HA_INPLACE_ADD_PK_INDEX_NO_WRITE) &&
6462           index_drop_count > 0)
6463       {
6464         /*
6465           Do copy, not in-place ALTER.
6466           Avoid setting ALTER_TABLE_METADATA_ONLY.
6467         */
6468       }
6469       else if ((alter_flags & needed_inplace_with_read_flags) ==
6470                needed_inplace_with_read_flags)
6471       {
6472         /* All required in-place flags to allow concurrent reads are present. */
6473         need_copy_table= ALTER_TABLE_METADATA_ONLY;
6474         need_lock_for_indexes= FALSE;
6475       }
6476       else if ((alter_flags & needed_inplace_flags) == needed_inplace_flags)
6477       {
6478         /* All required in-place flags are present. */
6479         need_copy_table= ALTER_TABLE_METADATA_ONLY;
6480       }
6481     }
6482     DBUG_PRINT("info", ("need_copy_table: %u  need_lock: %d",
6483                         need_copy_table, need_lock_for_indexes));
6484   }
6485 
6486   /*
6487     better have a negative test here, instead of positive, like
6488     alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|...
6489     so that ALTER TABLE won't break when somebody will add new flag
6490   */
6491   if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6492     create_info->frm_only= 1;
6493 
6494 #ifdef WITH_PARTITION_STORAGE_ENGINE
6495   if (table_for_fast_alter_partition)
6496   {
6497     DBUG_RETURN(fast_alter_partition_table(thd, table, alter_info,
6498                                            create_info, table_list,
6499                                            db, table_name,
6500                                            table_for_fast_alter_partition));
6501   }
6502 #endif
6503 
6504   my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
6505 	      current_pid, thd->thread_id);
6506   /* Safety fix for innodb */
6507   if (lower_case_table_names)
6508     my_casedn_str(files_charset_info, tmp_name);
6509 
6510   /*
6511     Handling of symlinked tables:
6512     If no rename:
6513       Create new data file and index file on the same disk as the
6514       old data and index files.
6515       Copy data.
6516       Rename new data file over old data file and new index file over
6517       old index file.
6518       Symlinks are not changed.
6519 
6520    If rename:
6521       Create new data file and index file on the same disk as the
6522       old data and index files.  Create also symlinks to point at
6523       the new tables.
6524       Copy data.
6525       At end, rename intermediate tables, and symlinks to intermediate
6526       table, to final table name.
6527       Remove old table and old symlinks
6528 
6529     If rename is made to another database:
6530       Create new tables in new database.
6531       Copy data.
6532       Remove old table and symlinks.
6533   */
6534   if (!strcmp(db, new_db))		// Ignore symlink if db changed
6535   {
6536     if (create_info->index_file_name)
6537     {
6538       /* Fix index_file_name to have 'tmp_name' as basename */
6539       strmov(index_file, tmp_name);
6540       create_info->index_file_name=fn_same(index_file,
6541 					   create_info->index_file_name,
6542 					   1);
6543     }
6544     if (create_info->data_file_name)
6545     {
6546       /* Fix data_file_name to have 'tmp_name' as basename */
6547       strmov(data_file, tmp_name);
6548       create_info->data_file_name=fn_same(data_file,
6549 					  create_info->data_file_name,
6550 					  1);
6551     }
6552   }
6553   else
6554     create_info->data_file_name=create_info->index_file_name=0;
6555 
6556   DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
6557   DBUG_EXECUTE_IF("sleep_before_create_table_no_lock",
6558                   my_sleep(100000););
6559   /*
6560     Create a table with a temporary name.
6561     With create_info->frm_only == 1 this creates a .frm file only.
6562     We don't log the statement, it will be logged later.
6563   */
6564   tmp_disable_binlog(thd);
6565   error= mysql_create_table_no_lock(thd, new_db, tmp_name,
6566                                     create_info,
6567                                     alter_info,
6568                                     1, 0, NULL);
6569   reenable_binlog(thd);
6570   if (error)
6571     goto err;
6572 
6573   /* Open the table if we need to copy the data. */
6574   DBUG_PRINT("info", ("need_copy_table: %u", need_copy_table));
6575   if (need_copy_table != ALTER_TABLE_METADATA_ONLY)
6576   {
6577     if (table->s->tmp_table)
6578     {
6579       Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
6580                                       MYSQL_LOCK_IGNORE_TIMEOUT));
6581       TABLE_LIST tbl;
6582       bzero((void*) &tbl, sizeof(tbl));
6583       tbl.db= new_db;
6584       tbl.table_name= tbl.alias= tmp_name;
6585       /* Table is in thd->temporary_tables */
6586       (void) open_table(thd, &tbl, thd->mem_root, &ot_ctx);
6587       new_table= tbl.table;
6588     }
6589     else
6590     {
6591       char path[FN_REFLEN + 1];
6592       /* table is a normal table: Create temporary table in same directory */
6593       build_table_filename(path, sizeof(path) - 1, new_db, tmp_name, "",
6594                            FN_IS_TMP);
6595       /* Open our intermediate table. */
6596       new_table= open_table_uncached(thd, path, new_db, tmp_name, TRUE);
6597     }
6598     if (!new_table)
6599       goto err_new_table_cleanup;
6600     /*
6601       Note: In case of MERGE table, we do not attach children. We do not
6602       copy data for MERGE tables. Only the children have data.
6603     */
6604   }
6605 
6606   /* Copy the data if necessary. */
6607   thd->count_cuted_fields= CHECK_FIELD_WARN;	// calc cuted fields
6608   thd->cuted_fields=0L;
6609   copied=deleted=0;
6610 
6611   if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
6612       thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
6613   {
6614     /*
6615       Temporarily close the TABLE instances belonging to this
6616       thread except the one to be used for ALTER TABLE.
6617 
6618       This is mostly needed to satisfy InnoDB assumptions/asserts.
6619     */
6620      close_all_tables_for_name(thd, table->s, false, table);
6621   }
6622 
6623   /*
6624     We do not copy data for MERGE tables. Only the children have data.
6625     MERGE tables have HA_NO_COPY_ON_ALTER set.
6626   */
6627   if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
6628   {
6629     /* We don't want update TIMESTAMP fields during ALTER TABLE. */
6630     new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
6631     new_table->next_number_field=new_table->found_next_number_field;
6632     thd_proc_info(thd, "copy to tmp table");
6633     DBUG_EXECUTE_IF("abort_copy_table", {
6634         my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
6635         goto err_new_table_cleanup;
6636       });
6637     error= copy_data_between_tables(table, new_table,
6638                                     alter_info->create_list, ignore,
6639                                     order_num, order, &copied, &deleted,
6640                                     alter_info->keys_onoff,
6641                                     alter_info->error_if_not_empty);
6642   }
6643   else
6644   {
6645     /*
6646       Ensure that we will upgrade the metadata lock if
6647       handler::enable/disable_indexes() will be called.
6648     */
6649     if (alter_info->keys_onoff != LEAVE_AS_IS ||
6650         table->file->indexes_are_disabled())
6651       need_lock_for_indexes= true;
6652     if (!table->s->tmp_table && need_lock_for_indexes &&
6653         wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
6654       goto err_new_table_cleanup;
6655     thd_proc_info(thd, "manage keys");
6656     DEBUG_SYNC(thd, "alter_table_manage_keys");
6657     alter_table_manage_keys(table, table->file->indexes_are_disabled(),
6658                             alter_info->keys_onoff);
6659     error= trans_commit_stmt(thd);
6660     if (trans_commit_implicit(thd))
6661       error= 1;
6662   }
6663   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
6664 
6665   if (error)
6666     goto err_new_table_cleanup;
6667 
6668   /* If we did not need to copy, we might still need to add/drop indexes. */
6669   if (! new_table)
6670   {
6671     uint          *key_numbers;
6672     uint          *keyno_p;
6673     KEY           *key_info;
6674     KEY           *key;
6675     uint          *idx_p;
6676     uint          *idx_end_p;
6677     KEY_PART_INFO *key_part;
6678     KEY_PART_INFO *part_end;
6679     DBUG_PRINT("info", ("No new_table, checking add/drop index"));
6680 
6681     table->file->ha_prepare_for_alter();
6682     if (index_add_count)
6683     {
6684       /* The add_index() method takes an array of KEY structs. */
6685       key_info= (KEY*) thd->alloc(sizeof(KEY) * index_add_count);
6686       key= key_info;
6687       for (idx_p= index_add_buffer, idx_end_p= idx_p + index_add_count;
6688            idx_p < idx_end_p;
6689            idx_p++, key++)
6690       {
6691         /* Copy the KEY struct. */
6692         *key= key_info_buffer[*idx_p];
6693         /* Fix the key parts. */
6694         part_end= key->key_part + key->key_parts;
6695         for (key_part= key->key_part; key_part < part_end; key_part++)
6696           key_part->field= table->field[key_part->fieldnr];
6697       }
6698       /* Add the indexes. */
6699       if ((error= table->file->add_index(table, key_info, index_add_count,
6700                                          &add)))
6701       {
6702         /*
6703           Exchange the key_info for the error message. If we exchange
6704           key number by key name in the message later, we need correct info.
6705         */
6706         KEY *save_key_info= table->key_info;
6707         table->key_info= key_info;
6708         table->file->print_error(error, MYF(0));
6709         table->key_info= save_key_info;
6710         goto err_new_table_cleanup;
6711       }
6712       pending_inplace_add_index= true;
6713     }
6714     /*end of if (index_add_count)*/
6715 
6716     if (index_drop_count)
6717     {
6718       /* Currently we must finalize add index if we also drop indexes */
6719       if (pending_inplace_add_index)
6720       {
6721         /* Committing index changes needs exclusive metadata lock. */
6722         DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
6723                                                    table_list->db,
6724                                                    table_list->table_name,
6725                                                    MDL_EXCLUSIVE));
6726         if ((error= table->file->final_add_index(add, true)))
6727         {
6728           table->file->print_error(error, MYF(0));
6729           goto err_new_table_cleanup;
6730         }
6731         pending_inplace_add_index= false;
6732       }
6733       /* The prepare_drop_index() method takes an array of key numbers. */
6734       key_numbers= (uint*) thd->alloc(sizeof(uint) * index_drop_count);
6735       keyno_p= key_numbers;
6736       /* Get the number of each key. */
6737       for (idx_p= index_drop_buffer, idx_end_p= idx_p + index_drop_count;
6738            idx_p < idx_end_p;
6739            idx_p++, keyno_p++)
6740         *keyno_p= *idx_p;
6741       /*
6742         Tell the handler to prepare for drop indexes.
6743         This re-numbers the indexes to get rid of gaps.
6744       */
6745       error= table->file->prepare_drop_index(table, key_numbers,
6746                                              index_drop_count);
6747       if (!error)
6748       {
6749         /* Tell the handler to finally drop the indexes. */
6750         error= table->file->final_drop_index(table);
6751       }
6752 
6753       if (error)
6754       {
6755         table->file->print_error(error, MYF(0));
6756         if (index_add_count) // Drop any new indexes added.
6757         {
6758           /*
6759             Temporarily set table-key_info to include information about the
6760             indexes added above that we now need to drop.
6761           */
6762           KEY *save_key_info= table->key_info;
6763           table->key_info= key_info_buffer;
6764           if ((error= table->file->prepare_drop_index(table, index_add_buffer,
6765                                                       index_add_count)))
6766             table->file->print_error(error, MYF(0));
6767           else if ((error= table->file->final_drop_index(table)))
6768             table->file->print_error(error, MYF(0));
6769           table->key_info= save_key_info;
6770         }
6771 
6772         /*
6773           Mark this TABLE instance as stale to avoid
6774           out-of-sync index information.
6775         */
6776         table->m_needs_reopen= true;
6777         goto err_new_table_cleanup;
6778       }
6779     }
6780     /*end of if (index_drop_count)*/
6781 
6782     /*
6783       The final .frm file is already created as a temporary file
6784       and will be renamed to the original table name later.
6785     */
6786 
6787     /* Need to commit before a table is unlocked (NDB requirement). */
6788     DBUG_PRINT("info", ("Committing before unlocking table"));
6789     if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
6790       goto err_new_table_cleanup;
6791   }
6792   /*end of if (! new_table) for add/drop index*/
6793 
6794   if (table->s->tmp_table != NO_TMP_TABLE)
6795   {
6796     /*
6797       In-place operations are not supported for temporary tables, so
6798       we don't have to call final_add_index() in this case. The assert
6799       verifies that in-place add index has not been done.
6800     */
6801     DBUG_ASSERT(!pending_inplace_add_index);
6802     /* Close lock if this is a transactional table */
6803     if (thd->lock)
6804     {
6805       if (thd->locked_tables_mode != LTM_LOCK_TABLES &&
6806           thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES)
6807       {
6808         mysql_unlock_tables(thd, thd->lock);
6809         thd->lock=0;
6810       }
6811       else
6812       {
6813         /*
6814           If LOCK TABLES list is not empty and contains this table,
6815           unlock the table and remove the table from this list.
6816         */
6817         mysql_lock_remove(thd, thd->lock, table);
6818       }
6819     }
6820     /* Remove link to old table and rename the new one */
6821     close_temporary_table(thd, table, 1, 1);
6822     /* Should pass the 'new_name' as we store table name in the cache */
6823     if (rename_temporary_table(thd, new_table, new_db, new_name))
6824       goto err_new_table_cleanup;
6825     /* We don't replicate alter table statement on temporary tables */
6826     if (!thd->is_current_stmt_binlog_format_row() &&
6827         write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
6828       DBUG_RETURN(TRUE);
6829     goto end_temporary;
6830   }
6831 
6832   /*
6833     Close the intermediate table that will be the new table, but do
6834     not delete it! Even altough MERGE tables do not have their children
6835     attached here it is safe to call close_temporary_table().
6836   */
6837   if (new_table)
6838   {
6839     close_temporary_table(thd, new_table, 1, 0);
6840     new_table= 0;
6841   }
6842   DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
6843 
6844   /*
6845     Data is copied. Now we:
6846     1) Wait until all other threads will stop using old version of table
6847        by upgrading shared metadata lock to exclusive one.
6848     2) Close instances of table open by this thread and replace them
6849        with placeholders to simplify reopen process.
6850     3) Rename the old table to a temp name, rename the new one to the
6851        old name.
6852     4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
6853        we reopen new version of table.
6854     5) Write statement to the binary log.
6855     6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
6856        remove placeholders and release metadata locks.
6857     7) If we are not not under LOCK TABLES we rely on the caller
6858       (mysql_execute_command()) to release metadata locks.
6859   */
6860 
6861   thd_proc_info(thd, "rename result table");
6862   my_snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
6863 	      current_pid, thd->thread_id);
6864   if (lower_case_table_names)
6865     my_casedn_str(files_charset_info, old_name);
6866 
6867   if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
6868   {
6869     if (pending_inplace_add_index)
6870     {
6871       pending_inplace_add_index= false;
6872       table->file->final_add_index(add, false);
6873     }
6874     // Mark this TABLE instance as stale to avoid out-of-sync index information.
6875     table->m_needs_reopen= true;
6876     goto err_new_table_cleanup;
6877   }
6878   if (pending_inplace_add_index)
6879   {
6880     pending_inplace_add_index= false;
6881     DBUG_EXECUTE_IF("alter_table_rollback_new_index", {
6882       table->file->final_add_index(add, false);
6883       my_error(ER_UNKNOWN_ERROR, MYF(0));
6884       goto err_new_table_cleanup;
6885     });
6886     if ((error= table->file->final_add_index(add, true)))
6887     {
6888       table->file->print_error(error, MYF(0));
6889       goto err_new_table_cleanup;
6890     }
6891   }
6892 
6893   close_all_tables_for_name(thd, table->s,
6894                             new_name != table_name || new_db != db, NULL);
6895 
6896   error=0;
6897   table_list->table= table= 0;                  /* Safety */
6898   save_old_db_type= old_db_type;
6899 
6900   /*
6901     This leads to the storage engine (SE) not being notified for renames in
6902     mysql_rename_table(), because we just juggle with the FRM and nothing
6903     more. If we have an intermediate table, then we notify the SE that
6904     it should become the actual table. Later, we will recycle the old table.
6905     However, in case of ALTER TABLE RENAME there might be no intermediate
6906     table. This is when the old and new tables are compatible, according to
6907     mysql_compare_table(). Then, we need one additional call to
6908     mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
6909     actual rename in the SE and the FRM is not touched. Note that, if the
6910     table is renamed and the SE is also changed, then an intermediate table
6911     is created and the additional call will not take place.
6912   */
6913   if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6914   {
6915     DBUG_ASSERT(new_db_type == old_db_type);
6916     /* This type cannot happen in regular ALTER. */
6917     new_db_type= old_db_type= NULL;
6918   }
6919   if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
6920                          FN_TO_IS_TMP))
6921   {
6922     error=1;
6923     (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
6924   }
6925   else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
6926                               new_alias, FN_FROM_IS_TMP))
6927   {
6928     /* Try to get everything back. */
6929     error= 1;
6930     (void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
6931     (void) mysql_rename_table(old_db_type, db, old_name, db, alias,
6932                             FN_FROM_IS_TMP | NO_FK_CHECKS);
6933   }
6934   else if (new_name != table_name || new_db != db)
6935   {
6936     if (need_copy_table == ALTER_TABLE_METADATA_ONLY &&
6937         mysql_rename_table(save_old_db_type, db, table_name, new_db,
6938                            new_alias, NO_FRM_RENAME))
6939     {
6940       /* Try to get everything back. */
6941       error= 1;
6942       (void) quick_rm_table(new_db_type, new_db, new_alias, 0);
6943       (void) mysql_rename_table(old_db_type, db, old_name, db, alias,
6944                                 FN_FROM_IS_TMP | NO_FK_CHECKS);
6945     }
6946     else if (Table_triggers_list::change_table_name(thd, db, alias,
6947                                                     table_name, new_db,
6948                                                     new_alias))
6949     {
6950       /* Try to get everything back. */
6951       error= 1;
6952       (void) quick_rm_table(new_db_type, new_db, new_alias, 0);
6953       (void) mysql_rename_table(old_db_type, db, old_name, db,
6954                                 alias, FN_FROM_IS_TMP | NO_FK_CHECKS);
6955       /*
6956         If we were performing "fast"/in-place ALTER TABLE we also need
6957         to restore old name of table in storage engine as a separate
6958         step, as the above rename affects .FRM only.
6959       */
6960       if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6961       {
6962         (void) mysql_rename_table(save_old_db_type, new_db, new_alias,
6963                                   db, table_name,
6964                                   NO_FRM_RENAME | NO_FK_CHECKS);
6965       }
6966     }
6967   }
6968 
6969   if (! error)
6970     (void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
6971 
6972   if (error)
6973   {
6974     /* This shouldn't happen. But let us play it safe. */
6975     goto err_with_mdl;
6976   }
6977 
6978   if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
6979   {
6980     /*
6981       Now we have to inform handler that new .FRM file is in place.
6982       To do this we need to obtain a handler object for it.
6983       NO need to tamper with MERGE tables. The real open is done later.
6984     */
6985     Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
6986     TABLE_LIST temp_table_list;
6987     TABLE_LIST *t_table_list;
6988     if (new_name != table_name || new_db != db)
6989     {
6990       temp_table_list.init_one_table(new_db, strlen(new_db),
6991                                      new_name, strlen(new_name),
6992                                      new_name, TL_READ_NO_INSERT);
6993       temp_table_list.mdl_request.ticket= target_mdl_request.ticket;
6994       t_table_list= &temp_table_list;
6995     }
6996     else
6997     {
6998       /*
6999         Under LOCK TABLES, we have a different mdl_lock_ticket
7000         points to a different instance than the one set initially
7001         to request the lock.
7002       */
7003       table_list->mdl_request.ticket= mdl_ticket;
7004       t_table_list= table_list;
7005     }
7006     if (open_table(thd, t_table_list, thd->mem_root, &ot_ctx))
7007     {
7008       goto err_with_mdl;
7009     }
7010 
7011     /* Tell the handler that a new frm file is in place. */
7012     error= t_table_list->table->file->ha_create_handler_files(path, NULL,
7013                                                               CHF_INDEX_FLAG,
7014                                                               create_info);
7015 
7016     DBUG_ASSERT(thd->open_tables == t_table_list->table);
7017     close_thread_table(thd, &thd->open_tables);
7018     t_table_list->table= NULL;
7019 
7020     if (error)
7021       goto err_with_mdl;
7022   }
7023   if (thd->locked_tables_list.reopen_tables(thd))
7024     goto err_with_mdl;
7025 
7026   thd_proc_info(thd, "end");
7027 
7028   DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
7029   DEBUG_SYNC(thd, "alter_table_before_main_binlog");
7030 
7031   ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
7032                       thd->query(), thd->query_length(),
7033                       db, table_name);
7034 
7035   DBUG_ASSERT(!(mysql_bin_log.is_open() &&
7036                 thd->is_current_stmt_binlog_format_row() &&
7037                 (create_info->options & HA_LEX_CREATE_TMP_TABLE)));
7038   if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
7039     DBUG_RETURN(TRUE);
7040 
7041   if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
7042   {
7043     /*
7044       For the alter table to be properly flushed to the logs, we
7045       have to open the new table.  If not, we get a problem on server
7046       shutdown. But we do not need to attach MERGE children.
7047     */
7048     char path[FN_REFLEN];
7049     TABLE *t_table;
7050     build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
7051     t_table= open_table_uncached(thd, path, new_db, tmp_name, FALSE);
7052     if (t_table)
7053     {
7054       intern_close_table(t_table);
7055       my_free(t_table);
7056     }
7057     else
7058       sql_print_warning("Could not open table %s.%s after rename\n",
7059                         new_db,table_name);
7060     ha_flush_logs(old_db_type);
7061   }
7062   table_list->table=0;				// For query cache
7063   query_cache_invalidate3(thd, table_list, 0);
7064 
7065   if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
7066       thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
7067   {
7068     if ((new_name != table_name || new_db != db))
7069       thd->mdl_context.release_all_locks_for_name(mdl_ticket);
7070     else
7071       mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
7072   }
7073 
7074 end_temporary:
7075   my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
7076 	      (ulong) (copied + deleted), (ulong) deleted,
7077 	      (ulong) thd->warning_info->statement_warn_count());
7078   my_ok(thd, copied + deleted, 0L, tmp_name);
7079   DBUG_RETURN(FALSE);
7080 
7081 err_new_table_cleanup:
7082   if (new_table)
7083   {
7084     /* close_temporary_table() frees the new_table pointer. */
7085     close_temporary_table(thd, new_table, 1, 1);
7086   }
7087   else
7088     (void) quick_rm_table(new_db_type, new_db, tmp_name,
7089                           create_info->frm_only ? FN_IS_TMP | FRM_ONLY : FN_IS_TMP);
7090 
7091 err:
7092 #ifdef WITH_PARTITION_STORAGE_ENGINE
7093   /* If prep_alter_part_table created an intermediate table, destroy it. */
7094   if (table_for_fast_alter_partition)
7095     close_temporary(table_for_fast_alter_partition, 1, 0);
7096 #endif /* WITH_PARTITION_STORAGE_ENGINE */
7097   /*
7098     No default value was provided for a DATE/DATETIME field, the
7099     current sql_mode doesn't allow the '0000-00-00' value and
7100     the table to be altered isn't empty.
7101     Report error here.
7102   */
7103   if (alter_info->error_if_not_empty &&
7104       thd->warning_info->current_row_for_warning())
7105   {
7106     const char *f_val= 0;
7107     enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
7108     switch (alter_info->datetime_field->sql_type)
7109     {
7110       case MYSQL_TYPE_DATE:
7111       case MYSQL_TYPE_NEWDATE:
7112         f_val= "0000-00-00";
7113         t_type= MYSQL_TIMESTAMP_DATE;
7114         break;
7115       case MYSQL_TYPE_DATETIME:
7116         f_val= "0000-00-00 00:00:00";
7117         t_type= MYSQL_TIMESTAMP_DATETIME;
7118         break;
7119       default:
7120         /* Shouldn't get here. */
7121         DBUG_ASSERT(0);
7122     }
7123     bool save_abort_on_warning= thd->abort_on_warning;
7124     thd->abort_on_warning= TRUE;
7125     make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
7126                                  f_val, strlength(f_val), t_type,
7127                                  alter_info->datetime_field->field_name);
7128     thd->abort_on_warning= save_abort_on_warning;
7129   }
7130 
7131   DBUG_RETURN(TRUE);
7132 
7133 err_with_mdl:
7134   /*
7135     An error happened while we were holding exclusive name metadata lock
7136     on table being altered. To be safe under LOCK TABLES we should
7137     remove all references to the altered table from the list of locked
7138     tables and release the exclusive metadata lock.
7139   */
7140   thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
7141   thd->mdl_context.release_all_locks_for_name(mdl_ticket);
7142   DBUG_RETURN(TRUE);
7143 }
7144 /* mysql_alter_table */
7145 
7146 
7147 
7148 /**
7149   Prepare the transaction for the alter table's copy phase.
7150 */
7151 
mysql_trans_prepare_alter_copy_data(THD * thd)7152 bool mysql_trans_prepare_alter_copy_data(THD *thd)
7153 {
7154   DBUG_ENTER("mysql_prepare_alter_copy_data");
7155   /*
7156     Turn off recovery logging since rollback of an alter table is to
7157     delete the new table so there is no need to log the changes to it.
7158 
7159     This needs to be done before external_lock.
7160   */
7161   if (ha_enable_transaction(thd, FALSE))
7162     DBUG_RETURN(TRUE);
7163   DBUG_RETURN(FALSE);
7164 }
7165 
7166 
7167 /**
7168   Commit the copy phase of the alter table.
7169 */
7170 
mysql_trans_commit_alter_copy_data(THD * thd)7171 bool mysql_trans_commit_alter_copy_data(THD *thd)
7172 {
7173   bool error= FALSE;
7174   DBUG_ENTER("mysql_commit_alter_copy_data");
7175 
7176   if (ha_enable_transaction(thd, TRUE))
7177     DBUG_RETURN(TRUE);
7178 
7179   /*
7180     Ensure that the new table is saved properly to disk before installing
7181     the new .frm.
7182     And that InnoDB's internal latches are released, to avoid deadlock
7183     when waiting on other instances of the table before rename (Bug#54747).
7184   */
7185   if (trans_commit_stmt(thd))
7186     error= TRUE;
7187   if (trans_commit_implicit(thd))
7188     error= TRUE;
7189 
7190   DBUG_RETURN(error);
7191 }
7192 
7193 
7194 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,enum enum_enable_or_disable keys_onoff,bool error_if_not_empty)7195 copy_data_between_tables(TABLE *from,TABLE *to,
7196 			 List<Create_field> &create,
7197                          bool ignore,
7198 			 uint order_num, ORDER *order,
7199 			 ha_rows *copied,
7200 			 ha_rows *deleted,
7201                          enum enum_enable_or_disable keys_onoff,
7202                          bool error_if_not_empty)
7203 {
7204   int error;
7205   Copy_field *copy,*copy_end;
7206   ulong found_count,delete_count;
7207   THD *thd= current_thd;
7208   uint length= 0;
7209   SORT_FIELD *sortorder;
7210   READ_RECORD info;
7211   TABLE_LIST   tables;
7212   List<Item>   fields;
7213   List<Item>   all_fields;
7214   ha_rows examined_rows;
7215   bool auto_increment_field_copied= 0;
7216   ulong save_sql_mode;
7217   ulonglong prev_insert_id;
7218   DBUG_ENTER("copy_data_between_tables");
7219 
7220   if (mysql_trans_prepare_alter_copy_data(thd))
7221     DBUG_RETURN(-1);
7222 
7223   if (!(copy= new Copy_field[to->s->fields]))
7224     DBUG_RETURN(-1);				/* purecov: inspected */
7225 
7226   if (to->file->ha_external_lock(thd, F_WRLCK))
7227     DBUG_RETURN(-1);
7228 
7229   /* We need external lock before we can disable/enable keys */
7230   alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
7231 
7232   /* We can abort alter table for any table type */
7233   thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
7234                                          (MODE_STRICT_TRANS_TABLES |
7235                                           MODE_STRICT_ALL_TABLES));
7236 
7237   from->file->info(HA_STATUS_VARIABLE);
7238   to->file->ha_start_bulk_insert(from->file->stats.records);
7239 
7240   save_sql_mode= thd->variables.sql_mode;
7241 
7242   List_iterator<Create_field> it(create);
7243   Create_field *def;
7244   copy_end=copy;
7245   for (Field **ptr=to->field ; *ptr ; ptr++)
7246   {
7247     def=it++;
7248     if (def->field)
7249     {
7250       if (*ptr == to->next_number_field)
7251       {
7252         auto_increment_field_copied= TRUE;
7253         /*
7254           If we are going to copy contents of one auto_increment column to
7255           another auto_increment column it is sensible to preserve zeroes.
7256           This condition also covers case when we are don't actually alter
7257           auto_increment column.
7258         */
7259         if (def->field == from->found_next_number_field)
7260           thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
7261       }
7262       (copy_end++)->set(*ptr,def->field,0);
7263     }
7264 
7265   }
7266 
7267   found_count=delete_count=0;
7268 
7269   if (order)
7270   {
7271     if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
7272     {
7273       char warn_buff[MYSQL_ERRMSG_SIZE];
7274       my_snprintf(warn_buff, sizeof(warn_buff),
7275                   "ORDER BY ignored as there is a user-defined clustered index"
7276                   " in the table '%-.192s'", from->s->table_name.str);
7277       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
7278                    warn_buff);
7279     }
7280     else
7281     {
7282       from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
7283                                                 MYF(MY_FAE | MY_ZEROFILL));
7284       bzero((char *) &tables, sizeof(tables));
7285       tables.table= from;
7286       tables.alias= tables.table_name= from->s->table_name.str;
7287       tables.db= from->s->db.str;
7288       error= 1;
7289 
7290       if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
7291           setup_order(thd, thd->lex->select_lex.ref_pointer_array,
7292                       &tables, fields, all_fields, order) ||
7293           !(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
7294           (from->sort.found_records= filesort(thd, from, sortorder, length,
7295                                               (SQL_SELECT *) 0, HA_POS_ERROR,
7296                                               1, &examined_rows)) ==
7297           HA_POS_ERROR)
7298         goto err;
7299     }
7300   };
7301 
7302   /* Tell handler that we have values for all columns in the to table */
7303   to->use_all_columns();
7304   init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE);
7305   if (ignore)
7306     to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
7307   thd->warning_info->reset_current_row_for_warning();
7308   restore_record(to, s->default_values);        // Create empty record
7309   while (!(error=info.read_record(&info)))
7310   {
7311     if (thd->killed)
7312     {
7313       thd->send_kill_message();
7314       error= 1;
7315       break;
7316     }
7317     /* Return error if source table isn't empty. */
7318     if (error_if_not_empty)
7319     {
7320       error= 1;
7321       break;
7322     }
7323     if (to->next_number_field)
7324     {
7325       if (auto_increment_field_copied)
7326         to->auto_increment_field_not_null= TRUE;
7327       else
7328         to->next_number_field->reset();
7329     }
7330 
7331     for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
7332     {
7333       copy_ptr->do_copy(copy_ptr);
7334     }
7335     prev_insert_id= to->file->next_insert_id;
7336     error=to->file->ha_write_row(to->record[0]);
7337     to->auto_increment_field_not_null= FALSE;
7338     if (error)
7339     {
7340       if (!ignore ||
7341           to->file->is_fatal_error(error, HA_CHECK_DUP))
7342       {
7343          if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
7344          {
7345            uint key_nr= to->file->get_dup_key(error);
7346            if ((int) key_nr >= 0)
7347            {
7348              const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
7349              if (key_nr == 0 &&
7350                  (to->key_info[0].key_part[0].field->flags &
7351                   AUTO_INCREMENT_FLAG))
7352                err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
7353              to->file->print_keydup_error(key_nr, err_msg);
7354              break;
7355            }
7356          }
7357 
7358 	to->file->print_error(error,MYF(0));
7359 	break;
7360       }
7361       to->file->restore_auto_increment(prev_insert_id);
7362       delete_count++;
7363     }
7364     else
7365       found_count++;
7366     thd->warning_info->inc_current_row_for_warning();
7367   }
7368   end_read_record(&info);
7369   free_io_cache(from);
7370   delete [] copy;				// This is never 0
7371 
7372   if (to->file->ha_end_bulk_insert() && error <= 0)
7373   {
7374     to->file->print_error(my_errno,MYF(0));
7375     error= 1;
7376   }
7377   to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
7378 
7379   if (mysql_trans_commit_alter_copy_data(thd))
7380     error= 1;
7381 
7382  err:
7383   thd->variables.sql_mode= save_sql_mode;
7384   thd->abort_on_warning= 0;
7385   free_io_cache(from);
7386   *copied= found_count;
7387   *deleted=delete_count;
7388   to->file->ha_release_auto_increment();
7389   if (to->file->ha_external_lock(thd,F_UNLCK))
7390     error=1;
7391   if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
7392     error= 1;
7393   DBUG_RETURN(error > 0 ? -1 : 0);
7394 }
7395 
7396 
7397 /*
7398   Recreates tables by calling mysql_alter_table().
7399 
7400   SYNOPSIS
7401     mysql_recreate_table()
7402     thd			Thread handler
7403     tables		Tables to recreate
7404 
7405  RETURN
7406     Like mysql_alter_table().
7407 */
mysql_recreate_table(THD * thd,TABLE_LIST * table_list)7408 bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
7409 {
7410   HA_CREATE_INFO create_info;
7411   Alter_info alter_info;
7412 
7413   DBUG_ENTER("mysql_recreate_table");
7414   DBUG_ASSERT(!table_list->next_global);
7415   /*
7416     table_list->table has been closed and freed. Do not reference
7417     uninitialized data. open_tables() could fail.
7418   */
7419   table_list->table= NULL;
7420   /* Same applies to MDL ticket. */
7421   table_list->mdl_request.ticket= NULL;
7422   /* Set lock type which is appropriate for ALTER TABLE. */
7423   table_list->lock_type= TL_READ_NO_INSERT;
7424   /* Same applies to MDL request. */
7425   table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
7426 
7427   bzero((char*) &create_info, sizeof(create_info));
7428   create_info.row_type=ROW_TYPE_NOT_USED;
7429   create_info.default_table_charset=default_charset_info;
7430   /* Force alter table to recreate table */
7431   alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
7432   DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info,
7433                                 table_list, &alter_info, 0,
7434                                 (ORDER *) 0, 0));
7435 }
7436 
7437 
mysql_checksum_table(THD * thd,TABLE_LIST * tables,HA_CHECK_OPT * check_opt)7438 bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
7439                           HA_CHECK_OPT *check_opt)
7440 {
7441   TABLE_LIST *table;
7442   List<Item> field_list;
7443   Item *item;
7444   Protocol *protocol= thd->protocol;
7445   DBUG_ENTER("mysql_checksum_table");
7446 
7447   /*
7448     CHECKSUM TABLE returns results and rollbacks statement transaction,
7449     so it should not be used in stored function or trigger.
7450   */
7451   DBUG_ASSERT(! thd->in_sub_stmt);
7452 
7453   field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
7454   item->maybe_null= 1;
7455   field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
7456                                           MY_INT64_NUM_DECIMAL_DIGITS));
7457   item->maybe_null= 1;
7458   if (protocol->send_result_set_metadata(&field_list,
7459                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
7460     DBUG_RETURN(TRUE);
7461 
7462   /* Open one table after the other to keep lock time as short as possible. */
7463   for (table= tables; table; table= table->next_local)
7464   {
7465     char table_name[NAME_LEN*2+2];
7466     TABLE *t;
7467 
7468     strxmov(table_name, table->db ,".", table->table_name, NullS);
7469 
7470     t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0);
7471 
7472     protocol->prepare_for_resend();
7473     protocol->store(table_name, system_charset_info);
7474 
7475     if (!t)
7476     {
7477       /* Table didn't exist */
7478       protocol->store_null();
7479     }
7480     else
7481     {
7482       if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
7483 	  !(check_opt->flags & T_EXTEND))
7484 	protocol->store((ulonglong)t->file->checksum());
7485       else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
7486 	       (check_opt->flags & T_QUICK))
7487 	protocol->store_null();
7488       else
7489       {
7490 	/* calculating table's checksum */
7491 	ha_checksum crc= 0;
7492         uchar null_mask=256 -  (1 << t->s->last_null_bit_pos);
7493 
7494         t->use_all_columns();
7495 
7496 	if (t->file->ha_rnd_init(1))
7497 	  protocol->store_null();
7498 	else
7499 	{
7500 	  for (;;)
7501 	  {
7502             if (thd->killed)
7503             {
7504               /*
7505                  we've been killed; let handler clean up, and remove the
7506                  partial current row from the recordset (embedded lib)
7507               */
7508               t->file->ha_rnd_end();
7509               thd->protocol->remove_last_row();
7510               goto err;
7511             }
7512 	    ha_checksum row_crc= 0;
7513             int error= t->file->rnd_next(t->record[0]);
7514             if (unlikely(error))
7515             {
7516               if (error == HA_ERR_RECORD_DELETED)
7517                 continue;
7518               break;
7519             }
7520 	    if (t->s->null_bytes)
7521             {
7522               /* fix undefined null bits */
7523               t->record[0][t->s->null_bytes-1] |= null_mask;
7524               if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
7525                 t->record[0][0] |= 1;
7526 
7527 	      row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
7528             }
7529 
7530 	    for (uint i= 0; i < t->s->fields; i++ )
7531 	    {
7532 	      Field *f= t->field[i];
7533 
7534              /*
7535                BLOB and VARCHAR have pointers in their field, we must convert
7536                to string; GEOMETRY is implemented on top of BLOB.
7537                BIT may store its data among NULL bits, convert as well.
7538              */
7539               switch (f->type()) {
7540                 case MYSQL_TYPE_BLOB:
7541                 case MYSQL_TYPE_VARCHAR:
7542                 case MYSQL_TYPE_GEOMETRY:
7543                 case MYSQL_TYPE_BIT:
7544                 {
7545                   String tmp;
7546                   f->val_str(&tmp);
7547                   row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
7548                            tmp.length());
7549                   break;
7550                 }
7551                 default:
7552                   row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
7553                   break;
7554 	      }
7555 	    }
7556 
7557 	    crc+= row_crc;
7558 	  }
7559 	  protocol->store((ulonglong)crc);
7560           t->file->ha_rnd_end();
7561 	}
7562       }
7563       trans_rollback_stmt(thd);
7564       close_thread_tables(thd);
7565       /*
7566         Don't release metadata locks, this will be done at
7567         statement end.
7568       */
7569       table->table=0;				// For query cache
7570     }
7571 
7572     if (thd->transaction_rollback_request)
7573     {
7574       /*
7575         If transaction rollback was requested we honor it. To do this we
7576         abort statement and return error as not only CHECKSUM TABLE is
7577         rolled back but the whole transaction in which it was used.
7578       */
7579       thd->protocol->remove_last_row();
7580       goto err;
7581     }
7582 
7583     /* Hide errors from client. Return NULL for problematic tables instead. */
7584     thd->clear_error();
7585 
7586     if (protocol->write())
7587       goto err;
7588   }
7589 
7590   my_eof(thd);
7591   DBUG_RETURN(FALSE);
7592 
7593 err:
7594   DBUG_RETURN(TRUE);
7595 }
7596 
7597 /**
7598   @brief Check if the table can be created in the specified storage engine.
7599 
7600   Checks if the storage engine is enabled and supports the given table
7601   type (e.g. normal, temporary, system). May do engine substitution
7602   if the requested engine is disabled.
7603 
7604   @param thd          Thread descriptor.
7605   @param db_name      Database name.
7606   @param table_name   Name of table to be created.
7607   @param create_info  Create info from parser, including engine.
7608 
7609   @retval true  Engine not available/supported, error has been reported.
7610   @retval false Engine available/supported.
7611 */
check_engine(THD * thd,const char * db_name,const char * table_name,HA_CREATE_INFO * create_info)7612 static bool check_engine(THD *thd, const char *db_name,
7613                          const char *table_name, HA_CREATE_INFO *create_info)
7614 {
7615   DBUG_ENTER("check_engine");
7616   handlerton **new_engine= &create_info->db_type;
7617   handlerton *req_engine= *new_engine;
7618   bool no_substitution=
7619         test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
7620   if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine),
7621                                   no_substitution, 1)))
7622     DBUG_RETURN(true);
7623 
7624   if (req_engine && req_engine != *new_engine)
7625   {
7626     push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
7627                        ER_WARN_USING_OTHER_HANDLER,
7628                        ER(ER_WARN_USING_OTHER_HANDLER),
7629                        ha_resolve_storage_engine_name(*new_engine),
7630                        table_name);
7631   }
7632   if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
7633       ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
7634   {
7635     if (create_info->used_fields & HA_CREATE_USED_ENGINE)
7636     {
7637       my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
7638                ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
7639       *new_engine= 0;
7640       DBUG_RETURN(true);
7641     }
7642     *new_engine= myisam_hton;
7643   }
7644 
7645   /*
7646     Check, if the given table name is system table, and if the storage engine
7647     does supports it.
7648   */
7649   if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
7650       !ha_check_if_supported_system_table(*new_engine, db_name, table_name))
7651   {
7652     my_error(ER_UNSUPPORTED_ENGINE, MYF(0),
7653              ha_resolve_storage_engine_name(*new_engine), db_name, table_name);
7654     *new_engine= NULL;
7655     DBUG_RETURN(true);
7656   }
7657 
7658   DBUG_RETURN(false);
7659 }
7660