summaryrefslogtreecommitdiff
path: root/sql/sql_table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r--sql/sql_table.cc1200
1 files changed, 677 insertions, 523 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index db64c5afbc2..79c6d4cbaf9 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2012, Oracle and/or its affiliates.
- Copyright (c) 2010, 2011, Monty Program Ab
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2013, Monty Program Ab.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +22,6 @@
#include "unireg.h"
#include "debug_sync.h"
#include "sql_table.h"
-#include "sql_rename.h" // do_rename
#include "sql_parse.h" // test_if_data_home_dir
#include "sql_cache.h" // query_cache_*
#include "sql_base.h" // open_table_uncached, lock_table_names
@@ -55,7 +54,7 @@
#include "sql_parse.h"
#include "sql_show.h"
#include "transaction.h"
-#include "datadict.h" // dd_frm_type()
+#include "sql_audit.h"
#ifdef __WIN__
#include <io.h>
@@ -74,13 +73,8 @@ static int copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, const char *, const char *, HA_CREATE_INFO *);
-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 create_table_mode);
+static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
+ uint *, handler *, KEY **, uint *, int);
/**
@brief Helper function for explain_filename
@@ -206,7 +200,6 @@ uint explain_filename(THD* thd,
uint to_length,
enum_explain_filename_mode explain_mode)
{
- uint res= 0;
char *to_p= to;
char *end_p= to_p + to_length;
const char *db_name= NULL;
@@ -217,7 +210,8 @@ uint explain_filename(THD* thd,
int part_name_len= 0;
const char *subpart_name= NULL;
int subpart_name_len= 0;
- uint name_variant= NORMAL_PART_NAME;
+ uint part_type= NORMAL_PART_NAME;
+
const char *tmp_p;
DBUG_ENTER("explain_filename");
DBUG_PRINT("enter", ("from '%s'", from));
@@ -236,17 +230,18 @@ uint explain_filename(THD* thd,
table_name= tmp_p;
}
tmp_p= table_name;
- while (!res && (tmp_p= strchr(tmp_p, '#')))
+ /* Look if there are partition tokens in the table name. */
+ while ((tmp_p= strchr(tmp_p, '#')))
{
tmp_p++;
switch (tmp_p[0]) {
case 'P':
case 'p':
if (tmp_p[1] == '#')
+ {
part_name= tmp_p + 2;
- else
- res= 1;
- tmp_p+= 2;
+ tmp_p+= 2;
+ }
break;
case 'S':
case 's':
@@ -256,48 +251,32 @@ uint explain_filename(THD* thd,
subpart_name= tmp_p + 3;
tmp_p+= 3;
}
- else if ((tmp_p[1] == 'Q' || tmp_p[1] == 'q') &&
- (tmp_p[2] == 'L' || tmp_p[2] == 'l') &&
- tmp_p[3] == '-')
- {
- tmp_p+= 4; /* sql- prefix found */
- }
- else
- res= 2;
break;
case 'T':
case 't':
if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
(tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
tmp_p[3] == '#' && !tmp_p[4])
- name_variant= TEMP_PART_NAME;
- else
- res= 3;
- tmp_p+= 4;
+ {
+ part_type= TEMP_PART_NAME;
+ tmp_p+= 4;
+ }
break;
case 'R':
case 'r':
if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
(tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
tmp_p[3] == '#' && !tmp_p[4])
- name_variant= RENAMED_PART_NAME;
- else
- res= 4;
- tmp_p+= 4;
+ {
+ part_type= RENAMED_PART_NAME;
+ tmp_p+= 4;
+ }
break;
default:
- res= 5;
+ /* Not partition name part. */
+ ;
}
}
- if (res)
- {
- /* Better to give something back if we fail parsing, than nothing at all */
- DBUG_PRINT("info", ("Error in explain_filename: %u", res));
- sql_print_warning("Invalid (old?) table or database name '%s'", from);
- DBUG_RETURN(my_snprintf(to, to_length,
- "<result %u when explaining filename '%s'>",
- res, from));
- }
if (part_name)
{
table_name_len= part_name - table_name - 3;
@@ -305,7 +284,7 @@ uint explain_filename(THD* thd,
subpart_name_len= strlen(subpart_name);
else
part_name_len= strlen(part_name);
- if (name_variant != NORMAL_PART_NAME)
+ if (part_type != NORMAL_PART_NAME)
{
if (subpart_name)
subpart_name_len-= 5;
@@ -347,9 +326,9 @@ uint explain_filename(THD* thd,
to_p= strnmov(to_p, " ", end_p - to_p);
else
to_p= strnmov(to_p, ", ", end_p - to_p);
- if (name_variant != NORMAL_PART_NAME)
+ if (part_type != NORMAL_PART_NAME)
{
- if (name_variant == TEMP_PART_NAME)
+ if (part_type == TEMP_PART_NAME)
to_p= strnmov(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME),
end_p - to_p);
else
@@ -401,31 +380,14 @@ uint filename_to_tablename(const char *from, char *to, uint to_length
DBUG_ENTER("filename_to_tablename");
DBUG_PRINT("enter", ("from '%s'", from));
- if (!strncmp(from, tmp_file_prefix, tmp_file_prefix_length))
- {
- /* Temporary table name. */
- res= (strnmov(to, from, to_length) - to);
- }
- else
+ res= strconvert(&my_charset_filename, from, FN_REFLEN,
+ system_charset_info, to, to_length, &errors);
+ if (errors) // Old 5.0 name
{
- res= strconvert(&my_charset_filename, from, FN_REFLEN,
- system_charset_info, to, to_length, &errors);
- if (errors) // Old 5.0 name
- {
- res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
- to);
-#ifndef DBUG_OFF
- if (!stay_quiet) {
-#endif /* DBUG_OFF */
- sql_print_error("Invalid (old?) table or database name '%s'", from);
-#ifndef DBUG_OFF
- }
-#endif /* DBUG_OFF */
- /*
- TODO: add a stored procedure for fix table and database names,
- and mention its name in error log.
- */
- }
+ res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) -
+ to);
+ if (IF_DBUG(!stay_quiet,0))
+ sql_print_error("Invalid (old?) table or database name '%s'", from);
}
DBUG_PRINT("exit", ("to '%s'", to));
@@ -1844,11 +1806,10 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
if (flags & WFRM_WRITE_SHADOW)
{
if (mysql_prepare_create_table(lpt->thd, lpt->create_info, lpt->alter_info,
- /*tmp_table*/ 1,
&lpt->db_options, lpt->table->file,
&lpt->key_info_buffer, &lpt->key_count,
C_ALTER_TABLE))
- {
+ {
DBUG_RETURN(TRUE);
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -1871,13 +1832,23 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
#endif
/* Write shadow frm file */
lpt->create_info->table_options= lpt->db_options;
- if ((mysql_create_frm(lpt->thd, shadow_frm_name, lpt->db,
- lpt->table_name, lpt->create_info,
- lpt->alter_info->create_list, lpt->key_count,
- lpt->key_info_buffer, lpt->table->file)) ||
- lpt->table->file->ha_create_handler_files(shadow_path, NULL,
- CHF_CREATE_FLAG,
- lpt->create_info))
+ LEX_CUSTRING frm= build_frm_image(lpt->thd, lpt->table_name,
+ lpt->create_info,
+ lpt->alter_info->create_list,
+ lpt->key_count, lpt->key_info_buffer,
+ lpt->table->file);
+ if (!frm.str)
+ {
+ error= 1;
+ goto end;
+ }
+
+ int error= writefrm(shadow_path, lpt->db, lpt->table_name,
+ lpt->create_info->tmp_table(), frm.str, frm.length);
+ my_free(const_cast<uchar*>(frm.str));
+
+ if (error || lpt->table->file->ha_create_partitioning_metadata(shadow_path,
+ NULL, CHF_CREATE_FLAG))
{
mysql_file_delete(key_file_frm, shadow_frm_name, MYF(0));
error= 1;
@@ -1892,12 +1863,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
handlers that have the main version of the frm file stored in the
handler.
*/
- uchar *data;
+ const uchar *data;
size_t length;
if (readfrm(shadow_path, &data, &length) ||
packfrm(data, length, &lpt->pack_frm_data, &lpt->pack_frm_len))
{
- my_free(data);
+ my_free(const_cast<uchar*>(data));
my_free(lpt->pack_frm_data);
mem_alloc_error(length);
error= 1;
@@ -1915,7 +1886,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
*/
build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- strxmov(frm_name, path, reg_ext, NullS);
+ strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS);
/*
When we are changing to use new frm file we need to ensure that we
don't collide with another thread in process to open the frm file.
@@ -1928,14 +1899,14 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
*/
if (mysql_file_delete(key_file_frm, frm_name, MYF(MY_WME)) ||
#ifdef WITH_PARTITION_STORAGE_ENGINE
- lpt->table->file->ha_create_handler_files(path, shadow_path,
- CHF_DELETE_FLAG, NULL) ||
+ lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
+ CHF_DELETE_FLAG) ||
deactivate_ddl_log_entry(part_info->frm_log_entry->entry_pos) ||
(sync_ddl_log(), FALSE) ||
mysql_file_rename(key_file_frm,
shadow_frm_name, frm_name, MYF(MY_WME)) ||
- lpt->table->file->ha_create_handler_files(path, shadow_path,
- CHF_RENAME_FLAG, NULL))
+ lpt->table->file->ha_create_partitioning_metadata(path, shadow_path,
+ CHF_RENAME_FLAG))
#else
mysql_file_rename(key_file_frm,
shadow_frm_name, frm_name, MYF(MY_WME)))
@@ -2093,13 +2064,6 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
if (lock_table_names(thd, tables, NULL,
thd->variables.lock_wait_timeout, 0))
DBUG_RETURN(true);
- for (table= tables; table; table= table->next_local)
- {
- if (is_temporary_table(table))
- continue;
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
- false);
- }
}
else
{
@@ -2315,8 +2279,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool is_trans;
char *db=table->db;
size_t db_length= table->db_length;
- handlerton *table_type;
- enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
+ handlerton *table_type= 0;
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx",
table->db, table->table_name, (long) table->table,
@@ -2396,29 +2359,14 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
non_temp_tables_count++;
- if (thd->locked_tables_mode)
- {
- if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED))
- {
- error= -1;
- goto err;
- }
- close_all_tables_for_name(thd, table->table->s,
- HA_EXTRA_PREPARE_FOR_DROP, NULL);
- table->table= 0;
- }
-
- /* Check that we have an exclusive lock on the table to be dropped. */
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
table->table_name,
- MDL_EXCLUSIVE));
+ MDL_SHARED));
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */
path_length= build_table_filename(path, sizeof(path) - 1, db, alias,
- reg_ext,
- table->internal_tmp_table ?
- FN_IS_TMP : 0);
+ reg_ext, 0);
/*
This handles the case where a "DROP" was executed and a regular
@@ -2451,14 +2399,9 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
}
}
DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table");
- DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table",
- my_sleep(100000););
error= 0;
- if (drop_temporary ||
- ((access(path, F_OK) &&
- ha_create_table_from_engine(thd, db, alias)) ||
- (!drop_view &&
- dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
+ if ((drop_temporary || !ha_table_exists(thd, db, alias, &table_type) ||
+ (!drop_view && table_type == view_pseudo_hton)))
{
/*
One of the following cases happened:
@@ -2489,29 +2432,46 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
char *end;
/*
- Cannot use the db_type from the table, since that might have changed
- while waiting for the exclusive name lock.
+ It could happen that table's share in the table_def_cache
+ is the only thing that keeps the engine plugin loaded
+ (if it is uninstalled and waits for the ref counter to drop to 0).
+
+ In this case, the tdc_remove_table() below will release and unload
+ the plugin. And ha_delete_table() will get a dangling pointer.
+
+ Let's lock the plugin till the end of the statement.
*/
- if (frm_db_type == DB_TYPE_UNKNOWN)
+ if (table_type && table_type != view_pseudo_hton)
+ ha_lock_engine(thd, table_type);
+
+ if (thd->locked_tables_mode)
{
- dd_frm_type(thd, path, &frm_db_type);
- DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
+ if (wait_while_table_is_used(thd, table->table, HA_EXTRA_NOT_USED,
+ TDC_RT_REMOVE_NOT_OWN_AND_MARK_NOT_USABLE))
+ {
+ error= -1;
+ goto err;
+ }
+ /* the following internally does TDC_RT_REMOVE_ALL */
+ close_all_tables_for_name(thd, table->table->s,
+ HA_EXTRA_PREPARE_FOR_DROP, NULL);
+ table->table= 0;
}
- table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
+ else
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name,
+ false);
+
+ /* Check that we have an exclusive lock on the table to be dropped. */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
+ table->table_name,
+ MDL_EXCLUSIVE));
+
// Remove extension for delete
*(end= path + path_length - reg_ext_length)= '\0';
- DBUG_PRINT("info", ("deleting table of type %d",
- (table_type ? table_type->db_type : 0)));
+
error= ha_delete_table(thd, table_type, path, db, table->table_name,
!dont_log_query);
- /* No error if non existent table and 'IF EXIST' clause or view */
- if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
- (if_exists || table_type == NULL))
- {
- error= 0;
- thd->clear_error();
- }
if (error == HA_ERR_ROW_IS_REFERENCED)
{
/* the table is referenced by a foreign key constraint */
@@ -2519,18 +2479,29 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
}
if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
{
- int new_error;
+ int frm_delete_error, trigger_drop_error= 0;
/* Delete the table definition file */
strmov(end,reg_ext);
- if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
+ frm_delete_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME));
+ if (frm_delete_error)
+ frm_delete_error= my_errno;
+ else
{
non_tmp_table_deleted= TRUE;
- new_error= Table_triggers_list::drop_all_triggers(thd, db,
- table->table_name);
+ trigger_drop_error=
+ Table_triggers_list::drop_all_triggers(thd, db, table->table_name);
+ }
+
+ if (trigger_drop_error ||
+ (frm_delete_error && frm_delete_error != ENOENT))
+ error= 1;
+ else if (!frm_delete_error || !error || if_exists)
+ {
+ error= 0;
+ thd->clear_error();
}
- error|= new_error;
}
- non_tmp_error= error ? TRUE : non_tmp_error;
+ non_tmp_error= error ? TRUE : non_tmp_error;
}
if (error)
{
@@ -2540,6 +2511,13 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
wrong_tables.append('.');
wrong_tables.append(table->table_name);
}
+ else
+ {
+ PSI_CALL_drop_table_share(false, table->db, table->db_length,
+ table->table_name, table->table_name_length);
+ mysql_audit_drop_table(thd, table);
+ }
+
DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table,
table->table ? (long) table->table->s : (long) -1));
@@ -2677,11 +2655,18 @@ bool quick_rm_table(THD *thd, handlerton *base, const char *db,
handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
if (!file)
DBUG_RETURN(true);
- (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, NULL);
+ (void) file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG);
delete file;
}
if (!(flags & (FRM_ONLY|NO_HA_TABLE)))
error|= ha_delete_table(current_thd, base, path, db, table_name, 0);
+
+ if (likely(error == 0))
+ {
+ PSI_CALL_drop_table_share(flags & FN_IS_TMP, db, strlen(db),
+ table_name, strlen(table_name));
+ }
+
DBUG_RETURN(error);
}
@@ -2947,6 +2932,8 @@ int prepare_create_field(Create_field *sql_field,
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIME2:
+ case MYSQL_TYPE_DATETIME2:
case MYSQL_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
@@ -2965,6 +2952,7 @@ int prepare_create_field(Create_field *sql_field,
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_TIMESTAMP2:
/* fall-through */
default:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
@@ -3035,7 +3023,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
while ((column_definition= it++) != NULL)
{
- if (column_definition->sql_type == MYSQL_TYPE_TIMESTAMP || // TIMESTAMP
+ if (is_timestamp_type(column_definition->sql_type) || // TIMESTAMP
column_definition->unireg_check == Field::TIMESTAMP_OLD_FIELD) // Legacy
{
if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL,
@@ -3063,12 +3051,12 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
thd Thread object.
create_info Create information (like MAX_ROWS).
alter_info List of columns and indexes to create
- tmp_table If a temporary table is to be created.
db_options INOUT Table options (like HA_OPTION_PACK_RECORD).
file The handler for the new table.
key_info_buffer OUT An array of KEY structs for the indexes.
key_count OUT The number of elements in the array.
- select_field_count The number of fields coming from a select table.
+ create_table_mode C_ORDINARY_CREATE, C_ALTER_TABLE,
+ C_CREATE_SELECT, C_ASSISTED_DISCOVERY
DESCRIPTION
Prepares the table and key structures for table creation.
@@ -3083,9 +3071,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
static int
mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool tmp_table,
- uint *db_options,
+ Alter_info *alter_info, uint *db_options,
handler *file, KEY **key_info_buffer,
uint *key_count, int create_table_mode)
{
@@ -3101,6 +3087,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
List_iterator<Create_field> it2(alter_info->create_list);
uint total_uneven_bit_length= 0;
int select_field_count= C_CREATE_SELECT(create_table_mode);
+ bool tmp_table= create_table_mode == C_ALTER_TABLE;
DBUG_ENTER("mysql_prepare_create_table");
select_field_pos= alter_info->create_list.elements - select_field_count;
@@ -3387,8 +3374,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->offset= record_offset;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
- if (parse_option_list(thd, &sql_field->option_struct,
- sql_field->option_list,
+ if (parse_option_list(thd, create_info->db_type, &sql_field->option_struct,
+ &sql_field->option_list,
create_info->db_type->field_options, FALSE,
thd->mem_root))
DBUG_RETURN(TRUE);
@@ -3418,15 +3405,13 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (auto_increment &&
(file->ha_table_flags() & HA_NO_AUTO_INCREMENT))
{
- my_message(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT,
- ER(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT), MYF(0));
+ my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
}
if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS))
{
- my_message(ER_TABLE_CANT_HANDLE_BLOB, ER(ER_TABLE_CANT_HANDLE_BLOB),
- MYF(0));
+ my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
}
@@ -3592,8 +3577,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_info->usable_key_parts= key_number;
key_info->algorithm= key->key_create_info.algorithm;
key_info->option_list= key->option_list;
- if (parse_option_list(thd, &key_info->option_struct,
- key_info->option_list,
+ if (parse_option_list(thd, create_info->db_type, &key_info->option_struct,
+ &key_info->option_list,
create_info->db_type->index_options, FALSE,
thd->mem_root))
DBUG_RETURN(TRUE);
@@ -3602,8 +3587,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (!(file->ha_table_flags() & HA_CAN_FULLTEXT))
{
- my_message(ER_TABLE_CANT_HANDLE_FT, ER(ER_TABLE_CANT_HANDLE_FT),
- MYF(0));
+ my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
}
}
@@ -3620,8 +3604,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS))
{
- my_message(ER_TABLE_CANT_HANDLE_SPKEYS, ER(ER_TABLE_CANT_HANDLE_SPKEYS),
- MYF(0));
+ my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0), file->table_type());
DBUG_RETURN(TRUE);
}
if (key_info->user_defined_key_parts != 1)
@@ -3736,7 +3719,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
{
- my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str);
+ my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str,
+ file->table_type());
DBUG_RETURN(TRUE);
}
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
@@ -3858,7 +3842,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
else if (length == 0 && (sql_field->flags & NOT_NULL_FLAG))
{
- my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
+ my_error(ER_WRONG_KEY_COLUMN, MYF(0), file->table_type(),
+ column->field_name.str);
DBUG_RETURN(TRUE);
}
if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
@@ -4000,7 +3985,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
!sql_field->def &&
- sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
+ is_timestamp_type(sql_field->sql_type) &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
{
@@ -4023,6 +4008,9 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
+ if (create_info->tmp_table())
+ create_info->options|=HA_CREATE_DELAY_KEY_WRITE;
+
/* Give warnings for not supported table options */
#if defined(WITH_ARIA_STORAGE_ENGINE)
extern handlerton *maria_hton;
@@ -4035,8 +4023,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
file->engine_name()->str,
"TRANSACTIONAL=1");
- if (parse_option_list(thd, &create_info->option_struct,
- create_info->option_list,
+ if (parse_option_list(thd, file->partition_ht(), &create_info->option_struct,
+ &create_info->option_list,
file->partition_ht()->table_options, FALSE,
thd->mem_root))
DBUG_RETURN(TRUE);
@@ -4183,146 +4171,40 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
}
-/**
- Check that there is no frm file for given table
-
- @param old_path path to the old frm file
- @param path path to the frm file in new encoding
- @param db database name
- @param table_name table name
- @param alias table name for error message (for new encoding)
- @param issue_error should we issue error messages
-
- @retval FALSE there is no frm file
- @retval TRUE there is frm file
-*/
-
-bool check_table_file_presence(char *old_path,
- char *path,
- const char *db,
- const char *table_name,
- const char *alias,
- bool issue_error)
-{
- if (!access(path,F_OK))
- {
- if (issue_error)
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),alias);
- return TRUE;
- }
- {
- /*
- Check if file of the table in 5.0 file name encoding exists.
-
- Except case when it is the same table.
- */
- char tbl50[FN_REFLEN];
-#ifdef _WIN32
- if (check_if_legal_tablename(table_name) != 0)
- {
- /*
- Check for reserved device names for which access() returns 0
- (CON, AUX etc).
- */
- return FALSE;
- }
-#endif
- strxmov(tbl50, mysql_data_home, "/", db, "/", table_name, NullS);
- fn_format(tbl50, tbl50, "", reg_ext, MY_UNPACK_FILENAME);
- if (!access(tbl50, F_OK) &&
- (old_path == NULL ||
- strcmp(old_path, tbl50) != 0))
- {
- if (issue_error)
- {
- strxmov(tbl50, MYSQL50_TABLE_NAME_PREFIX, table_name, NullS);
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tbl50);
- }
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-/**
- Create a table
-
- @param thd Thread object
- @param db Database
- @param table_name Table name
- @param path Path to table (i.e. to its .FRM file without
- the extension).
- @param create_info Create information (like MAX_ROWS)
- @param alter_info Description of fields and keys for new table
- @param internal_tmp_table Set to true if this is an internal temporary table
- (From ALTER TABLE)
- @param select_field_count Number of fields coming from SELECT part of
- CREATE TABLE ... SELECT statement. Must be zero
- for standard create of table.
- @param no_ha_table Indicates that only .FRM file (and PAR file if table
- is partitioned) needs to be created and not a table
- in the storage engine.
- @param[out] is_trans Identifies the type of engine where the table
- was created: either trans or non-trans.
- @param[out] key_info Array of KEY objects describing keys in table
- which was created.
- @param[out] key_count Number of keys in table which was created.
-
- If one creates a temporary table, this is automatically opened
-
- Note that this function assumes that caller already have taken
- exclusive metadata lock on table being created or used some other
- way to ensure that concurrent operations won't intervene.
- mysql_create_table() is a wrapper that can be used for this.
-
- @retval false OK
- @retval true error
-*/
-
-static
-bool create_table_impl(THD *thd,
- const char *db, const char *table_name,
- const char *path,
- HA_CREATE_INFO *create_info,
- Alter_info *alter_info,
- bool internal_tmp_table,
- bool no_ha_table,
- bool *is_trans,
- KEY **key_info,
- uint *key_count,
- int create_table_mode)
+handler *mysql_create_frm_image(THD *thd,
+ const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info, int create_table_mode,
+ KEY **key_info,
+ uint *key_count,
+ LEX_CUSTRING *frm)
{
- const char *alias;
uint db_options;
- handler *file;
- bool error= TRUE;
- DBUG_ENTER("create_table_impl");
- DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
- db, table_name, internal_tmp_table));
+ handler *file;
+ DBUG_ENTER("mysql_create_frm_image");
-
- /* Check for duplicate fields and check type of table to create */
if (!alter_info->create_list.elements)
{
- my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
- MYF(0));
- DBUG_RETURN(TRUE);
+ my_error(ER_TABLE_MUST_HAVE_COLUMNS, MYF(0));
+ DBUG_RETURN(NULL);
}
+
if (check_engine(thd, db, table_name, create_info))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(NULL);
set_table_default_charset(thd, create_info, (char*) db);
db_options= create_info->table_options;
- if (create_info->row_type == ROW_TYPE_DYNAMIC)
- db_options|=HA_OPTION_PACK_RECORD;
- alias= table_case_name(create_info, table_name);
+ if (create_table_mode != C_ALTER_TABLE_FRM_ONLY &&
+ create_info->row_type != ROW_TYPE_FIXED &&
+ create_info->row_type != ROW_TYPE_DEFAULT)
+ db_options|= HA_OPTION_PACK_RECORD;
+
if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
create_info->db_type)))
{
mem_alloc_error(sizeof(handler));
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(NULL);
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info= thd->work_part_info;
@@ -4339,7 +4221,7 @@ bool create_table_impl(THD *thd,
if (!part_info)
{
mem_alloc_error(sizeof(partition_info));
- DBUG_RETURN(TRUE);
+ goto err;
}
file->set_auto_partitions(part_info);
part_info->default_engine_type= create_info->db_type;
@@ -4355,12 +4237,11 @@ bool create_table_impl(THD *thd,
this information in the default_db_type variable, it is either
DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command.
*/
- Key *key;
handlerton *part_engine_type= create_info->db_type;
char *part_syntax_buf;
uint syntax_len;
handlerton *engine_type;
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info->tmp_table())
{
my_error(ER_PARTITION_NO_TEMPORARY, MYF(0));
goto err;
@@ -4423,9 +4304,8 @@ bool create_table_impl(THD *thd,
delete file;
create_info->db_type= partition_hton;
if (!(file= get_ha_partition(part_info)))
- {
- DBUG_RETURN(TRUE);
- }
+ DBUG_RETURN(NULL);
+
/*
If we have default number of partitions or subpartitions we
might require to set-up the part_info object such that it
@@ -4467,203 +4347,212 @@ bool create_table_impl(THD *thd,
engine_type)))
{
mem_alloc_error(sizeof(handler));
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(NULL);
}
}
- /*
- Unless table's storage engine supports partitioning natively
- don't allow foreign keys on partitioned tables (they won't
- work work even with InnoDB beneath of partitioning engine).
- If storage engine handles partitioning natively (like NDB)
- foreign keys support is possible, so we let the engine decide.
- */
- if (create_info->db_type == partition_hton)
+ }
+ /*
+ Unless table's storage engine supports partitioning natively
+ don't allow foreign keys on partitioned tables (they won't
+ work work even with InnoDB beneath of partitioning engine).
+ If storage engine handles partitioning natively (like NDB)
+ foreign keys support is possible, so we let the engine decide.
+ */
+ if (create_info->db_type == partition_hton)
+ {
+ List_iterator_fast<Key> key_iterator(alter_info->key_list);
+ Key *key;
+ while ((key= key_iterator++))
{
- List_iterator_fast<Key> key_iterator(alter_info->key_list);
- while ((key= key_iterator++))
+ if (key->type == Key::FOREIGN_KEY)
{
- if (key->type == Key::FOREIGN_KEY)
- {
- my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
- goto err;
- }
+ my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0));
+ goto err;
}
}
}
#endif
- if (mysql_prepare_create_table(thd, create_info, alter_info,
- internal_tmp_table,
- &db_options, file,
- key_info, key_count,
+ if (mysql_prepare_create_table(thd, create_info, alter_info, &db_options,
+ file, key_info, key_count,
create_table_mode))
goto err;
+ create_info->table_options=db_options;
+
+ *frm= build_frm_image(thd, table_name, create_info,
+ alter_info->create_list, *key_count,
+ *key_info, file);
+
+ if (frm->str)
+ DBUG_RETURN(file);
+
+err:
+ delete file;
+ DBUG_RETURN(NULL);
+}
+
+
+/**
+ Create a table
+
+ @param thd Thread object
+ @param db Database
+ @param table_name Table name
+ @param path Path to table (i.e. to its .FRM file without
+ the extension).
+ @param create_info Create information (like MAX_ROWS)
+ @param alter_info Description of fields and keys for new table
+ @param create_table_mode C_ORDINARY_CREATE, C_ALTER_TABLE, C_ASSISTED_DISCOVERY
+ or any positive number (for C_CREATE_SELECT).
+ @param[out] is_trans Identifies the type of engine where the table
+ was created: either trans or non-trans.
+ @param[out] key_info Array of KEY objects describing keys in table
+ which was created.
+ @param[out] key_count Number of keys in table which was created.
+
+ If one creates a temporary table, this is automatically opened
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
- create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
+ Note that this function assumes that caller already have taken
+ exclusive metadata lock on table being created or used some other
+ way to ensure that concurrent operations won't intervene.
+ mysql_create_table() is a wrapper that can be used for this.
- /* Check if table already exists */
- if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
- find_temporary_table(thd, db, table_name))
+ @retval false OK
+ @retval true error
+*/
+
+static
+bool create_table_impl(THD *thd,
+ const char *db, const char *table_name,
+ const char *path,
+ HA_CREATE_INFO *create_info,
+ Alter_info *alter_info,
+ int create_table_mode,
+ bool *is_trans,
+ KEY **key_info,
+ uint *key_count,
+ LEX_CUSTRING *frm)
+{
+ const char *alias;
+ handler *file= 0;
+ bool error= TRUE;
+ bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY;
+ bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only;
+ DBUG_ENTER("mysql_create_table_no_lock");
+ DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d",
+ db, table_name, internal_tmp_table));
+
+ if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
{
- if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
- alias);
- error= 0;
- goto err;
- }
- my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
- goto err;
+ if (create_info->data_file_name)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "DATA DIRECTORY");
+ if (create_info->index_file_name)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
+ "INDEX DIRECTORY");
+ create_info->data_file_name= create_info->index_file_name= 0;
}
+ else
+ if (error_if_data_home_dir(create_info->data_file_name, "DATA DIRECTORY") ||
+ error_if_data_home_dir(create_info->index_file_name, "INDEX DIRECTORY")||
+ check_partition_dirs(thd->lex->part_info))
+ goto err;
- if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
- {
- char frm_name[FN_REFLEN+1];
- strxnmov(frm_name, sizeof(frm_name) - 1, path, reg_ext, NullS);
+ alias= table_case_name(create_info, table_name);
- if (!access(frm_name, F_OK))
+ /* Check if table exists */
+ if (create_info->tmp_table())
+ {
+ if (find_temporary_table(thd, db, table_name))
{
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn;
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
goto err;
}
- /*
- We don't assert here, but check the result, because the table could be
- in the table definition cache and in the same time the .frm could be
- missing from the disk, in case of manual intervention which deletes
- the .frm file. The user has to use FLUSH TABLES; to clear the cache.
- Then she could create the table. This case is pretty obscure and
- therefore we don't introduce a new error message only for it.
- */
- mysql_mutex_lock(&LOCK_open);
- if (get_cached_table_share(db, table_name))
+ }
+ else
+ {
+ if (!internal_tmp_table && ha_table_exists(thd, db, table_name))
{
- mysql_mutex_unlock(&LOCK_open);
+ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ goto warn;
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto err;
}
- mysql_mutex_unlock(&LOCK_open);
}
- /*
- Check that table with given name does not already
- exist in any storage engine. In such a case it should
- be discovered and the error ER_TABLE_EXISTS_ERROR be returned
- unless user specified CREATE TABLE IF EXISTS
- An exclusive metadata lock ensures that no
- one else is attempting to discover the table. Since
- it's not on disk as a frm file, no one could be using it!
- */
- if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ THD_STAGE_INFO(thd, stage_creating_table);
+
+ if (create_table_mode == C_ASSISTED_DISCOVERY)
{
- bool create_if_not_exists =
- create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
- int retcode = ha_table_exists_in_engine(thd, db, table_name);
- DBUG_PRINT("info", ("exists_in_engine: %u",retcode));
- switch (retcode)
- {
- case HA_ERR_NO_SUCH_TABLE:
- /* Normal case, no table exists. we can go and create it */
- break;
- case HA_ERR_TABLE_EXIST:
- DBUG_PRINT("info", ("Table existed in handler"));
+ /* check that it's used correctly */
+ DBUG_ASSERT(alter_info->create_list.elements == 0);
+ DBUG_ASSERT(alter_info->key_list.elements == 0);
- if (create_if_not_exists)
- goto warn;
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- goto err;
- break;
- default:
- DBUG_PRINT("info", ("error: %u from storage engine", retcode));
- my_error(retcode, MYF(0),table_name);
- goto err;
+ TABLE_SHARE share;
+ handlerton *hton= create_info->db_type;
+ int ha_err;
+ Field *no_fields= 0;
+
+ if (!hton->discover_table_structure)
+ {
+ my_error(ER_ILLEGAL_HA, MYF(0), hton_name(hton)->str, db, table_name);
+ goto err;
}
- }
- THD_STAGE_INFO(thd, stage_creating_table);
+ init_tmp_table_share(thd, &share, db, 0, table_name, path);
- {
- size_t dirlen;
- char dirpath[FN_REFLEN];
+ /* prepare everything for discovery */
+ share.field= &no_fields;
+ share.db_plugin= ha_lock_engine(thd, hton);
+ share.option_list= create_info->option_list;
+ share.connect_string= create_info->connect_string;
+
+ if (parse_engine_table_options(thd, hton, &share))
+ goto err;
+
+ ha_err= hton->discover_table_structure(hton, thd, &share, create_info);
/*
- data_file_name and index_file_name include the table name without
- extension. Mostly this does not refer to an existing file. When
- comparing data_file_name or index_file_name against the data
- directory, we try to resolve all symbolic links. On some systems,
- we use realpath(3) for the resolution. This returns ENOENT if the
- resolved path does not refer to an existing file. my_realpath()
- does then copy the requested path verbatim, without symlink
- resolution. Thereafter the comparison can fail even if the
- requested path is within the data directory. E.g. if symlinks to
- another file system are used. To make realpath(3) return the
- resolved path, we strip the table name and compare the directory
- path only. If the directory doesn't exist either, table creation
- will fail anyway.
+ if discovery failed, the plugin will be auto-unlocked, as it
+ was locked on the THD, see above.
+ if discovery succeeded, the plugin was replaced by a globally
+ locked plugin, that will be unlocked by free_table_share()
*/
- if (create_info->data_file_name)
- {
- dirname_part(dirpath, create_info->data_file_name, &dirlen);
- if (test_if_data_home_dir(dirpath))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
- goto err;
- }
- }
- if (create_info->index_file_name)
+ if (ha_err)
+ share.db_plugin= 0; // will be auto-freed, locked above on the THD
+
+ free_table_share(&share);
+
+ if (ha_err)
{
- dirname_part(dirpath, create_info->index_file_name, &dirlen);
- if (test_if_data_home_dir(dirpath))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
- goto err;
- }
+ my_error(ER_GET_ERRNO, MYF(0), ha_err, hton_name(hton)->str);
+ goto err;
}
}
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
- if (check_partition_dirs(thd->lex->part_info))
- {
- goto err;
- }
-#endif /* WITH_PARTITION_STORAGE_ENGINE */
-
-#ifdef HAVE_READLINK
- if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
-#endif
+ else
{
- if (create_info->data_file_name)
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "DATA DIRECTORY");
- if (create_info->index_file_name)
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED),
- "INDEX DIRECTORY");
- create_info->data_file_name= create_info->index_file_name= 0;
+ file= mysql_create_frm_image(thd, db, table_name, create_info, alter_info,
+ create_table_mode, key_info, key_count, frm);
+ if (!file)
+ goto err;
+ if (rea_create_table(thd, frm, path, db, table_name, create_info,
+ file, frm_only))
+ goto err;
}
- create_info->table_options=db_options;
-
- /*
- Create .FRM (and .PAR file for partitioned table).
- If "no_ha_table" is false also create table in storage engine.
- */
- if (rea_create_table(thd, path, db, table_name,
- create_info, alter_info->create_list,
- *key_count, *key_info, file, no_ha_table))
- goto err;
- if (!no_ha_table && create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (!frm_only && create_info->tmp_table())
{
/*
Open a table (skipping table cache) and add it into
THD::temporary_tables list.
*/
- TABLE *table= open_table_uncached(thd, path, db, table_name, true, true);
+ TABLE *table= open_table_uncached(thd, create_info->db_type, path,
+ db, table_name, true, true);
if (!table)
{
@@ -4677,7 +4566,7 @@ bool create_table_impl(THD *thd,
thd->thread_specific_used= TRUE;
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
- else if (part_info && no_ha_table)
+ else if (thd->work_part_info && frm_only)
{
/*
For partitioned tables we can't find some problems with table
@@ -4694,7 +4583,7 @@ bool create_table_impl(THD *thd,
init_tmp_table_share(thd, &share, db, 0, table_name, path);
- bool result= (open_table_def(thd, &share, 0) ||
+ bool result= (open_table_def(thd, &share, GTS_TABLE) ||
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
0, &table, true));
if (!result)
@@ -4704,11 +4593,10 @@ bool create_table_impl(THD *thd,
if (result)
{
- char frm_name[FN_REFLEN + 1];
- strxnmov(frm_name, sizeof(frm_name) - 1, path, reg_ext, NullS);
+ char frm_name[FN_REFLEN];
+ strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS);
(void) mysql_file_delete(key_file_frm, frm_name, MYF(0));
- (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG,
- create_info);
+ (void) file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG);
goto err;
}
}
@@ -4728,7 +4616,6 @@ warn:
goto err;
}
-
/**
Simple wrapper around create_table_impl() to be used
in various version of CREATE TABLE statement.
@@ -4742,8 +4629,9 @@ bool mysql_create_table_no_lock(THD *thd,
KEY *not_used_1;
uint not_used_2;
char path[FN_REFLEN + 1];
+ LEX_CUSTRING frm= {0,0};
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info->tmp_table())
build_tmptable_filename(thd, path, sizeof(path));
else
{
@@ -4759,12 +4647,13 @@ bool mysql_create_table_no_lock(THD *thd,
}
}
- return create_table_impl(thd, db, table_name, path, create_info, alter_info,
- false, false, is_trans,
- &not_used_1, &not_used_2, create_table_mode);
+ bool res= create_table_impl(thd, db, table_name, path, create_info,
+ alter_info, create_table_mode, is_trans,
+ &not_used_1, &not_used_2, &frm);
+ my_free(const_cast<uchar*>(frm.str));
+ return res;
}
-
/**
Implementation of SQLCOM_CREATE_TABLE.
@@ -4779,19 +4668,17 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
HA_CREATE_INFO *create_info,
Alter_info *alter_info)
{
- bool result;
+ const char *db= create_table->db;
+ const char *table_name= create_table->table_name;
bool is_trans= FALSE;
int create_table_mode;
DBUG_ENTER("mysql_create_table");
- /*
- Open or obtain an exclusive metadata lock on table being created.
- */
+ /* Open or obtain an exclusive metadata lock on table being created */
if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
{
/* is_error() may be 0 if table existed and we generated a warning */
- result= thd->is_error();
- goto end;
+ DBUG_RETURN(thd->is_error());
}
/* Got lock. */
@@ -4803,20 +4690,16 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
create_table_mode= C_ASSISTED_DISCOVERY;
promote_first_timestamp_column(&alter_info->create_list);
- result= mysql_create_table_no_lock(thd, create_table->db,
- create_table->table_name, create_info,
- alter_info, &is_trans, create_table_mode);
- if (result)
- DBUG_RETURN(result);
+ if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info,
+ &is_trans, create_table_mode))
+ DBUG_RETURN(1);
/* In RBR we don't need to log CREATE TEMPORARY TABLE */
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
DBUG_RETURN(0);
+ bool result;
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
- thd->abort_on_warning= false;
-
-end:
DBUG_RETURN(result);
}
@@ -4940,16 +4823,20 @@ mysql_rename_table(handlerton *base, const char *old_db,
{
if (rename_file_ext(from,to,reg_ext))
error= my_errno;
- (void) file->ha_create_handler_files(to, from, CHF_RENAME_FLAG, NULL);
+ (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
}
else if (!file || !(error=file->ha_rename_table(from_base, to_base)))
{
if (!(flags & NO_FRM_RENAME) && rename_file_ext(from,to,reg_ext))
{
error=my_errno;
- /* Restore old file name */
if (file)
- file->ha_rename_table(to_base, from_base);
+ {
+ if (error == ENOENT)
+ error= 0; // this is ok if file->ha_rename_table() succeeded
+ else
+ file->ha_rename_table(to_base, from_base); // Restore old file name
+ }
}
}
delete file;
@@ -4957,20 +4844,19 @@ mysql_rename_table(handlerton *base, const char *old_db,
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE");
else if (error)
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
+ else if (!(flags & FN_IS_TMP))
+ mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
-
-#ifdef HAVE_PSI_TABLE_INTERFACE
/*
Remove the old table share from the pfs table share array. The new table
share will be created when the renamed table is first accessed.
*/
if (likely(error == 0))
{
- my_bool temp_table= (my_bool)is_prefix(old_name, tmp_file_prefix);
- PSI_TABLE_CALL(drop_table_share)
- (temp_table, old_db, strlen(old_db), old_name, strlen(old_name));
+ PSI_CALL_drop_table_share(flags & FN_FROM_IS_TMP,
+ old_db, strlen(old_db),
+ old_name, strlen(old_name));
}
-#endif
DBUG_RETURN(error != 0);
}
@@ -5049,7 +4935,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
/* Replace type of source table with one specified in the statement. */
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
- local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
+ local_create_info.options|= create_info->tmp_table();
/* Reset auto-increment counter for the new table. */
local_create_info.auto_increment_value= 0;
/*
@@ -5067,7 +4953,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
Ensure that we have an exclusive lock on target table if we are creating
non-temporary table.
*/
- DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
+ DBUG_ASSERT((create_info->tmp_table()) ||
thd->mdl_context.is_lock_owner(MDL_key::TABLE, table->db,
table->table_name,
MDL_EXCLUSIVE));
@@ -5094,7 +4980,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
4 temporary temporary Nothing
==== ========= ========= ==============================
*/
- if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+ if (!(create_info->tmp_table()))
{
if (src_table->table->s->tmp_table) // Case 2
{
@@ -5172,6 +5058,8 @@ int mysql_discard_or_import_tablespace(THD *thd,
int error;
DBUG_ENTER("mysql_discard_or_import_tablespace");
+ mysql_audit_alter_table(thd, table_list);
+
/*
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
ALTER TABLE
@@ -5255,11 +5143,248 @@ static bool is_candidate_key(KEY *key)
if (key_part->key_part_flag & HA_PART_KEY_SEG)
return false;
}
-
return true;
}
+/*
+ Preparation for table creation
+
+ SYNOPSIS
+ handle_if_exists_option()
+ thd Thread object.
+ table The altered table.
+ alter_info List of columns and indexes to create
+
+ DESCRIPTION
+ Looks for the IF [NOT] EXISTS options, checks the states and remove items
+ from the list if existing found.
+
+ RETURN VALUES
+ NONE
+*/
+
+static void
+handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info)
+{
+ Field **f_ptr;
+ DBUG_ENTER("handle_if_exists_option");
+
+ /* Handle ADD COLUMN IF NOT EXISTS. */
+ {
+ List_iterator<Create_field> it(alter_info->create_list);
+ Create_field *sql_field;
+
+ while ((sql_field=it++))
+ {
+ if (!sql_field->create_if_not_exists || sql_field->change)
+ continue;
+ /*
+ If there is a field with the same name in the table already,
+ remove the sql_field from the list.
+ */
+ for (f_ptr=table->field; *f_ptr; f_ptr++)
+ {
+ if (my_strcasecmp(system_charset_info,
+ sql_field->field_name, (*f_ptr)->field_name) == 0)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DUP_FIELDNAME, ER(ER_DUP_FIELDNAME),
+ sql_field->field_name);
+ it.remove();
+ if (alter_info->create_list.is_empty())
+ {
+ alter_info->flags&= ~Alter_info::ALTER_ADD_COLUMN;
+ if (alter_info->key_list.is_empty())
+ alter_info->flags&= ~Alter_info::ALTER_ADD_INDEX;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /* Handle MODIFY COLUMN IF EXISTS. */
+ {
+ List_iterator<Create_field> it(alter_info->create_list);
+ Create_field *sql_field;
+
+ while ((sql_field=it++))
+ {
+ if (!sql_field->create_if_not_exists || !sql_field->change)
+ continue;
+ /*
+ If there is NO field with the same name in the table already,
+ remove the sql_field from the list.
+ */
+ for (f_ptr=table->field; *f_ptr; f_ptr++)
+ {
+ if (my_strcasecmp(system_charset_info,
+ sql_field->field_name, (*f_ptr)->field_name) == 0)
+ {
+ break;
+ }
+ }
+ if (*f_ptr == NULL)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
+ sql_field->change, table->s->table_name.str);
+ it.remove();
+ if (alter_info->create_list.is_empty())
+ {
+ alter_info->flags&= ~(Alter_info::ALTER_ADD_COLUMN |
+ Alter_info::ALTER_CHANGE_COLUMN);
+ if (alter_info->key_list.is_empty())
+ alter_info->flags&= ~Alter_info::ALTER_ADD_INDEX;
+ }
+ }
+ }
+ }
+
+ /* Handle DROP COLUMN/KEY IF EXISTS. */
+ {
+ List_iterator<Alter_drop> drop_it(alter_info->drop_list);
+ Alter_drop *drop;
+ bool remove_drop;
+ while ((drop= drop_it++))
+ {
+ if (!drop->drop_if_exists)
+ continue;
+ remove_drop= TRUE;
+ if (drop->type == Alter_drop::COLUMN)
+ {
+ /*
+ If there is NO field with that name in the table,
+ remove the 'drop' from the list.
+ */
+ for (f_ptr=table->field; *f_ptr; f_ptr++)
+ {
+ if (my_strcasecmp(system_charset_info,
+ drop->name, (*f_ptr)->field_name) == 0)
+ {
+ remove_drop= FALSE;
+ break;
+ }
+ }
+ }
+ else /* Alter_drop::KEY */
+ {
+ uint n_key;
+ for (n_key=0; n_key < table->s->keys; n_key++)
+ {
+ if (my_strcasecmp(system_charset_info,
+ drop->name, table->key_info[n_key].name) == 0)
+ {
+ remove_drop= FALSE;
+ break;
+ }
+ }
+ }
+ if (remove_drop)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_CANT_DROP_FIELD_OR_KEY, ER(ER_CANT_DROP_FIELD_OR_KEY),
+ drop->name);
+ drop_it.remove();
+ if (alter_info->drop_list.is_empty())
+ alter_info->flags&= ~(Alter_info::ALTER_DROP_COLUMN |
+ Alter_info::ALTER_DROP_INDEX);
+ }
+ }
+ }
+
+ /* ALTER TABLE ADD KEY IF NOT EXISTS */
+ /* ALTER TABLE ADD FOREIGN KEY IF NOT EXISTS */
+ {
+ Key *key;
+ List_iterator<Key> key_it(alter_info->key_list);
+ uint n_key;
+ while ((key=key_it++))
+ {
+ if (!key->create_if_not_exists)
+ continue;
+ for (n_key=0; n_key < table->s->keys; n_key++)
+ {
+ if (my_strcasecmp(system_charset_info,
+ key->name.str, table->key_info[n_key].name) == 0)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DUP_KEYNAME, ER(ER_DUP_KEYNAME), key->name.str);
+ key_it.remove();
+ if (key->type == Key::FOREIGN_KEY)
+ {
+ /* ADD FOREIGN KEY appends two items. */
+ key_it.remove();
+ }
+ if (alter_info->key_list.is_empty())
+ alter_info->flags&= ~Alter_info::ALTER_ADD_INDEX;
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ partition_info *tab_part_info= table->part_info;
+ if (tab_part_info && thd->lex->check_exists)
+ {
+ /* ALTER TABLE ADD PARTITION IF NOT EXISTS */
+ if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION)
+ {
+ partition_info *alt_part_info= thd->lex->part_info;
+ if (alt_part_info)
+ {
+ List_iterator<partition_element> new_part_it(alt_part_info->partitions);
+ partition_element *pe;
+ while ((pe= new_part_it++))
+ {
+ if (!tab_part_info->has_unique_name(pe))
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SAME_NAME_PARTITION, ER(ER_SAME_NAME_PARTITION),
+ pe->partition_name);
+ alter_info->flags&= ~Alter_info::ALTER_ADD_PARTITION;
+ thd->lex->part_info= NULL;
+ break;
+ }
+ }
+ }
+ }
+ /* ALTER TABLE DROP PARTITION IF EXISTS */
+ if (alter_info->flags & Alter_info::ALTER_DROP_PARTITION)
+ {
+ List_iterator<char> names_it(alter_info->partition_names);
+ char *name;
+
+ while ((name= names_it++))
+ {
+ List_iterator<partition_element> part_it(tab_part_info->partitions);
+ partition_element *part_elem;
+ while ((part_elem= part_it++))
+ {
+ if (my_strcasecmp(system_charset_info,
+ part_elem->partition_name, name) == 0)
+ break;
+ }
+ if (!part_elem)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DROP_PARTITION_NON_EXISTENT,
+ ER(ER_DROP_PARTITION_NON_EXISTENT), "DROP");
+ names_it.remove();
+ }
+ }
+ if (alter_info->partition_names.elements == 0)
+ alter_info->flags&= ~Alter_info::ALTER_DROP_PARTITION;
+ }
+ }
+#endif /*WITH_PARTITION_STORAGE_ENGINE*/
+
+ DBUG_VOID_RETURN;
+}
+
+
/**
Get Create_field object for newly created table by field index.
@@ -5868,10 +5993,9 @@ bool mysql_compare_tables(TABLE *table,
int create_table_mode= table->s->tmp_table == NO_TMP_TABLE ?
C_ORDINARY_CREATE : C_ALTER_TABLE;
if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info,
- (table->s->tmp_table != NO_TMP_TABLE),
&db_options, table->file, &key_info_buffer,
&key_count, create_table_mode))
- DBUG_RETURN(true);
+ DBUG_RETURN(1);
/* Some very basic checks. */
if (table->s->fields != alter_info->create_list.elements ||
@@ -6012,6 +6136,7 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
switch (keys_onoff) {
case Alter_info::ENABLE:
+ DEBUG_SYNC(table->in_use, "alter_table_enable_indexes");
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
break;
case Alter_info::LEAVE_AS_IS:
@@ -6028,7 +6153,6 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
table->file->table_type(),
table->s->db.str, table->s->table_name.str);
-
error= 0;
} else if (error)
table->file->print_error(error, MYF(0));
@@ -6684,7 +6808,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
*/
if ((def->sql_type == MYSQL_TYPE_DATE ||
def->sql_type == MYSQL_TYPE_NEWDATE ||
- def->sql_type == MYSQL_TYPE_DATETIME) &&
+ def->sql_type == MYSQL_TYPE_DATETIME ||
+ def->sql_type == MYSQL_TYPE_DATETIME2) &&
!alter_ctx->datetime_field &&
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
thd->variables.sql_mode & MODE_NO_ZERO_DATE)
@@ -6902,7 +7027,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key= new Key(key_type, key_name, strlen(key_name),
&key_create_info,
test(key_info->flags & HA_GENERATED_KEY),
- key_parts, key_info->option_list);
+ key_parts, key_info->option_list, FALSE);
new_key_list.push_back(key);
}
}
@@ -7683,6 +7808,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
DBUG_RETURN(true);
}
+ if (table->s->tmp_table == NO_TMP_TABLE)
+ mysql_audit_alter_table(thd, table_list);
+
THD_STAGE_INFO(thd, stage_setup);
if (!(alter_info->flags & ~(Alter_info::ALTER_RENAME |
Alter_info::ALTER_KEYS_ONOFF)) &&
@@ -7698,9 +7826,23 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
"LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
DBUG_RETURN(true);
}
- DBUG_RETURN(simple_rename_or_index_change(thd, table_list,
- alter_info->keys_onoff,
- &alter_ctx));
+ bool res= simple_rename_or_index_change(thd, table_list,
+ alter_info->keys_onoff,
+ &alter_ctx);
+ DBUG_RETURN(res);
+ }
+
+ handle_if_exists_options(thd, table, alter_info);
+
+ /* Look if we have to do anything at all. */
+ /* Normally ALTER can become NOOP only after handling */
+ /* the IF (NOT) EXISTS options. */
+ if (alter_info->flags == 0)
+ {
+ my_snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name),
+ ER(ER_INSERT_INFO), 0L, 0L, 0L);
+ my_ok(thd, 0L, 0L, alter_ctx.tmp_name);
+ DBUG_RETURN(false);
}
/* We have to do full alter table. */
@@ -7871,8 +8013,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
- DBUG_EXECUTE_IF("sleep_before_create_table_no_lock",
- my_sleep(100000););
/* We can abort alter table for any table type */
thd->abort_on_warning= !ignore && thd->is_strict_mode();
@@ -7892,17 +8032,22 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_prepare_create_table().
*/
bool varchar= create_info->varchar;
+ LEX_CUSTRING frm= {0,0};
tmp_disable_binlog(thd);
+ create_info->options|=HA_CREATE_TMP_ALTER;
error= create_table_impl(thd, alter_ctx.new_db, alter_ctx.tmp_name,
alter_ctx.get_tmp_path(),
create_info, alter_info,
- true, true, NULL,
- &key_info, &key_count, FALSE);
+ C_ALTER_TABLE_FRM_ONLY, NULL,
+ &key_info, &key_count, &frm);
reenable_binlog(thd);
thd->abort_on_warning= false;
if (error)
+ {
+ my_free(const_cast<uchar*>(frm.str));
DBUG_RETURN(true);
+ }
/* Remember that we have not created table in storage engine yet. */
bool no_ha_table= true;
@@ -7924,10 +8069,32 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (fill_alter_inplace_info(thd, table, varchar, &ha_alter_info))
goto err_new_table_cleanup;
+ if (ha_alter_info.handler_flags == 0)
+ {
+ /*
+ No-op ALTER, no need to call handler API functions.
+
+ If this code path is entered for an ALTER statement that
+ should not be a real no-op, new handler flags should be added
+ and fill_alter_inplace_info() adjusted.
+
+ Note that we can end up here if an ALTER statement has clauses
+ that cancel each other out (e.g. ADD/DROP identically index).
+
+ Also note that we ignore the LOCK clause here.
+
+ TODO don't create the frm in the first place
+ */
+ deletefrm(alter_ctx.get_tmp_path());
+ my_free(const_cast<uchar*>(frm.str));
+ goto end_inplace;
+ }
+
// We assume that the table is non-temporary.
DBUG_ASSERT(!table->s->tmp_table);
- if (!(altered_table= open_table_uncached(thd, alter_ctx.get_tmp_path(),
+ if (!(altered_table= open_table_uncached(thd, new_db_type,
+ alter_ctx.get_tmp_path(),
alter_ctx.new_db,
alter_ctx.tmp_name,
true, false)))
@@ -7944,24 +8111,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
altered_table->column_bitmaps_set_no_signal(&altered_table->s->all_set,
&altered_table->s->all_set);
- if (ha_alter_info.handler_flags == 0)
- {
- /*
- No-op ALTER, no need to call handler API functions.
-
- If this code path is entered for an ALTER statement that
- should not be a real no-op, new handler flags should be added
- and fill_alter_inplace_info() adjusted.
-
- Note that we can end up here if an ALTER statement has clauses
- that cancel each other out (e.g. ADD/DROP identically index).
-
- Also note that we ignore the LOCK clause here.
- */
- close_temporary_table(thd, altered_table, true, false);
- goto end_inplace;
- }
-
// Ask storage engine whether to use copy or in-place
enum_alter_inplace_result inplace_supported=
table->file->check_if_supported_inplace_alter(altered_table,
@@ -8032,6 +8181,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (use_inplace)
{
+ my_free(const_cast<uchar*>(frm.str));
if (mysql_inplace_alter_table(thd, table_list, table,
altered_table,
&ha_alter_info,
@@ -8091,15 +8241,16 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (ha_create_table(thd, alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
- create_info, false))
+ create_info, &frm))
goto err_new_table_cleanup;
/* Mark that we have created table in storage engine. */
no_ha_table= false;
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ if (create_info->tmp_table())
{
- if (!open_table_uncached(thd, alter_ctx.get_tmp_path(),
+ if (!open_table_uncached(thd, new_db_type,
+ alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
true, true))
goto err_new_table_cleanup;
@@ -8122,7 +8273,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
/* table is a normal table: Create temporary table in same directory */
/* Open our intermediate table. */
- new_table= open_table_uncached(thd, alter_ctx.get_tmp_path(),
+ new_table= open_table_uncached(thd, new_db_type, alter_ctx.get_tmp_path(),
alter_ctx.new_db, alter_ctx.tmp_name,
true, true);
}
@@ -8202,6 +8353,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (!thd->is_current_stmt_binlog_format_row() &&
write_bin_log(thd, true, thd->query(), thd->query_length()))
DBUG_RETURN(true);
+ my_free(const_cast<uchar*>(frm.str));
goto end_temporary;
}
@@ -8243,6 +8395,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_EXTRA_NOT_USED,
NULL);
table_list->table= table= NULL; /* Safety */
+ my_free(const_cast<uchar*>(frm.str));
/*
Rename the old table to temporary name to have a backup in case
@@ -8316,7 +8469,6 @@ end_inplace:
THD_STAGE_INFO(thd, stage_end);
- DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
DEBUG_SYNC(thd, "alter_table_before_main_binlog");
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
@@ -8325,7 +8477,7 @@ end_inplace:
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->is_current_stmt_binlog_format_row() &&
- (create_info->options & HA_LEX_CREATE_TMP_TABLE)));
+ (create_info->tmp_table())));
if (write_bin_log(thd, true, thd->query(), thd->query_length()))
DBUG_RETURN(true);
@@ -8337,7 +8489,7 @@ end_inplace:
shutdown. But we do not need to attach MERGE children.
*/
TABLE *t_table;
- t_table= open_table_uncached(thd, alter_ctx.get_new_path(),
+ t_table= open_table_uncached(thd, new_db_type, alter_ctx.get_new_path(),
alter_ctx.new_db, alter_ctx.new_name,
false, true);
if (t_table)
@@ -8368,6 +8520,7 @@ end_temporary:
DBUG_RETURN(false);
err_new_table_cleanup:
+ my_free(const_cast<uchar*>(frm.str));
if (new_table)
{
/* close_temporary_table() frees the new_table pointer. */
@@ -8397,6 +8550,7 @@ err_new_table_cleanup:
t_type= MYSQL_TIMESTAMP_DATE;
break;
case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATETIME2:
f_val= "0000-00-00 00:00:00";
t_type= MYSQL_TIMESTAMP_DATETIME;
break;
@@ -8508,10 +8662,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
if (!(copy= new Copy_field[to->s->fields]))
DBUG_RETURN(-1); /* purecov: inspected */
+ /* We need external lock before we can disable/enable keys */
if (to->file->ha_external_lock(thd, F_WRLCK))
DBUG_RETURN(-1);
- /* We need external lock before we can disable/enable keys */
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
/* We can abort alter table for any table type */
@@ -8996,7 +9150,7 @@ static bool check_engine(THD *thd, const char *db_name,
ha_resolve_storage_engine_name(*new_engine),
table_name);
}
- if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
+ if (create_info->tmp_table() &&
ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
{
if (create_info->used_fields & HA_CREATE_USED_ENGINE)