2086
bool create_like_table(Session* session,
2087
identifier::Table::const_reference destination_identifier,
2088
identifier::Table::const_reference source_identifier,
2089
message::Table &create_table_proto,
2090
bool is_if_not_exists,
2913
bool mysql_create_like_table(Session* session, TableList* table, TableList* src_table,
2914
HA_CREATE_INFO *create_info)
2916
Table *name_lock= 0;
2917
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
2918
uint32_t dst_path_length;
2919
char *db= table->db;
2920
char *table_name= table->table_name;
2093
2922
bool res= true;
2094
bool table_exists= false;
2926
By opening source table we guarantee that it exists and no concurrent
2927
DDL operation will mess with it. Later we also take an exclusive
2928
name-lock on target table name, which makes copying of .frm file,
2929
call to ha_create_table() and binlogging atomic against concurrent DML
2930
and DDL operations on target table. Thus by holding both these "locks"
2931
we ensure that our statement is properly isolated from all concurrent
2932
operations which matter.
2934
if (open_tables(session, &src_table, ¬_used, 0))
2937
strxmov(src_path, src_table->table->s->path.str, reg_ext, NULL);
2097
2940
Check that destination tables does not exist. Note that its name
2098
2941
was already checked when it was added to the table list.
2100
For temporary tables we don't aim to grab locks.
2102
if (destination_identifier.isTmp())
2104
if (session->find_temporary_table(destination_identifier))
2110
bool was_created= create_table_wrapper(*session,
2112
destination_identifier,
2115
if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2117
(void) session->rm_temporary_table(destination_identifier, true);
2119
else if (not session->open_temporary_table(destination_identifier))
2121
// We created, but we can't open... also, a hack.
2122
(void) session->rm_temporary_table(destination_identifier, true);
2130
else // Standard table which will require locks.
2132
Table *name_lock= 0;
2134
if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2138
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2139
session->unlink_open_table(name_lock);
2149
else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2153
else // Otherwise we create the table
2157
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2158
was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2159
source_identifier, is_engine_set);
2162
// So we blew the creation of the table, and we scramble to clean up
2163
// anything that might have been created (read... it is a hack)
2164
if (not was_created)
2166
plugin::StorageEngine::dropTable(*session, destination_identifier);
2943
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
2945
if (find_temporary_table(session, db, table_name))
2947
dst_path_length= build_tmptable_filename(session, dst_path, sizeof(dst_path));
2948
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
2952
if (lock_table_name_if_not_cached(session, db, table_name, &name_lock))
2956
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
2957
db, table_name, reg_ext, 0);
2958
if (!access(dst_path, F_OK))
2963
Create a new table by copying from source table
2965
Altough exclusive name-lock on target table protects us from concurrent
2966
DML and DDL operations on it we still want to wrap .FRM creation and call
2967
to ha_create_table() in critical section protected by LOCK_open in order
2968
to provide minimal atomicity against operations which disregard name-locks,
2969
like I_S implementation, for example. This is a temporary and should not
2970
be copied. Instead we should fix our code to always honor name-locks.
2972
Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2973
during the call to ha_create_table(). See bug #28614 for more info.
2975
pthread_mutex_lock(&LOCK_open);
2976
if (src_table->schema_table)
2978
if (mysql_create_like_schema_frm(session, src_table, dst_path, create_info))
2980
pthread_mutex_unlock(&LOCK_open);
2984
else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
2986
if (my_errno == ENOENT)
2987
my_error(ER_BAD_DB_ERROR,MYF(0),db);
2989
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
2990
pthread_mutex_unlock(&LOCK_open);
2995
As mysql_truncate don't work on a new table at this stage of
2996
creation, instead create the table directly (for both normal
2997
and temporary tables).
2999
dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
3000
if (session->variables.keep_files_on_create)
3001
create_info->options|= HA_CREATE_KEEP_FILES;
3002
err= ha_create_table(session, dst_path, db, table_name, create_info, 1);
3003
pthread_mutex_unlock(&LOCK_open);
3005
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
3007
if (err || !open_temporary_table(session, dst_path, db, table_name, 1,
3010
(void) rm_temporary_table(create_info->db_type,
3011
dst_path, false); /* purecov: inspected */
3012
goto err; /* purecov: inspected */
3017
(void) quick_rm_table(create_info->db_type, db,
3018
table_name, 0); /* purecov: inspected */
3019
goto err; /* purecov: inspected */
3023
We have to write the query before we unlock the tables.
3025
if (session->current_stmt_binlog_row_based)
3028
Since temporary tables are not replicated under row-based
3029
replication, CREATE TABLE ... LIKE ... needs special
3030
treatement. We have four cases to consider, according to the
3031
following decision table:
3033
==== ========= ========= ==============================
3034
Case Target Source Write to binary log
3035
==== ========= ========= ==============================
3036
1 normal normal Original statement
3037
2 normal temporary Generated statement
3038
3 temporary normal Nothing
3039
4 temporary temporary Nothing
3040
==== ========= ========= ==============================
3042
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
3044
if (src_table->table->s->tmp_table) // Case 2
3047
String query(buf, sizeof(buf), system_charset_info);
3048
query.length(0); // Have to zero it since constructor doesn't
3052
Here we open the destination table, on which we already have
3053
name-lock. This is needed for store_create_info() to work.
3054
The table will be closed by unlink_open_table() at the end
3057
table->table= name_lock;
3058
pthread_mutex_lock(&LOCK_open);
3059
if (reopen_name_locked_table(session, table, false))
3061
pthread_mutex_unlock(&LOCK_open);
3064
pthread_mutex_unlock(&LOCK_open);
3066
int result= store_create_info(session, table, &query,
3069
assert(result == 0); // store_create_info() always return 0
3070
write_bin_log(session, true, query.ptr(), query.length());
3073
write_bin_log(session, true, session->query, session->query_length);
3076
Case 3 and 4 does nothing under RBR
3080
write_bin_log(session, true, session->query, session->query_length);
3086
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
3088
char warn_buff[DRIZZLE_ERRMSG_SIZE];
3089
snprintf(warn_buff, sizeof(warn_buff),
3090
ER(ER_TABLE_EXISTS_ERROR), table_name);
3091
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3092
ER_TABLE_EXISTS_ERROR,warn_buff);
3096
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
3101
pthread_mutex_lock(&LOCK_open);
3102
unlink_open_table(session, name_lock, false);
3103
pthread_mutex_unlock(&LOCK_open);
3109
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
3111
thr_lock_type lock_type = TL_READ_NO_INSERT;
3113
return(mysql_admin_table(session, tables, check_opt,
3114
"analyze", lock_type, 1, 0, 0, 0,
3115
&handler::ha_analyze));
3119
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
3121
thr_lock_type lock_type = TL_READ_NO_INSERT;
3123
return(mysql_admin_table(session, tables, check_opt,
3125
0, 0, HA_OPEN_FOR_REPAIR, 0,
3126
&handler::ha_check));
3130
/* table_list should contain just one table */
3132
mysql_discard_or_import_tablespace(Session *session,
3133
TableList *table_list,
3134
enum tablespace_op_type tablespace_op)
3141
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
3145
session->set_proc_info("discard_or_import_tablespace");
3147
discard= test(tablespace_op == DISCARD_TABLESPACE);
3150
We set this flag so that ha_innobase::open and ::external_lock() do
3151
not complain when we lock the table
3153
session->tablespace_op= true;
3154
if (!(table=open_ltable(session, table_list, TL_WRITE, 0)))
3156
session->tablespace_op=false;
3160
error= table->file->ha_discard_or_import_tablespace(discard);
3162
session->set_proc_info("end");
3167
/* The ALTER Table is always in its own transaction */
3168
error = ha_autocommit_or_rollback(session, 0);
3169
if (end_active_trans(session))
3173
write_bin_log(session, false, session->query, session->query_length);
3176
ha_autocommit_or_rollback(session, error);
3177
session->tablespace_op=false;
3185
table->file->print_error(error, MYF(0));
3191
Copy all changes detected by parser to the HA_ALTER_FLAGS
3194
void setup_ha_alter_flags(Alter_info *alter_info, HA_ALTER_FLAGS *alter_flags)
3196
uint32_t flags= alter_info->flags;
3198
if (ALTER_ADD_COLUMN & flags)
3199
*alter_flags|= HA_ADD_COLUMN;
3200
if (ALTER_DROP_COLUMN & flags)
3201
*alter_flags|= HA_DROP_COLUMN;
3202
if (ALTER_RENAME & flags)
3203
*alter_flags|= HA_RENAME_TABLE;
3204
if (ALTER_CHANGE_COLUMN & flags)
3205
*alter_flags|= HA_CHANGE_COLUMN;
3206
if (ALTER_COLUMN_DEFAULT & flags)
3207
*alter_flags|= HA_COLUMN_DEFAULT_VALUE;
3208
if (ALTER_COLUMN_STORAGE & flags)
3209
*alter_flags|= HA_COLUMN_STORAGE;
3210
if (ALTER_COLUMN_FORMAT & flags)
3211
*alter_flags|= HA_COLUMN_FORMAT;
3212
if (ALTER_COLUMN_ORDER & flags)
3213
*alter_flags|= HA_ALTER_COLUMN_ORDER;
3214
if (ALTER_STORAGE & flags)
3215
*alter_flags|= HA_ALTER_STORAGE;
3216
if (ALTER_ROW_FORMAT & flags)
3217
*alter_flags|= HA_ALTER_ROW_FORMAT;
3218
if (ALTER_RECREATE & flags)
3219
*alter_flags|= HA_RECREATE;
3220
if (ALTER_FOREIGN_KEY & flags)
3221
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3226
@param session Thread
3227
@param table The original table.
3228
@param alter_info Alter options, fields and keys for the new
3230
@param create_info Create options for the new table.
3231
@param order_num Number of order list elements.
3232
@param[out] ha_alter_flags Flags that indicate what will be changed
3233
@param[out] ha_alter_info Data structures needed for on-line alter
3234
@param[out] table_changes Information about particular change
3236
First argument 'table' contains information of the original
3237
table, which includes all corresponding parts that the new
3238
table has in arguments create_list, key_list and create_info.
3240
By comparing the changes between the original and new table
3241
we can determine how much it has changed after ALTER Table
3242
and whether we need to make a copy of the table, or just change
3245
Mark any changes detected in the ha_alter_flags.
3247
If there are no data changes, but index changes, 'index_drop_buffer'
3248
and/or 'index_add_buffer' are populated with offsets into
3249
table->key_info or key_info_buffer respectively for the indexes
3250
that need to be dropped and/or (re-)created.
3253
@retval false success
3258
compare_tables(Session *session,
3260
Alter_info *alter_info,
3261
HA_CREATE_INFO *create_info,
3263
HA_ALTER_FLAGS *alter_flags,
3264
HA_ALTER_INFO *ha_alter_info,
3265
uint32_t *table_changes)
3267
Field **f_ptr, *field;
3268
uint32_t table_changes_local= 0;
3269
List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3270
Create_field *new_field;
3271
KEY_PART_INFO *key_part;
3274
Remember if the new definition has new VARCHAR column;
3275
create_info->varchar will be reset in mysql_prepare_create_table.
3277
bool varchar= create_info->varchar;
3281
Create a copy of alter_info.
3282
To compare the new and old table definitions, we need to "prepare"
3283
the new definition - transform it from parser output to a format
3284
that describes the final table layout (all column defaults are
3285
initialized, duplicate columns are removed). This is done by
3286
mysql_prepare_create_table. Unfortunately,
3287
mysql_prepare_create_table performs its transformations
3288
"in-place", that is, modifies the argument. Since we would
3289
like to keep compare_tables() idempotent (not altering any
3290
of the arguments) we create a copy of alter_info here and
3291
pass it to mysql_prepare_create_table, then use the result
3292
to evaluate possibility of fast ALTER Table, and then
3295
Alter_info tmp_alter_info(*alter_info, session->mem_root);
3296
Session *session= table->in_use;
3297
uint32_t db_options= 0; /* not used */
3298
/* Create the prepared information. */
3299
if (mysql_prepare_create_table(session, create_info,
3301
(table->s->tmp_table != NO_TMP_TABLE),
3304
&ha_alter_info->key_info_buffer,
3305
&ha_alter_info->key_count,
3306
/* select_field_count */ 0))
3308
/* Allocate result buffers. */
3309
if (! (ha_alter_info->index_drop_buffer=
3310
(uint*) session->alloc(sizeof(uint) * table->s->keys)) ||
3311
! (ha_alter_info->index_add_buffer=
3312
(uint*) session->alloc(sizeof(uint) *
3313
tmp_alter_info.key_list.elements)))
3317
First we setup ha_alter_flags based on what was detected
3320
setup_ha_alter_flags(alter_info, alter_flags);
3324
Some very basic checks. If number of fields changes, or the
3325
handler, we need to run full ALTER Table. In the future
3326
new fields can be added and old dropped without copy, but
3329
Test also that engine was not given during ALTER Table, or
3330
we are force to run regular alter table (copy).
3331
E.g. ALTER Table tbl_name ENGINE=MyISAM.
3333
For the following ones we also want to run regular alter table:
3334
ALTER Table tbl_name order_st BY ..
3335
ALTER Table tbl_name CONVERT TO CHARACTER SET ..
3337
At the moment we can't handle altering temporary tables without a copy.
3338
We also test if OPTIMIZE Table was given and was mapped to alter table.
3339
In that case we always do full copy.
3341
There was a bug prior to mysql-4.0.25. Number of null fields was
3342
calculated incorrectly. As a result frm and data files gets out of
3343
sync after fast alter table. There is no way to determine by which
3344
mysql version (in 4.0 and 4.1 branches) table was created, thus we
3345
disable fast alter table for all tables created by mysql versions
3346
prior to 5.0 branch.
3349
if (table->s->fields != alter_info->create_list.elements ||
3350
table->s->db_type() != create_info->db_type ||
3351
table->s->tmp_table ||
3352
create_info->used_fields & HA_CREATE_USED_ENGINE ||
3353
create_info->used_fields & HA_CREATE_USED_CHARSET ||
3354
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3355
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3356
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3358
!table->s->mysql_version ||
3359
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3361
*table_changes= IS_EQUAL_NO;
3363
Check what has changed and set alter_flags
3365
if (table->s->fields < alter_info->create_list.elements)
3366
*alter_flags|= HA_ADD_COLUMN;
3367
else if (table->s->fields > alter_info->create_list.elements)
3368
*alter_flags|= HA_DROP_COLUMN;
3369
if (create_info->db_type != table->s->db_type() ||
3370
create_info->used_fields & HA_CREATE_USED_ENGINE)
3371
*alter_flags|= HA_ALTER_STORAGE_ENGINE;
3372
if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3373
*alter_flags|= HA_CHANGE_CHARACTER_SET;
3374
if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3375
*alter_flags|= HA_SET_DEFAULT_CHARACTER_SET;
3376
if (alter_info->flags & ALTER_RECREATE)
3377
*alter_flags|= HA_RECREATE;
3378
/* TODO check for ADD/DROP FOREIGN KEY */
3379
if (alter_info->flags & ALTER_FOREIGN_KEY)
3380
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3381
if (!table->s->mysql_version ||
3382
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3383
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3386
Go through fields and check if the original ones are compatible
3389
for (f_ptr= table->field, new_field= new_field_it++;
3390
(new_field && (field= *f_ptr));
3391
f_ptr++, new_field= new_field_it++)
3393
/* Make sure we have at least the default charset in use. */
3394
if (!new_field->charset)
3395
new_field->charset= create_info->default_table_charset;
3397
/* Don't pack rows in old tables if the user has requested this. */
3398
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3399
(new_field->flags & BLOB_FLAG) ||
3400
(new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3401
create_info->table_options|= HA_OPTION_PACK_RECORD;
3403
/* Check how fields have been modified */
3404
if (alter_info->flags & ALTER_CHANGE_COLUMN)
3406
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
3407
if (!(table_changes_local= field->is_equal(new_field)))
3408
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3411
Check if the altered column is a stored virtual field.
3412
TODO: Mark such a column with an alter flag only if
3413
the expression functions are not equal.
3415
if (field->is_stored && field->vcol_info)
3416
*alter_flags|= HA_ALTER_STORED_VCOL;
3418
/* Check if field was renamed */
3419
field->flags&= ~FIELD_IS_RENAMED;
3420
if (my_strcasecmp(system_charset_info,
3422
new_field->field_name))
3424
field->flags|= FIELD_IS_RENAMED;
3425
*alter_flags|= HA_ALTER_COLUMN_NAME;
3428
*table_changes&= table_changes_local;
3429
if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3430
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3432
/* Check that NULL behavior is same for old and new fields */
3433
if ((new_field->flags & NOT_NULL_FLAG) !=
3434
(uint) (field->flags & NOT_NULL_FLAG))
3436
*table_changes= IS_EQUAL_NO;
3437
*alter_flags|= HA_ALTER_COLUMN_NULLABLE;
3441
/* Clear indexed marker */
3442
field->flags&= ~FIELD_IN_ADD_INDEX;
3446
Go through keys and check if the original ones are compatible
3450
KEY *table_key_end= table->key_info + table->s->keys;
3453
ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3456
Step through all keys of the old table and search matching new keys.
3458
ha_alter_info->index_drop_count= 0;
3459
ha_alter_info->index_add_count= 0;
3460
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3462
KEY_PART_INFO *table_part;
3463
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3464
KEY_PART_INFO *new_part;
3466
/* Search a new key with the same name. */
3467
for (new_key= ha_alter_info->key_info_buffer;
3468
new_key < new_key_end;
3471
if (! strcmp(table_key->name, new_key->name))
3474
if (new_key >= new_key_end)
3476
/* Key not found. Add the offset of the key to the drop buffer. */
3477
ha_alter_info->index_drop_buffer
3478
[ha_alter_info->index_drop_count++]=
3479
table_key - table->key_info;
3480
if (table_key->flags & HA_NOSAME)
3482
/* Unique key. Check for "PRIMARY". */
3483
if (! my_strcasecmp(system_charset_info,
3484
table_key->name, primary_key_name))
3485
*alter_flags|= HA_DROP_PK_INDEX;
3487
*alter_flags|= HA_DROP_UNIQUE_INDEX;
3490
*alter_flags|= HA_DROP_INDEX;
3491
*table_changes= IS_EQUAL_NO;
3495
/* Check that the key types are compatible between old and new tables. */
3496
if ((table_key->algorithm != new_key->algorithm) ||
3497
((table_key->flags & HA_KEYFLAG_MASK) !=
3498
(new_key->flags & HA_KEYFLAG_MASK)) ||
3499
(table_key->key_parts != new_key->key_parts))
3501
if (table_key->flags & HA_NOSAME)
3503
// Unique key. Check for "PRIMARY".
3504
if (! my_strcasecmp(system_charset_info,
3505
table_key->name, primary_key_name))
3506
*alter_flags|= HA_ALTER_PK_INDEX;
3508
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3511
*alter_flags|= HA_ALTER_INDEX;
3516
Check that the key parts remain compatible between the old and
3519
for (table_part= table_key->key_part, new_part= new_key->key_part;
3520
table_part < table_part_end;
3521
table_part++, new_part++)
3524
Key definition has changed if we are using a different field or
3525
if the used key part length is different. We know that the fields
3526
did not change. Comparing field numbers is sufficient.
3528
if ((table_part->length != new_part->length) ||
3529
(table_part->fieldnr - 1 != new_part->fieldnr))
3531
if (table_key->flags & HA_NOSAME)
3533
/* Unique key. Check for "PRIMARY" */
3534
if (! my_strcasecmp(system_charset_info,
3535
table_key->name, primary_key_name))
3536
*alter_flags|= HA_ALTER_PK_INDEX;
3538
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3541
*alter_flags|= HA_ALTER_INDEX;
3548
/* Key modified. Add the offset of the key to both buffers. */
3549
ha_alter_info->index_drop_buffer
3550
[ha_alter_info->index_drop_count++]=
3551
table_key - table->key_info;
3552
ha_alter_info->index_add_buffer
3553
[ha_alter_info->index_add_count++]=
3554
new_key - ha_alter_info->key_info_buffer;
3555
key_part= new_key->key_part;
3556
end= key_part + new_key->key_parts;
3557
for(; key_part != end; key_part++)
3559
/* Mark field to be part of new key */
3560
if ((field= table->field[key_part->fieldnr]))
3561
field->flags|= FIELD_IN_ADD_INDEX;
3563
*table_changes= IS_EQUAL_NO;
3565
/*end of for (; table_key < table_key_end;) */
3568
Step through all keys of the new table and find matching old keys.
3570
for (new_key= ha_alter_info->key_info_buffer;
3571
new_key < new_key_end;
3574
/* Search an old key with the same name. */
3575
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3577
if (! strcmp(table_key->name, new_key->name))
3580
if (table_key >= table_key_end)
3582
/* Key not found. Add the offset of the key to the add buffer. */
3583
ha_alter_info->index_add_buffer
3584
[ha_alter_info->index_add_count++]=
3585
new_key - ha_alter_info->key_info_buffer;
3586
key_part= new_key->key_part;
3587
end= key_part + new_key->key_parts;
3588
for(; key_part != end; key_part++)
3590
/* Mark field to be part of new key */
3591
if ((field= table->field[key_part->fieldnr]))
3592
field->flags|= FIELD_IN_ADD_INDEX;
3594
if (new_key->flags & HA_NOSAME)
3596
/* Unique key. Check for "PRIMARY" */
3597
if (! my_strcasecmp(system_charset_info,
3598
new_key->name, primary_key_name))
3599
*alter_flags|= HA_ADD_PK_INDEX;
3601
*alter_flags|= HA_ADD_UNIQUE_INDEX;
3604
*alter_flags|= HA_ADD_INDEX;
3605
*table_changes= IS_EQUAL_NO;
3614
Manages enabling/disabling of indexes for ALTER Table
3617
alter_table_manage_keys()
3619
indexes_were_disabled Whether the indexes of the from table
3621
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
3629
bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
3630
enum enum_enable_or_disable keys_onoff)
3633
switch (keys_onoff) {
3635
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3638
if (!indexes_were_disabled)
3640
/* fall-through: disabled indexes */
3642
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3645
if (error == HA_ERR_WRONG_COMMAND)
3647
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3648
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3649
table->s->table_name.str);
3652
table->file->print_error(error, MYF(0));
3657
int create_temporary_table(Session *session,
3661
HA_CREATE_INFO *create_info,
3662
Alter_info *alter_info,
3666
char index_file[FN_REFLEN], data_file[FN_REFLEN];
3667
handlerton *old_db_type, *new_db_type;
3668
old_db_type= table->s->db_type();
3669
new_db_type= create_info->db_type;
3671
Handling of symlinked tables:
3673
Create new data file and index file on the same disk as the
3674
old data and index files.
3676
Rename new data file over old data file and new index file over
3678
Symlinks are not changed.
3681
Create new data file and index file on the same disk as the
3682
old data and index files. Create also symlinks to point at
3685
At end, rename intermediate tables, and symlinks to intermediate
3686
table, to final table name.
3687
Remove old table and old symlinks
3689
If rename is made to another database:
3690
Create new tables in new database.
3692
Remove old table and symlinks.
3694
if (db_changed) // Ignore symlink if db changed
3696
if (create_info->index_file_name)
3698
/* Fix index_file_name to have 'tmp_name' as basename */
3699
my_stpcpy(index_file, tmp_name);
3700
create_info->index_file_name=fn_same(index_file,
3701
create_info->index_file_name,
3704
if (create_info->data_file_name)
3706
/* Fix data_file_name to have 'tmp_name' as basename */
3707
my_stpcpy(data_file, tmp_name);
3708
create_info->data_file_name=fn_same(data_file,
3709
create_info->data_file_name,
3714
create_info->data_file_name=create_info->index_file_name=0;
3717
Create a table with a temporary name.
3718
With create_info->frm_only == 1 this creates a .frm file only.
3719
We don't log the statement, it will be logged later.
3721
tmp_disable_binlog(session);
3722
error= mysql_create_table(session, new_db, tmp_name,
3723
create_info, alter_info, 1, 0);
3724
reenable_binlog(session);
3730
Create a temporary table that reflects what an alter table operation
3734
create_altered_table()
3735
session Thread handle
3736
table The original table
3737
create_info Information from the parsing phase about new
3739
alter_info Lists of fields, keys to be changed, added
3741
db_change Specifies if the table is moved to another database
3743
A temporary table with all changes
3746
The temporary table is created without storing it in any storage engine
3747
and is opened only to get the table struct and frm file reference.
3749
Table *create_altered_table(Session *session,
3752
HA_CREATE_INFO *create_info,
3753
Alter_info *alter_info,
3757
HA_CREATE_INFO altered_create_info(*create_info);
3758
Table *altered_table;
3760
char path[FN_REFLEN];
3762
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64,
3763
tmp_file_prefix, current_pid, session->thread_id);
3764
/* Safety fix for InnoDB */
3765
if (lower_case_table_names)
3766
my_casedn_str(files_charset_info, tmp_name);
3767
altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3768
altered_create_info.frm_only= 1;
3769
if ((error= create_temporary_table(session, table, new_db, tmp_name,
3770
&altered_create_info,
3771
alter_info, db_change)))
3776
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3778
altered_table= open_temporary_table(session, path, new_db, tmp_name, 1,
3780
return(altered_table);
3787
Perform a fast or on-line alter table
3790
mysql_fast_or_online_alter_table()
3791
session Thread handle
3792
table The original table
3793
altered_table A temporary table showing how we will change table
3794
create_info Information from the parsing phase about new
3796
alter_info Storage place for data used during different phases
3797
ha_alter_flags Bitmask that shows what will be changed
3798
keys_onoff Specifies if keys are to be enabled/disabled
3801
>0 An error occured during the on-line alter table operation
3802
-1 Error when re-opening table
3804
If mysql_alter_table does not need to copy the table, it is
3805
either a fast alter table where the storage engine does not
3806
need to know about the change, only the frm will change,
3807
or the storage engine supports performing the alter table
3808
operation directly, on-line without mysql having to copy
3811
int mysql_fast_or_online_alter_table(Session *session,
3813
Table *altered_table,
3814
HA_CREATE_INFO *create_info,
3815
HA_ALTER_INFO *alter_info,
3816
HA_ALTER_FLAGS *ha_alter_flags,
3817
enum enum_enable_or_disable keys_onoff)
3820
bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3826
Tell the handler to prepare for the online alter
3828
if ((error= table->file->alter_table_phase1(session,
3838
Tell the storage engine to perform the online alter table
3840
if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3841
we need to wrap the next call with a DDL lock.
3843
if ((error= table->file->alter_table_phase2(session,
3853
The final .frm file is already created as a temporary file
3854
and will be renamed to the original table name.
3856
pthread_mutex_lock(&LOCK_open);
3857
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3858
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3860
close_data_files_and_morph_locks(session,
3861
table->pos_in_table_list->db,
3862
table->pos_in_table_list->table_name);
3863
if (mysql_rename_table(NULL,
3864
altered_table->s->db.str,
3865
altered_table->s->table_name.str,
3867
table->s->table_name.str, FN_FROM_IS_TMP))
3870
pthread_mutex_unlock(&LOCK_open);
3873
broadcast_refresh();
3874
pthread_mutex_unlock(&LOCK_open);
3877
The ALTER Table is always in its own transaction.
3878
Commit must not be called while LOCK_open is locked. It could call
3879
wait_if_global_read_lock(), which could create a deadlock if called
3882
error= ha_autocommit_or_rollback(session, 0);
3884
if (ha_commit(session))
3890
pthread_mutex_lock(&LOCK_open);
3891
if (reopen_table(table))
3896
pthread_mutex_unlock(&LOCK_open);
3900
Tell the handler that the changed frm is on disk and table
3903
if ((error= t_table->file->alter_table_phase3(session, t_table)))
3909
We are going to reopen table down on the road, so we have to restore
3910
state of the Table object which we used for obtaining of handler
3911
object to make it suitable for reopening.
3913
assert(t_table == table);
3914
table->open_placeholder= 1;
3915
pthread_mutex_lock(&LOCK_open);
3916
close_handle_and_leave_table_as_lock(table);
3917
pthread_mutex_unlock(&LOCK_open);
3928
Prepare column and key definitions for CREATE TABLE in ALTER Table.
3930
This function transforms parse output of ALTER Table - lists of
3931
columns and keys to add, drop or modify into, essentially,
3932
CREATE TABLE definition - a list of columns and keys of the new
3933
table. While doing so, it also performs some (bug not all)
3936
This function is invoked when we know that we're going to
3937
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
3938
is not possible, perhaps because the ALTER statement contains
3939
instructions that require change in table data, not only in
3940
table definition or indexes.
3942
@param[in,out] session thread handle. Used as a memory pool
3943
and source of environment information.
3944
@param[in] table the source table, open and locked
3945
Used as an interface to the storage engine
3946
to acquire additional information about
3948
@param[in,out] create_info A blob with CREATE/ALTER Table
3950
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
3951
Originally create_info was used only in
3952
CREATE TABLE and alter_info only in ALTER Table.
3953
But since ALTER might end-up doing CREATE,
3954
this distinction is gone and we just carry
3955
around two structures.
3958
Fills various create_info members based on information retrieved
3959
from the storage engine.
3960
Sets create_info->varchar if the table has a VARCHAR column.
3961
Prepares alter_info->create_list and alter_info->key_list with
3962
columns and keys of the new table.
3963
@retval true error, out of memory or a semantical error in ALTER
3965
@retval false success
3969
mysql_prepare_alter_table(Session *session, Table *table,
3970
HA_CREATE_INFO *create_info,
3971
Alter_info *alter_info)
3973
/* New column definitions are added here */
3974
List<Create_field> new_create_list;
3975
/* New key definitions are added here */
3976
List<Key> new_key_list;
3977
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
3978
List_iterator<Create_field> def_it(alter_info->create_list);
3979
List_iterator<Alter_column> alter_it(alter_info->alter_list);
3980
List_iterator<Key> key_it(alter_info->key_list);
3981
List_iterator<Create_field> find_it(new_create_list);
3982
List_iterator<Create_field> field_it(new_create_list);
3983
List<Key_part_spec> key_parts;
3984
uint32_t db_create_options= (table->s->db_create_options
3985
& ~(HA_OPTION_PACK_RECORD));
3986
uint32_t used_fields= create_info->used_fields;
3987
KEY *key_info=table->key_info;
3991
create_info->varchar= false;
3992
/* Let new create options override the old ones */
3993
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
3994
create_info->min_rows= table->s->min_rows;
3995
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
3996
create_info->max_rows= table->s->max_rows;
3997
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
3998
create_info->avg_row_length= table->s->avg_row_length;
3999
if (!(used_fields & HA_CREATE_USED_BLOCK_SIZE))
4000
create_info->block_size= table->s->block_size;
4001
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
4002
create_info->default_table_charset= table->s->table_charset;
4003
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
4005
/* Table has an autoincrement, copy value to new table */
4006
table->file->info(HA_STATUS_AUTO);
4007
create_info->auto_increment_value= table->file->stats.auto_increment_value;
4009
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
4010
create_info->key_block_size= table->s->key_block_size;
4012
restore_record(table, s->default_values); // Empty record for DEFAULT
4016
First collect all fields from table which isn't in drop_list
4018
Field **f_ptr,*field;
4019
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
4021
/* Check if field should be dropped */
4024
while ((drop=drop_it++))
4026
if (drop->type == Alter_drop::COLUMN &&
4027
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
4029
/* Reset auto_increment value if it was dropped */
4030
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
4031
!(used_fields & HA_CREATE_USED_AUTO))
4033
create_info->auto_increment_value=0;
4034
create_info->used_fields|=HA_CREATE_USED_AUTO;
4044
/* Check if field is changed */
4046
while ((def=def_it++))
4049
!my_strcasecmp(system_charset_info,field->field_name, def->change))
4053
{ // Field is changed
4055
if (field->is_stored != def->is_stored)
4057
my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN,
4059
"Changing the STORED status");
4064
new_create_list.push_back(def);
4071
This field was not dropped and not changed, add it to the list
4074
def= new Create_field(field, field);
4075
new_create_list.push_back(def);
4076
alter_it.rewind(); // Change default if ALTER
4077
Alter_column *alter;
4078
while ((alter=alter_it++))
4080
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
4085
if (def->sql_type == DRIZZLE_TYPE_BLOB)
4087
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
4090
if ((def->def=alter->def)) // Use new default
4091
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
4093
def->flags|= NO_DEFAULT_VALUE_FLAG;
4099
while ((def=def_it++)) // Add new columns
4101
if (def->change && ! def->field)
4103
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
4107
Check that the DATE/DATETIME not null field we are going to add is
4108
either has a default value or the '0000-00-00' is allowed by the
4110
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
4111
flag to allow ALTER Table only if the table to be altered is empty.
4113
if ((def->sql_type == DRIZZLE_TYPE_NEWDATE ||
4114
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
4115
!alter_info->datetime_field &&
4116
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
4117
session->variables.sql_mode & MODE_NO_ZERO_DATE)
4119
alter_info->datetime_field= def;
4120
alter_info->error_if_not_empty= true;
4123
new_create_list.push_back(def);
4124
else if (def->after == first_keyword)
4125
new_create_list.push_front(def);
4130
while ((find=find_it++)) // Add new columns
4132
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
4137
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
4140
find_it.after(def); // Put element after this
4142
XXX: hack for Bug#28427.
4143
If column order has changed, force OFFLINE ALTER Table
4144
without querying engine capabilities. If we ever have an
4145
engine that supports online ALTER Table CHANGE COLUMN
4146
<name> AFTER <name1> (Falcon?), this fix will effectively
4147
disable the capability.
4148
TODO: detect the situation in compare_tables, behave based
4149
on engine capabilities.
4151
if (alter_info->build_method == HA_BUILD_ONLINE)
4153
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4156
alter_info->build_method= HA_BUILD_OFFLINE;
4159
if (alter_info->alter_list.elements)
4161
my_error(ER_BAD_FIELD_ERROR, MYF(0),
4162
alter_info->alter_list.head()->name, table->s->table_name.str);
4165
if (!new_create_list.elements)
4167
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
4173
Collect all keys which isn't in drop list. Add only those
4174
for which some fields exists.
4177
for (uint32_t i=0 ; i < table->s->keys ; i++,key_info++)
4179
char *key_name= key_info->name;
4182
while ((drop=drop_it++))
4184
if (drop->type == Alter_drop::KEY &&
4185
!my_strcasecmp(system_charset_info,key_name, drop->name))
4194
KEY_PART_INFO *key_part= key_info->key_part;
4196
for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
4198
if (!key_part->field)
4199
continue; // Wrong field (from UNIREG)
4200
const char *key_part_name=key_part->field->field_name;
4201
Create_field *cfield;
4203
while ((cfield=field_it++))
4207
if (!my_strcasecmp(system_charset_info, key_part_name,
4211
else if (!my_strcasecmp(system_charset_info,
4212
key_part_name, cfield->field_name))
4216
continue; // Field is removed
4217
uint32_t key_part_length=key_part->length;
4218
if (cfield->field) // Not new field
4221
If the field can't have only a part used in a key according to its
4222
new type, or should not be used partially according to its
4223
previous type, or the field length is less than the key part
4224
length, unset the key part length.
4226
We also unset the key part length if it is the same as the
4227
old field's length, so the whole new field will be used.
4229
BLOBs may have cfield->length == 0, which is why we test it before
4230
checking whether cfield->length < key_part_length (in chars).
4232
if (!Field::type_can_have_key_part(cfield->field->type()) ||
4233
!Field::type_can_have_key_part(cfield->sql_type) ||
4234
(cfield->field->field_length == key_part_length &&
4235
!f_is_blob(key_part->key_type)) ||
4236
(cfield->length && (cfield->length < key_part_length /
4237
key_part->field->charset()->mbmaxlen)))
4238
key_part_length= 0; // Use whole field
4240
key_part_length /= key_part->field->charset()->mbmaxlen;
4241
key_parts.push_back(new Key_part_spec(cfield->field_name,
4242
strlen(cfield->field_name),
4245
if (key_parts.elements)
4247
KEY_CREATE_INFO key_create_info;
4249
enum Key::Keytype key_type;
4250
memset(&key_create_info, 0, sizeof(key_create_info));
4252
key_create_info.algorithm= key_info->algorithm;
4253
if (key_info->flags & HA_USES_BLOCK_SIZE)
4254
key_create_info.block_size= key_info->block_size;
4255
if (key_info->flags & HA_USES_COMMENT)
4256
key_create_info.comment= key_info->comment;
4258
if (key_info->flags & HA_NOSAME)
4260
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
4261
key_type= Key::PRIMARY;
4263
key_type= Key::UNIQUE;
4266
key_type= Key::MULTIPLE;
4268
key= new Key(key_type, key_name, strlen(key_name),
4270
test(key_info->flags & HA_GENERATED_KEY),
4272
new_key_list.push_back(key);
4277
while ((key=key_it++)) // Add new keys
4279
if (key->type == Key::FOREIGN_KEY &&
4280
((Foreign_key *)key)->validate(new_create_list))
4282
if (key->type != Key::FOREIGN_KEY)
4283
new_key_list.push_back(key);
4284
if (key->name.str &&
4285
!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
4287
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
4293
if (alter_info->drop_list.elements)
4295
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4296
alter_info->drop_list.head()->name);
4299
if (alter_info->alter_list.elements)
4301
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4302
alter_info->alter_list.head()->name);
4306
if (!create_info->comment.str)
4308
create_info->comment.str= table->s->comment.str;
4309
create_info->comment.length= table->s->comment.length;
4312
table->file->update_create_info(create_info);
4313
if ((create_info->table_options &
4314
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
4315
(used_fields & HA_CREATE_USED_PACK_KEYS))
4316
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
4317
if (create_info->table_options &
4318
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
4319
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
4320
if (create_info->table_options &
4321
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
4322
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
4323
HA_OPTION_NO_DELAY_KEY_WRITE);
4324
create_info->table_options|= db_create_options;
4326
if (table->s->tmp_table)
4327
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
4330
alter_info->create_list.swap(new_create_list);
4331
alter_info->key_list.swap(new_key_list);
4342
session Thread handle
4343
new_db If there is a RENAME clause
4344
new_name If there is a RENAME clause
4345
create_info Information from the parsing phase about new
4347
table_list The table to change.
4348
alter_info Lists of fields, keys to be changed, added
4350
order_num How many order_st BY fields has been specified.
4351
order List of fields to order_st BY.
4352
ignore Whether we have ALTER IGNORE Table
4355
This is a veery long function and is everything but the kitchen sink :)
4356
It is used to alter a table and not only by ALTER Table but also
4357
CREATE|DROP INDEX are mapped on this function.
4359
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
4360
or both, then this function short cuts its operation by renaming
4361
the table and/or enabling/disabling the keys. In this case, the FRM is
4362
not changed, directly by mysql_alter_table. However, if there is a
4363
RENAME + change of a field, or an index, the short cut is not used.
4364
See how `create_list` is used to generate the new FRM regarding the
4365
structure of the fields. The same is done for the indices of the table.
4367
Important is the fact, that this function tries to do as little work as
4368
possible, by finding out whether a intermediate table is needed to copy
4369
data into and when finishing the altering to use it as the original table.
4370
For this reason the function compare_tables() is called, which decides
4371
based on all kind of data how similar are the new and the original
4379
bool mysql_alter_table(Session *session,char *new_db, char *new_name,
4380
HA_CREATE_INFO *create_info,
4381
TableList *table_list,
4382
Alter_info *alter_info,
4383
uint32_t order_num, order_st *order, bool ignore)
4385
Table *table, *new_table=0, *name_lock= 0;;
4387
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
4388
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
4389
char path[FN_REFLEN];
4390
ha_rows copied= 0,deleted= 0;
4391
handlerton *old_db_type, *new_db_type, *save_old_db_type;
4392
legacy_db_type table_type;
4394
if (table_list && table_list->schema_table)
4396
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.str);
4401
Assign variables table_name, new_name, db, new_db, path
4402
to simplify further comparisons: we want to see if it's a RENAME
4403
later just by comparing the pointers, avoiding the need for strcmp.
4405
session->set_proc_info("init");
4406
table_name=table_list->table_name;
4407
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
4409
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
4411
build_table_filename(path, sizeof(path), db, table_name, "", 0);
4413
mysql_ha_rm_tables(session, table_list, false);
4415
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
4416
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
4417
/* Conditionally writes to binlog. */
4418
return(mysql_discard_or_import_tablespace(session,table_list,
4419
alter_info->tablespace_op));
4420
char* pos= new_name_buff;
4421
char* pos_end= pos+strlen(new_name_buff)-1;
4422
pos= my_stpncpy(new_name_buff, mysql_data_home, pos_end-pos);
4423
pos= my_stpncpy(new_name_buff, "/", pos_end-pos);
4424
pos= my_stpncpy(new_name_buff, db, pos_end-pos);
4425
pos= my_stpncpy(new_name_buff, "/", pos_end-pos);
4426
pos= my_stpncpy(new_name_buff, table_name, pos_end-pos);
4427
pos= my_stpncpy(new_name_buff, reg_ext, pos_end-pos);
4429
(void) unpack_filename(new_name_buff, new_name_buff);
4431
If this is just a rename of a view, short cut to the
4432
following scenario: 1) lock LOCK_open 2) do a RENAME
4433
2) unlock LOCK_open.
4434
This is a copy-paste added to make sure
4435
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
4436
as an independent branch in mysql_execute_command. The need
4437
for a copy-paste arose because the main code flow of ALTER Table
4438
... RENAME tries to use open_ltable, which does not work for views
4439
(open_ltable was never modified to merge table lists of child tables
4440
into the main table list, like open_tables does).
4441
This code is wrong and will be removed, please do not copy.
4443
(void)mysql_frm_type(session, new_name_buff, &table_type);
4445
if (!(table= open_n_lock_single_table(session, table_list, TL_WRITE_ALLOW_READ)))
4447
table->use_all_columns();
4449
/* Check that we are not trying to rename to an existing table */
4452
my_stpcpy(new_name_buff,new_name);
4453
my_stpcpy(new_alias= new_alias_buff, new_name);
4454
if (lower_case_table_names)
4456
if (lower_case_table_names != 2)
4458
my_casedn_str(files_charset_info, new_name_buff);
4459
new_alias= new_name; // Create lower case table name
4461
my_casedn_str(files_charset_info, new_name);
4464
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
4467
Source and destination table names are equal: make later check
4470
new_alias= new_name= table_name;
4474
if (table->s->tmp_table != NO_TMP_TABLE)
4476
if (find_temporary_table(session,new_db,new_name_buff))
4478
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
4484
if (lock_table_name_if_not_cached(session, new_db, new_name, &name_lock))
4488
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4492
build_table_filename(new_name_buff, sizeof(new_name_buff),
4493
new_db, new_name_buff, reg_ext, 0);
4494
if (!access(new_name_buff, F_OK))
4496
/* Table will be closed in do_command() */
4497
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4505
new_alias= (lower_case_table_names == 2) ? alias : table_name;
4506
new_name= table_name;
4509
old_db_type= table->s->db_type();
4510
if (!create_info->db_type)
4512
create_info->db_type= old_db_type;
4515
if (check_engine(session, new_name, create_info))
4517
new_db_type= create_info->db_type;
4519
if (new_db_type != old_db_type &&
4520
!table->file->can_switch_engines())
4523
my_error(ER_ROW_IS_REFERENCED, MYF(0));
4527
if (create_info->row_type == ROW_TYPE_NOT_USED)
4528
create_info->row_type= table->s->row_type;
4530
if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
4531
ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
4533
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
4537
session->set_proc_info("setup");
4538
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
4539
!table->s->tmp_table) // no need to touch frm
4541
switch (alter_info->keys_onoff) {
4546
wait_while_table_is_used() ensures that table being altered is
4547
opened only by this thread and that Table::TABLE_SHARE::version
4548
of Table object corresponding to this table is 0.
4549
The latter guarantees that no DML statement will open this table
4550
until ALTER Table finishes (i.e. until close_thread_tables())
4551
while the fact that the table is still open gives us protection
4552
from concurrent DDL statements.
4554
pthread_mutex_lock(&LOCK_open);
4555
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4556
pthread_mutex_unlock(&LOCK_open);
4557
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4558
/* COND_refresh will be signaled in close_thread_tables() */
4561
pthread_mutex_lock(&LOCK_open);
4562
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4563
pthread_mutex_unlock(&LOCK_open);
4564
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4565
/* COND_refresh will be signaled in close_thread_tables() */
4572
if (error == HA_ERR_WRONG_COMMAND)
4575
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4576
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4580
pthread_mutex_lock(&LOCK_open);
4582
Unlike to the above case close_cached_table() below will remove ALL
4583
instances of Table from table cache (it will also remove table lock
4584
held by this thread). So to make actual table renaming and writing
4585
to binlog atomic we have to put them into the same critical section
4586
protected by LOCK_open mutex. This also removes gap for races between
4587
access() and mysql_rename_table() calls.
4590
if (!error && (new_name != table_name || new_db != db))
4592
session->set_proc_info("rename");
4594
Then do a 'simple' rename of the table. First we need to close all
4595
instances of 'source' table.
4597
close_cached_table(session, table);
4599
Then, we want check once again that target table does not exist.
4600
Actually the order of these two steps does not matter since
4601
earlier we took name-lock on the target table, so we do them
4602
in this particular order only to be consistent with 5.0, in which
4603
we don't take this name-lock and where this order really matters.
4604
TODO: Investigate if we need this access() check at all.
4606
if (!access(new_name_buff,F_OK))
4608
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
4613
*fn_ext(new_name)=0;
4614
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
4618
mysql_rename_table(old_db_type, new_db, new_alias, db,
4625
if (error == HA_ERR_WRONG_COMMAND)
4628
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4629
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4635
write_bin_log(session, true, session->query, session->query_length);
4640
table->file->print_error(error, MYF(0));
2176
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2177
session->unlink_open_table(name_lock);
2183
if (is_if_not_exists)
4644
unlink_open_table(session, name_lock, false);
4645
pthread_mutex_unlock(&LOCK_open);
4646
table_list->table= NULL; // For query cache
4650
/* We have to do full alter table. */
4653
If the old table had partitions and we are doing ALTER Table ...
4654
engine= <new_engine>, the new table must preserve the original
4655
partitioning. That means that the new engine is still the
4656
partitioning engine, not the engine specified in the parser.
4657
This is discovered in prep_alter_part_table, which in such case
4658
updates create_info->db_type.
4659
Now we need to update the stack copy of create_info->db_type,
4660
as otherwise we won't be able to correctly move the files of the
4661
temporary table to the result table files.
4663
new_db_type= create_info->db_type;
4665
if (mysql_prepare_alter_table(session, table, create_info, alter_info))
4668
set_table_default_charset(session, create_info, db);
4671
if (session->variables.old_alter_table
4672
|| (table->s->db_type() != create_info->db_type)
4675
if (alter_info->build_method == HA_BUILD_ONLINE)
4677
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4680
alter_info->build_method= HA_BUILD_OFFLINE;
4683
if (alter_info->build_method != HA_BUILD_OFFLINE)
4685
Table *altered_table= 0;
4686
HA_ALTER_INFO ha_alter_info;
4687
HA_ALTER_FLAGS ha_alter_flags;
4688
uint32_t table_changes= IS_EQUAL_YES;
4689
bool need_copy_table= true;
4690
/* Check how much the tables differ. */
4691
if (compare_tables(session, table, alter_info,
4692
create_info, order_num,
4701
Check if storage engine supports altering the table
4707
If table is not renamed, changed database and
4708
some change was detected then check if engine
4709
can do the change on-line
4711
if (new_name == table_name && new_db == db &&
4712
ha_alter_flags.is_set())
4714
Alter_info tmp_alter_info(*alter_info, session->mem_root);
4718
check if table can be altered on-line
4720
if (!(altered_table= create_altered_table(session,
4725
!strcmp(db, new_db))))
4728
switch (table->file->check_if_supported_alter(altered_table,
4732
case HA_ALTER_SUPPORTED_WAIT_LOCK:
4733
case HA_ALTER_SUPPORTED_NO_LOCK:
4735
@todo: Currently we always acquire an exclusive name
4736
lock on the table metadata when performing fast or online
4737
ALTER Table. In future we may consider this unnecessary,
4738
and narrow the scope of the exclusive name lock to only
4739
cover manipulation with .frms. Storage engine API
4740
call check_if_supported_alter has provision for this
4743
need_copy_table= false;
4745
case HA_ALTER_NOT_SUPPORTED:
4746
if (alter_info->build_method == HA_BUILD_ONLINE)
4748
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4749
close_temporary_table(session, altered_table, 1, 1);
4752
need_copy_table= true;
4754
case HA_ALTER_ERROR:
4756
close_temporary_table(session, altered_table, 1, 1);
4761
/* TODO need to check if changes can be handled as fast ALTER Table */
4763
need_copy_table= true;
4765
if (!need_copy_table)
4767
error= mysql_fast_or_online_alter_table(session,
4773
alter_info->keys_onoff);
4776
mysql_unlock_tables(session, session->lock);
4779
close_temporary_table(session, altered_table, 1, 1);
4785
goto err_with_placeholders;
4792
pthread_mutex_lock(&LOCK_open);
4798
close_temporary_table(session, altered_table, 1, 1);
4801
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, tmp_file_prefix,
4802
current_pid, session->thread_id);
4803
/* Safety fix for innodb */
4804
if (lower_case_table_names)
4805
my_casedn_str(files_charset_info, tmp_name);
4808
/* Create a temporary table with the new format */
4809
if ((error= create_temporary_table(session, table, new_db, tmp_name,
4810
create_info, alter_info,
4811
!strcmp(db, new_db))))
4816
/* Open the table so we need to copy the data to it. */
4817
if (table->s->tmp_table)
4820
memset(&tbl, 0, sizeof(tbl));
4822
tbl.table_name= tbl.alias= tmp_name;
4823
/* Table is in session->temporary_tables */
4824
new_table= open_table(session, &tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
4828
char path[FN_REFLEN];
4829
/* table is a normal table: Create temporary table in same directory */
4830
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
4832
/* Open our intermediate table */
4833
new_table=open_temporary_table(session, path, new_db, tmp_name, 0, OTM_OPEN);
4838
/* Copy the data if necessary. */
4839
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
4840
session->cuted_fields=0L;
4841
session->set_proc_info("copy to tmp table");
4844
We do not copy data for MERGE tables. Only the children have data.
4845
MERGE tables have HA_NO_COPY_ON_ALTER set.
4847
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
4849
/* We don't want update TIMESTAMP fields during ALTER Table. */
4850
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
4851
new_table->next_number_field=new_table->found_next_number_field;
4852
error= copy_data_between_tables(table, new_table,
4853
alter_info->create_list, ignore,
4854
order_num, order, &copied, &deleted,
4855
alter_info->keys_onoff,
4856
alter_info->error_if_not_empty);
4860
pthread_mutex_lock(&LOCK_open);
4861
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4862
pthread_mutex_unlock(&LOCK_open);
4863
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
4864
alter_info->keys_onoff);
4865
error= ha_autocommit_or_rollback(session, 0);
4866
if (end_active_trans(session))
4869
session->count_cuted_fields= CHECK_FIELD_IGNORE;
4871
if (table->s->tmp_table != NO_TMP_TABLE)
4873
/* We changed a temporary table */
4876
/* Close lock if this is a transactional table */
4879
mysql_unlock_tables(session, session->lock);
4882
/* Remove link to old table and rename the new one */
4883
close_temporary_table(session, table, 1, 1);
4884
/* Should pass the 'new_name' as we store table name in the cache */
4885
if (rename_temporary_table(session, new_table, new_db, new_name))
4887
/* We don't replicate alter table statement on temporary tables */
4888
if (!session->current_stmt_binlog_row_based)
4889
write_bin_log(session, true, session->query, session->query_length);
4896
Close the intermediate table that will be the new table.
4897
Note that MERGE tables do not have their children attached here.
4899
intern_close_table(new_table);
4902
pthread_mutex_lock(&LOCK_open);
4905
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4906
pthread_mutex_unlock(&LOCK_open);
4911
Data is copied. Now we:
4912
1) Wait until all other threads close old version of table.
4913
2) Close instances of table open by this thread and replace them
4914
with exclusive name-locks.
4915
3) Rename the old table to a temp name, rename the new one to the
4917
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
4918
we reopen new version of table.
4919
5) Write statement to the binary log.
4920
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
4921
remove name-locks from list of open tables and table cache.
4922
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
4923
call to remove name-locks from table cache and list of open table.
4926
session->set_proc_info("rename result table");
4927
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, tmp_file_prefix,
4928
current_pid, session->thread_id);
4929
if (lower_case_table_names)
4930
my_casedn_str(files_charset_info, old_name);
4932
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
4933
close_data_files_and_morph_locks(session, db, table_name);
4936
save_old_db_type= old_db_type;
4939
This leads to the storage engine (SE) not being notified for renames in
4940
mysql_rename_table(), because we just juggle with the FRM and nothing
4941
more. If we have an intermediate table, then we notify the SE that
4942
it should become the actual table. Later, we will recycle the old table.
4943
However, in case of ALTER Table RENAME there might be no intermediate
4944
table. This is when the old and new tables are compatible, according to
4945
compare_table(). Then, we need one additional call to
4946
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
4947
actual rename in the SE and the FRM is not touched. Note that, if the
4948
table is renamed and the SE is also changed, then an intermediate table
4949
is created and the additional call will not take place.
4951
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
4955
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4957
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
4958
new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
4960
/* Try to get everything back. */
4962
quick_rm_table(new_db_type,new_db,new_alias, 0);
4963
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4964
mysql_rename_table(old_db_type, db, old_name, db, alias,
4970
/* This shouldn't happen. But let us play it safe. */
4971
goto err_with_placeholders;
4974
quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
4977
if (session->locked_tables && new_name == table_name && new_db == db)
4979
session->in_lock_tables= 1;
4980
error= reopen_tables(session, 1, 1);
4981
session->in_lock_tables= 0;
4983
goto err_with_placeholders;
4985
pthread_mutex_unlock(&LOCK_open);
4987
session->set_proc_info("end");
4989
assert(!(mysql_bin_log.is_open() &&
4990
session->current_stmt_binlog_row_based &&
4991
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
4992
write_bin_log(session, true, session->query, session->query_length);
4994
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
4997
For the alter table to be properly flushed to the logs, we
4998
have to open the new table. If not, we get a problem on server
4999
shutdown. But we do not need to attach MERGE children.
5001
char path[FN_REFLEN];
5003
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
5004
t_table= open_temporary_table(session, path, new_db, tmp_name, false, OTM_OPEN);
5007
intern_close_table(t_table);
5011
sql_print_warning(_("Could not open table %s.%s after rename\n"),
5013
ha_flush_logs(old_db_type);
5015
table_list->table=0; // For query cache
5017
if (session->locked_tables && (new_name != table_name || new_db != db))
5020
If are we under LOCK TABLES and did ALTER Table with RENAME we need
5021
to remove placeholders for the old table and for the target table
5022
from the list of open tables and table cache. If we are not under
5023
LOCK TABLES we can rely on close_thread_tables() doing this job.
5025
pthread_mutex_lock(&LOCK_open);
5026
unlink_open_table(session, table, false);
5027
unlink_open_table(session, name_lock, false);
5028
pthread_mutex_unlock(&LOCK_open);
5032
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
5033
(ulong) (copied + deleted), (ulong) deleted,
5034
(ulong) session->cuted_fields);
5035
my_ok(session, copied + deleted, 0L, tmp_name);
5036
session->some_tables_deleted=0;
5042
/* close_temporary_table() frees the new_table pointer. */
5043
close_temporary_table(session, new_table, 1, 1);
5046
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
5050
No default value was provided for a DATE/DATETIME field, the
5051
current sql_mode doesn't allow the '0000-00-00' value and
5052
the table to be altered isn't empty.
5055
if (alter_info->error_if_not_empty && session->row_count)
5057
const char *f_val= 0;
5058
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
5059
switch (alter_info->datetime_field->sql_type)
5061
case DRIZZLE_TYPE_NEWDATE:
5062
f_val= "0000-00-00";
5063
t_type= DRIZZLE_TIMESTAMP_DATE;
5065
case DRIZZLE_TYPE_DATETIME:
5066
f_val= "0000-00-00 00:00:00";
5067
t_type= DRIZZLE_TIMESTAMP_DATETIME;
5070
/* Shouldn't get here. */
5073
bool save_abort_on_warning= session->abort_on_warning;
5074
session->abort_on_warning= true;
5075
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5076
f_val, strlength(f_val), t_type,
5077
alter_info->datetime_field->field_name);
5078
session->abort_on_warning= save_abort_on_warning;
5082
pthread_mutex_lock(&LOCK_open);
5083
unlink_open_table(session, name_lock, false);
5084
pthread_mutex_unlock(&LOCK_open);
5088
err_with_placeholders:
5090
An error happened while we were holding exclusive name-lock on table
5091
being altered. To be safe under LOCK TABLES we should remove placeholders
5092
from list of open tables list and table cache.
5094
unlink_open_table(session, table, false);
5096
unlink_open_table(session, name_lock, false);
5097
pthread_mutex_unlock(&LOCK_open);
5100
/* mysql_alter_table */
5103
copy_data_between_tables(Table *from,Table *to,
5104
List<Create_field> &create,
5106
uint32_t order_num, order_st *order,
5109
enum enum_enable_or_disable keys_onoff,
5110
bool error_if_not_empty)
5113
Copy_field *copy,*copy_end;
5114
ulong found_count,delete_count;
5115
Session *session= current_session;
5117
SORT_FIELD *sortorder;
5121
List<Item> all_fields;
5122
ha_rows examined_rows;
5123
bool auto_increment_field_copied= 0;
5124
ulong save_sql_mode;
5125
uint64_t prev_insert_id;
5128
Turn off recovery logging since rollback of an alter table is to
5129
delete the new table so there is no need to log the changes to it.
5131
This needs to be done before external_lock
5133
error= ha_enable_transaction(session, false);
5137
if (!(copy= new Copy_field[to->s->fields]))
5138
return(-1); /* purecov: inspected */
5140
if (to->file->ha_external_lock(session, F_WRLCK))
5143
/* We need external lock before we can disable/enable keys */
5144
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
5146
/* We can abort alter table for any table type */
5147
session->abort_on_warning= !ignore;
5149
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5150
to->file->ha_start_bulk_insert(from->file->stats.records);
5152
save_sql_mode= session->variables.sql_mode;
5154
List_iterator<Create_field> it(create);
5157
for (Field **ptr=to->field ; *ptr ; ptr++)
5162
if (*ptr == to->next_number_field)
5163
auto_increment_field_copied= true;
5165
(copy_end++)->set(*ptr,def->field,0);
5170
found_count=delete_count=0;
5174
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
2185
5176
char warn_buff[DRIZZLE_ERRMSG_SIZE];
2186
snprintf(warn_buff, sizeof(warn_buff),
2187
ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
2188
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2189
ER_TABLE_EXISTS_ERROR, warn_buff);
2193
my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
5177
snprintf(warn_buff, sizeof(warn_buff),
5178
_("order_st BY ignored because there is a user-defined clustered "
5179
"index in the table '%-.192s'"),
5180
from->s->table_name.str);
5181
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
5186
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
5187
MYF(MY_FAE | MY_ZEROFILL));
5188
memset(&tables, 0, sizeof(tables));
5190
tables.alias= tables.table_name= from->s->table_name.str;
5191
tables.db= from->s->db.str;
5194
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
5195
setup_order(session, session->lex->select_lex.ref_pointer_array,
5196
&tables, fields, all_fields, order) ||
5197
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
5198
(from->sort.found_records= filesort(session, from, sortorder, length,
5199
(SQL_SELECT *) 0, HA_POS_ERROR,
5200
1, &examined_rows)) ==
5206
/* Tell handler that we have values for all columns in the to table */
5207
to->use_all_columns();
5208
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
5210
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
5211
session->row_count= 0;
5212
restore_record(to, s->default_values); // Create empty record
5213
while (!(error=info.read_record(&info)))
5215
if (session->killed)
5217
session->send_kill_message();
5221
session->row_count++;
5222
/* Return error if source table isn't empty. */
5223
if (error_if_not_empty)
5228
if (to->next_number_field)
5230
if (auto_increment_field_copied)
5231
to->auto_increment_field_not_null= true;
5233
to->next_number_field->reset();
5236
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
5238
copy_ptr->do_copy(copy_ptr);
5240
prev_insert_id= to->file->next_insert_id;
5241
update_virtual_fields_marked_for_write(to, false);
5242
error=to->file->ha_write_row(to->record[0]);
5243
to->auto_increment_field_not_null= false;
5247
to->file->is_fatal_error(error, HA_CHECK_DUP))
5249
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
5251
uint32_t key_nr= to->file->get_dup_key(error);
5252
if ((int) key_nr >= 0)
5254
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
5256
(to->key_info[0].key_part[0].field->flags &
5257
AUTO_INCREMENT_FLAG))
5258
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
5259
to->file->print_keydup_error(key_nr, err_msg);
5264
to->file->print_error(error,MYF(0));
5267
to->file->restore_auto_increment(prev_insert_id);
5273
end_read_record(&info);
5274
free_io_cache(from);
5275
delete [] copy; // This is never 0
5277
if (to->file->ha_end_bulk_insert() && error <= 0)
5279
to->file->print_error(my_errno,MYF(0));
5282
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
5284
if (ha_enable_transaction(session, true))
5291
Ensure that the new table is saved properly to disk so that we
5294
if (ha_autocommit_or_rollback(session, 0))
5296
if (end_active_trans(session))
5300
session->variables.sql_mode= save_sql_mode;
5301
session->abort_on_warning= 0;
5302
free_io_cache(from);
5303
*copied= found_count;
5304
*deleted=delete_count;
5305
to->file->ha_release_auto_increment();
5306
if (to->file->ha_external_lock(session,F_UNLCK))
5308
return(error > 0 ? -1 : 0);
5313
Recreates tables by calling mysql_alter_table().
5316
mysql_recreate_table()
5317
session Thread handler
5318
tables Tables to recreate
5321
Like mysql_alter_table().
5323
bool mysql_recreate_table(Session *session, TableList *table_list)
5325
HA_CREATE_INFO create_info;
5326
Alter_info alter_info;
5328
assert(!table_list->next_global);
5330
table_list->table has been closed and freed. Do not reference
5331
uninitialized data. open_tables() could fail.
5333
table_list->table= NULL;
5335
memset(&create_info, 0, sizeof(create_info));
5336
create_info.row_type=ROW_TYPE_NOT_USED;
5337
create_info.default_table_charset=default_charset_info;
5338
/* Force alter table to recreate table */
5339
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
5340
return(mysql_alter_table(session, NULL, NULL, &create_info,
5341
table_list, &alter_info, 0,
5342
(order_st *) 0, 0));
5346
bool mysql_checksum_table(Session *session, TableList *tables,
5347
HA_CHECK_OPT *check_opt)
5350
List<Item> field_list;
5352
Protocol *protocol= session->protocol;
5354
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
5355
item->maybe_null= 1;
5356
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
5357
MY_INT64_NUM_DECIMAL_DIGITS));
5358
item->maybe_null= 1;
5359
if (protocol->send_fields(&field_list,
5360
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
5363
/* Open one table after the other to keep lock time as short as possible. */
5364
for (table= tables; table; table= table->next_local)
5366
char table_name[NAME_LEN*2+2];
5369
strxmov(table_name, table->db ,".", table->table_name, NULL);
5371
t= table->table= open_n_lock_single_table(session, table, TL_READ);
5372
session->clear_error(); // these errors shouldn't get client
5374
protocol->prepare_for_resend();
5375
protocol->store(table_name, system_charset_info);
5379
/* Table didn't exist */
5380
protocol->store_null();
5381
session->clear_error();
5385
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
5386
!(check_opt->flags & T_EXTEND))
5387
protocol->store((uint64_t)t->file->checksum());
5388
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
5389
(check_opt->flags & T_QUICK))
5390
protocol->store_null();
5393
/* calculating table's checksum */
5395
unsigned char null_mask=256 - (1 << t->s->last_null_bit_pos);
5397
t->use_all_columns();
5399
if (t->file->ha_rnd_init(1))
5400
protocol->store_null();
5405
ha_checksum row_crc= 0;
5406
int error= t->file->rnd_next(t->record[0]);
5407
if (unlikely(error))
5409
if (error == HA_ERR_RECORD_DELETED)
5413
if (t->s->null_bytes)
5415
/* fix undefined null bits */
5416
t->record[0][t->s->null_bytes-1] |= null_mask;
5417
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
5418
t->record[0][0] |= 1;
5420
row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
5423
for (uint32_t i= 0; i < t->s->fields; i++ )
5425
Field *f= t->field[i];
5426
if ((f->type() == DRIZZLE_TYPE_BLOB) ||
5427
(f->type() == DRIZZLE_TYPE_VARCHAR))
5431
row_crc= my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
5434
row_crc= my_checksum(row_crc, f->ptr,
5440
protocol->store((uint64_t)crc);
5441
t->file->ha_rnd_end();
5444
session->clear_error();
5445
close_thread_tables(session);
5446
table->table=0; // For query cache
5448
if (protocol->write())
5456
close_thread_tables(session); // Shouldn't be needed
5462
static bool check_engine(Session *session, const char *table_name,
5463
HA_CREATE_INFO *create_info)
5465
handlerton **new_engine= &create_info->db_type;
5466
handlerton *req_engine= *new_engine;
5467
bool no_substitution= 1;
5468
if (!(*new_engine= ha_checktype(session, ha_legacy_type(req_engine),
5469
no_substitution, 1)))
2202
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2204
thr_lock_type lock_type = TL_READ_NO_INSERT;
2206
return(admin_table(session, tables, check_opt,
2207
"analyze", lock_type, true,
2208
&Cursor::ha_analyze));
2212
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2214
thr_lock_type lock_type = TL_READ_NO_INSERT;
2216
return(admin_table(session, tables, check_opt,
2219
&Cursor::ha_check));
2222
} /* namespace drizzled */
5472
if (req_engine && req_engine != *new_engine)
5474
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
5475
ER_WARN_USING_OTHER_HANDLER,
5476
ER(ER_WARN_USING_OTHER_HANDLER),
5477
ha_resolve_storage_engine_name(*new_engine),
5480
if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
5481
ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
5483
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5485
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
5486
ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
5490
*new_engine= myisam_hton;