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.cc1027
1 files changed, 675 insertions, 352 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 27d1b96886c..f5f2ffb0b63 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2010, 2016, MariaDB
+ Copyright (c) 2010, 2017, MariaDB Corporation.
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
@@ -25,7 +25,7 @@
#include "sql_table.h"
#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
+#include "sql_base.h" // lock_table_names
#include "lock.h" // mysql_unlock_tables
#include "strfunc.h" // find_type2, find_set
#include "sql_truncate.h" // regenerate_locked_table
@@ -37,8 +37,7 @@
#include "sql_time.h" // make_truncated_value_warning
#include "records.h" // init_read_record, end_read_record
#include "filesort.h" // filesort_free_buffers
-#include "sql_select.h" // setup_order,
- // make_unireg_sortorder
+#include "sql_select.h" // setup_order
#include "sql_handler.h" // mysql_ha_rm_tables
#include "discover.h" // readfrm
#include "my_pthread.h" // pthread_mutex_t
@@ -56,6 +55,7 @@
#include "transaction.h"
#include "sql_audit.h"
+
#ifdef __WIN__
#include <io.h>
#endif
@@ -63,7 +63,11 @@
const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
-static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
+static char *make_unique_key_name(THD *thd, const char *field_name, KEY *start,
+ KEY *end);
+static void make_unique_constraint_name(THD *thd, LEX_STRING *name,
+ List<Virtual_column_info> *vcol,
+ uint *nr);
static int copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
List<Create_field> &create, bool ignore,
uint order_num, ORDER *order,
@@ -71,7 +75,7 @@ static int copy_data_between_tables(THD *thd, TABLE *from,TABLE *to,
Alter_info::enum_enable_or_disable keys_onoff,
Alter_table_ctx *alter_ctx);
-static bool prepare_blob_field(THD *thd, Create_field *sql_field);
+static bool prepare_blob_field(THD *thd, Column_definition *sql_field);
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
uint *, handler *, KEY **, uint *, int);
static uint blob_length_by_type(enum_field_types type);
@@ -89,7 +93,7 @@ static char* add_identifier(THD* thd, char *to_p, const char * end_p,
{
uint res;
uint errors;
- const char *conv_name;
+ const char *conv_name, *conv_name_end;
char tmp_name[FN_REFLEN];
char conv_string[FN_REFLEN];
int quote;
@@ -110,22 +114,24 @@ static char* add_identifier(THD* thd, char *to_p, const char * end_p,
{
DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors));
conv_name= name;
+ conv_name_end= name + name_len;
}
else
{
DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
conv_name= conv_string;
+ conv_name_end= conv_string + res;
}
- quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"';
+ quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '`';
if (quote != EOF && (end_p - to_p > 2))
{
*(to_p++)= (char) quote;
while (*conv_name && (end_p - to_p - 1) > 0)
{
- uint length= my_mbcharlen(system_charset_info, *conv_name);
- if (!length)
+ int length= my_charlen(system_charset_info, conv_name, conv_name_end);
+ if (length <= 0)
length= 1;
if (length == 1 && *conv_name == (char) quote)
{
@@ -572,7 +578,7 @@ uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen)
DBUG_ENTER("build_tmptable_filename");
char *p= strnmov(buff, mysql_tmpdir, bufflen);
- my_snprintf(p, bufflen - (p - buff), "/%s%lx_%lx_%x",
+ my_snprintf(p, bufflen - (p - buff), "/%s%lx_%llx_%x",
tmp_file_prefix, current_pid,
thd->thread_id, thd->tmp_table++);
@@ -1639,7 +1645,7 @@ void execute_ddl_log_recovery()
/*
To be able to run this from boot, we allocate a temporary THD
*/
- if (!(thd=new THD))
+ if (!(thd=new THD(0)))
DBUG_VOID_RETURN;
thd->thread_stack= (char*) &thd;
thd->store_globals();
@@ -1813,7 +1819,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
partition_info *part_info= lpt->table->part_info;
if (part_info)
{
- if (!(part_syntax_buf= generate_partition_syntax(part_info,
+ if (!(part_syntax_buf= generate_partition_syntax(lpt->thd, part_info,
&syntax_len,
TRUE, TRUE,
lpt->create_info,
@@ -1896,7 +1902,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
TABLE_SHARE *share= lpt->table->s;
char *tmp_part_syntax_str;
- if (!(part_syntax_buf= generate_partition_syntax(part_info,
+ if (!(part_syntax_buf= generate_partition_syntax(lpt->thd, part_info,
&syntax_len,
TRUE, TRUE,
lpt->create_info,
@@ -2027,7 +2033,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY ||
- !find_temporary_table(thd, table))
+ !thd->find_temporary_table(table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
@@ -2280,25 +2286,20 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
DBUG_ASSERT(!(thd->locked_tables_mode &&
table->open_type != OT_BASE_ONLY &&
- find_temporary_table(thd, table) &&
+ thd->find_temporary_table(table) &&
table->mdl_request.ticket != NULL));
- /*
- drop_temporary_table may return one of the following error codes:
- . 0 - a temporary table was successfully dropped.
- . 1 - a temporary table was not found.
- . -1 - a temporary table is used by an outer statement.
- */
if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table))
error= 1;
else
{
table_creation_was_logged= table->table->s->table_creation_was_logged;
- if ((error= drop_temporary_table(thd, table->table, &is_trans)) == -1)
+ if (thd->drop_temporary_table(table->table, &is_trans, true))
{
- DBUG_ASSERT(thd->in_sub_stmt);
+ error= 1;
goto err;
}
+ error= 0;
table->table= 0;
}
@@ -2523,8 +2524,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
table->table ? (long) table->table->s : (long) -1));
DBUG_EXECUTE_IF("bug43138",
- my_printf_error(ER_BAD_TABLE_ERROR,
- ER_THD(thd, ER_BAD_TABLE_ERROR), MYF(0),
+ my_error(ER_BAD_TABLE_ERROR, MYF(0),
table->table_name););
}
DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog");
@@ -2536,12 +2536,9 @@ err:
{
DBUG_ASSERT(errors);
if (errors == 1 && was_view)
- my_printf_error(ER_IT_IS_A_VIEW, ER_THD(thd, ER_IT_IS_A_VIEW), MYF(0),
- wrong_tables.c_ptr_safe());
+ my_error(ER_IT_IS_A_VIEW, MYF(0), wrong_tables.c_ptr_safe());
else if (errors > 1 || !thd->is_error())
- my_printf_error(ER_BAD_TABLE_ERROR, ER_THD(thd, ER_BAD_TABLE_ERROR),
- MYF(0),
- wrong_tables.c_ptr_safe());
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), wrong_tables.c_ptr_safe());
error= 1;
}
@@ -2889,11 +2886,12 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
1 Error
*/
-int prepare_create_field(Create_field *sql_field,
+int prepare_create_field(Column_definition *sql_field,
uint *blob_columns,
- longlong table_flags)
+ ulonglong table_flags)
{
- unsigned int dup_val_count;
+ uint dup_val_count;
+ uint decimals= sql_field->decimals;
DBUG_ENTER("prepare_create_field");
/*
@@ -2913,15 +2911,13 @@ int prepare_create_field(Create_field *sql_field,
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
- sql_field->unireg_check=Field::BLOB_FIELD;
(*blob_columns)++;
break;
case MYSQL_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
if (!(table_flags & HA_CAN_GEOMETRY))
{
- my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
- MYF(0), "GEOMETRY");
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
DBUG_RETURN(1);
}
sql_field->pack_flag=FIELDFLAG_GEOM |
@@ -2930,11 +2926,10 @@ int prepare_create_field(Create_field *sql_field,
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
- sql_field->unireg_check=Field::BLOB_FIELD;
(*blob_columns)++;
break;
#else
- my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
+ my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
DBUG_RETURN(1);
#endif /*HAVE_SPATIAL*/
@@ -2949,8 +2944,7 @@ int prepare_create_field(Create_field *sql_field,
if ((sql_field->length / sql_field->charset->mbmaxlen) >
MAX_FIELD_CHARLENGTH)
{
- my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
- MYF(0), sql_field->field_name,
+ my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
static_cast<ulong>(MAX_FIELD_CHARLENGTH));
DBUG_RETURN(1);
}
@@ -2967,7 +2961,6 @@ int prepare_create_field(Create_field *sql_field,
FIELDFLAG_INTERVAL;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->unireg_check=Field::INTERVAL_FIELD;
if (check_duplicates_in_interval("ENUM",sql_field->field_name,
sql_field->interval,
sql_field->charset, &dup_val_count))
@@ -2978,7 +2971,6 @@ int prepare_create_field(Create_field *sql_field,
FIELDFLAG_BITFIELD;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
- sql_field->unireg_check=Field::BIT_FIELD;
if (check_duplicates_in_interval("SET",sql_field->field_name,
sql_field->interval,
sql_field->charset, &dup_val_count))
@@ -3011,8 +3003,18 @@ int prepare_create_field(Create_field *sql_field,
FIELDFLAG_DECIMAL) |
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
- (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ (decimals << FIELDFLAG_DEC_SHIFT));
break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ /*
+ User specified FLOAT() or DOUBLE() without precision. Change to
+ FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB
+ versions.
+ */
+ if (decimals >= FLOATING_POINT_DECIMALS)
+ decimals= FLOATING_POINT_DECIMALS;
+ /* fall-trough */
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_TIMESTAMP2:
/* fall-through */
@@ -3023,7 +3025,7 @@ int prepare_create_field(Create_field *sql_field,
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
f_settype((uint) sql_field->sql_type) |
- (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ (decimals << FIELDFLAG_DEC_SHIFT));
break;
}
if (!(sql_field->flags & NOT_NULL_FLAG) ||
@@ -3076,19 +3078,20 @@ CHARSET_INFO* get_sql_field_charset(Create_field *sql_field,
@param column_definitions The list of column definitions, in the physical
order in which they appear in the table.
- */
+*/
+
void promote_first_timestamp_column(List<Create_field> *column_definitions)
{
- List_iterator<Create_field> it(*column_definitions);
+ List_iterator_fast<Create_field> it(*column_definitions);
Create_field *column_definition;
while ((column_definition= it++) != NULL)
{
- if (is_timestamp_type(column_definition->sql_type) || // 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,
- column_definition->def == NULL && // no constant default,
+ column_definition->default_value == NULL && // no constant default,
column_definition->unireg_check == Field::NONE && // no function default
column_definition->vcol_info == NULL)
{
@@ -3126,8 +3129,8 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info,
if (!key->key_create_info.check_for_duplicate_indexes || key->generated)
return;
- List_iterator<Key> key_list_iterator(*key_list);
- List_iterator<Key_part_spec> key_column_iterator(key->columns);
+ List_iterator_fast<Key> key_list_iterator(*key_list);
+ List_iterator_fast<Key_part_spec> key_column_iterator(key->columns);
Key *k;
while ((k= key_list_iterator++))
@@ -3151,7 +3154,7 @@ static void check_duplicate_key(THD *thd, Key *key, KEY *key_info,
Check that the keys have identical columns in the same order.
*/
- List_iterator<Key_part_spec> k_column_iterator(k->columns);
+ List_iterator_fast<Key_part_spec> k_column_iterator(k->columns);
bool all_columns_are_identical= true;
@@ -3226,7 +3229,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
KEY_PART_INFO *key_part_info;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
- List_iterator<Create_field> it(alter_info->create_list);
+ List_iterator_fast<Create_field> it(alter_info->create_list);
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);
@@ -3254,37 +3257,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
!(sql_field->charset= find_bin_collation(sql_field->charset)))
DBUG_RETURN(TRUE);
- /*
- Convert the default value from client character
- set into the column character set if necessary.
- */
- if (sql_field->def &&
- save_cs != sql_field->def->collation.collation &&
- (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
- sql_field->sql_type == MYSQL_TYPE_STRING ||
- sql_field->sql_type == MYSQL_TYPE_SET ||
- sql_field->sql_type == MYSQL_TYPE_ENUM))
- {
- /*
- Starting from 5.1 we work here with a copy of Create_field
- created by the caller, not with the instance that was
- originally created during parsing. It's OK to create
- a temporary item and initialize with it a member of the
- copy -- this item will be thrown away along with the copy
- at the end of execution, and thus not introduce a dangling
- pointer in the parsed tree of a prepared statement or a
- stored procedure statement.
- */
- sql_field->def= sql_field->def->safe_charset_converter(thd, save_cs);
-
- if (sql_field->def == NULL)
- {
- /* Could not convert */
- my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(TRUE);
- }
- }
-
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
{
@@ -3350,36 +3322,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (sql_field->sql_type == MYSQL_TYPE_SET)
{
uint32 field_length;
- if (sql_field->def != NULL)
- {
- char *not_used;
- uint not_used2;
- bool not_found= 0;
- String str, *def= sql_field->def->val_str(&str);
- if (def == NULL) /* SQL "NULL" maps to NULL */
- {
- if ((sql_field->flags & NOT_NULL_FLAG) != 0)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(TRUE);
- }
-
- /* else, NULL is an allowed value */
- (void) find_set(interval, NULL, 0,
- cs, &not_used, &not_used2, &not_found);
- }
- else /* not NULL */
- {
- (void) find_set(interval, def->ptr(), def->length(),
- cs, &not_used, &not_used2, &not_found);
- }
-
- if (not_found)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(TRUE);
- }
- }
calculate_interval_lengths(cs, interval, &dummy, &field_length);
sql_field->length= field_length + (interval->count - 1);
}
@@ -3387,29 +3329,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
{
uint32 field_length;
DBUG_ASSERT(sql_field->sql_type == MYSQL_TYPE_ENUM);
- if (sql_field->def != NULL)
- {
- String str, *def= sql_field->def->val_str(&str);
- if (def == NULL) /* SQL "NULL" maps to NULL */
- {
- if ((sql_field->flags & NOT_NULL_FLAG) != 0)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(TRUE);
- }
-
- /* else, the defaults yield the correct length for NULLs. */
- }
- else /* not NULL */
- {
- def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
- if (find_type2(interval, def->ptr(), def->length(), cs) == 0) /* not found */
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
- DBUG_RETURN(TRUE);
- }
- }
- }
calculate_interval_lengths(cs, interval, &field_length, &dummy);
sql_field->length= field_length;
}
@@ -3429,6 +3348,73 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (prepare_blob_field(thd, sql_field))
DBUG_RETURN(TRUE);
+ /*
+ Convert the default value from client character
+ set into the column character set if necessary.
+ We can only do this for constants as we have not yet run fix_fields.
+ */
+ if (sql_field->default_value &&
+ sql_field->default_value->expr->basic_const_item() &&
+ save_cs != sql_field->default_value->expr->collation.collation &&
+ (sql_field->sql_type == MYSQL_TYPE_VAR_STRING ||
+ sql_field->sql_type == MYSQL_TYPE_STRING ||
+ sql_field->sql_type == MYSQL_TYPE_SET ||
+ sql_field->sql_type == MYSQL_TYPE_TINY_BLOB ||
+ sql_field->sql_type == MYSQL_TYPE_MEDIUM_BLOB ||
+ sql_field->sql_type == MYSQL_TYPE_LONG_BLOB ||
+ sql_field->sql_type == MYSQL_TYPE_BLOB ||
+ sql_field->sql_type == MYSQL_TYPE_ENUM))
+ {
+ Item *item;
+ if (!(item= sql_field->default_value->expr->
+ safe_charset_converter(thd, save_cs)))
+ {
+ /* Could not convert */
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(TRUE);
+ }
+ /* Fix for prepare statement */
+ thd->change_item_tree(&sql_field->default_value->expr, item);
+ }
+
+ if (sql_field->default_value &&
+ sql_field->default_value->expr->basic_const_item() &&
+ (sql_field->sql_type == MYSQL_TYPE_SET ||
+ sql_field->sql_type == MYSQL_TYPE_ENUM))
+ {
+ StringBuffer<MAX_FIELD_WIDTH> str;
+ String *def= sql_field->default_value->expr->val_str(&str);
+ bool not_found;
+ if (def == NULL) /* SQL "NULL" maps to NULL */
+ {
+ not_found= sql_field->flags & NOT_NULL_FLAG;
+ }
+ else
+ {
+ not_found= false;
+ if (sql_field->sql_type == MYSQL_TYPE_SET)
+ {
+ char *not_used;
+ uint not_used2;
+ find_set(sql_field->interval, def->ptr(), def->length(),
+ sql_field->charset, &not_used, &not_used2, &not_found);
+ }
+ else /* MYSQL_TYPE_ENUM */
+ {
+ def->length(sql_field->charset->cset->lengthsp(sql_field->charset,
+ def->ptr(), def->length()));
+ not_found= !find_type2(sql_field->interval, def->ptr(),
+ def->length(), sql_field->charset);
+ }
+ }
+
+ if (not_found)
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(TRUE);
+ }
+ }
+
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
@@ -3466,7 +3452,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
file->ha_table_flags() & HA_CAN_BIT_FIELD)
total_uneven_bit_length-= sql_field->length & 7;
- sql_field->def= dup_field->def;
+ sql_field->default_value= dup_field->default_value;
sql_field->sql_type= dup_field->sql_type;
/*
@@ -3501,7 +3487,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->create_length_to_internal_length();
sql_field->interval= dup_field->interval;
sql_field->vcol_info= dup_field->vcol_info;
- sql_field->stored_in_db= dup_field->stored_in_db;
it2.remove(); // Remove first (create) definition
select_field_pos--;
break;
@@ -3543,14 +3528,14 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
(virtual fields) and update their offset later
(see the next loop).
*/
- if (sql_field->stored_in_db)
+ if (sql_field->stored_in_db())
record_offset+= sql_field->pack_length;
}
/* Update virtual fields' offset*/
it.rewind();
while ((sql_field=it++))
{
- if (!sql_field->stored_in_db)
+ if (!sql_field->stored_in_db())
{
sql_field->offset= record_offset;
record_offset+= sql_field->pack_length;
@@ -3581,7 +3566,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
therefore mark it as unsafe.
*/
if (select_field_count > 0 && auto_increment)
- thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC);
/* Create keys */
@@ -3821,9 +3806,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (!my_strcasecmp(system_charset_info,
column->field_name.str, dup_column->field_name.str))
{
- my_printf_error(ER_DUP_FIELDNAME,
- ER_THD(thd, ER_DUP_FIELDNAME),MYF(0),
- column->field_name.str);
+ my_error(ER_DUP_FIELDNAME, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
}
}
@@ -3899,16 +3882,21 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
#endif
- if (!sql_field->stored_in_db)
+ if (sql_field->vcol_info)
{
- /* Key fields must always be physically stored. */
- my_error(ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN, MYF(0));
- DBUG_RETURN(TRUE);
- }
- if (key->type == Key::PRIMARY && sql_field->vcol_info)
- {
- my_error(ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN, MYF(0));
- DBUG_RETURN(TRUE);
+ if (key->type == Key::PRIMARY)
+ {
+ my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (sql_field->vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC)
+ {
+ /* use check_expression() to report an error */
+ check_expression(sql_field->vcol_info, sql_field->field_name,
+ VCOL_GENERATED_STORED);
+ DBUG_ASSERT(thd->is_error());
+ DBUG_RETURN(TRUE);
+ }
}
if (!(sql_field->flags & NOT_NULL_FLAG))
{
@@ -3961,7 +3949,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->type == Key::MULTIPLE)
{
/* not a critical problem */
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TOO_LONG_KEY,
ER_THD(thd, ER_TOO_LONG_KEY),
key_part_length);
@@ -4058,7 +4046,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
primary_key=1;
}
else if (!(key_name= key->name.str))
- key_name=make_unique_key_name(sql_field->field_name,
+ key_name=make_unique_key_name(thd, sql_field->field_name,
*key_info_buffer, key_info);
if (check_if_keyname_exists(key_name, *key_info_buffer, key_info))
{
@@ -4128,7 +4116,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
it is NOT NULL, not an AUTO_INCREMENT field, not a TIMESTAMP and not
updated trough a NOW() function.
*/
- if (!sql_field->def &&
+ if (!sql_field->default_value &&
!sql_field->has_default_function() &&
(sql_field->flags & NOT_NULL_FLAG) &&
!is_timestamp_type(sql_field->sql_type))
@@ -4138,7 +4126,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->vcol_info &&
+ !sql_field->default_value && !sql_field->vcol_info &&
is_timestamp_type(sql_field->sql_type) &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
@@ -4162,6 +4150,46 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
+ /* Check table level constraints */
+ create_info->check_constraint_list= &alter_info->check_constraint_list;
+ {
+ uint nr= 1;
+ List_iterator_fast<Virtual_column_info> c_it(alter_info->check_constraint_list);
+ Virtual_column_info *check;
+ while ((check= c_it++))
+ {
+ if (!check->name.length)
+ make_unique_constraint_name(thd, &check->name,
+ &alter_info->check_constraint_list,
+ &nr);
+ {
+ /* Check that there's no repeating constraint names. */
+ List_iterator_fast<Virtual_column_info>
+ dup_it(alter_info->check_constraint_list);
+ Virtual_column_info *dup_check;
+ while ((dup_check= dup_it++) && dup_check != check)
+ {
+ if (check->name.length == dup_check->name.length &&
+ my_strcasecmp(system_charset_info,
+ check->name.str, dup_check->name.str) == 0)
+ {
+ my_error(ER_DUP_CONSTRAINT_NAME, MYF(0), "CHECK", check->name.str);
+ DBUG_RETURN(TRUE);
+ }
+ }
+ }
+
+ if (check_string_char_length(&check->name, 0, NAME_CHAR_LEN,
+ system_charset_info, 1))
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), check->name.str);
+ DBUG_RETURN(TRUE);
+ }
+ if (check_expression(check, check->name.str, VCOL_CHECK_TABLE))
+ DBUG_RETURN(TRUE);
+ }
+ }
+
/* Give warnings for not supported table options */
#if defined(WITH_ARIA_STORAGE_ENGINE)
extern handlerton *maria_hton;
@@ -4230,7 +4258,7 @@ bool validate_comment_length(THD *thd, LEX_STRING *comment, size_t max_len,
create_info Table create information
DESCRIPTION
- If the table character set was not given explicitely,
+ If the table character set was not given explicitly,
let's fetch the database default character set and
apply it to the table.
*/
@@ -4267,7 +4295,7 @@ static void set_table_default_charset(THD *thd,
In this case the error is given
*/
-static bool prepare_blob_field(THD *thd, Create_field *sql_field)
+static bool prepare_blob_field(THD *thd, Column_definition *sql_field)
{
DBUG_ENTER("prepare_blob_field");
@@ -4277,7 +4305,7 @@ static bool prepare_blob_field(THD *thd, Create_field *sql_field)
/* Convert long VARCHAR columns to TEXT or BLOB */
char warn_buff[MYSQL_ERRMSG_SIZE];
- if (sql_field->def || thd->is_strict_mode())
+ if (thd->is_strict_mode())
{
my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name,
static_cast<ulong>(MAX_FIELD_VARCHARLENGTH /
@@ -4326,7 +4354,7 @@ static bool prepare_blob_field(THD *thd, Create_field *sql_field)
*/
-void sp_prepare_create_field(THD *thd, Create_field *sql_field)
+void sp_prepare_create_field(THD *thd, Column_definition *sql_field)
{
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
@@ -4356,7 +4384,7 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
FIELDFLAG_TREAT_BIT_AS_CHAR;
}
sql_field->create_length_to_internal_length();
- DBUG_ASSERT(sql_field->def == 0);
+ DBUG_ASSERT(sql_field->default_value == 0);
/* Can't go wrong as sql_field->def is not defined */
(void) prepare_blob_field(thd, sql_field);
}
@@ -4508,7 +4536,7 @@ handler *mysql_create_frm_image(THD *thd,
We reverse the partitioning parser and generate a standard format
for syntax stored in frm file.
*/
- if (!(part_syntax_buf= generate_partition_syntax(part_info,
+ if (!(part_syntax_buf= generate_partition_syntax(thd, part_info,
&syntax_len,
TRUE, TRUE,
create_info,
@@ -4639,7 +4667,8 @@ err:
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 one creates a temporary table, its is automatically opened and its
+ TABLE_SHARE is added to THD::all_temp_tables list.
Note that this function assumes that caller already have taken
exclusive metadata lock on table being created or used some other
@@ -4699,20 +4728,22 @@ int create_table_impl(THD *thd,
/* Check if table exists */
if (create_info->tmp_table())
{
- TABLE *tmp_table;
- if (find_and_use_temporary_table(thd, db, table_name, &tmp_table))
- goto err;
+ /*
+ If a table exists, it must have been pre-opened. Try looking for one
+ in-use in THD::all_temp_tables list of TABLE_SHAREs.
+ */
+ TABLE *tmp_table= thd->find_temporary_table(db, table_name);
+
if (tmp_table)
{
bool table_creation_was_logged= tmp_table->s->table_creation_was_logged;
if (options.or_replace())
{
- bool tmp;
/*
We are using CREATE OR REPLACE on an existing temporary table
Remove the old table so that we can re-create it.
*/
- if (drop_temporary_table(thd, tmp_table, &tmp))
+ if (thd->drop_temporary_table(tmp_table, NULL, true))
goto err;
}
else if (options.if_not_exists())
@@ -4851,17 +4882,12 @@ int create_table_impl(THD *thd,
create_info->table= 0;
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, create_info->db_type, frm, path,
- db, table_name, true, true);
+ TABLE *table= thd->create_and_open_tmp_table(create_info->db_type, frm,
+ path, db, table_name, true);
if (!table)
{
- (void) rm_temporary_table(create_info->db_type, path);
+ (void) thd->rm_temporary_table(create_info->db_type, path);
goto err;
}
@@ -4893,7 +4919,7 @@ int create_table_impl(THD *thd,
open_table_from_share(thd, &share, "", 0, (uint) READ_ALL,
0, &table, true));
if (!result)
- (void) closefrm(&table, 0);
+ (void) closefrm(&table);
free_table_share(&share);
@@ -5100,7 +5126,7 @@ check_if_keyname_exists(const char *name, KEY *start, KEY *end)
static char *
-make_unique_key_name(const char *field_name,KEY *start,KEY *end)
+make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
{
char buff[MAX_FIELD_NAME],*buff_end;
@@ -5118,11 +5144,43 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end)
*buff_end= '_';
int10_to_str(i, buff_end+1, 10);
if (!check_if_keyname_exists(buff,start,end))
- return sql_strdup(buff);
+ return thd->strdup(buff);
}
return (char*) "not_specified"; // Should never happen
}
+/**
+ Make an unique name for constraints without a name
+*/
+
+static void make_unique_constraint_name(THD *thd, LEX_STRING *name,
+ List<Virtual_column_info> *vcol,
+ uint *nr)
+{
+ char buff[MAX_FIELD_NAME], *end;
+ List_iterator_fast<Virtual_column_info> it(*vcol);
+
+ end=strmov(buff, "CONSTRAINT_");
+ for (;;)
+ {
+ Virtual_column_info *check;
+ char *real_end= int10_to_str((*nr)++, end, 10);
+ it.rewind();
+ while ((check= it++))
+ {
+ if (check->name.str &&
+ !my_strcasecmp(system_charset_info, buff, check->name.str))
+ break;
+ }
+ if (!check) // Found unique name
+ {
+ name->length= (size_t) (real_end - buff);
+ name->str= thd->strmake(buff, name->length);
+ return;
+ }
+ }
+}
+
/****************************************************************************
** Alter a table definition
@@ -5819,7 +5877,19 @@ drop_create_field:
}
}
}
- else /* Alter_drop::KEY */
+ else if (drop->type == Alter_drop::CHECK_CONSTRAINT)
+ {
+ for (uint i=table->s->field_check_constraints; i < table->s->table_check_constraints; i++)
+ {
+ if (my_strcasecmp(system_charset_info, drop->name,
+ table->check_constraints[i]->name.str) == 0)
+ {
+ remove_drop= FALSE;
+ break;
+ }
+ }
+ }
+ else /* Alter_drop::KEY and Alter_drop::FOREIGN_KEY */
{
uint n_key;
if (drop->type != Alter_drop::FOREIGN_KEY)
@@ -5876,7 +5946,7 @@ drop_create_field:
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_CANT_DROP_FIELD_OR_KEY,
ER_THD(thd, ER_CANT_DROP_FIELD_OR_KEY),
- drop->name);
+ drop->type_name(), drop->name);
drop_it.remove();
if (alter_info->drop_list.is_empty())
alter_info->flags&= ~(Alter_info::ALTER_DROP_COLUMN |
@@ -6059,6 +6129,39 @@ remove_key:
}
#endif /*WITH_PARTITION_STORAGE_ENGINE*/
+ /* ADD CONSTRAINT IF NOT EXISTS. */
+ {
+ List_iterator<Virtual_column_info> it(alter_info->check_constraint_list);
+ Virtual_column_info *check;
+ TABLE_SHARE *share= table->s;
+ uint c;
+ while ((check=it++))
+ {
+ if (!(check->flags & Alter_info::CHECK_CONSTRAINT_IF_NOT_EXISTS) &&
+ check->name.length)
+ continue;
+ check->flags= 0;
+ for (c= share->field_check_constraints;
+ c < share->table_check_constraints ; c++)
+ {
+ Virtual_column_info *dup= table->check_constraints[c];
+ if (dup->name.length == check->name.length &&
+ my_strcasecmp(system_charset_info,
+ check->name.str, dup->name.str) == 0)
+ {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME),
+ "CHECK", check->name.str);
+ it.remove();
+ if (alter_info->check_constraint_list.elements == 0)
+ alter_info->flags&= ~Alter_info::ALTER_ADD_CHECK_CONSTRAINT;
+
+ break;
+ }
+ }
+ }
+ }
+
DBUG_VOID_RETURN;
}
@@ -6153,11 +6256,6 @@ static bool fill_alter_inplace_info(THD *thd,
alter_info->key_list.elements)))
DBUG_RETURN(true);
- /* First we setup ha_alter_flags based on what was detected by parser. */
- if (alter_info->flags & Alter_info::ALTER_ADD_COLUMN)
- ha_alter_info->handler_flags|= Alter_inplace_info::ADD_COLUMN;
- if (alter_info->flags & Alter_info::ALTER_DROP_COLUMN)
- ha_alter_info->handler_flags|= Alter_inplace_info::DROP_COLUMN;
/*
Comparing new and old default values of column is cumbersome.
So instead of using such a comparison for detecting if default
@@ -6195,13 +6293,17 @@ static bool fill_alter_inplace_info(THD *thd,
/* Check for: ALTER TABLE FORCE, ALTER TABLE ENGINE and OPTIMIZE TABLE. */
if (alter_info->flags & Alter_info::ALTER_RECREATE)
ha_alter_info->handler_flags|= Alter_inplace_info::RECREATE_TABLE;
+ if (alter_info->flags & Alter_info::ALTER_ADD_CHECK_CONSTRAINT)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ADD_CHECK_CONSTRAINT;
+ if (alter_info->flags & Alter_info::ALTER_DROP_CHECK_CONSTRAINT)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_CHECK_CONSTRAINT;
/*
If we altering table with old VARCHAR fields we will be automatically
upgrading VARCHAR column types.
*/
if (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_STORED_COLUMN_TYPE;
/*
Go through fields in old version of table and detect changes to them.
@@ -6215,20 +6317,23 @@ static bool fill_alter_inplace_info(THD *thd,
about nature of changes than those provided from parser.
*/
bool maybe_alter_vcol= false;
- for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
+ uint field_stored_index= 0;
+ for (f_ptr= table->field; (field= *f_ptr); f_ptr++,
+ field_stored_index+= field->stored_in_db())
{
/* Clear marker for renamed or dropped field
which we are going to set later. */
field->flags&= ~(FIELD_IS_RENAMED | FIELD_IS_DROPPED);
/* Use transformed info to evaluate flags for storage engine. */
- uint new_field_index= 0;
+ uint new_field_index= 0, new_field_stored_index= 0;
new_field_it.init(alter_info->create_list);
while ((new_field= new_field_it++))
{
if (new_field->field == field)
break;
new_field_index++;
+ new_field_stored_index+= new_field->stored_in_db();
}
if (new_field)
@@ -6243,7 +6348,12 @@ static bool fill_alter_inplace_info(THD *thd,
{
case IS_EQUAL_NO:
/* New column type is incompatible with old one. */
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
+ if (field->stored_in_db())
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_STORED_COLUMN_TYPE;
+ else
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE;
if (table->s->tmp_table == NO_TMP_TABLE)
{
delete_statistics_for_column(thd, table, field);
@@ -6288,22 +6398,59 @@ static bool fill_alter_inplace_info(THD *thd,
default:
DBUG_ASSERT(0);
/* Safety. */
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_TYPE;
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_STORED_COLUMN_TYPE;
}
- /*
- Check if the column is computed and either
- is stored or is used in the partitioning expression.
- */
- if (field->vcol_info &&
- (field->stored_in_db || field->vcol_info->is_in_partitioning_expr()))
+ if (field->vcol_info || new_field->vcol_info)
{
- if (is_equal == IS_EQUAL_NO ||
- !new_field->vcol_info ||
- !field->vcol_info->is_equal(new_field->vcol_info))
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
- else
- maybe_alter_vcol= true;
+ /* base <-> virtual or stored <-> virtual */
+ if (field->stored_in_db() != new_field->stored_in_db())
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_STORED_COLUMN_TYPE |
+ Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE;
+ if (field->vcol_info && new_field->vcol_info)
+ {
+ bool value_changes= is_equal == IS_EQUAL_NO;
+ Alter_inplace_info::HA_ALTER_FLAGS alter_expr;
+ if (field->stored_in_db())
+ alter_expr= Alter_inplace_info::ALTER_STORED_GCOL_EXPR;
+ else
+ alter_expr= Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR;
+ if (!field->vcol_info->is_equal(new_field->vcol_info))
+ {
+ ha_alter_info->handler_flags|= alter_expr;
+ value_changes= true;
+ }
+
+ if ((ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_DEFAULT)
+ && !(ha_alter_info->handler_flags & alter_expr))
+ { /*
+ a DEFAULT value of a some column was changed. see if this vcol
+ uses DEFAULT() function. The check is kind of expensive, so don't
+ do it if ALTER_COLUMN_VCOL is already set.
+ */
+ if (field->vcol_info->expr->walk(
+ &Item::check_func_default_processor, 0, 0))
+ {
+ ha_alter_info->handler_flags|= alter_expr;
+ value_changes= true;
+ }
+ }
+
+ if (field->vcol_info->is_in_partitioning_expr() ||
+ field->flags & PART_KEY_FLAG)
+ {
+ if (value_changes)
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_COLUMN_VCOL;
+ else
+ maybe_alter_vcol= true;
+ }
+ }
+ else /* base <-> stored */
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_STORED_COLUMN_TYPE;
}
/* Check if field was renamed */
@@ -6336,8 +6483,18 @@ static bool fill_alter_inplace_info(THD *thd,
/*
Detect changes in column order.
*/
- if (field->field_index != new_field_index)
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_ORDER;
+ if (field->stored_in_db())
+ {
+ if (field_stored_index != new_field_stored_index)
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_STORED_COLUMN_ORDER;
+ }
+ else
+ {
+ if (field->field_index != new_field_index)
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER;
+ }
/* Detect changes in storage type of column */
if (new_field->field_storage_type() != field->field_storage_type())
@@ -6360,27 +6517,28 @@ static bool fill_alter_inplace_info(THD *thd,
}
else
{
- /*
- Field is not present in new version of table and therefore was dropped.
- Corresponding storage engine flag should be already set.
- */
- DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::DROP_COLUMN);
+ // Field is not present in new version of table and therefore was dropped.
field->flags|= FIELD_IS_DROPPED;
+ if (field->stored_in_db())
+ ha_alter_info->handler_flags|= Alter_inplace_info::DROP_STORED_COLUMN;
+ else
+ ha_alter_info->handler_flags|= Alter_inplace_info::DROP_VIRTUAL_COLUMN;
}
}
if (maybe_alter_vcol)
{
/*
- No virtual column was altered, but perhaps one of the other columns was,
- and that column was part of the vcol expression?
- We don't detect this correctly (FIXME), so let's just say that a vcol
- *might* be affected if any other column was altered.
+ What if one of the normal columns was altered and it was part of the some
+ virtual column expression? Currently we don't detect this correctly
+ (FIXME), so let's just say that a vcol *might* be affected if any other
+ column was altered.
*/
if (ha_alter_info->handler_flags &
- ( Alter_inplace_info::ALTER_COLUMN_TYPE
- | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE
- | Alter_inplace_info::ALTER_COLUMN_OPTION ))
+ ( Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
+ | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE
+ | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE
+ | Alter_inplace_info::ALTER_COLUMN_OPTION ))
ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
}
@@ -6389,18 +6547,17 @@ static bool fill_alter_inplace_info(THD *thd,
{
if (! new_field->field)
{
- /*
- Field is not present in old version of table and therefore was added.
- Again corresponding storage engine flag should be already set.
- */
- DBUG_ASSERT(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN);
-
- if (new_field->vcol_info &&
- (new_field->stored_in_db || new_field->vcol_info->is_in_partitioning_expr()))
- {
- ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_COLUMN_VCOL;
- }
- break;
+ // Field is not present in old version of table and therefore was added.
+ if (new_field->vcol_info)
+ if (new_field->stored_in_db())
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ADD_STORED_GENERATED_COLUMN;
+ else
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ADD_VIRTUAL_COLUMN;
+ else
+ ha_alter_info->handler_flags|=
+ Alter_inplace_info::ADD_STORED_BASE_COLUMN;
}
}
@@ -6947,6 +7104,14 @@ static bool is_inplace_alter_impossible(TABLE *table,
if (!table->s->mysql_version)
DBUG_RETURN(true);
+ /*
+ If we are using a MySQL 5.7 table with virtual fields, ALTER TABLE must
+ recreate the table as we need to rewrite generated fields
+ */
+ if (table->s->mysql_version > 50700 && table->s->mysql_version < 100000 &&
+ table->s->virtual_fields)
+ DBUG_RETURN(TRUE);
+
DBUG_RETURN(false);
}
@@ -7170,7 +7335,8 @@ static bool mysql_inplace_alter_table(THD *thd,
HA_EXTRA_NOT_USED,
NULL);
table_list->table= table= NULL;
- close_temporary_table(thd, altered_table, true, false);
+
+ thd->drop_temporary_table(altered_table, NULL, false);
/*
Replace the old .FRM with the new .FRM, but keep the old name for now.
@@ -7260,7 +7426,7 @@ static bool mysql_inplace_alter_table(THD *thd,
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
/* QQ; do something about metadata locks ? */
}
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
// Delete temporary .frm/.par
(void) quick_rm_table(thd, create_info->db_type, alter_ctx->new_db,
alter_ctx->tmp_name, FN_IS_TMP | NO_HA_TABLE);
@@ -7356,6 +7522,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
List_iterator<Create_field> find_it(new_create_list);
List_iterator<Create_field> field_it(new_create_list);
List<Key_part_spec> key_parts;
+ List<Virtual_column_info> new_constraint_list;
uint db_create_options= (table->s->db_create_options
& ~(HA_OPTION_PACK_RECORD));
uint used_fields;
@@ -7466,9 +7633,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
of the list for now. Their positions will be corrected later.
*/
new_create_list.push_back(def, thd->mem_root);
- if (field->stored_in_db != def->stored_in_db)
+ if (field->stored_in_db() != def->stored_in_db())
{
- my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN, MYF(0));
+ my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0));
goto err;
}
if (!def->after)
@@ -7500,12 +7667,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (alter)
{
- if (def->sql_type == MYSQL_TYPE_BLOB)
- {
- my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
- goto err;
- }
- if ((def->def=alter->def)) // Use new default
+ if ((def->default_value= alter->default_value))
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
else
def->flags|= NO_DEFAULT_VALUE_FLAG;
@@ -7779,6 +7941,33 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
}
+ /* Add all table level constraints which are not in the drop list */
+ if (table->s->table_check_constraints)
+ {
+ TABLE_SHARE *share= table->s;
+
+ for (uint i= share->field_check_constraints;
+ i < share->table_check_constraints ; i++)
+ {
+ Virtual_column_info *check= table->check_constraints[i];
+ Alter_drop *drop;
+ drop_it.rewind();
+ while ((drop=drop_it++))
+ {
+ if (drop->type == Alter_drop::CHECK_CONSTRAINT &&
+ !my_strcasecmp(system_charset_info, check->name.str, drop->name))
+ {
+ drop_it.remove();
+ break;
+ }
+ }
+ if (!drop)
+ new_constraint_list.push_back(check, thd->mem_root);
+ }
+ }
+ /* Add new constraints */
+ new_constraint_list.append(&alter_info->check_constraint_list);
+
if (alter_info->drop_list.elements)
{
Alter_drop *drop;
@@ -7787,8 +7976,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
switch (drop->type) {
case Alter_drop::KEY:
case Alter_drop::COLUMN:
- my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
- alter_info->drop_list.head()->name);
+ case Alter_drop::CHECK_CONSTRAINT:
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->type_name(),
+ alter_info->drop_list.head()->name);
goto err;
case Alter_drop::FOREIGN_KEY:
// Leave the DROP FOREIGN KEY names in the alter_info->drop_list.
@@ -7796,12 +7986,6 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
}
}
- if (alter_info->alter_list.elements)
- {
- my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
- alter_info->alter_list.head()->name);
- goto err;
- }
if (!create_info->comment.str)
{
@@ -7834,6 +8018,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
rc= FALSE;
alter_info->create_list.swap(new_create_list);
alter_info->key_list.swap(new_key_list);
+ alter_info->check_constraint_list.swap(new_constraint_list);
err:
DBUG_RETURN(rc);
}
@@ -8080,11 +8265,14 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
DBUG_RETURN(true);
case FK_COLUMN_DROPPED:
{
- char buff[NAME_LEN*2+2];
- strxnmov(buff, sizeof(buff)-1, f_key->foreign_db->str, ".",
- f_key->foreign_table->str, NullS);
+ StringBuffer<NAME_LEN*2+2> buff(system_charset_info);
+ LEX_STRING *db= f_key->foreign_db, *tbl= f_key->foreign_table;
+
+ append_identifier(thd, &buff, db->str, db->length);
+ buff.append('.');
+ append_identifier(thd, &buff, tbl->str,tbl->length);
my_error(ER_FK_COLUMN_CANNOT_DROP_CHILD, MYF(0), bad_column_name,
- f_key->foreign_id->str, buff);
+ f_key->foreign_id->str, buff.c_ptr());
DBUG_RETURN(true);
}
default:
@@ -8156,6 +8344,72 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table,
DBUG_RETURN(false);
}
+/**
+ Rename temporary table and/or turn indexes on/off without touching .FRM.
+ Its a variant of simple_rename_or_index_change() to be used exclusively
+ for temporary tables.
+
+ @param thd Thread handler
+ @param table_list TABLE_LIST for the table to change
+ @param keys_onoff ENABLE or DISABLE KEYS?
+ @param alter_ctx ALTER TABLE runtime context.
+
+ @return Operation status
+ @retval false Success
+ @retval true Failure
+*/
+static bool
+simple_tmp_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
+ Alter_info::enum_enable_or_disable keys_onoff,
+ Alter_table_ctx *alter_ctx)
+{
+ DBUG_ENTER("simple_tmp_rename_or_index_change");
+
+ TABLE *table= table_list->table;
+ bool error= false;
+
+ DBUG_ASSERT(table->s->tmp_table);
+
+ if (keys_onoff != Alter_info::LEAVE_AS_IS)
+ {
+ THD_STAGE_INFO(thd, stage_manage_keys);
+ error= alter_table_manage_keys(table, table->file->indexes_are_disabled(),
+ keys_onoff);
+ }
+
+ if (!error && alter_ctx->is_table_renamed())
+ {
+ THD_STAGE_INFO(thd, stage_rename);
+
+ /*
+ If THD::rename_temporary_table() fails, there is no need to rename it
+ back to the original name (unlike the case for non-temporary tables),
+ as it was an allocation error and the table was not renamed.
+ */
+ error= thd->rename_temporary_table(table, alter_ctx->new_db,
+ alter_ctx->new_alias);
+ }
+
+ if (!error)
+ {
+ int res= 0;
+ /*
+ We do not replicate alter table statement on temporary tables under
+ ROW-based replication.
+ */
+ if (!thd->is_current_stmt_binlog_format_row())
+ {
+ res= write_bin_log(thd, true, thd->query(), thd->query_length());
+ }
+ if (res != 0)
+ error= true;
+ else
+ my_ok(thd);
+ }
+
+ DBUG_RETURN(error);
+}
+
/**
Rename table and/or turn indexes on/off without touching .FRM
@@ -8192,6 +8446,7 @@ simple_rename_or_index_change(THD *thd, TABLE_LIST *table_list,
if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0))
DBUG_RETURN(true);
+ THD_STAGE_INFO(thd, stage_manage_keys);
error= alter_table_manage_keys(table,
table->file->indexes_are_disabled(),
keys_onoff);
@@ -8412,7 +8667,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (table->s->tmp_table != NO_TMP_TABLE)
{
- if (find_temporary_table(thd, alter_ctx.new_db, alter_ctx.new_name))
+ /*
+ Check whether a temporary table exists with same requested new name.
+ If such table exists, there must be a corresponding TABLE_SHARE in
+ THD::all_temp_tables list.
+ */
+ if (thd->find_tmp_table_share(alter_ctx.new_db, alter_ctx.new_name))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias);
DBUG_RETURN(true);
@@ -8565,29 +8825,48 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->get_stmt_da()->current_statement_warn_count());
my_ok(thd, 0L, 0L, alter_ctx.tmp_name);
- if (write_bin_log(thd, true, thd->query(), thd->query_length()))
- DBUG_RETURN(true);
+ /* We don't replicate alter table statement on temporary tables */
+ if (table->s->tmp_table == NO_TMP_TABLE ||
+ !thd->is_current_stmt_binlog_format_row())
+ {
+ if (write_bin_log(thd, true, thd->query(), thd->query_length()))
+ DBUG_RETURN(true);
+ }
DBUG_RETURN(false);
}
+ /*
+ Test if we are only doing RENAME or KEYS ON/OFF. This works
+ as we are testing if flags == 0 above.
+ */
if (!(alter_info->flags & ~(Alter_info::ALTER_RENAME |
Alter_info::ALTER_KEYS_ONOFF)) &&
alter_info->requested_algorithm !=
- Alter_info::ALTER_TABLE_ALGORITHM_COPY &&
- !table->s->tmp_table) // no need to touch frm
+ Alter_info::ALTER_TABLE_ALGORITHM_COPY) // No need to touch frm.
{
- // This requires X-lock, no other lock levels supported.
- if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT &&
- alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
+ bool res;
+
+ if (!table->s->tmp_table)
{
- my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
- "LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
- DBUG_RETURN(true);
+ // This requires X-lock, no other lock levels supported.
+ if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT &&
+ alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)
+ {
+ my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0),
+ "LOCK=NONE/SHARED", "LOCK=EXCLUSIVE");
+ DBUG_RETURN(true);
+ }
+ res= simple_rename_or_index_change(thd, table_list,
+ alter_info->keys_onoff,
+ &alter_ctx);
+ }
+ else
+ {
+ res= simple_tmp_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);
}
@@ -8848,11 +9127,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
// We assume that the table is non-temporary.
DBUG_ASSERT(!table->s->tmp_table);
- if (!(altered_table= open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db,
- alter_ctx.tmp_name,
- true, false)))
+ if (!(altered_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ false)))
goto err_new_table_cleanup;
/* Set markers for fields in TABLE object for altered table. */
@@ -8866,7 +9145,10 @@ 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);
restore_record(altered_table, s->default_values); // Create empty record
- if (altered_table->default_field && altered_table->update_default_fields())
+ /* Check that we can call default functions with default field values */
+ altered_table->reset_default_fields();
+ if (altered_table->default_field &&
+ altered_table->update_default_fields(0, 1))
goto err_new_table_cleanup;
// Ask storage engine whether to use copy or in-place
@@ -8892,7 +9174,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
ha_alter_info.report_unsupported_error("LOCK=NONE/SHARED",
"LOCK=EXCLUSIVE");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
break;
@@ -8903,7 +9185,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_info::ALTER_TABLE_LOCK_NONE)
{
ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
break;
@@ -8917,7 +9199,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
ha_alter_info.report_unsupported_error("ALGORITHM=INPLACE",
"ALGORITHM=COPY");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
// COPY with LOCK=NONE is not supported, no point in trying.
@@ -8925,7 +9207,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_info::ALTER_TABLE_LOCK_NONE)
{
ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
// Otherwise use COPY
@@ -8933,7 +9215,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
break;
case HA_ALTER_ERROR:
default:
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
goto err_new_table_cleanup;
}
@@ -8952,7 +9234,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
else
{
- close_temporary_table(thd, altered_table, true, false);
+ thd->drop_temporary_table(altered_table, NULL, false);
}
}
@@ -9005,13 +9287,20 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->tmp_table())
{
- if (!open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db, alter_ctx.tmp_name,
- true, true))
+ TABLE *tmp_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ true);
+ if (!tmp_table)
+ {
goto err_new_table_cleanup;
+ }
+ /* in case of alter temp table send the tracker in OK packet */
+ SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
}
+
/* Open the table since we need to copy the data. */
if (table->s->tmp_table != NO_TMP_TABLE)
{
@@ -9019,18 +9308,24 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
tbl.init_one_table(alter_ctx.new_db, strlen(alter_ctx.new_db),
alter_ctx.tmp_name, strlen(alter_ctx.tmp_name),
alter_ctx.tmp_name, TL_READ_NO_INSERT);
- /* Table is in thd->temporary_tables */
- (void) open_temporary_table(thd, &tbl);
+ /*
+ Table can be found in the list of open tables in THD::all_temp_tables
+ list.
+ */
+ tbl.table= thd->find_temporary_table(&tbl);
new_table= tbl.table;
}
else
{
- /* table is a normal table: Create temporary table in same directory */
- /* Open our intermediate table. */
- new_table= open_table_uncached(thd, new_db_type, &frm,
- alter_ctx.get_tmp_path(),
- alter_ctx.new_db, alter_ctx.tmp_name,
- true, true);
+ /*
+ table is a normal table: Create temporary table in same directory.
+ Open our intermediate table.
+ */
+ new_table=
+ thd->create_and_open_tmp_table(new_db_type, &frm,
+ alter_ctx.get_tmp_path(),
+ alter_ctx.new_db, alter_ctx.tmp_name,
+ true);
}
if (!new_table)
goto err_new_table_cleanup;
@@ -9098,10 +9393,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
new_table->s->table_creation_was_logged=
table->s->table_creation_was_logged;
/* Remove link to old table and rename the new one */
- close_temporary_table(thd, table, true, true);
+ thd->drop_temporary_table(table, NULL, true);
/* Should pass the 'new_name' as we store table name in the cache */
- if (rename_temporary_table(thd, new_table,
- alter_ctx.new_db, alter_ctx.new_name))
+ if (thd->rename_temporary_table(new_table, alter_ctx.new_db,
+ alter_ctx.new_name))
goto err_new_table_cleanup;
/* We don't replicate alter table statement on temporary tables */
if (!thd->is_current_stmt_binlog_format_row() &&
@@ -9113,10 +9408,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/*
Close the intermediate table that will be the new table, but do
- not delete it! Even altough MERGE tables do not have their children
- attached here it is safe to call close_temporary_table().
+ not delete it! Even though MERGE tables do not have their children
+ attached here it is safe to call THD::drop_temporary_table().
*/
- close_temporary_table(thd, new_table, true, false);
+ thd->drop_temporary_table(new_table, NULL, false);
new_table= NULL;
DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
@@ -9258,8 +9553,7 @@ err_new_table_cleanup:
my_free(const_cast<uchar*>(frm.str));
if (new_table)
{
- /* close_temporary_table() frees the new_table pointer. */
- close_temporary_table(thd, new_table, true, true);
+ thd->drop_temporary_table(new_table, NULL, true);
}
else
(void) quick_rm_table(thd, new_db_type,
@@ -9306,6 +9600,9 @@ err_new_table_cleanup:
err_with_mdl_after_alter:
/* the table was altered. binlog the operation */
+ DBUG_ASSERT(!(mysql_bin_log.is_open() &&
+ thd->is_current_stmt_binlog_format_row() &&
+ (create_info->tmp_table())));
write_bin_log(thd, true, thd->query(), thd->query_length());
err_with_mdl:
@@ -9379,16 +9676,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
int error= 1;
Copy_field *copy= NULL, *copy_end;
ha_rows found_count= 0, delete_count= 0;
- uint length= 0;
- SORT_FIELD *sortorder;
+ SORT_INFO *file_sort= 0;
READ_RECORD info;
TABLE_LIST tables;
List<Item> fields;
List<Item> all_fields;
- ha_rows examined_rows;
- ha_rows found_rows;
bool auto_increment_field_copied= 0;
- ulonglong save_sql_mode= thd->variables.sql_mode;
+ bool init_read_record_done= 0;
+ sql_mode_t save_sql_mode= thd->variables.sql_mode;
ulonglong prev_insert_id, time_to_report_progress;
Field **dfield_ptr= to->default_field;
DBUG_ENTER("copy_data_between_tables");
@@ -9446,7 +9741,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
Old fields keep their current values, and therefore should not be
present in the set of autoupdate fields.
*/
- if ((*ptr)->has_insert_default_function())
+ if ((*ptr)->default_value)
{
*(dfield_ptr++)= *ptr;
++to->s->default_fields;
@@ -9470,9 +9765,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
}
else
{
- from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
- MYF(MY_FAE | MY_ZEROFILL |
- MY_THREAD_SPECIFIC));
bzero((char *) &tables, sizeof(tables));
tables.table= from;
tables.alias= tables.table_name= from->s->table_name.str;
@@ -9480,16 +9772,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
THD_STAGE_INFO(thd, stage_sorting);
Filesort_tracker dummy_tracker(false);
+ Filesort fsort(order, HA_POS_ERROR, true, NULL);
+
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
- &tables, fields, all_fields, order) ||
- !(sortorder= make_unireg_sortorder(thd, NULL, 0, order, &length, NULL)) ||
- (from->sort.found_records= filesort(thd, from, sortorder, length,
- NULL, HA_POS_ERROR,
- true,
- &examined_rows, &found_rows,
- &dummy_tracker)) ==
- HA_POS_ERROR)
+ &tables, fields, all_fields, order))
+ goto err;
+
+ if (!(file_sort= filesort(thd, from, &fsort, &dummy_tracker)))
goto err;
}
thd_progress_next_stage(thd);
@@ -9498,16 +9788,19 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
THD_STAGE_INFO(thd, stage_copy_to_tmp_table);
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
- to->mark_virtual_columns_for_write(TRUE);
- if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE))
+ /* Add virtual columns to vcol_set to ensure they are updated */
+ if (to->vfield)
+ to->mark_virtual_columns_for_write(TRUE);
+ if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, file_sort, 1, 1,
+ FALSE))
goto err;
+ init_read_record_done= 1;
if (ignore && !alter_ctx->fk_error_if_delete_row)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->get_stmt_da()->reset_current_row_for_warning();
restore_record(to, s->default_values); // Create empty record
- if (to->default_field && to->update_default_fields())
- goto err;
+ to->reset_default_fields();
thd->progress.max_counter= from->file->records();
time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10;
@@ -9520,8 +9813,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
error= 1;
break;
}
- if (from->vfield)
- update_virtual_fields(thd, from);
if (++thd->progress.counter >= time_to_report_progress)
{
time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10;
@@ -9548,8 +9839,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
copy_ptr->do_copy(copy_ptr);
}
prev_insert_id= to->file->next_insert_id;
+ if (to->default_field)
+ to->update_default_fields(0, ignore);
if (to->vfield)
- update_virtual_fields(thd, to, VCOL_UPDATE_FOR_WRITE);
+ to->update_virtual_fields(to->file, VCOL_UPDATE_FOR_WRITE);
+
+ /* This will set thd->is_error() if fatal failure */
+ if (to->verify_constraints(ignore) == VIEW_CHECK_SKIP)
+ continue;
if (thd->is_error())
{
error= 1;
@@ -9615,14 +9912,11 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
found_count++;
thd->get_stmt_da()->inc_current_row_for_warning();
}
- end_read_record(&info);
- free_io_cache(from);
- delete [] copy;
THD_STAGE_INFO(thd, stage_enabling_keys);
thd_progress_next_stage(thd);
- if (error > 0)
+ if (error > 0 && !from->s->tmp_table)
{
/* We are going to drop the temporary table */
to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
@@ -9638,6 +9932,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
error= 1;
err:
+ /* Free resources */
+ if (init_read_record_done)
+ end_read_record(&info);
+ delete [] copy;
+ delete file_sort;
+
thd->variables.sql_mode= save_sql_mode;
thd->abort_on_warning= 0;
*copied= found_count;
@@ -9645,7 +9945,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->ha_release_auto_increment();
if (to->file->ha_external_lock(thd,F_UNLCK))
error=1;
- if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
+ if (error < 0 && !from->s->tmp_table &&
+ to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
error= 1;
thd_progress_end(thd);
DBUG_RETURN(error > 0 ? -1 : 0);
@@ -9698,6 +9999,18 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy)
}
+static void flush_checksum(ha_checksum *row_crc, uchar **checksum_start,
+ size_t *checksum_length)
+{
+ if (*checksum_start)
+ {
+ *row_crc= my_checksum(*row_crc, *checksum_start, *checksum_length);
+ *checksum_start= NULL;
+ *checksum_length= 0;
+ }
+}
+
+
bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
HA_CHECK_OPT *check_opt)
{
@@ -9750,7 +10063,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
/* Allow to open real tables only. */
table->required_type= FRMTYPE_TABLE;
- if (open_temporary_tables(thd, table) ||
+ if (thd->open_temporary_tables(table) ||
open_and_lock_tables(thd, table, FALSE, 0))
{
t= NULL;
@@ -9774,23 +10087,23 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
if (!(check_opt->flags & T_EXTEND) &&
(((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) && thd->variables.old_mode) ||
((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) && !thd->variables.old_mode)))
- protocol->store((ulonglong)t->file->checksum());
+ protocol->store((ulonglong)t->file->checksum());
else if (check_opt->flags & T_QUICK)
- protocol->store_null();
+ protocol->store_null();
else
{
- /* calculating table's checksum */
- ha_checksum crc= 0;
+ /* calculating table's checksum */
+ ha_checksum crc= 0;
uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
t->use_all_columns();
- if (t->file->ha_rnd_init(1))
- protocol->store_null();
- else
- {
- for (;;)
- {
+ if (t->file->ha_rnd_init(1))
+ protocol->store_null();
+ else
+ {
+ for (;;)
+ {
if (thd->killed)
{
/*
@@ -9801,7 +10114,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
thd->protocol->remove_last_row();
goto err;
}
- ha_checksum row_crc= 0;
+ ha_checksum row_crc= 0;
int error= t->file->ha_rnd_next(t->record[0]);
if (unlikely(error))
{
@@ -9809,22 +10122,27 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
continue;
break;
}
- if (t->s->null_bytes)
+ if (t->s->null_bytes)
{
/* fix undefined null bits */
t->record[0][t->s->null_bytes-1] |= null_mask;
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
t->record[0][0] |= 1;
- row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
+ row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
}
- for (uint i= 0; i < t->s->fields; i++ )
- {
- Field *f= t->field[i];
+ uchar *checksum_start= NULL;
+ size_t checksum_length= 0;
+ for (uint i= 0; i < t->s->fields; i++ )
+ {
+ Field *f= t->field[i];
if (! thd->variables.old_mode && f->is_real_null(0))
+ {
+ flush_checksum(&row_crc, &checksum_start, &checksum_length);
continue;
+ }
/*
BLOB and VARCHAR have pointers in their field, we must convert
to string; GEOMETRY is implemented on top of BLOB.
@@ -9836,6 +10154,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_BIT:
{
+ flush_checksum(&row_crc, &checksum_start, &checksum_length);
String tmp;
f->val_str(&tmp);
row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(),
@@ -9843,16 +10162,20 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
break;
}
default:
- row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
+ if (!checksum_start)
+ checksum_start= f->ptr;
+ DBUG_ASSERT(checksum_start + checksum_length == f->ptr);
+ checksum_length+= f->pack_length();
break;
- }
- }
+ }
+ }
+ flush_checksum(&row_crc, &checksum_start, &checksum_length);
- crc+= row_crc;
- }
- protocol->store((ulonglong)crc);
+ crc+= row_crc;
+ }
+ protocol->store((ulonglong)crc);
t->file->ha_rnd_end();
- }
+ }
}
trans_rollback_stmt(thd);
close_thread_tables(thd);