2264
3142
return(mysql_admin_table(session, tables, check_opt,
2265
3143
"check", lock_type,
2267
&Cursor::ha_check));
3144
0, 0, HA_OPEN_FOR_REPAIR, 0,
3145
&handler::ha_check));
3149
/* table_list should contain just one table */
3151
mysql_discard_or_import_tablespace(Session *session,
3152
TableList *table_list,
3153
enum tablespace_op_type tablespace_op)
3160
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
3164
session->set_proc_info("discard_or_import_tablespace");
3166
discard= test(tablespace_op == DISCARD_TABLESPACE);
3169
We set this flag so that ha_innobase::open and ::external_lock() do
3170
not complain when we lock the table
3172
session->tablespace_op= true;
3173
if (!(table=open_ltable(session, table_list, TL_WRITE, 0)))
3175
session->tablespace_op=false;
3179
error= table->file->ha_discard_or_import_tablespace(discard);
3181
session->set_proc_info("end");
3186
/* The ALTER Table is always in its own transaction */
3187
error = ha_autocommit_or_rollback(session, 0);
3188
if (end_active_trans(session))
3192
write_bin_log(session, false, session->query, session->query_length);
3195
ha_autocommit_or_rollback(session, error);
3196
session->tablespace_op=false;
3204
table->file->print_error(error, MYF(0));
3210
Copy all changes detected by parser to the HA_ALTER_FLAGS
3213
void setup_ha_alter_flags(Alter_info *alter_info, HA_ALTER_FLAGS *alter_flags)
3215
uint32_t flags= alter_info->flags;
3217
if (ALTER_ADD_COLUMN & flags)
3218
*alter_flags|= HA_ADD_COLUMN;
3219
if (ALTER_DROP_COLUMN & flags)
3220
*alter_flags|= HA_DROP_COLUMN;
3221
if (ALTER_RENAME & flags)
3222
*alter_flags|= HA_RENAME_TABLE;
3223
if (ALTER_CHANGE_COLUMN & flags)
3224
*alter_flags|= HA_CHANGE_COLUMN;
3225
if (ALTER_COLUMN_DEFAULT & flags)
3226
*alter_flags|= HA_COLUMN_DEFAULT_VALUE;
3227
if (ALTER_COLUMN_STORAGE & flags)
3228
*alter_flags|= HA_COLUMN_STORAGE;
3229
if (ALTER_COLUMN_FORMAT & flags)
3230
*alter_flags|= HA_COLUMN_FORMAT;
3231
if (ALTER_COLUMN_ORDER & flags)
3232
*alter_flags|= HA_ALTER_COLUMN_ORDER;
3233
if (ALTER_STORAGE & flags)
3234
*alter_flags|= HA_ALTER_STORAGE;
3235
if (ALTER_ROW_FORMAT & flags)
3236
*alter_flags|= HA_ALTER_ROW_FORMAT;
3237
if (ALTER_RECREATE & flags)
3238
*alter_flags|= HA_RECREATE;
3239
if (ALTER_FOREIGN_KEY & flags)
3240
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3245
@param session Thread
3246
@param table The original table.
3247
@param alter_info Alter options, fields and keys for the new
3249
@param create_info Create options for the new table.
3250
@param order_num Number of order list elements.
3251
@param[out] ha_alter_flags Flags that indicate what will be changed
3252
@param[out] ha_alter_info Data structures needed for on-line alter
3253
@param[out] table_changes Information about particular change
3255
First argument 'table' contains information of the original
3256
table, which includes all corresponding parts that the new
3257
table has in arguments create_list, key_list and create_info.
3259
By comparing the changes between the original and new table
3260
we can determine how much it has changed after ALTER Table
3261
and whether we need to make a copy of the table, or just change
3264
Mark any changes detected in the ha_alter_flags.
3266
If there are no data changes, but index changes, 'index_drop_buffer'
3267
and/or 'index_add_buffer' are populated with offsets into
3268
table->key_info or key_info_buffer respectively for the indexes
3269
that need to be dropped and/or (re-)created.
3272
@retval false success
3277
compare_tables(Session *session,
3279
Alter_info *alter_info,
3280
HA_CREATE_INFO *create_info,
3282
HA_ALTER_FLAGS *alter_flags,
3283
HA_ALTER_INFO *ha_alter_info,
3284
uint32_t *table_changes)
3286
Field **f_ptr, *field;
3287
uint32_t table_changes_local= 0;
3288
List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3289
Create_field *new_field;
3290
KEY_PART_INFO *key_part;
3295
Create a copy of alter_info.
3296
To compare the new and old table definitions, we need to "prepare"
3297
the new definition - transform it from parser output to a format
3298
that describes the final table layout (all column defaults are
3299
initialized, duplicate columns are removed). This is done by
3300
mysql_prepare_create_table. Unfortunately,
3301
mysql_prepare_create_table performs its transformations
3302
"in-place", that is, modifies the argument. Since we would
3303
like to keep compare_tables() idempotent (not altering any
3304
of the arguments) we create a copy of alter_info here and
3305
pass it to mysql_prepare_create_table, then use the result
3306
to evaluate possibility of fast ALTER Table, and then
3309
Alter_info tmp_alter_info(*alter_info, session->mem_root);
3310
session= table->in_use;
3311
uint32_t db_options= 0; /* not used */
3312
/* Create the prepared information. */
3313
if (mysql_prepare_create_table(session, create_info,
3315
(table->s->tmp_table != NO_TMP_TABLE),
3318
&ha_alter_info->key_info_buffer,
3319
&ha_alter_info->key_count,
3320
/* select_field_count */ 0))
3322
/* Allocate result buffers. */
3323
if (! (ha_alter_info->index_drop_buffer=
3324
(uint*) session->alloc(sizeof(uint32_t) * table->s->keys)) ||
3325
! (ha_alter_info->index_add_buffer=
3326
(uint*) session->alloc(sizeof(uint32_t) *
3327
tmp_alter_info.key_list.elements)))
3331
First we setup ha_alter_flags based on what was detected
3334
setup_ha_alter_flags(alter_info, alter_flags);
3338
Some very basic checks. If number of fields changes, or the
3339
handler, we need to run full ALTER Table. In the future
3340
new fields can be added and old dropped without copy, but
3343
Test also that engine was not given during ALTER Table, or
3344
we are force to run regular alter table (copy).
3345
E.g. ALTER Table tbl_name ENGINE=MyISAM.
3347
For the following ones we also want to run regular alter table:
3348
ALTER Table tbl_name order_st BY ..
3349
ALTER Table tbl_name CONVERT TO CHARACTER SET ..
3351
At the moment we can't handle altering temporary tables without a copy.
3352
We also test if OPTIMIZE Table was given and was mapped to alter table.
3353
In that case we always do full copy.
3355
There was a bug prior to mysql-4.0.25. Number of null fields was
3356
calculated incorrectly. As a result frm and data files gets out of
3357
sync after fast alter table. There is no way to determine by which
3358
mysql version (in 4.0 and 4.1 branches) table was created, thus we
3359
disable fast alter table for all tables created by mysql versions
3360
prior to 5.0 branch.
3363
if (table->s->fields != alter_info->create_list.elements ||
3364
table->s->db_type() != create_info->db_type ||
3365
table->s->tmp_table ||
3366
create_info->used_fields & HA_CREATE_USED_ENGINE ||
3367
create_info->used_fields & HA_CREATE_USED_CHARSET ||
3368
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3369
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3370
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3372
!table->s->mysql_version)
3374
*table_changes= IS_EQUAL_NO;
3376
Check what has changed and set alter_flags
3378
if (table->s->fields < alter_info->create_list.elements)
3379
*alter_flags|= HA_ADD_COLUMN;
3380
else if (table->s->fields > alter_info->create_list.elements)
3381
*alter_flags|= HA_DROP_COLUMN;
3382
if (create_info->db_type != table->s->db_type() ||
3383
create_info->used_fields & HA_CREATE_USED_ENGINE)
3384
*alter_flags|= HA_ALTER_STORAGE_ENGINE;
3385
if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3386
*alter_flags|= HA_CHANGE_CHARACTER_SET;
3387
if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3388
*alter_flags|= HA_SET_DEFAULT_CHARACTER_SET;
3389
if (alter_info->flags & ALTER_RECREATE)
3390
*alter_flags|= HA_RECREATE;
3391
/* TODO check for ADD/DROP FOREIGN KEY */
3392
if (alter_info->flags & ALTER_FOREIGN_KEY)
3393
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3396
Go through fields and check if the original ones are compatible
3399
for (f_ptr= table->field, new_field= new_field_it++;
3400
(new_field && (field= *f_ptr));
3401
f_ptr++, new_field= new_field_it++)
3403
/* Make sure we have at least the default charset in use. */
3404
if (!new_field->charset)
3405
new_field->charset= create_info->default_table_charset;
3407
/* Don't pack rows in old tables if the user has requested this. */
3408
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3409
(new_field->flags & BLOB_FLAG) ||
3410
(new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3411
create_info->table_options|= HA_OPTION_PACK_RECORD;
3413
/* Check how fields have been modified */
3414
if (alter_info->flags & ALTER_CHANGE_COLUMN)
3416
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
3417
if (!(table_changes_local= field->is_equal(new_field)))
3418
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3421
Check if the altered column is a stored virtual field.
3422
TODO: Mark such a column with an alter flag only if
3423
the expression functions are not equal.
3425
if (field->is_stored && field->vcol_info)
3426
*alter_flags|= HA_ALTER_STORED_VCOL;
3428
/* Check if field was renamed */
3429
field->flags&= ~FIELD_IS_RENAMED;
3430
if (my_strcasecmp(system_charset_info,
3432
new_field->field_name))
3434
field->flags|= FIELD_IS_RENAMED;
3435
*alter_flags|= HA_ALTER_COLUMN_NAME;
3438
*table_changes&= table_changes_local;
3439
if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3440
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3442
/* Check that NULL behavior is same for old and new fields */
3443
if ((new_field->flags & NOT_NULL_FLAG) !=
3444
(uint32_t) (field->flags & NOT_NULL_FLAG))
3446
*table_changes= IS_EQUAL_NO;
3447
*alter_flags|= HA_ALTER_COLUMN_NULLABLE;
3451
/* Clear indexed marker */
3452
field->flags&= ~FIELD_IN_ADD_INDEX;
3456
Go through keys and check if the original ones are compatible
3460
KEY *table_key_end= table->key_info + table->s->keys;
3463
ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3466
Step through all keys of the old table and search matching new keys.
3468
ha_alter_info->index_drop_count= 0;
3469
ha_alter_info->index_add_count= 0;
3470
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3472
KEY_PART_INFO *table_part;
3473
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3474
KEY_PART_INFO *new_part;
3476
/* Search a new key with the same name. */
3477
for (new_key= ha_alter_info->key_info_buffer;
3478
new_key < new_key_end;
3481
if (! strcmp(table_key->name, new_key->name))
3484
if (new_key >= new_key_end)
3486
/* Key not found. Add the offset of the key to the drop buffer. */
3487
ha_alter_info->index_drop_buffer
3488
[ha_alter_info->index_drop_count++]=
3489
table_key - table->key_info;
3490
if (table_key->flags & HA_NOSAME)
3492
/* Unique key. Check for "PRIMARY". */
3493
if (is_primary_key(table_key))
3494
*alter_flags|= HA_DROP_PK_INDEX;
3496
*alter_flags|= HA_DROP_UNIQUE_INDEX;
3499
*alter_flags|= HA_DROP_INDEX;
3500
*table_changes= IS_EQUAL_NO;
3504
/* Check that the key types are compatible between old and new tables. */
3505
if ((table_key->algorithm != new_key->algorithm) ||
3506
((table_key->flags & HA_KEYFLAG_MASK) !=
3507
(new_key->flags & HA_KEYFLAG_MASK)) ||
3508
(table_key->key_parts != new_key->key_parts))
3510
if (table_key->flags & HA_NOSAME)
3512
// Unique key. Check for "PRIMARY".
3513
if (is_primary_key(table_key))
3514
*alter_flags|= HA_ALTER_PK_INDEX;
3516
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3519
*alter_flags|= HA_ALTER_INDEX;
3524
Check that the key parts remain compatible between the old and
3527
for (table_part= table_key->key_part, new_part= new_key->key_part;
3528
table_part < table_part_end;
3529
table_part++, new_part++)
3532
Key definition has changed if we are using a different field or
3533
if the used key part length is different. We know that the fields
3534
did not change. Comparing field numbers is sufficient.
3536
if ((table_part->length != new_part->length) ||
3537
(table_part->fieldnr - 1 != new_part->fieldnr))
3539
if (table_key->flags & HA_NOSAME)
3541
/* Unique key. Check for "PRIMARY" */
3542
if (is_primary_key(table_key))
3543
*alter_flags|= HA_ALTER_PK_INDEX;
3545
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3548
*alter_flags|= HA_ALTER_INDEX;
3555
/* Key modified. Add the offset of the key to both buffers. */
3556
ha_alter_info->index_drop_buffer
3557
[ha_alter_info->index_drop_count++]=
3558
table_key - table->key_info;
3559
ha_alter_info->index_add_buffer
3560
[ha_alter_info->index_add_count++]=
3561
new_key - ha_alter_info->key_info_buffer;
3562
key_part= new_key->key_part;
3563
end= key_part + new_key->key_parts;
3564
for(; key_part != end; key_part++)
3566
/* Mark field to be part of new key */
3567
if ((field= table->field[key_part->fieldnr]))
3568
field->flags|= FIELD_IN_ADD_INDEX;
3570
*table_changes= IS_EQUAL_NO;
3572
/*end of for (; table_key < table_key_end;) */
3575
Step through all keys of the new table and find matching old keys.
3577
for (new_key= ha_alter_info->key_info_buffer;
3578
new_key < new_key_end;
3581
/* Search an old key with the same name. */
3582
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3584
if (! strcmp(table_key->name, new_key->name))
3587
if (table_key >= table_key_end)
3589
/* Key not found. Add the offset of the key to the add buffer. */
3590
ha_alter_info->index_add_buffer
3591
[ha_alter_info->index_add_count++]=
3592
new_key - ha_alter_info->key_info_buffer;
3593
key_part= new_key->key_part;
3594
end= key_part + new_key->key_parts;
3595
for(; key_part != end; key_part++)
3597
/* Mark field to be part of new key */
3598
if ((field= table->field[key_part->fieldnr]))
3599
field->flags|= FIELD_IN_ADD_INDEX;
3601
if (new_key->flags & HA_NOSAME)
3603
/* Unique key. Check for "PRIMARY" */
3604
if (is_primary_key(new_key))
3605
*alter_flags|= HA_ADD_PK_INDEX;
3607
*alter_flags|= HA_ADD_UNIQUE_INDEX;
3610
*alter_flags|= HA_ADD_INDEX;
3611
*table_changes= IS_EQUAL_NO;
3620
Manages enabling/disabling of indexes for ALTER Table
3623
alter_table_manage_keys()
3625
indexes_were_disabled Whether the indexes of the from table
3627
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
3635
bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
3636
enum enum_enable_or_disable keys_onoff)
3639
switch (keys_onoff) {
3641
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3644
if (!indexes_were_disabled)
3646
/* fall-through: disabled indexes */
3648
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3651
if (error == HA_ERR_WRONG_COMMAND)
3653
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3654
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3655
table->s->table_name.str);
3658
table->file->print_error(error, MYF(0));
3663
int create_temporary_table(Session *session,
3667
HA_CREATE_INFO *create_info,
3668
Alter_info *alter_info,
3672
char index_file[FN_REFLEN], data_file[FN_REFLEN];
3673
handlerton *old_db_type, *new_db_type;
3674
old_db_type= table->s->db_type();
3675
new_db_type= create_info->db_type;
3677
Handling of symlinked tables:
3679
Create new data file and index file on the same disk as the
3680
old data and index files.
3682
Rename new data file over old data file and new index file over
3684
Symlinks are not changed.
3687
Create new data file and index file on the same disk as the
3688
old data and index files. Create also symlinks to point at
3691
At end, rename intermediate tables, and symlinks to intermediate
3692
table, to final table name.
3693
Remove old table and old symlinks
3695
If rename is made to another database:
3696
Create new tables in new database.
3698
Remove old table and symlinks.
3700
if (db_changed) // Ignore symlink if db changed
3702
if (create_info->index_file_name)
3704
/* Fix index_file_name to have 'tmp_name' as basename */
3705
strcpy(index_file, tmp_name);
3706
create_info->index_file_name=fn_same(index_file,
3707
create_info->index_file_name,
3710
if (create_info->data_file_name)
3712
/* Fix data_file_name to have 'tmp_name' as basename */
3713
strcpy(data_file, tmp_name);
3714
create_info->data_file_name=fn_same(data_file,
3715
create_info->data_file_name,
3720
create_info->data_file_name=create_info->index_file_name=0;
3723
Create a table with a temporary name.
3724
We don't log the statement, it will be logged later.
3726
error= mysql_create_table(session, new_db, tmp_name,
3727
create_info, alter_info, 1, 0);
3733
Create a temporary table that reflects what an alter table operation
3737
create_altered_table()
3738
session Thread handle
3739
table The original table
3740
create_info Information from the parsing phase about new
3742
alter_info Lists of fields, keys to be changed, added
3744
db_change Specifies if the table is moved to another database
3746
A temporary table with all changes
3749
The temporary table is created without storing it in any storage engine
3750
and is opened only to get the table struct and frm file reference.
3752
Table *create_altered_table(Session *session,
3755
HA_CREATE_INFO *create_info,
3756
Alter_info *alter_info,
3760
HA_CREATE_INFO altered_create_info(*create_info);
3761
Table *altered_table;
3763
char path[FN_REFLEN];
3765
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64,
3766
TMP_FILE_PREFIX, (unsigned long)current_pid, session->thread_id);
3767
/* Safety fix for InnoDB */
3768
if (lower_case_table_names)
3769
my_casedn_str(files_charset_info, tmp_name);
3770
altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3772
if ((error= create_temporary_table(session, table, new_db, tmp_name,
3773
&altered_create_info,
3774
alter_info, db_change)))
3779
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3781
altered_table= open_temporary_table(session, path, new_db, tmp_name, 1,
3783
return(altered_table);
3790
Perform a fast or on-line alter table
3793
mysql_fast_or_online_alter_table()
3794
session Thread handle
3795
table The original table
3796
altered_table A temporary table showing how we will change table
3797
create_info Information from the parsing phase about new
3799
alter_info Storage place for data used during different phases
3800
ha_alter_flags Bitmask that shows what will be changed
3801
keys_onoff Specifies if keys are to be enabled/disabled
3804
>0 An error occured during the on-line alter table operation
3805
-1 Error when re-opening table
3807
If mysql_alter_table does not need to copy the table, it is
3808
either a fast alter table where the storage engine does not
3809
need to know about the change, only the frm will change,
3810
or the storage engine supports performing the alter table
3811
operation directly, on-line without mysql having to copy
3814
int mysql_fast_or_online_alter_table(Session *session,
3816
Table *altered_table,
3817
HA_CREATE_INFO *create_info,
3818
HA_ALTER_INFO *alter_info,
3819
HA_ALTER_FLAGS *ha_alter_flags,
3820
enum enum_enable_or_disable keys_onoff)
3823
bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3829
Tell the handler to prepare for the online alter
3831
if ((error= table->file->alter_table_phase1(session,
3841
Tell the storage engine to perform the online alter table
3843
if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3844
we need to wrap the next call with a DDL lock.
3846
if ((error= table->file->alter_table_phase2(session,
3856
The final .frm file is already created as a temporary file
3857
and will be renamed to the original table name.
3859
pthread_mutex_lock(&LOCK_open);
3860
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3861
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3863
close_data_files_and_morph_locks(session,
3864
table->pos_in_table_list->db,
3865
table->pos_in_table_list->table_name);
3866
if (mysql_rename_table(NULL,
3867
altered_table->s->db.str,
3868
altered_table->s->table_name.str,
3870
table->s->table_name.str, FN_FROM_IS_TMP))
3873
pthread_mutex_unlock(&LOCK_open);
3876
broadcast_refresh();
3877
pthread_mutex_unlock(&LOCK_open);
3880
The ALTER Table is always in its own transaction.
3881
Commit must not be called while LOCK_open is locked. It could call
3882
wait_if_global_read_lock(), which could create a deadlock if called
3885
error= ha_autocommit_or_rollback(session, 0);
3887
if (ha_commit(session))
3893
pthread_mutex_lock(&LOCK_open);
3894
if (reopen_table(table))
3899
pthread_mutex_unlock(&LOCK_open);
3903
Tell the handler that the changed frm is on disk and table
3906
if ((error= t_table->file->alter_table_phase3(session, t_table)))
3912
We are going to reopen table down on the road, so we have to restore
3913
state of the Table object which we used for obtaining of handler
3914
object to make it suitable for reopening.
3916
assert(t_table == table);
3917
table->open_placeholder= 1;
3918
pthread_mutex_lock(&LOCK_open);
3919
close_handle_and_leave_table_as_lock(table);
3920
pthread_mutex_unlock(&LOCK_open);
3931
Prepare column and key definitions for CREATE TABLE in ALTER Table.
3933
This function transforms parse output of ALTER Table - lists of
3934
columns and keys to add, drop or modify into, essentially,
3935
CREATE TABLE definition - a list of columns and keys of the new
3936
table. While doing so, it also performs some (bug not all)
3939
This function is invoked when we know that we're going to
3940
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
3941
is not possible, perhaps because the ALTER statement contains
3942
instructions that require change in table data, not only in
3943
table definition or indexes.
3945
@param[in,out] session thread handle. Used as a memory pool
3946
and source of environment information.
3947
@param[in] table the source table, open and locked
3948
Used as an interface to the storage engine
3949
to acquire additional information about
3951
@param[in,out] create_info A blob with CREATE/ALTER Table
3953
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
3954
Originally create_info was used only in
3955
CREATE TABLE and alter_info only in ALTER Table.
3956
But since ALTER might end-up doing CREATE,
3957
this distinction is gone and we just carry
3958
around two structures.
3961
Fills various create_info members based on information retrieved
3962
from the storage engine.
3963
Sets create_info->varchar if the table has a VARCHAR column.
3964
Prepares alter_info->create_list and alter_info->key_list with
3965
columns and keys of the new table.
3966
@retval true error, out of memory or a semantical error in ALTER
3968
@retval false success
3972
mysql_prepare_alter_table(Session *session, Table *table,
3973
HA_CREATE_INFO *create_info,
3974
Alter_info *alter_info)
3976
/* New column definitions are added here */
3977
List<Create_field> new_create_list;
3978
/* New key definitions are added here */
3979
List<Key> new_key_list;
3980
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
3981
List_iterator<Create_field> def_it(alter_info->create_list);
3982
List_iterator<Alter_column> alter_it(alter_info->alter_list);
3983
List_iterator<Key> key_it(alter_info->key_list);
3984
List_iterator<Create_field> find_it(new_create_list);
3985
List_iterator<Create_field> field_it(new_create_list);
3986
List<Key_part_spec> key_parts;
3987
uint32_t db_create_options= (table->s->db_create_options
3988
& ~(HA_OPTION_PACK_RECORD));
3989
uint32_t used_fields= create_info->used_fields;
3990
KEY *key_info=table->key_info;
3994
create_info->varchar= false;
3995
/* Let new create options override the old ones */
3996
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
3997
create_info->min_rows= table->s->min_rows;
3998
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
3999
create_info->max_rows= table->s->max_rows;
4000
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
4001
create_info->avg_row_length= table->s->avg_row_length;
4002
if (!(used_fields & HA_CREATE_USED_BLOCK_SIZE))
4003
create_info->block_size= table->s->block_size;
4004
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
4005
create_info->default_table_charset= table->s->table_charset;
4006
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
4008
/* Table has an autoincrement, copy value to new table */
4009
table->file->info(HA_STATUS_AUTO);
4010
create_info->auto_increment_value= table->file->stats.auto_increment_value;
4012
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
4013
create_info->key_block_size= table->s->key_block_size;
4015
restore_record(table, s->default_values); // Empty record for DEFAULT
4019
First collect all fields from table which isn't in drop_list
4021
Field **f_ptr,*field;
4022
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
4024
/* Check if field should be dropped */
4027
while ((drop=drop_it++))
4029
if (drop->type == Alter_drop::COLUMN &&
4030
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
4032
/* Reset auto_increment value if it was dropped */
4033
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
4034
!(used_fields & HA_CREATE_USED_AUTO))
4036
create_info->auto_increment_value=0;
4037
create_info->used_fields|=HA_CREATE_USED_AUTO;
4047
/* Check if field is changed */
4049
while ((def=def_it++))
4052
!my_strcasecmp(system_charset_info,field->field_name, def->change))
4056
{ // Field is changed
4058
if (field->is_stored != def->is_stored)
4060
my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN,
4062
"Changing the STORED status");
4067
new_create_list.push_back(def);
4074
This field was not dropped and not changed, add it to the list
4077
def= new Create_field(field, field);
4078
new_create_list.push_back(def);
4079
alter_it.rewind(); // Change default if ALTER
4080
Alter_column *alter;
4081
while ((alter=alter_it++))
4083
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
4088
if (def->sql_type == DRIZZLE_TYPE_BLOB)
4090
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
4093
if ((def->def=alter->def)) // Use new default
4094
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
4096
def->flags|= NO_DEFAULT_VALUE_FLAG;
4102
while ((def=def_it++)) // Add new columns
4104
if (def->change && ! def->field)
4106
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
4110
Check that the DATE/DATETIME not null field we are going to add is
4111
either has a default value or the '0000-00-00' is allowed by the
4113
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
4114
flag to allow ALTER Table only if the table to be altered is empty.
4116
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
4117
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
4118
!alter_info->datetime_field &&
4119
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
4120
session->variables.sql_mode & MODE_NO_ZERO_DATE)
4122
alter_info->datetime_field= def;
4123
alter_info->error_if_not_empty= true;
4126
new_create_list.push_back(def);
4127
else if (def->after == first_keyword)
4128
new_create_list.push_front(def);
4133
while ((find=find_it++)) // Add new columns
4135
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
4140
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
4143
find_it.after(def); // Put element after this
4145
XXX: hack for Bug#28427.
4146
If column order has changed, force OFFLINE ALTER Table
4147
without querying engine capabilities. If we ever have an
4148
engine that supports online ALTER Table CHANGE COLUMN
4149
<name> AFTER <name1> (Falcon?), this fix will effectively
4150
disable the capability.
4151
TODO: detect the situation in compare_tables, behave based
4152
on engine capabilities.
4154
if (alter_info->build_method == HA_BUILD_ONLINE)
4156
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4159
alter_info->build_method= HA_BUILD_OFFLINE;
4162
if (alter_info->alter_list.elements)
4164
my_error(ER_BAD_FIELD_ERROR, MYF(0),
4165
alter_info->alter_list.head()->name, table->s->table_name.str);
4168
if (!new_create_list.elements)
4170
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
4176
Collect all keys which isn't in drop list. Add only those
4177
for which some fields exists.
4180
for (uint32_t i=0 ; i < table->s->keys ; i++,key_info++)
4182
char *key_name= key_info->name;
4185
while ((drop=drop_it++))
4187
if (drop->type == Alter_drop::KEY &&
4188
!my_strcasecmp(system_charset_info,key_name, drop->name))
4197
KEY_PART_INFO *key_part= key_info->key_part;
4199
for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
4201
if (!key_part->field)
4202
continue; // Wrong field (from UNIREG)
4203
const char *key_part_name=key_part->field->field_name;
4204
Create_field *cfield;
4206
while ((cfield=field_it++))
4210
if (!my_strcasecmp(system_charset_info, key_part_name,
4214
else if (!my_strcasecmp(system_charset_info,
4215
key_part_name, cfield->field_name))
4219
continue; // Field is removed
4220
uint32_t key_part_length=key_part->length;
4221
if (cfield->field) // Not new field
4224
If the field can't have only a part used in a key according to its
4225
new type, or should not be used partially according to its
4226
previous type, or the field length is less than the key part
4227
length, unset the key part length.
4229
We also unset the key part length if it is the same as the
4230
old field's length, so the whole new field will be used.
4232
BLOBs may have cfield->length == 0, which is why we test it before
4233
checking whether cfield->length < key_part_length (in chars).
4235
if (!Field::type_can_have_key_part(cfield->field->type()) ||
4236
!Field::type_can_have_key_part(cfield->sql_type) ||
4237
(cfield->field->field_length == key_part_length &&
4238
!f_is_blob(key_part->key_type)) ||
4239
(cfield->length && (cfield->length < key_part_length /
4240
key_part->field->charset()->mbmaxlen)))
4241
key_part_length= 0; // Use whole field
4243
key_part_length /= key_part->field->charset()->mbmaxlen;
4244
key_parts.push_back(new Key_part_spec(cfield->field_name,
4245
strlen(cfield->field_name),
4248
if (key_parts.elements)
4250
KEY_CREATE_INFO key_create_info;
4252
enum Key::Keytype key_type;
4253
memset(&key_create_info, 0, sizeof(key_create_info));
4255
key_create_info.algorithm= key_info->algorithm;
4256
if (key_info->flags & HA_USES_BLOCK_SIZE)
4257
key_create_info.block_size= key_info->block_size;
4258
if (key_info->flags & HA_USES_COMMENT)
4259
key_create_info.comment= key_info->comment;
4261
if (key_info->flags & HA_NOSAME)
4263
if (is_primary_key_name(key_name))
4264
key_type= Key::PRIMARY;
4266
key_type= Key::UNIQUE;
4269
key_type= Key::MULTIPLE;
4271
key= new Key(key_type, key_name, strlen(key_name),
4273
test(key_info->flags & HA_GENERATED_KEY),
4275
new_key_list.push_back(key);
4280
while ((key=key_it++)) // Add new keys
4282
if (key->type == Key::FOREIGN_KEY &&
4283
((Foreign_key *)key)->validate(new_create_list))
4285
if (key->type != Key::FOREIGN_KEY)
4286
new_key_list.push_back(key);
4287
if (key->name.str && is_primary_key_name(key->name.str))
4289
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
4295
if (alter_info->drop_list.elements)
4297
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4298
alter_info->drop_list.head()->name);
4301
if (alter_info->alter_list.elements)
4303
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4304
alter_info->alter_list.head()->name);
4308
if (!create_info->comment.str)
4310
create_info->comment.str= table->s->comment.str;
4311
create_info->comment.length= table->s->comment.length;
4314
table->file->update_create_info(create_info);
4315
if ((create_info->table_options &
4316
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
4317
(used_fields & HA_CREATE_USED_PACK_KEYS))
4318
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
4319
if (create_info->table_options &
4320
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
4321
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
4322
if (create_info->table_options &
4323
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
4324
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
4325
HA_OPTION_NO_DELAY_KEY_WRITE);
4326
create_info->table_options|= db_create_options;
4328
if (table->s->tmp_table)
4329
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
4332
alter_info->create_list.swap(new_create_list);
4333
alter_info->key_list.swap(new_key_list);
4344
session Thread handle
4345
new_db If there is a RENAME clause
4346
new_name If there is a RENAME clause
4347
create_info Information from the parsing phase about new
4349
table_list The table to change.
4350
alter_info Lists of fields, keys to be changed, added
4352
order_num How many order_st BY fields has been specified.
4353
order List of fields to order_st BY.
4354
ignore Whether we have ALTER IGNORE Table
4357
This is a veery long function and is everything but the kitchen sink :)
4358
It is used to alter a table and not only by ALTER Table but also
4359
CREATE|DROP INDEX are mapped on this function.
4361
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
4362
or both, then this function short cuts its operation by renaming
4363
the table and/or enabling/disabling the keys. In this case, the FRM is
4364
not changed, directly by mysql_alter_table. However, if there is a
4365
RENAME + change of a field, or an index, the short cut is not used.
4366
See how `create_list` is used to generate the new FRM regarding the
4367
structure of the fields. The same is done for the indices of the table.
4369
Important is the fact, that this function tries to do as little work as
4370
possible, by finding out whether a intermediate table is needed to copy
4371
data into and when finishing the altering to use it as the original table.
4372
For this reason the function compare_tables() is called, which decides
4373
based on all kind of data how similar are the new and the original
4381
bool mysql_alter_table(Session *session,char *new_db, char *new_name,
4382
HA_CREATE_INFO *create_info,
4383
TableList *table_list,
4384
Alter_info *alter_info,
4385
uint32_t order_num, order_st *order, bool ignore)
4387
Table *table, *new_table=0, *name_lock= 0;;
4388
string new_name_str;
4390
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
4391
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
4392
char path[FN_REFLEN];
4393
ha_rows copied= 0,deleted= 0;
4394
handlerton *old_db_type, *new_db_type, *save_old_db_type;
4396
new_name_buff[0]= '\0';
4398
if (table_list && table_list->schema_table)
4400
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
4405
Assign variables table_name, new_name, db, new_db, path
4406
to simplify further comparisons: we want to see if it's a RENAME
4407
later just by comparing the pointers, avoiding the need for strcmp.
4409
session->set_proc_info("init");
4410
table_name=table_list->table_name;
4411
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
4413
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
4415
build_table_filename(path, sizeof(path), db, table_name, "", 0);
4417
mysql_ha_rm_tables(session, table_list, false);
4419
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
4420
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
4421
/* Conditionally writes to binlog. */
4422
return(mysql_discard_or_import_tablespace(session,table_list,
4423
alter_info->tablespace_op));
4425
oss << drizzle_data_home << "/" << db << "/" << table_name << reg_ext;
4427
(void) unpack_filename(new_name_buff, oss.str().c_str());
4429
If this is just a rename of a view, short cut to the
4430
following scenario: 1) lock LOCK_open 2) do a RENAME
4431
2) unlock LOCK_open.
4432
This is a copy-paste added to make sure
4433
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
4434
as an independent branch in mysql_execute_command. The need
4435
for a copy-paste arose because the main code flow of ALTER Table
4436
... RENAME tries to use open_ltable, which does not work for views
4437
(open_ltable was never modified to merge table lists of child tables
4438
into the main table list, like open_tables does).
4439
This code is wrong and will be removed, please do not copy.
4442
if (!(table= open_n_lock_single_table(session, table_list, TL_WRITE_ALLOW_READ)))
4444
table->use_all_columns();
4446
/* Check that we are not trying to rename to an existing table */
4449
strcpy(new_name_buff,new_name);
4450
strcpy(new_alias= new_alias_buff, new_name);
4451
if (lower_case_table_names)
4453
if (lower_case_table_names != 2)
4455
my_casedn_str(files_charset_info, new_name_buff);
4456
new_alias= new_name; // Create lower case table name
4458
my_casedn_str(files_charset_info, new_name);
4461
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
4464
Source and destination table names are equal: make later check
4467
new_alias= new_name= table_name;
4471
if (table->s->tmp_table != NO_TMP_TABLE)
4473
if (find_temporary_table(session,new_db,new_name_buff))
4475
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
4481
if (lock_table_name_if_not_cached(session, new_db, new_name, &name_lock))
4485
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4489
build_table_filename(new_name_buff, sizeof(new_name_buff),
4490
new_db, new_name_buff, reg_ext, 0);
4491
if (!access(new_name_buff, F_OK))
4493
/* Table will be closed in do_command() */
4494
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4502
new_alias= (lower_case_table_names == 2) ? alias : table_name;
4503
new_name= table_name;
4506
old_db_type= table->s->db_type();
4507
if (!create_info->db_type)
4509
create_info->db_type= old_db_type;
4512
if (check_engine(session, new_name, create_info))
4514
new_db_type= create_info->db_type;
4516
if (new_db_type != old_db_type &&
4517
!table->file->can_switch_engines())
4520
my_error(ER_ROW_IS_REFERENCED, MYF(0));
4524
if (create_info->row_type == ROW_TYPE_NOT_USED)
4525
create_info->row_type= table->s->row_type;
4527
if (ha_check_storage_engine_flag(old_db_type, HTON_BIT_ALTER_NOT_SUPPORTED) ||
4528
ha_check_storage_engine_flag(new_db_type, HTON_BIT_ALTER_NOT_SUPPORTED))
4530
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
4534
session->set_proc_info("setup");
4535
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
4536
!table->s->tmp_table) // no need to touch frm
4538
switch (alter_info->keys_onoff) {
4543
wait_while_table_is_used() ensures that table being altered is
4544
opened only by this thread and that Table::TABLE_SHARE::version
4545
of Table object corresponding to this table is 0.
4546
The latter guarantees that no DML statement will open this table
4547
until ALTER Table finishes (i.e. until close_thread_tables())
4548
while the fact that the table is still open gives us protection
4549
from concurrent DDL statements.
4551
pthread_mutex_lock(&LOCK_open);
4552
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4553
pthread_mutex_unlock(&LOCK_open);
4554
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4555
/* COND_refresh will be signaled in close_thread_tables() */
4558
pthread_mutex_lock(&LOCK_open);
4559
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4560
pthread_mutex_unlock(&LOCK_open);
4561
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4562
/* COND_refresh will be signaled in close_thread_tables() */
4569
if (error == HA_ERR_WRONG_COMMAND)
4572
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4573
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4577
pthread_mutex_lock(&LOCK_open);
4579
Unlike to the above case close_cached_table() below will remove ALL
4580
instances of Table from table cache (it will also remove table lock
4581
held by this thread). So to make actual table renaming and writing
4582
to binlog atomic we have to put them into the same critical section
4583
protected by LOCK_open mutex. This also removes gap for races between
4584
access() and mysql_rename_table() calls.
4587
if (!error && (new_name != table_name || new_db != db))
4589
session->set_proc_info("rename");
4591
Then do a 'simple' rename of the table. First we need to close all
4592
instances of 'source' table.
4594
close_cached_table(session, table);
4596
Then, we want check once again that target table does not exist.
4597
Actually the order of these two steps does not matter since
4598
earlier we took name-lock on the target table, so we do them
4599
in this particular order only to be consistent with 5.0, in which
4600
we don't take this name-lock and where this order really matters.
4601
TODO: Investigate if we need this access() check at all.
4603
if (!access(new_name_buff,F_OK))
4605
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
4610
*fn_ext(new_name)=0;
4611
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
4615
mysql_rename_table(old_db_type, new_db, new_alias, db,
4622
if (error == HA_ERR_WRONG_COMMAND)
4625
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4626
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4632
write_bin_log(session, true, session->query, session->query_length);
4637
table->file->print_error(error, MYF(0));
4641
unlink_open_table(session, name_lock, false);
4642
pthread_mutex_unlock(&LOCK_open);
4643
table_list->table= NULL; // For query cache
4647
/* We have to do full alter table. */
4650
If the old table had partitions and we are doing ALTER Table ...
4651
engine= <new_engine>, the new table must preserve the original
4652
partitioning. That means that the new engine is still the
4653
partitioning engine, not the engine specified in the parser.
4654
This is discovered in prep_alter_part_table, which in such case
4655
updates create_info->db_type.
4656
Now we need to update the stack copy of create_info->db_type,
4657
as otherwise we won't be able to correctly move the files of the
4658
temporary table to the result table files.
4660
new_db_type= create_info->db_type;
4662
if (mysql_prepare_alter_table(session, table, create_info, alter_info))
4665
set_table_default_charset(session, create_info, db);
4667
if (session->variables.old_alter_table
4668
|| (table->s->db_type() != create_info->db_type)
4671
if (alter_info->build_method == HA_BUILD_ONLINE)
4673
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4676
alter_info->build_method= HA_BUILD_OFFLINE;
4679
if (alter_info->build_method != HA_BUILD_OFFLINE)
4681
Table *altered_table= 0;
4682
HA_ALTER_INFO ha_alter_info;
4683
HA_ALTER_FLAGS ha_alter_flags;
4684
uint32_t table_changes= IS_EQUAL_YES;
4685
bool need_copy_table= true;
4686
/* Check how much the tables differ. */
4687
if (compare_tables(session, table, alter_info,
4688
create_info, order_num,
4697
Check if storage engine supports altering the table
4703
If table is not renamed, changed database and
4704
some change was detected then check if engine
4705
can do the change on-line
4707
if (new_name == table_name && new_db == db &&
4708
ha_alter_flags.is_set())
4710
Alter_info tmp_alter_info(*alter_info, session->mem_root);
4714
check if table can be altered on-line
4716
if (!(altered_table= create_altered_table(session,
4721
!strcmp(db, new_db))))
4724
switch (table->file->check_if_supported_alter(altered_table,
4728
case HA_ALTER_SUPPORTED_WAIT_LOCK:
4729
case HA_ALTER_SUPPORTED_NO_LOCK:
4731
@todo: Currently we always acquire an exclusive name
4732
lock on the table metadata when performing fast or online
4733
ALTER Table. In future we may consider this unnecessary,
4734
and narrow the scope of the exclusive name lock to only
4735
cover manipulation with .frms. Storage engine API
4736
call check_if_supported_alter has provision for this
4739
need_copy_table= false;
4741
case HA_ALTER_NOT_SUPPORTED:
4742
if (alter_info->build_method == HA_BUILD_ONLINE)
4744
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4745
close_temporary_table(session, altered_table, 1, 1);
4748
need_copy_table= true;
4750
case HA_ALTER_ERROR:
4752
close_temporary_table(session, altered_table, 1, 1);
4757
/* TODO need to check if changes can be handled as fast ALTER Table */
4759
need_copy_table= true;
4761
if (!need_copy_table)
4763
error= mysql_fast_or_online_alter_table(session,
4769
alter_info->keys_onoff);
4772
mysql_unlock_tables(session, session->lock);
4775
close_temporary_table(session, altered_table, 1, 1);
4781
goto err_with_placeholders;
4788
pthread_mutex_lock(&LOCK_open);
4794
close_temporary_table(session, altered_table, 1, 1);
4797
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX,
4798
(unsigned long)current_pid, session->thread_id);
4799
/* Safety fix for innodb */
4800
if (lower_case_table_names)
4801
my_casedn_str(files_charset_info, tmp_name);
4804
/* Create a temporary table with the new format */
4805
if ((error= create_temporary_table(session, table, new_db, tmp_name,
4806
create_info, alter_info,
4807
!strcmp(db, new_db))))
4812
/* Open the table so we need to copy the data to it. */
4813
if (table->s->tmp_table)
4816
memset(&tbl, 0, sizeof(tbl));
4818
tbl.table_name= tbl.alias= tmp_name;
4819
/* Table is in session->temporary_tables */
4820
new_table= open_table(session, &tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
4824
char tmp_path[FN_REFLEN];
4825
/* table is a normal table: Create temporary table in same directory */
4826
build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, "",
4828
/* Open our intermediate table */
4829
new_table=open_temporary_table(session, tmp_path, new_db, tmp_name, 0, OTM_OPEN);
4834
/* Copy the data if necessary. */
4835
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
4836
session->cuted_fields=0L;
4837
session->set_proc_info("copy to tmp table");
4840
We do not copy data for MERGE tables. Only the children have data.
4841
MERGE tables have HA_NO_COPY_ON_ALTER set.
4843
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
4845
/* We don't want update TIMESTAMP fields during ALTER Table. */
4846
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
4847
new_table->next_number_field=new_table->found_next_number_field;
4848
error= copy_data_between_tables(table, new_table,
4849
alter_info->create_list, ignore,
4850
order_num, order, &copied, &deleted,
4851
alter_info->keys_onoff,
4852
alter_info->error_if_not_empty);
4856
pthread_mutex_lock(&LOCK_open);
4857
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4858
pthread_mutex_unlock(&LOCK_open);
4859
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
4860
alter_info->keys_onoff);
4861
error= ha_autocommit_or_rollback(session, 0);
4862
if (end_active_trans(session))
4865
/* We must not ignore bad input! */;
4866
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
4868
if (table->s->tmp_table != NO_TMP_TABLE)
4870
/* We changed a temporary table */
4873
/* Close lock if this is a transactional table */
4876
mysql_unlock_tables(session, session->lock);
4879
/* Remove link to old table and rename the new one */
4880
close_temporary_table(session, table, 1, 1);
4881
/* Should pass the 'new_name' as we store table name in the cache */
4882
if (rename_temporary_table(session, new_table, new_db, new_name))
4890
Close the intermediate table that will be the new table.
4891
Note that MERGE tables do not have their children attached here.
4893
intern_close_table(new_table);
4896
pthread_mutex_lock(&LOCK_open);
4899
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4900
pthread_mutex_unlock(&LOCK_open);
4905
Data is copied. Now we:
4906
1) Wait until all other threads close old version of table.
4907
2) Close instances of table open by this thread and replace them
4908
with exclusive name-locks.
4909
3) Rename the old table to a temp name, rename the new one to the
4911
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
4912
we reopen new version of table.
4913
5) Write statement to the binary log.
4914
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
4915
remove name-locks from list of open tables and table cache.
4916
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
4917
call to remove name-locks from table cache and list of open table.
4920
session->set_proc_info("rename result table");
4921
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX,
4922
(unsigned long)current_pid, session->thread_id);
4923
if (lower_case_table_names)
4924
my_casedn_str(files_charset_info, old_name);
4926
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
4927
close_data_files_and_morph_locks(session, db, table_name);
4930
save_old_db_type= old_db_type;
4933
This leads to the storage engine (SE) not being notified for renames in
4934
mysql_rename_table(), because we just juggle with the FRM and nothing
4935
more. If we have an intermediate table, then we notify the SE that
4936
it should become the actual table. Later, we will recycle the old table.
4937
However, in case of ALTER Table RENAME there might be no intermediate
4938
table. This is when the old and new tables are compatible, according to
4939
compare_table(). Then, we need one additional call to
4940
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
4941
actual rename in the SE and the FRM is not touched. Note that, if the
4942
table is renamed and the SE is also changed, then an intermediate table
4943
is created and the additional call will not take place.
4945
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
4949
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4951
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
4952
new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
4954
/* Try to get everything back. */
4956
quick_rm_table(new_db_type,new_db,new_alias, 0);
4957
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4958
mysql_rename_table(old_db_type, db, old_name, db, alias,
4964
/* This shouldn't happen. But let us play it safe. */
4965
goto err_with_placeholders;
4968
quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
4971
if (session->locked_tables && new_name == table_name && new_db == db)
4973
session->in_lock_tables= 1;
4974
error= reopen_tables(session, 1, 1);
4975
session->in_lock_tables= 0;
4977
goto err_with_placeholders;
4979
pthread_mutex_unlock(&LOCK_open);
4981
session->set_proc_info("end");
4983
write_bin_log(session, true, session->query, session->query_length);
4985
if (ha_check_storage_engine_flag(old_db_type, HTON_BIT_FLUSH_AFTER_RENAME))
4988
For the alter table to be properly flushed to the logs, we
4989
have to open the new table. If not, we get a problem on server
4990
shutdown. But we do not need to attach MERGE children.
4992
char table_path[FN_REFLEN];
4994
build_table_filename(table_path, sizeof(table_path), new_db, table_name, "", 0);
4995
t_table= open_temporary_table(session, table_path, new_db, tmp_name, false, OTM_OPEN);
4998
intern_close_table(t_table);
5002
errmsg_printf(ERRMSG_LVL_WARN,
5003
_("Could not open table %s.%s after rename\n"),
5005
ha_flush_logs(old_db_type);
5007
table_list->table=0; // For query cache
5009
if (session->locked_tables && (new_name != table_name || new_db != db))
5012
If are we under LOCK TABLES and did ALTER Table with RENAME we need
5013
to remove placeholders for the old table and for the target table
5014
from the list of open tables and table cache. If we are not under
5015
LOCK TABLES we can rely on close_thread_tables() doing this job.
5017
pthread_mutex_lock(&LOCK_open);
5018
unlink_open_table(session, table, false);
5019
unlink_open_table(session, name_lock, false);
5020
pthread_mutex_unlock(&LOCK_open);
5025
* Field::store() may have called my_error(). If this is
5026
* the case, we must not send an ok packet, since
5027
* Diagnostics_area::is_set() will fail an assert.
5029
if (! session->is_error())
5031
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
5032
(ulong) (copied + deleted), (ulong) deleted,
5033
(ulong) session->cuted_fields);
5034
session->my_ok(copied + deleted, 0L, tmp_name);
5035
session->some_tables_deleted=0;
5040
/* my_error() was called. Return true (which means error...) */
5047
/* close_temporary_table() frees the new_table pointer. */
5048
close_temporary_table(session, new_table, 1, 1);
5051
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
5055
No default value was provided for a DATE/DATETIME field, the
5056
current sql_mode doesn't allow the '0000-00-00' value and
5057
the table to be altered isn't empty.
5060
if (alter_info->error_if_not_empty && session->row_count)
5062
const char *f_val= 0;
5063
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
5064
switch (alter_info->datetime_field->sql_type)
5066
case DRIZZLE_TYPE_DATE:
5067
f_val= "0000-00-00";
5068
t_type= DRIZZLE_TIMESTAMP_DATE;
5070
case DRIZZLE_TYPE_DATETIME:
5071
f_val= "0000-00-00 00:00:00";
5072
t_type= DRIZZLE_TIMESTAMP_DATETIME;
5075
/* Shouldn't get here. */
5078
bool save_abort_on_warning= session->abort_on_warning;
5079
session->abort_on_warning= true;
5080
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5081
f_val, strlength(f_val), t_type,
5082
alter_info->datetime_field->field_name);
5083
session->abort_on_warning= save_abort_on_warning;
5087
pthread_mutex_lock(&LOCK_open);
5088
unlink_open_table(session, name_lock, false);
5089
pthread_mutex_unlock(&LOCK_open);
5093
err_with_placeholders:
5095
An error happened while we were holding exclusive name-lock on table
5096
being altered. To be safe under LOCK TABLES we should remove placeholders
5097
from list of open tables list and table cache.
5099
unlink_open_table(session, table, false);
5101
unlink_open_table(session, name_lock, false);
5102
pthread_mutex_unlock(&LOCK_open);
5105
/* mysql_alter_table */
5108
copy_data_between_tables(Table *from,Table *to,
5109
List<Create_field> &create,
5111
uint32_t order_num, order_st *order,
5114
enum enum_enable_or_disable keys_onoff,
5115
bool error_if_not_empty)
5118
Copy_field *copy,*copy_end;
5119
ulong found_count,delete_count;
5120
Session *session= current_session;
5122
SORT_FIELD *sortorder;
5126
List<Item> all_fields;
5127
ha_rows examined_rows;
5128
bool auto_increment_field_copied= 0;
5129
ulong save_sql_mode;
5130
uint64_t prev_insert_id;
5133
Turn off recovery logging since rollback of an alter table is to
5134
delete the new table so there is no need to log the changes to it.
5136
This needs to be done before external_lock
5138
error= ha_enable_transaction(session, false);
5142
if (!(copy= new Copy_field[to->s->fields]))
5143
return(-1); /* purecov: inspected */
5145
if (to->file->ha_external_lock(session, F_WRLCK))
5148
/* We need external lock before we can disable/enable keys */
5149
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
5151
/* We can abort alter table for any table type */
5152
session->abort_on_warning= !ignore;
5154
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5155
to->file->ha_start_bulk_insert(from->file->stats.records);
5157
save_sql_mode= session->variables.sql_mode;
5159
List_iterator<Create_field> it(create);
5162
for (Field **ptr=to->field ; *ptr ; ptr++)
5167
if (*ptr == to->next_number_field)
5168
auto_increment_field_copied= true;
5170
(copy_end++)->set(*ptr,def->field,0);
5175
found_count=delete_count=0;
5179
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
5181
char warn_buff[DRIZZLE_ERRMSG_SIZE];
5182
snprintf(warn_buff, sizeof(warn_buff),
5183
_("order_st BY ignored because there is a user-defined clustered "
5184
"index in the table '%-.192s'"),
5185
from->s->table_name.str);
5186
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
5191
from->sort.io_cache= new IO_CACHE;
5192
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
5194
memset(&tables, 0, sizeof(tables));
5196
tables.alias= tables.table_name= from->s->table_name.str;
5197
tables.db= from->s->db.str;
5200
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
5201
setup_order(session, session->lex->select_lex.ref_pointer_array,
5202
&tables, fields, all_fields, order) ||
5203
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
5204
(from->sort.found_records= filesort(session, from, sortorder, length,
5205
(SQL_SELECT *) 0, HA_POS_ERROR,
5206
1, &examined_rows)) ==
5212
/* Tell handler that we have values for all columns in the to table */
5213
to->use_all_columns();
5214
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
5216
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
5217
session->row_count= 0;
5218
restore_record(to, s->default_values); // Create empty record
5219
while (!(error=info.read_record(&info)))
5221
if (session->killed)
5223
session->send_kill_message();
5227
session->row_count++;
5228
/* Return error if source table isn't empty. */
5229
if (error_if_not_empty)
5234
if (to->next_number_field)
5236
if (auto_increment_field_copied)
5237
to->auto_increment_field_not_null= true;
5239
to->next_number_field->reset();
5242
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
5244
copy_ptr->do_copy(copy_ptr);
5246
prev_insert_id= to->file->next_insert_id;
5247
update_virtual_fields_marked_for_write(to, false);
5248
error=to->file->ha_write_row(to->record[0]);
5249
to->auto_increment_field_not_null= false;
5253
to->file->is_fatal_error(error, HA_CHECK_DUP))
5255
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
5257
uint32_t key_nr= to->file->get_dup_key(error);
5258
if ((int) key_nr >= 0)
5260
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
5262
(to->key_info[0].key_part[0].field->flags &
5263
AUTO_INCREMENT_FLAG))
5264
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
5265
to->file->print_keydup_error(key_nr, err_msg);
5270
to->file->print_error(error,MYF(0));
5273
to->file->restore_auto_increment(prev_insert_id);
5279
end_read_record(&info);
5280
free_io_cache(from);
5281
delete [] copy; // This is never 0
5283
if (to->file->ha_end_bulk_insert() && error <= 0)
5285
to->file->print_error(my_errno,MYF(0));
5288
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
5290
if (ha_enable_transaction(session, true))
5297
Ensure that the new table is saved properly to disk so that we
5300
if (ha_autocommit_or_rollback(session, 0))
5302
if (end_active_trans(session))
5306
session->variables.sql_mode= save_sql_mode;
5307
session->abort_on_warning= 0;
5308
free_io_cache(from);
5309
*copied= found_count;
5310
*deleted=delete_count;
5311
to->file->ha_release_auto_increment();
5312
if (to->file->ha_external_lock(session,F_UNLCK))
5314
return(error > 0 ? -1 : 0);
5319
Recreates tables by calling mysql_alter_table().
5322
mysql_recreate_table()
5323
session Thread handler
5324
tables Tables to recreate
5327
Like mysql_alter_table().
5329
bool mysql_recreate_table(Session *session, TableList *table_list)
5331
HA_CREATE_INFO create_info;
5332
Alter_info alter_info;
5334
assert(!table_list->next_global);
5336
table_list->table has been closed and freed. Do not reference
5337
uninitialized data. open_tables() could fail.
5339
table_list->table= NULL;
5341
memset(&create_info, 0, sizeof(create_info));
5342
create_info.row_type=ROW_TYPE_NOT_USED;
5343
create_info.default_table_charset=default_charset_info;
5344
/* Force alter table to recreate table */
5345
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
5346
return(mysql_alter_table(session, NULL, NULL, &create_info,
5347
table_list, &alter_info, 0,
5348
(order_st *) 0, 0));
2271
5352
bool mysql_checksum_table(Session *session, TableList *tables,
5353
HA_CHECK_OPT *check_opt)
2274
5355
TableList *table;
2275
5356
List<Item> field_list;
5358
Protocol *protocol= session->protocol;
2278
5360
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
2279
5361
item->maybe_null= 1;
2280
5362
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
2281
5363
MY_INT64_NUM_DECIMAL_DIGITS));
2282
5364
item->maybe_null= 1;
2283
if (session->client->sendFields(&field_list))
5365
if (protocol->send_fields(&field_list,
5366
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2286
5369
/* Open one table after the other to keep lock time as short as possible. */
2287
5370
for (table= tables; table; table= table->next_local)