3188
pthread_mutex_lock(&LOCK_open);
3189
unlink_open_table(thd, name_lock, false);
2460
pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2461
session->unlink_open_table(name_lock);
3190
2462
pthread_mutex_unlock(&LOCK_open);
3196
bool mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
2468
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
3198
2470
thr_lock_type lock_type = TL_READ_NO_INSERT;
3200
return(mysql_admin_table(thd, tables, check_opt,
3201
"analyze", lock_type, 1, 0, 0, 0,
3202
&handler::ha_analyze));
2472
return(mysql_admin_table(session, tables, check_opt,
2473
"analyze", lock_type, true,
2474
&Cursor::ha_analyze));
3206
bool mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
2478
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
3208
2480
thr_lock_type lock_type = TL_READ_NO_INSERT;
3210
return(mysql_admin_table(thd, tables, check_opt,
2482
return(mysql_admin_table(session, tables, check_opt,
3211
2483
"check", lock_type,
3212
0, 0, HA_OPEN_FOR_REPAIR, 0,
3213
&handler::ha_check));
3217
/* table_list should contain just one table */
3219
mysql_discard_or_import_tablespace(THD *thd,
3220
TABLE_LIST *table_list,
3221
enum tablespace_op_type tablespace_op)
3228
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
3232
thd_proc_info(thd, "discard_or_import_tablespace");
3234
discard= test(tablespace_op == DISCARD_TABLESPACE);
3237
We set this flag so that ha_innobase::open and ::external_lock() do
3238
not complain when we lock the table
3240
thd->tablespace_op= true;
3241
if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
3243
thd->tablespace_op=false;
3247
error= table->file->ha_discard_or_import_tablespace(discard);
3249
thd_proc_info(thd, "end");
3254
/* The ALTER TABLE is always in its own transaction */
3255
error = ha_autocommit_or_rollback(thd, 0);
3256
if (end_active_trans(thd))
3260
write_bin_log(thd, false, thd->query, thd->query_length);
3263
ha_autocommit_or_rollback(thd, error);
3264
thd->tablespace_op=false;
3272
table->file->print_error(error, MYF(0));
3278
Copy all changes detected by parser to the HA_ALTER_FLAGS
3281
void setup_ha_alter_flags(Alter_info *alter_info, HA_ALTER_FLAGS *alter_flags)
3283
uint flags= alter_info->flags;
3285
if (ALTER_ADD_COLUMN & flags)
3286
*alter_flags|= HA_ADD_COLUMN;
3287
if (ALTER_DROP_COLUMN & flags)
3288
*alter_flags|= HA_DROP_COLUMN;
3289
if (ALTER_RENAME & flags)
3290
*alter_flags|= HA_RENAME_TABLE;
3291
if (ALTER_CHANGE_COLUMN & flags)
3292
*alter_flags|= HA_CHANGE_COLUMN;
3293
if (ALTER_COLUMN_DEFAULT & flags)
3294
*alter_flags|= HA_COLUMN_DEFAULT_VALUE;
3295
if (ALTER_COLUMN_STORAGE & flags)
3296
*alter_flags|= HA_COLUMN_STORAGE;
3297
if (ALTER_COLUMN_FORMAT & flags)
3298
*alter_flags|= HA_COLUMN_FORMAT;
3299
if (ALTER_COLUMN_ORDER & flags)
3300
*alter_flags|= HA_ALTER_COLUMN_ORDER;
3301
if (ALTER_STORAGE & flags)
3302
*alter_flags|= HA_ALTER_STORAGE;
3303
if (ALTER_ROW_FORMAT & flags)
3304
*alter_flags|= HA_ALTER_ROW_FORMAT;
3305
if (ALTER_RECREATE & flags)
3306
*alter_flags|= HA_RECREATE;
3307
if (ALTER_FOREIGN_KEY & flags)
3308
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3314
@param table The original table.
3315
@param alter_info Alter options, fields and keys for the new
3317
@param create_info Create options for the new table.
3318
@param order_num Number of order list elements.
3319
@param[out] ha_alter_flags Flags that indicate what will be changed
3320
@param[out] ha_alter_info Data structures needed for on-line alter
3321
@param[out] table_changes Information about particular change
3323
First argument 'table' contains information of the original
3324
table, which includes all corresponding parts that the new
3325
table has in arguments create_list, key_list and create_info.
3327
By comparing the changes between the original and new table
3328
we can determine how much it has changed after ALTER TABLE
3329
and whether we need to make a copy of the table, or just change
3332
Mark any changes detected in the ha_alter_flags.
3334
If there are no data changes, but index changes, 'index_drop_buffer'
3335
and/or 'index_add_buffer' are populated with offsets into
3336
table->key_info or key_info_buffer respectively for the indexes
3337
that need to be dropped and/or (re-)created.
3340
@retval false success
3345
compare_tables(THD *thd,
3347
Alter_info *alter_info,
3348
HA_CREATE_INFO *create_info,
3350
HA_ALTER_FLAGS *alter_flags,
3351
HA_ALTER_INFO *ha_alter_info,
3352
uint *table_changes)
3354
Field **f_ptr, *field;
3355
uint table_changes_local= 0;
3356
List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3357
Create_field *new_field;
3358
KEY_PART_INFO *key_part;
3361
Remember if the new definition has new VARCHAR column;
3362
create_info->varchar will be reset in mysql_prepare_create_table.
3364
bool varchar= create_info->varchar;
3368
Create a copy of alter_info.
3369
To compare the new and old table definitions, we need to "prepare"
3370
the new definition - transform it from parser output to a format
3371
that describes the final table layout (all column defaults are
3372
initialized, duplicate columns are removed). This is done by
3373
mysql_prepare_create_table. Unfortunately,
3374
mysql_prepare_create_table performs its transformations
3375
"in-place", that is, modifies the argument. Since we would
3376
like to keep compare_tables() idempotent (not altering any
3377
of the arguments) we create a copy of alter_info here and
3378
pass it to mysql_prepare_create_table, then use the result
3379
to evaluate possibility of fast ALTER TABLE, and then
3382
Alter_info tmp_alter_info(*alter_info, thd->mem_root);
3383
THD *thd= table->in_use;
3384
uint db_options= 0; /* not used */
3385
/* Create the prepared information. */
3386
if (mysql_prepare_create_table(thd, create_info,
3388
(table->s->tmp_table != NO_TMP_TABLE),
3391
&ha_alter_info->key_info_buffer,
3392
&ha_alter_info->key_count,
3393
/* select_field_count */ 0))
3395
/* Allocate result buffers. */
3396
if (! (ha_alter_info->index_drop_buffer=
3397
(uint*) thd->alloc(sizeof(uint) * table->s->keys)) ||
3398
! (ha_alter_info->index_add_buffer=
3399
(uint*) thd->alloc(sizeof(uint) *
3400
tmp_alter_info.key_list.elements)))
3404
First we setup ha_alter_flags based on what was detected
3407
setup_ha_alter_flags(alter_info, alter_flags);
3411
Some very basic checks. If number of fields changes, or the
3412
handler, we need to run full ALTER TABLE. In the future
3413
new fields can be added and old dropped without copy, but
3416
Test also that engine was not given during ALTER TABLE, or
3417
we are force to run regular alter table (copy).
3418
E.g. ALTER TABLE tbl_name ENGINE=MyISAM.
3420
For the following ones we also want to run regular alter table:
3421
ALTER TABLE tbl_name ORDER BY ..
3422
ALTER TABLE tbl_name CONVERT TO CHARACTER SET ..
3424
At the moment we can't handle altering temporary tables without a copy.
3425
We also test if OPTIMIZE TABLE was given and was mapped to alter table.
3426
In that case we always do full copy.
3428
There was a bug prior to mysql-4.0.25. Number of null fields was
3429
calculated incorrectly. As a result frm and data files gets out of
3430
sync after fast alter table. There is no way to determine by which
3431
mysql version (in 4.0 and 4.1 branches) table was created, thus we
3432
disable fast alter table for all tables created by mysql versions
3433
prior to 5.0 branch.
3436
if (table->s->fields != alter_info->create_list.elements ||
3437
table->s->db_type() != create_info->db_type ||
3438
table->s->tmp_table ||
3439
create_info->used_fields & HA_CREATE_USED_ENGINE ||
3440
create_info->used_fields & HA_CREATE_USED_CHARSET ||
3441
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3442
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3443
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3445
!table->s->mysql_version ||
3446
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3448
*table_changes= IS_EQUAL_NO;
3450
Check what has changed and set alter_flags
3452
if (table->s->fields < alter_info->create_list.elements)
3453
*alter_flags|= HA_ADD_COLUMN;
3454
else if (table->s->fields > alter_info->create_list.elements)
3455
*alter_flags|= HA_DROP_COLUMN;
3456
if (create_info->db_type != table->s->db_type() ||
3457
create_info->used_fields & HA_CREATE_USED_ENGINE)
3458
*alter_flags|= HA_ALTER_STORAGE_ENGINE;
3459
if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3460
*alter_flags|= HA_CHANGE_CHARACTER_SET;
3461
if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3462
*alter_flags|= HA_SET_DEFAULT_CHARACTER_SET;
3463
if (alter_info->flags & ALTER_RECREATE)
3464
*alter_flags|= HA_RECREATE;
3465
/* TODO check for ADD/DROP FOREIGN KEY */
3466
if (alter_info->flags & ALTER_FOREIGN_KEY)
3467
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3468
if (!table->s->mysql_version ||
3469
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3470
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3473
Go through fields and check if the original ones are compatible
3476
for (f_ptr= table->field, new_field= new_field_it++;
3477
(new_field && (field= *f_ptr));
3478
f_ptr++, new_field= new_field_it++)
3480
/* Make sure we have at least the default charset in use. */
3481
if (!new_field->charset)
3482
new_field->charset= create_info->default_table_charset;
3484
/* Don't pack rows in old tables if the user has requested this. */
3485
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3486
(new_field->flags & BLOB_FLAG) ||
3487
(new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3488
create_info->table_options|= HA_OPTION_PACK_RECORD;
3490
/* Check how fields have been modified */
3491
if (alter_info->flags & ALTER_CHANGE_COLUMN)
3493
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
3494
if (!(table_changes_local= field->is_equal(new_field)))
3495
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3497
/* Check if field was renamed */
3498
field->flags&= ~FIELD_IS_RENAMED;
3499
if (my_strcasecmp(system_charset_info,
3501
new_field->field_name))
3503
field->flags|= FIELD_IS_RENAMED;
3504
*alter_flags|= HA_ALTER_COLUMN_NAME;
3507
*table_changes&= table_changes_local;
3508
if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3509
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3511
/* Check that NULL behavior is same for old and new fields */
3512
if ((new_field->flags & NOT_NULL_FLAG) !=
3513
(uint) (field->flags & NOT_NULL_FLAG))
3515
*table_changes= IS_EQUAL_NO;
3516
*alter_flags|= HA_ALTER_COLUMN_NULLABLE;
3520
/* Clear indexed marker */
3521
field->flags&= ~FIELD_IN_ADD_INDEX;
3525
Go through keys and check if the original ones are compatible
3529
KEY *table_key_end= table->key_info + table->s->keys;
3532
ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3535
Step through all keys of the old table and search matching new keys.
3537
ha_alter_info->index_drop_count= 0;
3538
ha_alter_info->index_add_count= 0;
3539
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3541
KEY_PART_INFO *table_part;
3542
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3543
KEY_PART_INFO *new_part;
3545
/* Search a new key with the same name. */
3546
for (new_key= ha_alter_info->key_info_buffer;
3547
new_key < new_key_end;
3550
if (! strcmp(table_key->name, new_key->name))
3553
if (new_key >= new_key_end)
3555
/* Key not found. Add the offset of the key to the drop buffer. */
3556
ha_alter_info->index_drop_buffer
3557
[ha_alter_info->index_drop_count++]=
3558
table_key - table->key_info;
3559
if (table_key->flags & HA_NOSAME)
3561
/* Unique key. Check for "PRIMARY". */
3562
if (! my_strcasecmp(system_charset_info,
3563
table_key->name, primary_key_name))
3564
*alter_flags|= HA_DROP_PK_INDEX;
3566
*alter_flags|= HA_DROP_UNIQUE_INDEX;
3569
*alter_flags|= HA_DROP_INDEX;
3570
*table_changes= IS_EQUAL_NO;
3574
/* Check that the key types are compatible between old and new tables. */
3575
if ((table_key->algorithm != new_key->algorithm) ||
3576
((table_key->flags & HA_KEYFLAG_MASK) !=
3577
(new_key->flags & HA_KEYFLAG_MASK)) ||
3578
(table_key->key_parts != new_key->key_parts))
3580
if (table_key->flags & HA_NOSAME)
3582
// Unique key. Check for "PRIMARY".
3583
if (! my_strcasecmp(system_charset_info,
3584
table_key->name, primary_key_name))
3585
*alter_flags|= HA_ALTER_PK_INDEX;
3587
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3590
*alter_flags|= HA_ALTER_INDEX;
3595
Check that the key parts remain compatible between the old and
3598
for (table_part= table_key->key_part, new_part= new_key->key_part;
3599
table_part < table_part_end;
3600
table_part++, new_part++)
3603
Key definition has changed if we are using a different field or
3604
if the used key part length is different. We know that the fields
3605
did not change. Comparing field numbers is sufficient.
3607
if ((table_part->length != new_part->length) ||
3608
(table_part->fieldnr - 1 != new_part->fieldnr))
3610
if (table_key->flags & HA_NOSAME)
3612
/* Unique key. Check for "PRIMARY" */
3613
if (! my_strcasecmp(system_charset_info,
3614
table_key->name, primary_key_name))
3615
*alter_flags|= HA_ALTER_PK_INDEX;
3617
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3620
*alter_flags|= HA_ALTER_INDEX;
3627
/* Key modified. Add the offset of the key to both buffers. */
3628
ha_alter_info->index_drop_buffer
3629
[ha_alter_info->index_drop_count++]=
3630
table_key - table->key_info;
3631
ha_alter_info->index_add_buffer
3632
[ha_alter_info->index_add_count++]=
3633
new_key - ha_alter_info->key_info_buffer;
3634
key_part= new_key->key_part;
3635
end= key_part + new_key->key_parts;
3636
for(; key_part != end; key_part++)
3638
/* Mark field to be part of new key */
3639
if ((field= table->field[key_part->fieldnr]))
3640
field->flags|= FIELD_IN_ADD_INDEX;
3642
*table_changes= IS_EQUAL_NO;
3644
/*end of for (; table_key < table_key_end;) */
3647
Step through all keys of the new table and find matching old keys.
3649
for (new_key= ha_alter_info->key_info_buffer;
3650
new_key < new_key_end;
3653
/* Search an old key with the same name. */
3654
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3656
if (! strcmp(table_key->name, new_key->name))
3659
if (table_key >= table_key_end)
3661
/* Key not found. Add the offset of the key to the add buffer. */
3662
ha_alter_info->index_add_buffer
3663
[ha_alter_info->index_add_count++]=
3664
new_key - ha_alter_info->key_info_buffer;
3665
key_part= new_key->key_part;
3666
end= key_part + new_key->key_parts;
3667
for(; key_part != end; key_part++)
3669
/* Mark field to be part of new key */
3670
if ((field= table->field[key_part->fieldnr]))
3671
field->flags|= FIELD_IN_ADD_INDEX;
3673
if (new_key->flags & HA_NOSAME)
3675
/* Unique key. Check for "PRIMARY" */
3676
if (! my_strcasecmp(system_charset_info,
3677
new_key->name, primary_key_name))
3678
*alter_flags|= HA_ADD_PK_INDEX;
3680
*alter_flags|= HA_ADD_UNIQUE_INDEX;
3683
*alter_flags|= HA_ADD_INDEX;
3684
*table_changes= IS_EQUAL_NO;
3693
Manages enabling/disabling of indexes for ALTER TABLE
3696
alter_table_manage_keys()
3698
indexes_were_disabled Whether the indexes of the from table
3700
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
3708
bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
3709
enum enum_enable_or_disable keys_onoff)
3712
switch (keys_onoff) {
3714
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3717
if (!indexes_were_disabled)
3719
/* fall-through: disabled indexes */
3721
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3724
if (error == HA_ERR_WRONG_COMMAND)
3726
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
3727
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3728
table->s->table_name.str);
3731
table->file->print_error(error, MYF(0));
3736
int create_temporary_table(THD *thd,
3740
HA_CREATE_INFO *create_info,
3741
Alter_info *alter_info,
3745
char index_file[FN_REFLEN], data_file[FN_REFLEN];
3746
handlerton *old_db_type, *new_db_type;
3747
old_db_type= table->s->db_type();
3748
new_db_type= create_info->db_type;
3750
Handling of symlinked tables:
3752
Create new data file and index file on the same disk as the
3753
old data and index files.
3755
Rename new data file over old data file and new index file over
3757
Symlinks are not changed.
3760
Create new data file and index file on the same disk as the
3761
old data and index files. Create also symlinks to point at
3764
At end, rename intermediate tables, and symlinks to intermediate
3765
table, to final table name.
3766
Remove old table and old symlinks
3768
If rename is made to another database:
3769
Create new tables in new database.
3771
Remove old table and symlinks.
3773
if (db_changed) // Ignore symlink if db changed
3775
if (create_info->index_file_name)
3777
/* Fix index_file_name to have 'tmp_name' as basename */
3778
strmov(index_file, tmp_name);
3779
create_info->index_file_name=fn_same(index_file,
3780
create_info->index_file_name,
3783
if (create_info->data_file_name)
3785
/* Fix data_file_name to have 'tmp_name' as basename */
3786
strmov(data_file, tmp_name);
3787
create_info->data_file_name=fn_same(data_file,
3788
create_info->data_file_name,
3793
create_info->data_file_name=create_info->index_file_name=0;
3796
Create a table with a temporary name.
3797
With create_info->frm_only == 1 this creates a .frm file only.
3798
We don't log the statement, it will be logged later.
3800
tmp_disable_binlog(thd);
3801
error= mysql_create_table(thd, new_db, tmp_name,
3802
create_info, alter_info, 1, 0);
3803
reenable_binlog(thd);
3809
Create a temporary table that reflects what an alter table operation
3813
create_altered_table()
3815
table The original table
3816
create_info Information from the parsing phase about new
3818
alter_info Lists of fields, keys to be changed, added
3820
db_change Specifies if the table is moved to another database
3822
A temporary table with all changes
3825
The temporary table is created without storing it in any storage engine
3826
and is opened only to get the table struct and frm file reference.
3828
TABLE *create_altered_table(THD *thd,
3831
HA_CREATE_INFO *create_info,
3832
Alter_info *alter_info,
3836
HA_CREATE_INFO altered_create_info(*create_info);
3837
TABLE *altered_table;
3839
char path[FN_REFLEN];
3841
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx",
3842
tmp_file_prefix, current_pid, thd->thread_id);
3843
/* Safety fix for InnoDB */
3844
if (lower_case_table_names)
3845
my_casedn_str(files_charset_info, tmp_name);
3846
altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3847
altered_create_info.frm_only= 1;
3848
if ((error= create_temporary_table(thd, table, new_db, tmp_name,
3849
&altered_create_info,
3850
alter_info, db_change)))
3855
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3857
altered_table= open_temporary_table(thd, path, new_db, tmp_name, 1,
3859
return(altered_table);
3866
Perform a fast or on-line alter table
3869
mysql_fast_or_online_alter_table()
3871
table The original table
3872
altered_table A temporary table showing how we will change table
3873
create_info Information from the parsing phase about new
3875
alter_info Storage place for data used during different phases
3876
ha_alter_flags Bitmask that shows what will be changed
3877
keys_onoff Specifies if keys are to be enabled/disabled
3880
>0 An error occured during the on-line alter table operation
3881
-1 Error when re-opening table
3883
If mysql_alter_table does not need to copy the table, it is
3884
either a fast alter table where the storage engine does not
3885
need to know about the change, only the frm will change,
3886
or the storage engine supports performing the alter table
3887
operation directly, on-line without mysql having to copy
3890
int mysql_fast_or_online_alter_table(THD *thd,
3892
TABLE *altered_table,
3893
HA_CREATE_INFO *create_info,
3894
HA_ALTER_INFO *alter_info,
3895
HA_ALTER_FLAGS *ha_alter_flags,
3896
enum enum_enable_or_disable keys_onoff)
3899
bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3905
Tell the handler to prepare for the online alter
3907
if ((error= table->file->alter_table_phase1(thd,
3917
Tell the storage engine to perform the online alter table
3919
if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3920
we need to wrap the next call with a DDL lock.
3922
if ((error= table->file->alter_table_phase2(thd,
3932
The final .frm file is already created as a temporary file
3933
and will be renamed to the original table name.
3935
VOID(pthread_mutex_lock(&LOCK_open));
3936
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
3937
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3939
close_data_files_and_morph_locks(thd,
3940
table->pos_in_table_list->db,
3941
table->pos_in_table_list->table_name);
3942
if (mysql_rename_table(NULL,
3943
altered_table->s->db.str,
3944
altered_table->s->table_name.str,
3946
table->s->table_name.str, FN_FROM_IS_TMP))
3949
VOID(pthread_mutex_unlock(&LOCK_open));
3952
broadcast_refresh();
3953
VOID(pthread_mutex_unlock(&LOCK_open));
3956
The ALTER TABLE is always in its own transaction.
3957
Commit must not be called while LOCK_open is locked. It could call
3958
wait_if_global_read_lock(), which could create a deadlock if called
3961
error= ha_autocommit_or_rollback(thd, 0);
3969
VOID(pthread_mutex_lock(&LOCK_open));
3970
if (reopen_table(table))
3975
VOID(pthread_mutex_unlock(&LOCK_open));
3979
Tell the handler that the changed frm is on disk and table
3982
if ((error= t_table->file->alter_table_phase3(thd, t_table)))
3988
We are going to reopen table down on the road, so we have to restore
3989
state of the TABLE object which we used for obtaining of handler
3990
object to make it suitable for reopening.
3992
assert(t_table == table);
3993
table->open_placeholder= 1;
3994
VOID(pthread_mutex_lock(&LOCK_open));
3995
close_handle_and_leave_table_as_lock(table);
3996
VOID(pthread_mutex_unlock(&LOCK_open));
4007
Prepare column and key definitions for CREATE TABLE in ALTER TABLE.
4009
This function transforms parse output of ALTER TABLE - lists of
4010
columns and keys to add, drop or modify into, essentially,
4011
CREATE TABLE definition - a list of columns and keys of the new
4012
table. While doing so, it also performs some (bug not all)
4015
This function is invoked when we know that we're going to
4016
perform ALTER TABLE via a temporary table -- i.e. fast ALTER TABLE
4017
is not possible, perhaps because the ALTER statement contains
4018
instructions that require change in table data, not only in
4019
table definition or indexes.
4021
@param[in,out] thd thread handle. Used as a memory pool
4022
and source of environment information.
4023
@param[in] table the source table, open and locked
4024
Used as an interface to the storage engine
4025
to acquire additional information about
4027
@param[in,out] create_info A blob with CREATE/ALTER TABLE
4029
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
4030
Originally create_info was used only in
4031
CREATE TABLE and alter_info only in ALTER TABLE.
4032
But since ALTER might end-up doing CREATE,
4033
this distinction is gone and we just carry
4034
around two structures.
4037
Fills various create_info members based on information retrieved
4038
from the storage engine.
4039
Sets create_info->varchar if the table has a VARCHAR column.
4040
Prepares alter_info->create_list and alter_info->key_list with
4041
columns and keys of the new table.
4042
@retval true error, out of memory or a semantical error in ALTER
4044
@retval false success
4048
mysql_prepare_alter_table(THD *thd, TABLE *table,
4049
HA_CREATE_INFO *create_info,
4050
Alter_info *alter_info)
4052
/* New column definitions are added here */
4053
List<Create_field> new_create_list;
4054
/* New key definitions are added here */
4055
List<Key> new_key_list;
4056
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
4057
List_iterator<Create_field> def_it(alter_info->create_list);
4058
List_iterator<Alter_column> alter_it(alter_info->alter_list);
4059
List_iterator<Key> key_it(alter_info->key_list);
4060
List_iterator<Create_field> find_it(new_create_list);
4061
List_iterator<Create_field> field_it(new_create_list);
4062
List<Key_part_spec> key_parts;
4063
uint db_create_options= (table->s->db_create_options
4064
& ~(HA_OPTION_PACK_RECORD));
4065
uint used_fields= create_info->used_fields;
4066
KEY *key_info=table->key_info;
4070
create_info->varchar= false;
4071
/* Let new create options override the old ones */
4072
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
4073
create_info->min_rows= table->s->min_rows;
4074
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
4075
create_info->max_rows= table->s->max_rows;
4076
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
4077
create_info->avg_row_length= table->s->avg_row_length;
4078
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
4079
create_info->default_table_charset= table->s->table_charset;
4080
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
4082
/* Table has an autoincrement, copy value to new table */
4083
table->file->info(HA_STATUS_AUTO);
4084
create_info->auto_increment_value= table->file->stats.auto_increment_value;
4086
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
4087
create_info->key_block_size= table->s->key_block_size;
4088
if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL))
4089
create_info->transactional= table->s->transactional;
4091
restore_record(table, s->default_values); // Empty record for DEFAULT
4095
First collect all fields from table which isn't in drop_list
4097
Field **f_ptr,*field;
4098
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
4100
if (field->type() == DRIZZLE_TYPE_STRING)
4101
create_info->varchar= true;
4102
/* Check if field should be dropped */
4105
while ((drop=drop_it++))
4107
if (drop->type == Alter_drop::COLUMN &&
4108
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
4110
/* Reset auto_increment value if it was dropped */
4111
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
4112
!(used_fields & HA_CREATE_USED_AUTO))
4114
create_info->auto_increment_value=0;
4115
create_info->used_fields|=HA_CREATE_USED_AUTO;
4125
/* Check if field is changed */
4127
while ((def=def_it++))
4130
!my_strcasecmp(system_charset_info,field->field_name, def->change))
4134
{ // Field is changed
4138
new_create_list.push_back(def);
4145
This field was not dropped and not changed, add it to the list
4148
def= new Create_field(field, field);
4149
new_create_list.push_back(def);
4150
alter_it.rewind(); // Change default if ALTER
4151
Alter_column *alter;
4152
while ((alter=alter_it++))
4154
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
4159
if (def->sql_type == DRIZZLE_TYPE_BLOB)
4161
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
4164
if ((def->def=alter->def)) // Use new default
4165
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
4167
def->flags|= NO_DEFAULT_VALUE_FLAG;
4173
while ((def=def_it++)) // Add new columns
4175
if (def->change && ! def->field)
4177
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
4181
Check that the DATE/DATETIME not null field we are going to add is
4182
either has a default value or the '0000-00-00' is allowed by the
4184
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
4185
flag to allow ALTER TABLE only if the table to be altered is empty.
4187
if ((def->sql_type == DRIZZLE_TYPE_NEWDATE ||
4188
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
4189
!alter_info->datetime_field &&
4190
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
4191
thd->variables.sql_mode & MODE_NO_ZERO_DATE)
4193
alter_info->datetime_field= def;
4194
alter_info->error_if_not_empty= true;
4197
new_create_list.push_back(def);
4198
else if (def->after == first_keyword)
4199
new_create_list.push_front(def);
4204
while ((find=find_it++)) // Add new columns
4206
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
4211
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
4214
find_it.after(def); // Put element after this
4216
XXX: hack for Bug#28427.
4217
If column order has changed, force OFFLINE ALTER TABLE
4218
without querying engine capabilities. If we ever have an
4219
engine that supports online ALTER TABLE CHANGE COLUMN
4220
<name> AFTER <name1> (Falcon?), this fix will effectively
4221
disable the capability.
4222
TODO: detect the situation in compare_tables, behave based
4223
on engine capabilities.
4225
if (alter_info->build_method == HA_BUILD_ONLINE)
4227
my_error(ER_NOT_SUPPORTED_YET, MYF(0), thd->query);
4230
alter_info->build_method= HA_BUILD_OFFLINE;
4233
if (alter_info->alter_list.elements)
4235
my_error(ER_BAD_FIELD_ERROR, MYF(0),
4236
alter_info->alter_list.head()->name, table->s->table_name.str);
4239
if (!new_create_list.elements)
4241
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
4247
Collect all keys which isn't in drop list. Add only those
4248
for which some fields exists.
4251
for (uint i=0 ; i < table->s->keys ; i++,key_info++)
4253
char *key_name= key_info->name;
4256
while ((drop=drop_it++))
4258
if (drop->type == Alter_drop::KEY &&
4259
!my_strcasecmp(system_charset_info,key_name, drop->name))
4268
KEY_PART_INFO *key_part= key_info->key_part;
4270
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
4272
if (!key_part->field)
4273
continue; // Wrong field (from UNIREG)
4274
const char *key_part_name=key_part->field->field_name;
4275
Create_field *cfield;
4277
while ((cfield=field_it++))
4281
if (!my_strcasecmp(system_charset_info, key_part_name,
4285
else if (!my_strcasecmp(system_charset_info,
4286
key_part_name, cfield->field_name))
4290
continue; // Field is removed
4291
uint key_part_length=key_part->length;
4292
if (cfield->field) // Not new field
4295
If the field can't have only a part used in a key according to its
4296
new type, or should not be used partially according to its
4297
previous type, or the field length is less than the key part
4298
length, unset the key part length.
4300
We also unset the key part length if it is the same as the
4301
old field's length, so the whole new field will be used.
4303
BLOBs may have cfield->length == 0, which is why we test it before
4304
checking whether cfield->length < key_part_length (in chars).
4306
if (!Field::type_can_have_key_part(cfield->field->type()) ||
4307
!Field::type_can_have_key_part(cfield->sql_type) ||
4308
(cfield->field->field_length == key_part_length &&
4309
!f_is_blob(key_part->key_type)) ||
4310
(cfield->length && (cfield->length < key_part_length /
4311
key_part->field->charset()->mbmaxlen)))
4312
key_part_length= 0; // Use whole field
4314
key_part_length /= key_part->field->charset()->mbmaxlen;
4315
key_parts.push_back(new Key_part_spec(cfield->field_name,
4316
strlen(cfield->field_name),
4319
if (key_parts.elements)
4321
KEY_CREATE_INFO key_create_info;
4323
enum Key::Keytype key_type;
4324
bzero((char*) &key_create_info, sizeof(key_create_info));
4326
key_create_info.algorithm= key_info->algorithm;
4327
if (key_info->flags & HA_USES_BLOCK_SIZE)
4328
key_create_info.block_size= key_info->block_size;
4329
if (key_info->flags & HA_USES_COMMENT)
4330
key_create_info.comment= key_info->comment;
4332
if (key_info->flags & HA_NOSAME)
4334
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
4335
key_type= Key::PRIMARY;
4337
key_type= Key::UNIQUE;
4340
key_type= Key::MULTIPLE;
4342
key= new Key(key_type, key_name, strlen(key_name),
4344
test(key_info->flags & HA_GENERATED_KEY),
4346
new_key_list.push_back(key);
4351
while ((key=key_it++)) // Add new keys
4353
if (key->type != Key::FOREIGN_KEY)
4354
new_key_list.push_back(key);
4355
if (key->name.str &&
4356
!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
4358
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
4364
if (alter_info->drop_list.elements)
4366
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4367
alter_info->drop_list.head()->name);
4370
if (alter_info->alter_list.elements)
4372
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4373
alter_info->alter_list.head()->name);
4377
if (!create_info->comment.str)
4379
create_info->comment.str= table->s->comment.str;
4380
create_info->comment.length= table->s->comment.length;
4383
table->file->update_create_info(create_info);
4384
if ((create_info->table_options &
4385
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
4386
(used_fields & HA_CREATE_USED_PACK_KEYS))
4387
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
4388
if (create_info->table_options &
4389
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
4390
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
4391
if (create_info->table_options &
4392
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
4393
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
4394
HA_OPTION_NO_DELAY_KEY_WRITE);
4395
create_info->table_options|= db_create_options;
4397
if (table->s->tmp_table)
4398
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
4401
alter_info->create_list.swap(new_create_list);
4402
alter_info->key_list.swap(new_key_list);
4414
new_db If there is a RENAME clause
4415
new_name If there is a RENAME clause
4416
create_info Information from the parsing phase about new
4418
table_list The table to change.
4419
alter_info Lists of fields, keys to be changed, added
4421
order_num How many ORDER BY fields has been specified.
4422
order List of fields to ORDER BY.
4423
ignore Whether we have ALTER IGNORE TABLE
4426
This is a veery long function and is everything but the kitchen sink :)
4427
It is used to alter a table and not only by ALTER TABLE but also
4428
CREATE|DROP INDEX are mapped on this function.
4430
When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS,
4431
or both, then this function short cuts its operation by renaming
4432
the table and/or enabling/disabling the keys. In this case, the FRM is
4433
not changed, directly by mysql_alter_table. However, if there is a
4434
RENAME + change of a field, or an index, the short cut is not used.
4435
See how `create_list` is used to generate the new FRM regarding the
4436
structure of the fields. The same is done for the indices of the table.
4438
Important is the fact, that this function tries to do as little work as
4439
possible, by finding out whether a intermediate table is needed to copy
4440
data into and when finishing the altering to use it as the original table.
4441
For this reason the function compare_tables() is called, which decides
4442
based on all kind of data how similar are the new and the original
4450
bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
4451
HA_CREATE_INFO *create_info,
4452
TABLE_LIST *table_list,
4453
Alter_info *alter_info,
4454
uint order_num, ORDER *order, bool ignore)
4456
TABLE *table, *new_table=0, *name_lock= 0;;
4458
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
4459
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
4460
char path[FN_REFLEN];
4461
ha_rows copied= 0,deleted= 0;
4462
handlerton *old_db_type, *new_db_type, *save_old_db_type;
4463
legacy_db_type table_type;
4464
frm_type_enum frm_type;
4466
if (table_list && table_list->schema_table)
4468
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.str);
4473
Assign variables table_name, new_name, db, new_db, path
4474
to simplify further comparisons: we want to see if it's a RENAME
4475
later just by comparing the pointers, avoiding the need for strcmp.
4477
thd_proc_info(thd, "init");
4478
table_name=table_list->table_name;
4479
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
4481
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
4483
build_table_filename(path, sizeof(path), db, table_name, "", 0);
4485
mysql_ha_rm_tables(thd, table_list, false);
4487
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */
4488
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
4489
/* Conditionally writes to binlog. */
4490
return(mysql_discard_or_import_tablespace(thd,table_list,
4491
alter_info->tablespace_op));
4492
strxnmov(new_name_buff, sizeof (new_name_buff) - 1, mysql_data_home, "/", db,
4493
"/", table_name, reg_ext, NullS);
4494
(void) unpack_filename(new_name_buff, new_name_buff);
4496
If this is just a rename of a view, short cut to the
4497
following scenario: 1) lock LOCK_open 2) do a RENAME
4498
2) unlock LOCK_open.
4499
This is a copy-paste added to make sure
4500
ALTER (sic:) TABLE .. RENAME works for views. ALTER VIEW is handled
4501
as an independent branch in mysql_execute_command. The need
4502
for a copy-paste arose because the main code flow of ALTER TABLE
4503
... RENAME tries to use open_ltable, which does not work for views
4504
(open_ltable was never modified to merge table lists of child tables
4505
into the main table list, like open_tables does).
4506
This code is wrong and will be removed, please do not copy.
4508
frm_type= mysql_frm_type(thd, new_name_buff, &table_type);
4510
if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ)))
4512
table->use_all_columns();
4515
Prohibit changing of the UNION list of a non-temporary MERGE table
4516
under LOCK tables. It would be quite difficult to reuse a shrinked
4517
set of tables from the old table or to open a new TABLE object for
4518
an extended list and verify that they belong to locked tables.
4520
if (thd->locked_tables &&
4521
(create_info->used_fields & HA_CREATE_USED_UNION) &&
4522
(table->s->tmp_table == NO_TMP_TABLE))
4524
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
4528
/* Check that we are not trying to rename to an existing table */
4531
strmov(new_name_buff,new_name);
4532
strmov(new_alias= new_alias_buff, new_name);
4533
if (lower_case_table_names)
4535
if (lower_case_table_names != 2)
4537
my_casedn_str(files_charset_info, new_name_buff);
4538
new_alias= new_name; // Create lower case table name
4540
my_casedn_str(files_charset_info, new_name);
4543
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
4546
Source and destination table names are equal: make later check
4549
new_alias= new_name= table_name;
4553
if (table->s->tmp_table != NO_TMP_TABLE)
4555
if (find_temporary_table(thd,new_db,new_name_buff))
4557
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
4563
if (lock_table_name_if_not_cached(thd, new_db, new_name, &name_lock))
4567
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4571
build_table_filename(new_name_buff, sizeof(new_name_buff),
4572
new_db, new_name_buff, reg_ext, 0);
4573
if (!access(new_name_buff, F_OK))
4575
/* Table will be closed in do_command() */
4576
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4584
new_alias= (lower_case_table_names == 2) ? alias : table_name;
4585
new_name= table_name;
4588
old_db_type= table->s->db_type();
4589
if (!create_info->db_type)
4591
create_info->db_type= old_db_type;
4594
if (check_engine(thd, new_name, create_info))
4596
new_db_type= create_info->db_type;
4598
if (new_db_type != old_db_type &&
4599
!table->file->can_switch_engines())
4602
my_error(ER_ROW_IS_REFERENCED, MYF(0));
4606
if (create_info->row_type == ROW_TYPE_NOT_USED)
4607
create_info->row_type= table->s->row_type;
4609
if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
4610
ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
4612
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
4616
thd_proc_info(thd, "setup");
4617
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
4618
!table->s->tmp_table) // no need to touch frm
4620
switch (alter_info->keys_onoff) {
4625
wait_while_table_is_used() ensures that table being altered is
4626
opened only by this thread and that TABLE::TABLE_SHARE::version
4627
of TABLE object corresponding to this table is 0.
4628
The latter guarantees that no DML statement will open this table
4629
until ALTER TABLE finishes (i.e. until close_thread_tables())
4630
while the fact that the table is still open gives us protection
4631
from concurrent DDL statements.
4633
VOID(pthread_mutex_lock(&LOCK_open));
4634
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
4635
VOID(pthread_mutex_unlock(&LOCK_open));
4636
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4637
/* COND_refresh will be signaled in close_thread_tables() */
4640
VOID(pthread_mutex_lock(&LOCK_open));
4641
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
4642
VOID(pthread_mutex_unlock(&LOCK_open));
4643
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4644
/* COND_refresh will be signaled in close_thread_tables() */
4651
if (error == HA_ERR_WRONG_COMMAND)
4654
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4655
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4659
VOID(pthread_mutex_lock(&LOCK_open));
4661
Unlike to the above case close_cached_table() below will remove ALL
4662
instances of TABLE from table cache (it will also remove table lock
4663
held by this thread). So to make actual table renaming and writing
4664
to binlog atomic we have to put them into the same critical section
4665
protected by LOCK_open mutex. This also removes gap for races between
4666
access() and mysql_rename_table() calls.
4669
if (!error && (new_name != table_name || new_db != db))
4671
thd_proc_info(thd, "rename");
4673
Then do a 'simple' rename of the table. First we need to close all
4674
instances of 'source' table.
4676
close_cached_table(thd, table);
4678
Then, we want check once again that target table does not exist.
4679
Actually the order of these two steps does not matter since
4680
earlier we took name-lock on the target table, so we do them
4681
in this particular order only to be consistent with 5.0, in which
4682
we don't take this name-lock and where this order really matters.
4683
TODO: Investigate if we need this access() check at all.
4685
if (!access(new_name_buff,F_OK))
4687
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
4692
*fn_ext(new_name)=0;
4693
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
4697
VOID(mysql_rename_table(old_db_type, new_db, new_alias, db,
4704
if (error == HA_ERR_WRONG_COMMAND)
4707
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
4708
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4714
write_bin_log(thd, true, thd->query, thd->query_length);
4719
table->file->print_error(error, MYF(0));
4723
unlink_open_table(thd, name_lock, false);
4724
VOID(pthread_mutex_unlock(&LOCK_open));
4725
table_list->table= NULL; // For query cache
4729
/* We have to do full alter table. */
4732
If the old table had partitions and we are doing ALTER TABLE ...
4733
engine= <new_engine>, the new table must preserve the original
4734
partitioning. That means that the new engine is still the
4735
partitioning engine, not the engine specified in the parser.
4736
This is discovered in prep_alter_part_table, which in such case
4737
updates create_info->db_type.
4738
Now we need to update the stack copy of create_info->db_type,
4739
as otherwise we won't be able to correctly move the files of the
4740
temporary table to the result table files.
4742
new_db_type= create_info->db_type;
4744
if (mysql_prepare_alter_table(thd, table, create_info, alter_info))
4747
set_table_default_charset(thd, create_info, db);
4750
if (thd->variables.old_alter_table
4751
|| (table->s->db_type() != create_info->db_type)
4754
if (alter_info->build_method == HA_BUILD_ONLINE)
4756
my_error(ER_NOT_SUPPORTED_YET, MYF(0), thd->query);
4759
alter_info->build_method= HA_BUILD_OFFLINE;
4762
if (alter_info->build_method != HA_BUILD_OFFLINE)
4764
TABLE *altered_table= 0;
4765
HA_ALTER_INFO ha_alter_info;
4766
HA_ALTER_FLAGS ha_alter_flags;
4767
uint table_changes= IS_EQUAL_YES;
4768
bool need_copy_table= true;
4769
/* Check how much the tables differ. */
4770
if (compare_tables(thd, table, alter_info,
4771
create_info, order_num,
4780
Check if storage engine supports altering the table
4786
If table is not renamed, changed database and
4787
some change was detected then check if engine
4788
can do the change on-line
4790
if (new_name == table_name && new_db == db &&
4791
ha_alter_flags.is_set())
4793
Alter_info tmp_alter_info(*alter_info, thd->mem_root);
4797
check if table can be altered on-line
4799
if (!(altered_table= create_altered_table(thd,
4804
!strcmp(db, new_db))))
4807
switch (table->file->check_if_supported_alter(altered_table,
4811
case HA_ALTER_SUPPORTED_WAIT_LOCK:
4812
case HA_ALTER_SUPPORTED_NO_LOCK:
4814
@todo: Currently we always acquire an exclusive name
4815
lock on the table metadata when performing fast or online
4816
ALTER TABLE. In future we may consider this unnecessary,
4817
and narrow the scope of the exclusive name lock to only
4818
cover manipulation with .frms. Storage engine API
4819
call check_if_supported_alter has provision for this
4822
need_copy_table= false;
4824
case HA_ALTER_NOT_SUPPORTED:
4825
if (alter_info->build_method == HA_BUILD_ONLINE)
4827
my_error(ER_NOT_SUPPORTED_YET, MYF(0), thd->query);
4828
close_temporary_table(thd, altered_table, 1, 1);
4831
need_copy_table= true;
4833
case HA_ALTER_ERROR:
4835
close_temporary_table(thd, altered_table, 1, 1);
4840
/* TODO need to check if changes can be handled as fast ALTER TABLE */
4842
need_copy_table= true;
4844
if (!need_copy_table)
4846
error= mysql_fast_or_online_alter_table(thd,
4852
alter_info->keys_onoff);
4855
mysql_unlock_tables(thd, thd->lock);
4858
close_temporary_table(thd, altered_table, 1, 1);
4864
goto err_with_placeholders;
4871
pthread_mutex_lock(&LOCK_open);
4877
close_temporary_table(thd, altered_table, 1, 1);
4880
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
4881
current_pid, thd->thread_id);
4882
/* Safety fix for innodb */
4883
if (lower_case_table_names)
4884
my_casedn_str(files_charset_info, tmp_name);
4887
/* Create a temporary table with the new format */
4888
if ((error= create_temporary_table(thd, table, new_db, tmp_name,
4889
create_info, alter_info,
4890
!strcmp(db, new_db))))
4895
/* Open the table so we need to copy the data to it. */
4896
if (table->s->tmp_table)
4899
bzero((void*) &tbl, sizeof(tbl));
4901
tbl.table_name= tbl.alias= tmp_name;
4902
/* Table is in thd->temporary_tables */
4903
new_table= open_table(thd, &tbl, thd->mem_root, (bool*) 0,
4904
MYSQL_LOCK_IGNORE_FLUSH);
4908
char path[FN_REFLEN];
4909
/* table is a normal table: Create temporary table in same directory */
4910
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
4912
/* Open our intermediate table */
4913
new_table=open_temporary_table(thd, path, new_db, tmp_name, 0, OTM_OPEN);
4918
/* Copy the data if necessary. */
4919
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
4920
thd->cuted_fields=0L;
4921
thd_proc_info(thd, "copy to tmp table");
4924
We do not copy data for MERGE tables. Only the children have data.
4925
MERGE tables have HA_NO_COPY_ON_ALTER set.
4927
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
4929
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
4930
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
4931
new_table->next_number_field=new_table->found_next_number_field;
4932
error= copy_data_between_tables(table, new_table,
4933
alter_info->create_list, ignore,
4934
order_num, order, &copied, &deleted,
4935
alter_info->keys_onoff,
4936
alter_info->error_if_not_empty);
4940
VOID(pthread_mutex_lock(&LOCK_open));
4941
wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
4942
VOID(pthread_mutex_unlock(&LOCK_open));
4943
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
4944
alter_info->keys_onoff);
4945
error= ha_autocommit_or_rollback(thd, 0);
4946
if (end_active_trans(thd))
4949
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
4951
if (table->s->tmp_table != NO_TMP_TABLE)
4953
/* We changed a temporary table */
4956
/* Close lock if this is a transactional table */
4959
mysql_unlock_tables(thd, thd->lock);
4962
/* Remove link to old table and rename the new one */
4963
close_temporary_table(thd, table, 1, 1);
4964
/* Should pass the 'new_name' as we store table name in the cache */
4965
if (rename_temporary_table(thd, new_table, new_db, new_name))
4967
/* We don't replicate alter table statement on temporary tables */
4968
if (!thd->current_stmt_binlog_row_based)
4969
write_bin_log(thd, true, thd->query, thd->query_length);
4976
Close the intermediate table that will be the new table.
4977
Note that MERGE tables do not have their children attached here.
4979
intern_close_table(new_table);
4980
my_free(new_table,MYF(0));
4982
VOID(pthread_mutex_lock(&LOCK_open));
4985
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
4986
VOID(pthread_mutex_unlock(&LOCK_open));
4991
Data is copied. Now we:
4992
1) Wait until all other threads close old version of table.
4993
2) Close instances of table open by this thread and replace them
4994
with exclusive name-locks.
4995
3) Rename the old table to a temp name, rename the new one to the
4997
4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME
4998
we reopen new version of table.
4999
5) Write statement to the binary log.
5000
6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we
5001
remove name-locks from list of open tables and table cache.
5002
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
5003
call to remove name-locks from table cache and list of open table.
5006
thd_proc_info(thd, "rename result table");
5007
snprintf(old_name, sizeof(old_name), "%s2-%lx-%lx", tmp_file_prefix,
5008
current_pid, thd->thread_id);
5009
if (lower_case_table_names)
5010
my_casedn_str(files_charset_info, old_name);
5012
wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME);
5013
close_data_files_and_morph_locks(thd, db, table_name);
5016
save_old_db_type= old_db_type;
5019
This leads to the storage engine (SE) not being notified for renames in
5020
mysql_rename_table(), because we just juggle with the FRM and nothing
5021
more. If we have an intermediate table, then we notify the SE that
5022
it should become the actual table. Later, we will recycle the old table.
5023
However, in case of ALTER TABLE RENAME there might be no intermediate
5024
table. This is when the old and new tables are compatible, according to
5025
compare_table(). Then, we need one additional call to
5026
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
5027
actual rename in the SE and the FRM is not touched. Note that, if the
5028
table is renamed and the SE is also changed, then an intermediate table
5029
is created and the additional call will not take place.
5031
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
5035
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
5037
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
5038
new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
5040
/* Try to get everything back. */
5042
VOID(quick_rm_table(new_db_type,new_db,new_alias, 0));
5043
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
5044
VOID(mysql_rename_table(old_db_type, db, old_name, db, alias,
5050
/* This shouldn't happen. But let us play it safe. */
5051
goto err_with_placeholders;
5054
VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP));
5057
if (thd->locked_tables && new_name == table_name && new_db == db)
5059
thd->in_lock_tables= 1;
5060
error= reopen_tables(thd, 1, 1);
5061
thd->in_lock_tables= 0;
5063
goto err_with_placeholders;
5065
VOID(pthread_mutex_unlock(&LOCK_open));
5067
thd_proc_info(thd, "end");
5069
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
5070
thd->query, thd->query_length,
5073
assert(!(mysql_bin_log.is_open() &&
5074
thd->current_stmt_binlog_row_based &&
5075
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
5076
write_bin_log(thd, true, thd->query, thd->query_length);
5078
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
5081
For the alter table to be properly flushed to the logs, we
5082
have to open the new table. If not, we get a problem on server
5083
shutdown. But we do not need to attach MERGE children.
5085
char path[FN_REFLEN];
5087
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
5088
t_table= open_temporary_table(thd, path, new_db, tmp_name, false, OTM_OPEN);
5091
intern_close_table(t_table);
5092
my_free(t_table, MYF(0));
5095
sql_print_warning("Could not open table %s.%s after rename\n",
5097
ha_flush_logs(old_db_type);
5099
table_list->table=0; // For query cache
5101
if (thd->locked_tables && (new_name != table_name || new_db != db))
5104
If are we under LOCK TABLES and did ALTER TABLE with RENAME we need
5105
to remove placeholders for the old table and for the target table
5106
from the list of open tables and table cache. If we are not under
5107
LOCK TABLES we can rely on close_thread_tables() doing this job.
5109
pthread_mutex_lock(&LOCK_open);
5110
unlink_open_table(thd, table, false);
5111
unlink_open_table(thd, name_lock, false);
5112
pthread_mutex_unlock(&LOCK_open);
5116
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
5117
(ulong) (copied + deleted), (ulong) deleted,
5118
(ulong) thd->cuted_fields);
5119
my_ok(thd, copied + deleted, 0L, tmp_name);
5120
thd->some_tables_deleted=0;
5126
/* close_temporary_table() frees the new_table pointer. */
5127
close_temporary_table(thd, new_table, 1, 1);
5130
VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP));
5134
No default value was provided for a DATE/DATETIME field, the
5135
current sql_mode doesn't allow the '0000-00-00' value and
5136
the table to be altered isn't empty.
5139
if (alter_info->error_if_not_empty && thd->row_count)
5141
const char *f_val= 0;
5142
enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
5143
switch (alter_info->datetime_field->sql_type)
5145
case DRIZZLE_TYPE_NEWDATE:
5146
f_val= "0000-00-00";
5147
t_type= MYSQL_TIMESTAMP_DATE;
5149
case DRIZZLE_TYPE_DATETIME:
5150
f_val= "0000-00-00 00:00:00";
5151
t_type= MYSQL_TIMESTAMP_DATETIME;
5154
/* Shouldn't get here. */
5157
bool save_abort_on_warning= thd->abort_on_warning;
5158
thd->abort_on_warning= true;
5159
make_truncated_value_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
5160
f_val, strlength(f_val), t_type,
5161
alter_info->datetime_field->field_name);
5162
thd->abort_on_warning= save_abort_on_warning;
5166
pthread_mutex_lock(&LOCK_open);
5167
unlink_open_table(thd, name_lock, false);
5168
pthread_mutex_unlock(&LOCK_open);
5172
err_with_placeholders:
5174
An error happened while we were holding exclusive name-lock on table
5175
being altered. To be safe under LOCK TABLES we should remove placeholders
5176
from list of open tables list and table cache.
5178
unlink_open_table(thd, table, false);
5180
unlink_open_table(thd, name_lock, false);
5181
VOID(pthread_mutex_unlock(&LOCK_open));
5184
/* mysql_alter_table */
5187
copy_data_between_tables(TABLE *from,TABLE *to,
5188
List<Create_field> &create,
5190
uint order_num, ORDER *order,
5193
enum enum_enable_or_disable keys_onoff,
5194
bool error_if_not_empty)
5197
Copy_field *copy,*copy_end;
5198
ulong found_count,delete_count;
5199
THD *thd= current_thd;
5201
SORT_FIELD *sortorder;
5205
List<Item> all_fields;
5206
ha_rows examined_rows;
5207
bool auto_increment_field_copied= 0;
5208
ulong save_sql_mode;
5209
uint64_t prev_insert_id;
5212
Turn off recovery logging since rollback of an alter table is to
5213
delete the new table so there is no need to log the changes to it.
5215
This needs to be done before external_lock
5217
error= ha_enable_transaction(thd, false);
5221
if (!(copy= new Copy_field[to->s->fields]))
5222
return(-1); /* purecov: inspected */
5224
if (to->file->ha_external_lock(thd, F_WRLCK))
5227
/* We need external lock before we can disable/enable keys */
5228
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
5230
/* We can abort alter table for any table type */
5231
thd->abort_on_warning= !ignore;
5233
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5234
to->file->ha_start_bulk_insert(from->file->stats.records);
5236
save_sql_mode= thd->variables.sql_mode;
5238
List_iterator<Create_field> it(create);
5241
for (Field **ptr=to->field ; *ptr ; ptr++)
5246
if (*ptr == to->next_number_field)
5248
auto_increment_field_copied= true;
5250
If we are going to copy contents of one auto_increment column to
5251
another auto_increment column it is sensible to preserve zeroes.
5252
This condition also covers case when we are don't actually alter
5253
auto_increment column.
5255
if (def->field == from->found_next_number_field)
5256
thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO;
5258
(copy_end++)->set(*ptr,def->field,0);
5263
found_count=delete_count=0;
5267
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
5269
char warn_buff[MYSQL_ERRMSG_SIZE];
5270
snprintf(warn_buff, sizeof(warn_buff),
5271
"ORDER BY ignored as there is a user-defined clustered index"
5272
" in the table '%-.192s'", from->s->table_name.str);
5273
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
5278
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
5279
MYF(MY_FAE | MY_ZEROFILL));
5280
bzero((char *) &tables, sizeof(tables));
5282
tables.alias= tables.table_name= from->s->table_name.str;
5283
tables.db= from->s->db.str;
5286
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
5287
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
5288
&tables, fields, all_fields, order) ||
5289
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
5290
(from->sort.found_records= filesort(thd, from, sortorder, length,
5291
(SQL_SELECT *) 0, HA_POS_ERROR,
5292
1, &examined_rows)) ==
5298
/* Tell handler that we have values for all columns in the to table */
5299
to->use_all_columns();
5300
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1);
5302
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
5304
restore_record(to, s->default_values); // Create empty record
5305
while (!(error=info.read_record(&info)))
5309
thd->send_kill_message();
5314
/* Return error if source table isn't empty. */
5315
if (error_if_not_empty)
5320
if (to->next_number_field)
5322
if (auto_increment_field_copied)
5323
to->auto_increment_field_not_null= true;
5325
to->next_number_field->reset();
5328
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
5330
copy_ptr->do_copy(copy_ptr);
5332
prev_insert_id= to->file->next_insert_id;
5333
error=to->file->ha_write_row(to->record[0]);
5334
to->auto_increment_field_not_null= false;
5338
to->file->is_fatal_error(error, HA_CHECK_DUP))
5340
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
5342
uint key_nr= to->file->get_dup_key(error);
5343
if ((int) key_nr >= 0)
5345
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
5347
(to->key_info[0].key_part[0].field->flags &
5348
AUTO_INCREMENT_FLAG))
5349
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
5350
to->file->print_keydup_error(key_nr, err_msg);
5355
to->file->print_error(error,MYF(0));
5358
to->file->restore_auto_increment(prev_insert_id);
5364
end_read_record(&info);
5365
free_io_cache(from);
5366
delete [] copy; // This is never 0
5368
if (to->file->ha_end_bulk_insert() && error <= 0)
5370
to->file->print_error(my_errno,MYF(0));
5373
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
5375
if (ha_enable_transaction(thd, true))
5382
Ensure that the new table is saved properly to disk so that we
5385
if (ha_autocommit_or_rollback(thd, 0))
5387
if (end_active_trans(thd))
5391
thd->variables.sql_mode= save_sql_mode;
5392
thd->abort_on_warning= 0;
5393
free_io_cache(from);
5394
*copied= found_count;
5395
*deleted=delete_count;
5396
to->file->ha_release_auto_increment();
5397
if (to->file->ha_external_lock(thd,F_UNLCK))
5399
return(error > 0 ? -1 : 0);
5404
Recreates tables by calling mysql_alter_table().
5407
mysql_recreate_table()
5409
tables Tables to recreate
5412
Like mysql_alter_table().
5414
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
5416
HA_CREATE_INFO create_info;
5417
Alter_info alter_info;
5419
assert(!table_list->next_global);
5421
table_list->table has been closed and freed. Do not reference
5422
uninitialized data. open_tables() could fail.
5424
table_list->table= NULL;
5426
bzero((char*) &create_info, sizeof(create_info));
5427
create_info.row_type=ROW_TYPE_NOT_USED;
5428
create_info.default_table_charset=default_charset_info;
5429
/* Force alter table to recreate table */
5430
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
5431
return(mysql_alter_table(thd, NullS, NullS, &create_info,
5432
table_list, &alter_info, 0,
5437
bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
5438
HA_CHECK_OPT *check_opt)
2485
&Cursor::ha_check));
2489
bool mysql_checksum_table(Session *session, TableList *tables,
5441
2493
List<Item> field_list;
5443
Protocol *protocol= thd->protocol;
5445
2496
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
5446
2497
item->maybe_null= 1;
5447
2498
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
5448
2499
MY_INT64_NUM_DECIMAL_DIGITS));
5449
2500
item->maybe_null= 1;
5450
if (protocol->send_fields(&field_list,
5451
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2501
if (session->client->sendFields(&field_list))
5454
2504
/* Open one table after the other to keep lock time as short as possible. */
5455
2505
for (table= tables; table; table= table->next_local)
5457
2507
char table_name[NAME_LEN*2+2];
5460
strxmov(table_name, table->db ,".", table->table_name, NullS);
5462
t= table->table= open_n_lock_single_table(thd, table, TL_READ);
5463
thd->clear_error(); // these errors shouldn't get client
5465
protocol->prepare_for_resend();
5466
protocol->store(table_name, system_charset_info);
2510
sprintf(table_name,"%s.%s",table->db,table->table_name);
2512
t= table->table= session->openTableLock(table, TL_READ);
2513
session->clear_error(); // these errors shouldn't get client
2515
session->client->store(table_name);
5470
2519
/* Table didn't exist */
5471
protocol->store_null();
2520
session->client->store();
2521
session->clear_error();
5476
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
5477
!(check_opt->flags & T_EXTEND))
5478
protocol->store((uint64_t)t->file->checksum());
5479
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
5480
(check_opt->flags & T_QUICK))
5481
protocol->store_null();
2526
@note if the engine keeps a checksum then we return the checksum, otherwise we calculate
2528
if (t->cursor->getEngine()->check_flag(HTON_BIT_HAS_CHECKSUM))
2530
session->client->store((uint64_t)t->cursor->checksum());
5484
2534
/* calculating table's checksum */
5485
2535
ha_checksum crc= 0;
5486
uchar null_mask=256 - (1 << t->s->last_null_bit_pos);
2536
unsigned char null_mask=256 - (1 << t->s->last_null_bit_pos);
5488
2538
t->use_all_columns();
5490
if (t->file->ha_rnd_init(1))
5491
protocol->store_null();
2540
if (t->cursor->ha_rnd_init(1))
2541
session->client->store();
5496
2546
ha_checksum row_crc= 0;
5497
int error= t->file->rnd_next(t->record[0]);
2547
int error= t->cursor->rnd_next(t->record[0]);
5498
2548
if (unlikely(error))
5500
2550
if (error == HA_ERR_RECORD_DELETED)