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.cc199
1 files changed, 159 insertions, 40 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6cd73978eed..a05afb39174 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -65,6 +65,9 @@ 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(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,
@@ -3082,7 +3085,7 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
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)
{
@@ -3255,32 +3258,30 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/*
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->def &&
- save_cs != sql_field->def->collation.collation &&
+ if (sql_field->default_value &&
+ sql_field->default_value->expr_item->basic_const_item() &&
+ save_cs != sql_field->default_value->expr_item->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))
{
- /*
- 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)
+ Item *item;
+ if (!(item= sql_field->default_value->expr_item->
+ 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, item);
}
if (sql_field->sql_type == MYSQL_TYPE_SET ||
@@ -3348,12 +3349,13 @@ 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)
+ if (sql_field->default_value &&
+ sql_field->default_value->expr_item->basic_const_item())
{
char *not_used;
uint not_used2;
bool not_found= 0;
- String str, *def= sql_field->def->val_str(&str);
+ String str, *def= sql_field->default_value->expr_item->val_str(&str);
if (def == NULL) /* SQL "NULL" maps to NULL */
{
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
@@ -3385,9 +3387,10 @@ 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)
+ if (sql_field->default_value &&
+ sql_field->default_value->expr_item->basic_const_item())
{
- String str, *def= sql_field->def->val_str(&str);
+ String str, *def= sql_field->default_value->expr_item->val_str(&str);
if (def == NULL) /* SQL "NULL" maps to NULL */
{
if ((sql_field->flags & NOT_NULL_FLAG) != 0)
@@ -3464,7 +3467,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;
/*
@@ -4129,7 +4132,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))
@@ -4139,7 +4142,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->default_value &&
is_timestamp_type(sql_field->sql_type) &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
@@ -4163,6 +4166,31 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
+ /* Check table level constraints */
+ create_info->constraint_list= &alter_info->constraint_list;
+ {
+ uint nr= 1;
+ List_iterator_fast<Virtual_column_info> c_it(alter_info->constraint_list);
+ Virtual_column_info *check;
+ while ((check= c_it++))
+ {
+ if (!check->name.length)
+ make_unique_constraint_name(thd, &check->name,
+ &alter_info->constraint_list,
+ &nr);
+
+ if (check_string_char_length(&check->name, 0, NAME_CHAR_LEN,
+ system_charset_info, 1))
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
+ DBUG_RETURN(TRUE);
+ }
+ if (check_expression(check, "CONSTRAINT CHECK",
+ check->name.str ? check->name.str : "", 0))
+ DBUG_RETURN(TRUE);
+ }
+ }
+
/* Give warnings for not supported table options */
#if defined(WITH_ARIA_STORAGE_ENGINE)
extern handlerton *maria_hton;
@@ -4278,7 +4306,7 @@ static bool prepare_blob_field(THD *thd, Column_definition *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 /
@@ -4357,7 +4385,7 @@ void sp_prepare_create_field(THD *thd, Column_definition *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);
}
@@ -5122,6 +5150,38 @@ make_unique_key_name(THD *thd, const char *field_name,KEY *start,KEY *end)
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
@@ -6176,6 +6236,10 @@ 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_CONSTRAINT)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ADD_CONSTRAINT;
+ if (alter_info->flags & Alter_info::ALTER_DROP_CONSTRAINT)
+ ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_DROP_CONSTRAINT;
/*
If we altering table with old VARCHAR fields we will be automatically
@@ -6923,6 +6987,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);
}
@@ -7333,6 +7405,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;
@@ -7477,12 +7550,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;
@@ -7756,6 +7824,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::CONSTRAINT_CHECK &&
+ !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->constraint_list);
+
if (alter_info->drop_list.elements)
{
Alter_drop *drop;
@@ -7764,8 +7859,15 @@ 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::CONSTRAINT_CHECK:
+ if (drop->drop_if_exists)
+ 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);
+ else
+ my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
+ 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.
@@ -7811,6 +7913,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->constraint_list.swap(new_constraint_list);
err:
DBUG_RETURN(rc);
}
@@ -8848,13 +8951,21 @@ 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
enum_alter_inplace_result inplace_supported=
- table->file->check_if_supported_inplace_alter(altered_table,
- &ha_alter_info);
+ HA_ALTER_INPLACE_NOT_SUPPORTED;
+ if (!(ha_alter_info.handler_flags &
+ Alter_inplace_info::ALTER_ADD_CONSTRAINT) ||
+ (thd->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS))
+ inplace_supported=
+ table->file->check_if_supported_inplace_alter(altered_table,
+ &ha_alter_info);
switch (inplace_supported) {
case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
@@ -9435,7 +9546,8 @@ 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 ||
+ ((*ptr)->has_insert_default_function()))
{
*(dfield_ptr++)= *ptr;
++to->s->default_fields;
@@ -9482,7 +9594,9 @@ 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);
+ /* 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;
@@ -9492,8 +9606,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
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;
@@ -9534,8 +9647,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);
+
+ /* This will set thd->is_error() if fatal failure */
+ if (to->verify_constraints(ignore) == VIEW_CHECK_SKIP)
+ continue;
if (thd->is_error())
{
error= 1;