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.cc338
1 files changed, 234 insertions, 104 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 72fb4ea930b..98b3e4ebaf2 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -45,6 +45,7 @@
#include <hash.h>
#include <myisam.h>
#include <my_dir.h>
+#include "create_options.h"
#include "sp_head.h"
#include "sp.h"
#include "sql_trigger.h"
@@ -70,14 +71,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, 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 select_field_count);
-
+static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
+ bool, uint *, handler *, KEY **, uint *, int);
/**
@brief Helper function for explain_filename
@@ -2697,7 +2692,12 @@ int prepare_create_field(Create_field *sql_field,
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
}
- if (!(sql_field->flags & NOT_NULL_FLAG))
+ if (sql_field->flags & NOT_NULL_FLAG)
+ DBUG_PRINT("info", ("1"));
+ if (sql_field->vcol_info)
+ DBUG_PRINT("info", ("2"));
+ if (!(sql_field->flags & NOT_NULL_FLAG) ||
+ (sql_field->vcol_info)) /* Make virtual columns allow NULL values */
sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
@@ -3050,6 +3050,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
null_fields--;
sql_field->flags= dup_field->flags;
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;
@@ -3059,7 +3061,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
/* Don't pack rows in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
(sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
- create_info->row_type != ROW_TYPE_FIXED))
+ create_info->row_type != ROW_TYPE_FIXED))
(*db_options)|= HA_OPTION_PACK_RECORD;
it2.rewind();
}
@@ -3082,7 +3084,28 @@ 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++;
- record_offset+= sql_field->pack_length;
+ if (parse_option_list(thd, &sql_field->option_struct,
+ sql_field->option_list,
+ create_info->db_type->field_options, FALSE,
+ thd->mem_root))
+ DBUG_RETURN(TRUE);
+ /*
+ For now skip fields that are not physically stored in the database
+ (virtual fields) and update their offset later
+ (see the next loop).
+ */
+ 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)
+ {
+ sql_field->offset= record_offset;
+ record_offset+= sql_field->pack_length;
+ }
}
if (timestamps_with_niladic > 1)
{
@@ -3131,6 +3154,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->type == Key::FOREIGN_KEY)
{
fk_key_count++;
+ if (((Foreign_key *)key)->validate(alter_info->create_list))
+ DBUG_RETURN(TRUE);
Foreign_key *fk_key= (Foreign_key*) key;
if (fk_key->ref_columns.elements &&
fk_key->ref_columns.elements != fk_key->columns.elements)
@@ -3260,6 +3285,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
key_info->key_part=key_part_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,
+ create_info->db_type->index_options, FALSE,
+ thd->mem_root))
+ DBUG_RETURN(TRUE);
if (key->type == Key::FULLTEXT)
{
@@ -3424,6 +3455,17 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
#endif
+ if (!sql_field->stored_in_db)
+ {
+ /* 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 (!(sql_field->flags & NOT_NULL_FLAG))
{
if (key->type == Key::PRIMARY)
@@ -3508,7 +3550,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
length=column->length;
}
- else if (length == 0)
+ else if (length == 0 && (sql_field->flags & NOT_NULL_FLAG))
{
my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name.str);
DBUG_RETURN(TRUE);
@@ -3676,6 +3718,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
+ if (parse_option_list(thd, &create_info->option_struct,
+ create_info->option_list,
+ file->partition_ht()->table_options, FALSE,
+ thd->mem_root))
+ DBUG_RETURN(TRUE);
+
DBUG_RETURN(FALSE);
}
@@ -3885,8 +3933,9 @@ bool mysql_create_table_no_lock(THD *thd,
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;
+ if (create_info->row_type != ROW_TYPE_FIXED &&
+ create_info->row_type != ROW_TYPE_DEFAULT)
+ db_options|= HA_OPTION_PACK_RECORD;
alias= table_case_name(create_info, table_name);
if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
create_info->db_type)))
@@ -4091,6 +4140,15 @@ bool mysql_create_table_no_lock(THD *thd,
goto err;
}
+ /* Give warnings for not supported table options */
+ if (create_info->transactional && !file->ht->commit)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ ER(ER_ILLEGAL_HA_CREATE_OPTION),
+ file->engine_name()->str,
+ "TRANSACTIONAL=1");
+
+
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
@@ -4145,7 +4203,6 @@ bool mysql_create_table_no_lock(THD *thd,
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);
@@ -4379,7 +4436,7 @@ mysql_rename_table(handlerton *base, const char *old_db,
char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
char *from_base= from, *to_base= to;
- char tmp_name[NAME_LEN+1];
+ char tmp_name[SAFE_NAME_LEN+1];
handler *file;
int error=0;
DBUG_ENTER("mysql_rename_table");
@@ -4765,6 +4822,7 @@ mysql_compare_tables(TABLE *table,
KEY_PART_INFO *key_part;
KEY_PART_INFO *end;
THD *thd= table->in_use;
+ uint i;
/*
Remember if the new definition has new VARCHAR column;
create_info->varchar will be reset in mysql_prepare_create_table.
@@ -4791,6 +4849,9 @@ mysql_compare_tables(TABLE *table,
Alter_info tmp_alter_info(*alter_info, thd->mem_root);
uint db_options= 0; /* not used */
+ /* Set default value for return value (to ensure it's always set) */
+ *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+
/* Create the prepared information. */
if (mysql_prepare_create_table(thd, create_info,
&tmp_alter_info,
@@ -4839,6 +4900,8 @@ mysql_compare_tables(TABLE *table,
create_info->used_fields & HA_CREATE_USED_CHARSET ||
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
(table->s->row_type != create_info->row_type) ||
+ create_info->used_fields & HA_CREATE_USED_PAGE_CHECKSUM ||
+ create_info->used_fields & HA_CREATE_USED_TRANSACTIONAL ||
create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
@@ -4846,10 +4909,16 @@ mysql_compare_tables(TABLE *table,
!table->s->mysql_version ||
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
{
- *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_PRINT("info", ("Basic checks -> ALTER_TABLE_DATA_CHANGED"));
DBUG_RETURN(0);
}
+ if ((create_info->fileds_option_struct=
+ (void**)thd->calloc(sizeof(void*) * table->s->fields)) == NULL ||
+ (create_info->indexes_option_struct=
+ (void**)thd->calloc(sizeof(void*) * table->s->keys)) == NULL)
+ DBUG_RETURN(1);
+
/*
Use transformed info to evaluate possibility of fast ALTER TABLE
but use the preserved field to persist modifications.
@@ -4861,12 +4930,15 @@ mysql_compare_tables(TABLE *table,
Go through fields and check if the original ones are compatible
with new table.
*/
- for (f_ptr= table->field, new_field= new_field_it++,
+ for (i= 0, f_ptr= table->field, new_field= new_field_it++,
tmp_new_field= tmp_new_field_it++;
(field= *f_ptr);
- f_ptr++, new_field= new_field_it++,
+ i++, f_ptr++, new_field= new_field_it++,
tmp_new_field= tmp_new_field_it++)
{
+ DBUG_ASSERT(i < table->s->fields);
+ create_info->fileds_option_struct[i]= tmp_new_field->option_struct;
+
/* Make sure we have at least the default charset in use. */
if (!new_field->charset)
new_field->charset= create_info->default_table_charset;
@@ -4875,16 +4947,30 @@ mysql_compare_tables(TABLE *table,
if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
(uint) (field->flags & NOT_NULL_FLAG))
{
+ DBUG_PRINT("info", ("NULL behaviour difference in field '%s' -> "
+ "ALTER_TABLE_DATA_CHANGED", new_field->field_name));
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Check if the altered column is computed and either
+ is stored or is used in the partitioning expression.
+ TODO: Mark such a column with an alter flag only if
+ the defining expression has changed.
+ */
+ if (field->vcol_info &&
+ (field->stored_in_db || field->vcol_info->is_in_partitioning_expr()))
+ {
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
DBUG_RETURN(0);
}
/* Don't pack rows in old tables if the user has requested this. */
- if (create_info->row_type == ROW_TYPE_DYNAMIC ||
- (tmp_new_field->flags & BLOB_FLAG) ||
- (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
- create_info->row_type != ROW_TYPE_FIXED))
- create_info->table_options|= HA_OPTION_PACK_RECORD;
+ if (create_info->row_type == ROW_TYPE_DYNAMIC ||
+ (tmp_new_field->flags & BLOB_FLAG) ||
+ (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
+ create_info->row_type != ROW_TYPE_FIXED))
+ create_info->table_options|= HA_OPTION_PACK_RECORD;
/* Check if field was renamed */
field->flags&= ~FIELD_IS_RENAMED;
@@ -4896,7 +4982,8 @@ mysql_compare_tables(TABLE *table,
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
if (!(tmp= field->is_equal(tmp_new_field)))
{
- *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_PRINT("info", ("!field_is_equal('%s') -> ALTER_TABLE_DATA_CHANGED",
+ new_field->field_name));
DBUG_RETURN(0);
}
// Clear indexed marker
@@ -5005,7 +5092,9 @@ mysql_compare_tables(TABLE *table,
for (new_key= *key_info_buffer; new_key < new_key_end; new_key++)
{
/* Search an old key with the same name. */
- for (table_key= table->key_info; table_key < table_key_end; table_key++)
+ for (i= 0, table_key= table->key_info;
+ table_key < table_key_end;
+ i++, table_key++)
{
if (! strcmp(table_key->name, new_key->name))
break;
@@ -5024,21 +5113,31 @@ mysql_compare_tables(TABLE *table,
}
DBUG_PRINT("info", ("index added: '%s'", new_key->name));
}
+ else
+ {
+ DBUG_ASSERT(i < table->s->keys);
+ create_info->indexes_option_struct[i]= new_key->option_struct;
+ }
}
/* Check if changes are compatible with current handler without a copy */
if (table->file->check_if_incompatible_data(create_info, changes))
{
- *need_copy_table= ALTER_TABLE_DATA_CHANGED;
+ DBUG_PRINT("info", ("check_if_incompatible_data() -> "
+ "ALTER_TABLE_DATA_CHANGED"));
DBUG_RETURN(0);
}
if (*index_drop_count || *index_add_count)
{
+ DBUG_PRINT("info", ("Index dropped=%u added=%u -> "
+ "ALTER_TABLE_INDEX_CHANGED",
+ *index_drop_count, *index_add_count));
*need_copy_table= ALTER_TABLE_INDEX_CHANGED;
DBUG_RETURN(0);
}
+ DBUG_PRINT("info", (" -> ALTER_TABLE_METADATA_ONLY"));
*need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible
DBUG_RETURN(0);
}
@@ -5157,6 +5256,7 @@ blob_length_by_type(enum_field_types type)
Sets create_info->varchar if the table has a VARCHAR column.
Prepares alter_info->create_list and alter_info->key_list with
columns and keys of the new table.
+
@retval TRUE error, out of memory or a semantical error in ALTER
TABLE instructions
@retval FALSE success
@@ -5183,7 +5283,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
uint used_fields= create_info->used_fields;
KEY *key_info=table->key_info;
bool rc= TRUE;
-
+ Create_field *def;
+ Field **f_ptr,*field;
DBUG_ENTER("mysql_prepare_alter_table");
create_info->varchar= FALSE;
@@ -5204,6 +5305,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
create_info->key_block_size= table->s->key_block_size;
+ if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL))
+ create_info->transactional= table->s->transactional;
if (!create_info->tablespace && create_info->storage_media != HA_SM_MEMORY)
{
@@ -5217,18 +5320,18 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
create_info->tablespace= tablespace;
}
restore_record(table, s->default_values); // Empty record for DEFAULT
- Create_field *def;
+ create_info->option_list= merge_engine_table_options(table->s->option_list,
+ create_info->option_list, thd->mem_root);
/*
First collect all fields from table which isn't in drop_list
*/
- Field **f_ptr,*field;
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
+ Alter_drop *drop;
if (field->type() == MYSQL_TYPE_STRING)
create_info->varchar= TRUE;
/* Check if field should be dropped */
- Alter_drop *drop;
drop_it.rewind();
while ((drop=drop_it++))
{
@@ -5261,6 +5364,13 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (def)
{ // Field is changed
def->field=field;
+ if (field->stored_in_db != def->stored_in_db)
+ {
+ my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN,
+ MYF(0),
+ "Changing the STORED status");
+ goto err;
+ }
if (!def->after)
{
new_create_list.push_back(def);
@@ -5302,7 +5412,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{
if (def->change && ! def->field)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change,
+ table->s->table_name.str);
goto err;
}
/*
@@ -5337,7 +5448,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!find)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after,
+ table->s->table_name.str);
goto err;
}
find_it.after(def); // Put element after this
@@ -5387,6 +5499,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
continue; // Wrong field (from UNIREG)
const char *key_part_name=key_part->field->field_name;
Create_field *cfield;
+ uint key_part_length;
+
field_it.rewind();
while ((cfield=field_it++))
{
@@ -5402,7 +5516,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!cfield)
continue; // Field is removed
- uint key_part_length=key_part->length;
+ key_part_length= key_part->length;
if (cfield->field) // Not new field
{
/*
@@ -5475,7 +5589,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_parts, key_info->option_list);
new_key_list.push_back(key);
}
}
@@ -5483,6 +5597,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
Key *key;
while ((key=key_it++)) // Add new keys
{
+ if (key->type == Key::FOREIGN_KEY &&
+ ((Foreign_key *)key)->validate(new_create_list))
+ goto err;
if (key->type != Key::FOREIGN_KEY)
new_key_list.push_back(key);
if (key->name.str &&
@@ -5611,6 +5728,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
uint *index_add_buffer= NULL;
uint candidate_key_count= 0;
bool no_pk;
+ ulong explicit_used_fields= 0;
+ enum ha_extra_function extra_func= thd->locked_tables ? HA_EXTRA_NOT_USED
+ : HA_EXTRA_FORCE_REOPEN;
DBUG_ENTER("mysql_alter_table");
/*
@@ -5825,19 +5945,21 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/*
- If this is an ALTER TABLE and no explicit row type specified reuse
- the table's row type.
- Note : this is the same as if the row type was specified explicitly.
+ If this is an ALTER TABLE and no explicit row type specified reuse
+ the table's row type.
+ Note: this is the same as if the row type was specified explicitly and
+ we must thus set HA_CREATE_USED_ROW_FORMAT!
*/
if (create_info->row_type == ROW_TYPE_NOT_USED)
{
/* ALTER TABLE without explicit row type */
create_info->row_type= table->s->row_type;
- }
- else
- {
- /* ALTER TABLE with specific row type */
- create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
+ /*
+ We have to mark the row type as used, as otherwise the engine may
+ change the row format in update_create_info().
+ */
+ create_info->used_fields|= HA_CREATE_USED_ROW_FORMAT;
+ explicit_used_fields|= HA_CREATE_USED_ROW_FORMAT;
}
DBUG_PRINT("info", ("old type: %s new type: %s",
@@ -5859,13 +5981,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
case LEAVE_AS_IS:
break;
case ENABLE:
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, table, extra_func))
goto err;
DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000););
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
break;
case DISABLE:
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, table, extra_func))
goto err;
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
break;
@@ -5893,7 +6015,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
simple rename did nothing and therefore we can safely return
without additional clean-up.
*/
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, table, extra_func))
goto err;
close_all_tables_for_name(thd, table->s, TRUE);
/*
@@ -5991,6 +6113,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_prepare_alter_table(thd, table, create_info, alter_info))
goto err;
+ /* Remove markers set for update_create_info */
+ create_info->used_fields&= ~explicit_used_fields;
+
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
need_copy_table= alter_info->change_level;
@@ -6340,7 +6465,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
else
{
if (!table->s->tmp_table &&
- wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ wait_while_table_is_used(thd, table, extra_func))
goto err_new_table_cleanup;
thd_proc_info(thd, "manage keys");
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
@@ -6384,6 +6509,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Add the indexes. */
if ((error= table->file->add_index(table, key_info, index_add_count)))
{
+#warning fix the following
+#ifdef UNKNOWN_MONTY_ADDITION
+ /* Only report error if handler has not already reported an error */
+ if (!thd->main_da.is_error())
+#endif
+ {
/*
Exchange the key_info for the error message. If we exchange
key number by key name in the message later, we need correct info.
@@ -6392,6 +6523,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
table->key_info= key_info;
table->file->print_error(error, MYF(0));
table->key_info= save_key_info;
+ }
goto err_new_table_cleanup;
}
}
@@ -6548,11 +6680,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
new_alias, FN_FROM_IS_TMP) ||
((new_name != table_name || new_db != db) && // we also do rename
- (need_copy_table != ALTER_TABLE_METADATA_ONLY ||
- mysql_rename_table(save_old_db_type, db, table_name, new_db,
- new_alias, NO_FRM_RENAME)) &&
- Table_triggers_list::change_table_name(thd, db, table_name,
- new_db, new_alias)))
+ (need_copy_table != ALTER_TABLE_METADATA_ONLY ||
+ mysql_rename_table(save_old_db_type, db, table_name, new_db,
+ new_alias, NO_FRM_RENAME)) &&
+ Table_triggers_list::change_table_name(thd, db, table_name,
+ new_db, new_alias)))
{
/* Try to get everything back. */
error=1;
@@ -6633,27 +6765,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
DBUG_RETURN(TRUE);
- if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
- {
- /*
- For the alter table to be properly flushed to the logs, we
- have to open the new table. If not, we get a problem on server
- shutdown. But we do not need to attach MERGE children.
- */
- char path[FN_REFLEN];
- TABLE *t_table;
- build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
- t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
- if (t_table)
- {
- intern_close_table(t_table);
- my_free(t_table);
- }
- else
- sql_print_warning("Could not open table %s.%s after rename\n",
- new_db,table_name);
- ha_flush_logs(old_db_type);
- }
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
@@ -6739,7 +6850,9 @@ err_with_mdl:
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
DBUG_RETURN(TRUE);
}
-/* mysql_alter_table */
+
+
+/* Copy all rows from one table to another */
@@ -6799,9 +6912,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
enum enum_enable_or_disable keys_onoff,
bool error_if_not_empty)
{
- int error;
- Copy_field *copy,*copy_end;
- ulong found_count,delete_count;
+ int error= 1, errpos= 0;
+ Copy_field *copy= NULL, *copy_end;
+ ha_rows found_count= 0, delete_count= 0;
THD *thd= current_thd;
uint length= 0;
SORT_FIELD *sortorder;
@@ -6811,18 +6924,22 @@ copy_data_between_tables(TABLE *from,TABLE *to,
List<Item> all_fields;
ha_rows examined_rows;
bool auto_increment_field_copied= 0;
- ulong save_sql_mode;
+ ulong save_sql_mode= thd->variables.sql_mode;
ulonglong prev_insert_id;
+ List_iterator<Create_field> it(create);
+ Create_field *def;
DBUG_ENTER("copy_data_between_tables");
if (mysql_trans_prepare_alter_copy_data(thd))
- DBUG_RETURN(-1);
-
+ goto err;
+ errpos=1;
+
if (!(copy= new Copy_field[to->s->fields]))
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (to->file->ha_external_lock(thd, F_WRLCK))
- DBUG_RETURN(-1);
+ goto err;
+ errpos= 2;
/* We need external lock before we can disable/enable keys */
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
@@ -6834,11 +6951,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
from->file->info(HA_STATUS_VARIABLE);
to->file->ha_start_bulk_insert(from->file->stats.records);
+ errpos= 3;
- save_sql_mode= thd->variables.sql_mode;
-
- List_iterator<Create_field> it(create);
- Create_field *def;
copy_end=copy;
for (Field **ptr=to->field ; *ptr ; ptr++)
{
@@ -6862,8 +6976,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
- found_count=delete_count=0;
-
if (order)
{
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
@@ -6883,7 +6995,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.table= from;
tables.alias= tables.table_name= from->s->table_name.str;
tables.db= from->s->db.str;
- error= 1;
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
@@ -6899,7 +7010,10 @@ copy_data_between_tables(TABLE *from,TABLE *to,
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
- init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE);
+ to->mark_virtual_columns_for_write(TRUE);
+ if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE))
+ goto err;
+ errpos= 4;
if (ignore)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->warning_info->reset_current_row_for_warning();
@@ -6912,6 +7026,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
error= 1;
break;
}
+ update_virtual_fields(thd, from);
/* Return error if source table isn't empty. */
if (error_if_not_empty)
{
@@ -6931,6 +7046,12 @@ copy_data_between_tables(TABLE *from,TABLE *to,
copy_ptr->do_copy(copy_ptr);
}
prev_insert_id= to->file->next_insert_id;
+ update_virtual_fields(thd, to, TRUE);
+ if (thd->is_error())
+ {
+ error= 1;
+ break;
+ }
error=to->file->ha_write_row(to->record[0]);
to->auto_increment_field_not_null= FALSE;
if (error)
@@ -6963,28 +7084,31 @@ copy_data_between_tables(TABLE *from,TABLE *to,
found_count++;
thd->warning_info->inc_current_row_for_warning();
}
- end_read_record(&info);
+
+err:
+ if (errpos >= 4)
+ end_read_record(&info);
free_io_cache(from);
- delete [] copy; // This is never 0
+ delete [] copy;
- if (to->file->ha_end_bulk_insert() && error <= 0)
+ if (error > 0)
+ to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ if (errpos >= 3 && to->file->ha_end_bulk_insert() && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
error= 1;
}
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- if (mysql_trans_commit_alter_copy_data(thd))
+ if (errpos >= 1 && mysql_trans_commit_alter_copy_data(thd))
error= 1;
- err:
thd->variables.sql_mode= save_sql_mode;
thd->abort_on_warning= 0;
- free_io_cache(from);
*copied= found_count;
*deleted=delete_count;
to->file->ha_release_auto_increment();
- if (to->file->ha_external_lock(thd,F_UNLCK))
+ if (errpos >= 2 && to->file->ha_external_lock(thd,F_UNLCK))
error=1;
if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
error= 1;
@@ -7054,7 +7178,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
/* Open one table after the other to keep lock time as short as possible. */
for (table= tables; table; table= table->next_local)
{
- char table_name[NAME_LEN*2+2];
+ char table_name[SAFE_NAME_LEN*2+2];
TABLE *t;
strxmov(table_name, table->db ,".", table->table_name, NullS);
@@ -7073,11 +7197,14 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
}
else
{
- if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
- !(check_opt->flags & T_EXTEND))
+ /* Call ->checksum() if the table checksum matches 'old_mode' settings */
+ 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());
- else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
- (check_opt->flags & T_QUICK))
+ else if (check_opt->flags & T_QUICK)
protocol->store_null();
else
{
@@ -7104,7 +7231,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
goto err;
}
ha_checksum row_crc= 0;
- int error= t->file->rnd_next(t->record[0]);
+ int error= t->file->ha_rnd_next(t->record[0]);
if (unlikely(error))
{
if (error == HA_ERR_RECORD_DELETED)
@@ -7125,6 +7252,9 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
{
Field *f= t->field[i];
+ if (! thd->variables.old_mode &&
+ f->is_real_null(0))
+ continue;
/*
BLOB and VARCHAR have pointers in their field, we must convert
to string; GEOMETRY is implemented on top of BLOB.
@@ -7200,7 +7330,7 @@ static bool check_engine(THD *thd, const char *table_name,
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
{
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
- ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
+ hton_name(*new_engine)->str, "TEMPORARY");
*new_engine= 0;
return TRUE;
}