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, ¬_used, ¬_used2, ¬_found);
3009 }
3010 else /* not NULL */
3011 {
3012 (void) find_set(interval, def->ptr(), def->length(),
3013 cs, ¬_used, ¬_used2, ¬_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 ×tamps, ×tamps_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, ¬_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