2103
bool create_like_table(Session* session,
2104
identifier::Table::const_reference destination_identifier,
2105
identifier::Table::const_reference source_identifier,
2106
message::Table &create_table_proto,
2107
bool is_if_not_exists,
2943
bool mysql_create_like_table(Session* session, TableList* table, TableList* src_table,
2944
HA_CREATE_INFO *create_info)
2946
Table *name_lock= 0;
2947
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
2948
uint32_t dst_path_length;
2949
char *db= table->db;
2950
char *table_name= table->table_name;
2110
2952
bool res= true;
2111
bool table_exists= false;
2956
By opening source table we guarantee that it exists and no concurrent
2957
DDL operation will mess with it. Later we also take an exclusive
2958
name-lock on target table name, which makes copying of .frm file,
2959
call to ha_create_table() and binlogging atomic against concurrent DML
2960
and DDL operations on target table. Thus by holding both these "locks"
2961
we ensure that our statement is properly isolated from all concurrent
2962
operations which matter.
2964
if (open_tables(session, &src_table, ¬_used, 0))
2967
sprintf(src_path,"%s%s",src_table->table->s->path.str, reg_ext);
2114
2970
Check that destination tables does not exist. Note that its name
2115
2971
was already checked when it was added to the table list.
2117
For temporary tables we don't aim to grab locks.
2119
if (destination_identifier.isTmp())
2121
if (session->find_temporary_table(destination_identifier))
2127
bool was_created= create_table_wrapper(*session,
2129
destination_identifier,
2132
if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2134
(void) session->rm_temporary_table(destination_identifier, true);
2136
else if (not session->open_temporary_table(destination_identifier))
2138
// We created, but we can't open... also, a hack.
2139
(void) session->rm_temporary_table(destination_identifier, true);
2147
else // Standard table which will require locks.
2149
Table *name_lock= 0;
2151
if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2155
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2156
session->unlink_open_table(name_lock);
2166
else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2170
else // Otherwise we create the table
2174
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2175
was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2176
source_identifier, is_engine_set);
2179
// So we blew the creation of the table, and we scramble to clean up
2180
// anything that might have been created (read... it is a hack)
2181
if (not was_created)
2183
plugin::StorageEngine::dropTable(*session, destination_identifier);
2973
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
2975
if (find_temporary_table(session, db, table_name))
2977
dst_path_length= build_tmptable_filename(session, dst_path, sizeof(dst_path));
2978
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
2982
if (lock_table_name_if_not_cached(session, db, table_name, &name_lock))
2986
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
2987
db, table_name, reg_ext, 0);
2988
if (!access(dst_path, F_OK))
2993
Create a new table by copying from source table
2995
Altough exclusive name-lock on target table protects us from concurrent
2996
DML and DDL operations on it we still want to wrap .FRM creation and call
2997
to ha_create_table() in critical section protected by LOCK_open in order
2998
to provide minimal atomicity against operations which disregard name-locks,
2999
like I_S implementation, for example. This is a temporary and should not
3000
be copied. Instead we should fix our code to always honor name-locks.
3002
Also some engines (e.g. NDB cluster) require that LOCK_open should be held
3003
during the call to ha_create_table(). See bug #28614 for more info.
3005
pthread_mutex_lock(&LOCK_open);
3006
if (src_table->schema_table)
3008
if (mysql_create_like_schema_frm(session, src_table, dst_path, create_info))
3010
pthread_mutex_unlock(&LOCK_open);
3014
else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
3016
if (my_errno == ENOENT)
3017
my_error(ER_BAD_DB_ERROR,MYF(0),db);
3019
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
3020
pthread_mutex_unlock(&LOCK_open);
3025
As mysql_truncate don't work on a new table at this stage of
3026
creation, instead create the table directly (for both normal
3027
and temporary tables).
3029
dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
3030
if (session->variables.keep_files_on_create)
3031
create_info->options|= HA_CREATE_KEEP_FILES;
3032
err= ha_create_table(session, dst_path, db, table_name, create_info, 1);
3033
pthread_mutex_unlock(&LOCK_open);
3035
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
3037
if (err || !open_temporary_table(session, dst_path, db, table_name, 1,
3040
(void) rm_temporary_table(create_info->db_type,
3042
goto err; /* purecov: inspected */
3047
(void) quick_rm_table(create_info->db_type, db,
3048
table_name, 0); /* purecov: inspected */
3049
goto err; /* purecov: inspected */
3053
We have to write the query before we unlock the tables.
3057
Since temporary tables are not replicated under row-based
3058
replication, CREATE TABLE ... LIKE ... needs special
3059
treatement. We have four cases to consider, according to the
3060
following decision table:
3062
==== ========= ========= ==============================
3063
Case Target Source Write to binary log
3064
==== ========= ========= ==============================
3065
1 normal normal Original statement
3066
2 normal temporary Generated statement
3067
3 temporary normal Nothing
3068
4 temporary temporary Nothing
3069
==== ========= ========= ==============================
3071
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
3073
if (src_table->table->s->tmp_table) // Case 2
3076
String query(buf, sizeof(buf), system_charset_info);
3077
query.length(0); // Have to zero it since constructor doesn't
3081
Here we open the destination table, on which we already have
3082
name-lock. This is needed for store_create_info() to work.
3083
The table will be closed by unlink_open_table() at the end
3086
table->table= name_lock;
3087
pthread_mutex_lock(&LOCK_open);
3088
if (reopen_name_locked_table(session, table, false))
3090
pthread_mutex_unlock(&LOCK_open);
3093
pthread_mutex_unlock(&LOCK_open);
3095
int result= store_create_info(session, table, &query,
3098
assert(result == 0); // store_create_info() always return 0
3099
write_bin_log(session, true, query.ptr(), query.length());
3102
write_bin_log(session, true, session->query, session->query_length);
3105
Case 3 and 4 does nothing under RBR
3113
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
3115
char warn_buff[DRIZZLE_ERRMSG_SIZE];
3116
snprintf(warn_buff, sizeof(warn_buff),
3117
ER(ER_TABLE_EXISTS_ERROR), table_name);
3118
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3119
ER_TABLE_EXISTS_ERROR,warn_buff);
3123
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
3128
pthread_mutex_lock(&LOCK_open);
3129
unlink_open_table(session, name_lock, false);
3130
pthread_mutex_unlock(&LOCK_open);
3136
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
3138
thr_lock_type lock_type = TL_READ_NO_INSERT;
3140
return(mysql_admin_table(session, tables, check_opt,
3141
"analyze", lock_type, 1, 0, 0, 0,
3142
&handler::ha_analyze));
3146
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
3148
thr_lock_type lock_type = TL_READ_NO_INSERT;
3150
return(mysql_admin_table(session, tables, check_opt,
3152
0, 0, HA_OPEN_FOR_REPAIR, 0,
3153
&handler::ha_check));
3157
/* table_list should contain just one table */
3159
mysql_discard_or_import_tablespace(Session *session,
3160
TableList *table_list,
3161
enum tablespace_op_type tablespace_op)
3168
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
3172
session->set_proc_info("discard_or_import_tablespace");
3174
discard= test(tablespace_op == DISCARD_TABLESPACE);
3177
We set this flag so that ha_innobase::open and ::external_lock() do
3178
not complain when we lock the table
3180
session->tablespace_op= true;
3181
if (!(table=open_ltable(session, table_list, TL_WRITE, 0)))
3183
session->tablespace_op=false;
3187
error= table->file->ha_discard_or_import_tablespace(discard);
3189
session->set_proc_info("end");
3194
/* The ALTER Table is always in its own transaction */
3195
error = ha_autocommit_or_rollback(session, 0);
3196
if (end_active_trans(session))
3200
write_bin_log(session, false, session->query, session->query_length);
3203
ha_autocommit_or_rollback(session, error);
3204
session->tablespace_op=false;
3212
table->file->print_error(error, MYF(0));
3218
Copy all changes detected by parser to the HA_ALTER_FLAGS
3221
void setup_ha_alter_flags(Alter_info *alter_info, HA_ALTER_FLAGS *alter_flags)
3223
uint32_t flags= alter_info->flags;
3225
if (ALTER_ADD_COLUMN & flags)
3226
*alter_flags|= HA_ADD_COLUMN;
3227
if (ALTER_DROP_COLUMN & flags)
3228
*alter_flags|= HA_DROP_COLUMN;
3229
if (ALTER_RENAME & flags)
3230
*alter_flags|= HA_RENAME_TABLE;
3231
if (ALTER_CHANGE_COLUMN & flags)
3232
*alter_flags|= HA_CHANGE_COLUMN;
3233
if (ALTER_COLUMN_DEFAULT & flags)
3234
*alter_flags|= HA_COLUMN_DEFAULT_VALUE;
3235
if (ALTER_COLUMN_STORAGE & flags)
3236
*alter_flags|= HA_COLUMN_STORAGE;
3237
if (ALTER_COLUMN_FORMAT & flags)
3238
*alter_flags|= HA_COLUMN_FORMAT;
3239
if (ALTER_COLUMN_ORDER & flags)
3240
*alter_flags|= HA_ALTER_COLUMN_ORDER;
3241
if (ALTER_STORAGE & flags)
3242
*alter_flags|= HA_ALTER_STORAGE;
3243
if (ALTER_ROW_FORMAT & flags)
3244
*alter_flags|= HA_ALTER_ROW_FORMAT;
3245
if (ALTER_RECREATE & flags)
3246
*alter_flags|= HA_RECREATE;
3247
if (ALTER_FOREIGN_KEY & flags)
3248
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3253
@param session Thread
3254
@param table The original table.
3255
@param alter_info Alter options, fields and keys for the new
3257
@param create_info Create options for the new table.
3258
@param order_num Number of order list elements.
3259
@param[out] ha_alter_flags Flags that indicate what will be changed
3260
@param[out] ha_alter_info Data structures needed for on-line alter
3261
@param[out] table_changes Information about particular change
3263
First argument 'table' contains information of the original
3264
table, which includes all corresponding parts that the new
3265
table has in arguments create_list, key_list and create_info.
3267
By comparing the changes between the original and new table
3268
we can determine how much it has changed after ALTER Table
3269
and whether we need to make a copy of the table, or just change
3272
Mark any changes detected in the ha_alter_flags.
3274
If there are no data changes, but index changes, 'index_drop_buffer'
3275
and/or 'index_add_buffer' are populated with offsets into
3276
table->key_info or key_info_buffer respectively for the indexes
3277
that need to be dropped and/or (re-)created.
3280
@retval false success
3285
compare_tables(Session *session,
3287
Alter_info *alter_info,
3288
HA_CREATE_INFO *create_info,
3290
HA_ALTER_FLAGS *alter_flags,
3291
HA_ALTER_INFO *ha_alter_info,
3292
uint32_t *table_changes)
3294
Field **f_ptr, *field;
3295
uint32_t table_changes_local= 0;
3296
List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3297
Create_field *new_field;
3298
KEY_PART_INFO *key_part;
3303
Create a copy of alter_info.
3304
To compare the new and old table definitions, we need to "prepare"
3305
the new definition - transform it from parser output to a format
3306
that describes the final table layout (all column defaults are
3307
initialized, duplicate columns are removed). This is done by
3308
mysql_prepare_create_table. Unfortunately,
3309
mysql_prepare_create_table performs its transformations
3310
"in-place", that is, modifies the argument. Since we would
3311
like to keep compare_tables() idempotent (not altering any
3312
of the arguments) we create a copy of alter_info here and
3313
pass it to mysql_prepare_create_table, then use the result
3314
to evaluate possibility of fast ALTER Table, and then
3317
Alter_info tmp_alter_info(*alter_info, session->mem_root);
3318
Session *session= table->in_use;
3319
uint32_t db_options= 0; /* not used */
3320
/* Create the prepared information. */
3321
if (mysql_prepare_create_table(session, create_info,
3323
(table->s->tmp_table != NO_TMP_TABLE),
3326
&ha_alter_info->key_info_buffer,
3327
&ha_alter_info->key_count,
3328
/* select_field_count */ 0))
3330
/* Allocate result buffers. */
3331
if (! (ha_alter_info->index_drop_buffer=
3332
(uint*) session->alloc(sizeof(uint) * table->s->keys)) ||
3333
! (ha_alter_info->index_add_buffer=
3334
(uint*) session->alloc(sizeof(uint) *
3335
tmp_alter_info.key_list.elements)))
3339
First we setup ha_alter_flags based on what was detected
3342
setup_ha_alter_flags(alter_info, alter_flags);
3346
Some very basic checks. If number of fields changes, or the
3347
handler, we need to run full ALTER Table. In the future
3348
new fields can be added and old dropped without copy, but
3351
Test also that engine was not given during ALTER Table, or
3352
we are force to run regular alter table (copy).
3353
E.g. ALTER Table tbl_name ENGINE=MyISAM.
3355
For the following ones we also want to run regular alter table:
3356
ALTER Table tbl_name order_st BY ..
3357
ALTER Table tbl_name CONVERT TO CHARACTER SET ..
3359
At the moment we can't handle altering temporary tables without a copy.
3360
We also test if OPTIMIZE Table was given and was mapped to alter table.
3361
In that case we always do full copy.
3363
There was a bug prior to mysql-4.0.25. Number of null fields was
3364
calculated incorrectly. As a result frm and data files gets out of
3365
sync after fast alter table. There is no way to determine by which
3366
mysql version (in 4.0 and 4.1 branches) table was created, thus we
3367
disable fast alter table for all tables created by mysql versions
3368
prior to 5.0 branch.
3371
if (table->s->fields != alter_info->create_list.elements ||
3372
table->s->db_type() != create_info->db_type ||
3373
table->s->tmp_table ||
3374
create_info->used_fields & HA_CREATE_USED_ENGINE ||
3375
create_info->used_fields & HA_CREATE_USED_CHARSET ||
3376
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3377
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3378
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3380
!table->s->mysql_version)
3382
*table_changes= IS_EQUAL_NO;
3384
Check what has changed and set alter_flags
3386
if (table->s->fields < alter_info->create_list.elements)
3387
*alter_flags|= HA_ADD_COLUMN;
3388
else if (table->s->fields > alter_info->create_list.elements)
3389
*alter_flags|= HA_DROP_COLUMN;
3390
if (create_info->db_type != table->s->db_type() ||
3391
create_info->used_fields & HA_CREATE_USED_ENGINE)
3392
*alter_flags|= HA_ALTER_STORAGE_ENGINE;
3393
if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3394
*alter_flags|= HA_CHANGE_CHARACTER_SET;
3395
if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3396
*alter_flags|= HA_SET_DEFAULT_CHARACTER_SET;
3397
if (alter_info->flags & ALTER_RECREATE)
3398
*alter_flags|= HA_RECREATE;
3399
/* TODO check for ADD/DROP FOREIGN KEY */
3400
if (alter_info->flags & ALTER_FOREIGN_KEY)
3401
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3404
Go through fields and check if the original ones are compatible
3407
for (f_ptr= table->field, new_field= new_field_it++;
3408
(new_field && (field= *f_ptr));
3409
f_ptr++, new_field= new_field_it++)
3411
/* Make sure we have at least the default charset in use. */
3412
if (!new_field->charset)
3413
new_field->charset= create_info->default_table_charset;
3415
/* Don't pack rows in old tables if the user has requested this. */
3416
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3417
(new_field->flags & BLOB_FLAG) ||
3418
(new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3419
create_info->table_options|= HA_OPTION_PACK_RECORD;
3421
/* Check how fields have been modified */
3422
if (alter_info->flags & ALTER_CHANGE_COLUMN)
3424
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
3425
if (!(table_changes_local= field->is_equal(new_field)))
3426
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3429
Check if the altered column is a stored virtual field.
3430
TODO: Mark such a column with an alter flag only if
3431
the expression functions are not equal.
3433
if (field->is_stored && field->vcol_info)
3434
*alter_flags|= HA_ALTER_STORED_VCOL;
3436
/* Check if field was renamed */
3437
field->flags&= ~FIELD_IS_RENAMED;
3438
if (my_strcasecmp(system_charset_info,
3440
new_field->field_name))
3442
field->flags|= FIELD_IS_RENAMED;
3443
*alter_flags|= HA_ALTER_COLUMN_NAME;
3446
*table_changes&= table_changes_local;
3447
if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3448
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3450
/* Check that NULL behavior is same for old and new fields */
3451
if ((new_field->flags & NOT_NULL_FLAG) !=
3452
(uint) (field->flags & NOT_NULL_FLAG))
3454
*table_changes= IS_EQUAL_NO;
3455
*alter_flags|= HA_ALTER_COLUMN_NULLABLE;
3459
/* Clear indexed marker */
3460
field->flags&= ~FIELD_IN_ADD_INDEX;
3464
Go through keys and check if the original ones are compatible
3468
KEY *table_key_end= table->key_info + table->s->keys;
3471
ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3474
Step through all keys of the old table and search matching new keys.
3476
ha_alter_info->index_drop_count= 0;
3477
ha_alter_info->index_add_count= 0;
3478
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3480
KEY_PART_INFO *table_part;
3481
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3482
KEY_PART_INFO *new_part;
3484
/* Search a new key with the same name. */
3485
for (new_key= ha_alter_info->key_info_buffer;
3486
new_key < new_key_end;
3489
if (! strcmp(table_key->name, new_key->name))
3492
if (new_key >= new_key_end)
3494
/* Key not found. Add the offset of the key to the drop buffer. */
3495
ha_alter_info->index_drop_buffer
3496
[ha_alter_info->index_drop_count++]=
3497
table_key - table->key_info;
3498
if (table_key->flags & HA_NOSAME)
3500
/* Unique key. Check for "PRIMARY". */
3501
if (is_primary_key(table_key))
3502
*alter_flags|= HA_DROP_PK_INDEX;
3504
*alter_flags|= HA_DROP_UNIQUE_INDEX;
3507
*alter_flags|= HA_DROP_INDEX;
3508
*table_changes= IS_EQUAL_NO;
3512
/* Check that the key types are compatible between old and new tables. */
3513
if ((table_key->algorithm != new_key->algorithm) ||
3514
((table_key->flags & HA_KEYFLAG_MASK) !=
3515
(new_key->flags & HA_KEYFLAG_MASK)) ||
3516
(table_key->key_parts != new_key->key_parts))
3518
if (table_key->flags & HA_NOSAME)
3520
// Unique key. Check for "PRIMARY".
3521
if (is_primary_key(table_key))
3522
*alter_flags|= HA_ALTER_PK_INDEX;
3524
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3527
*alter_flags|= HA_ALTER_INDEX;
3532
Check that the key parts remain compatible between the old and
3535
for (table_part= table_key->key_part, new_part= new_key->key_part;
3536
table_part < table_part_end;
3537
table_part++, new_part++)
3540
Key definition has changed if we are using a different field or
3541
if the used key part length is different. We know that the fields
3542
did not change. Comparing field numbers is sufficient.
3544
if ((table_part->length != new_part->length) ||
3545
(table_part->fieldnr - 1 != new_part->fieldnr))
3547
if (table_key->flags & HA_NOSAME)
3549
/* Unique key. Check for "PRIMARY" */
3550
if (is_primary_key(table_key))
3551
*alter_flags|= HA_ALTER_PK_INDEX;
3553
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3556
*alter_flags|= HA_ALTER_INDEX;
3563
/* Key modified. Add the offset of the key to both buffers. */
3564
ha_alter_info->index_drop_buffer
3565
[ha_alter_info->index_drop_count++]=
3566
table_key - table->key_info;
3567
ha_alter_info->index_add_buffer
3568
[ha_alter_info->index_add_count++]=
3569
new_key - ha_alter_info->key_info_buffer;
3570
key_part= new_key->key_part;
3571
end= key_part + new_key->key_parts;
3572
for(; key_part != end; key_part++)
3574
/* Mark field to be part of new key */
3575
if ((field= table->field[key_part->fieldnr]))
3576
field->flags|= FIELD_IN_ADD_INDEX;
3578
*table_changes= IS_EQUAL_NO;
3580
/*end of for (; table_key < table_key_end;) */
3583
Step through all keys of the new table and find matching old keys.
3585
for (new_key= ha_alter_info->key_info_buffer;
3586
new_key < new_key_end;
3589
/* Search an old key with the same name. */
3590
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3592
if (! strcmp(table_key->name, new_key->name))
3595
if (table_key >= table_key_end)
3597
/* Key not found. Add the offset of the key to the add buffer. */
3598
ha_alter_info->index_add_buffer
3599
[ha_alter_info->index_add_count++]=
3600
new_key - ha_alter_info->key_info_buffer;
3601
key_part= new_key->key_part;
3602
end= key_part + new_key->key_parts;
3603
for(; key_part != end; key_part++)
3605
/* Mark field to be part of new key */
3606
if ((field= table->field[key_part->fieldnr]))
3607
field->flags|= FIELD_IN_ADD_INDEX;
3609
if (new_key->flags & HA_NOSAME)
3611
/* Unique key. Check for "PRIMARY" */
3612
if (is_primary_key(new_key))
3613
*alter_flags|= HA_ADD_PK_INDEX;
3615
*alter_flags|= HA_ADD_UNIQUE_INDEX;
3618
*alter_flags|= HA_ADD_INDEX;
3619
*table_changes= IS_EQUAL_NO;
3628
Manages enabling/disabling of indexes for ALTER Table
3631
alter_table_manage_keys()
3633
indexes_were_disabled Whether the indexes of the from table
3635
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
3643
bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
3644
enum enum_enable_or_disable keys_onoff)
3647
switch (keys_onoff) {
3649
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3652
if (!indexes_were_disabled)
3654
/* fall-through: disabled indexes */
3656
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3659
if (error == HA_ERR_WRONG_COMMAND)
3661
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3662
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3663
table->s->table_name.str);
3666
table->file->print_error(error, MYF(0));
3671
int create_temporary_table(Session *session,
3675
HA_CREATE_INFO *create_info,
3676
Alter_info *alter_info,
3680
char index_file[FN_REFLEN], data_file[FN_REFLEN];
3681
handlerton *old_db_type, *new_db_type;
3682
old_db_type= table->s->db_type();
3683
new_db_type= create_info->db_type;
3685
Handling of symlinked tables:
3687
Create new data file and index file on the same disk as the
3688
old data and index files.
3690
Rename new data file over old data file and new index file over
3692
Symlinks are not changed.
3695
Create new data file and index file on the same disk as the
3696
old data and index files. Create also symlinks to point at
3699
At end, rename intermediate tables, and symlinks to intermediate
3700
table, to final table name.
3701
Remove old table and old symlinks
3703
If rename is made to another database:
3704
Create new tables in new database.
3706
Remove old table and symlinks.
3708
if (db_changed) // Ignore symlink if db changed
3710
if (create_info->index_file_name)
3712
/* Fix index_file_name to have 'tmp_name' as basename */
3713
strcpy(index_file, tmp_name);
3714
create_info->index_file_name=fn_same(index_file,
3715
create_info->index_file_name,
3718
if (create_info->data_file_name)
3720
/* Fix data_file_name to have 'tmp_name' as basename */
3721
strcpy(data_file, tmp_name);
3722
create_info->data_file_name=fn_same(data_file,
3723
create_info->data_file_name,
3728
create_info->data_file_name=create_info->index_file_name=0;
3731
Create a table with a temporary name.
3732
We don't log the statement, it will be logged later.
3734
tmp_disable_binlog(session);
3735
error= mysql_create_table(session, new_db, tmp_name,
3736
create_info, alter_info, 1, 0);
3737
reenable_binlog(session);
3743
Create a temporary table that reflects what an alter table operation
3747
create_altered_table()
3748
session Thread handle
3749
table The original table
3750
create_info Information from the parsing phase about new
3752
alter_info Lists of fields, keys to be changed, added
3754
db_change Specifies if the table is moved to another database
3756
A temporary table with all changes
3759
The temporary table is created without storing it in any storage engine
3760
and is opened only to get the table struct and frm file reference.
3762
Table *create_altered_table(Session *session,
3765
HA_CREATE_INFO *create_info,
3766
Alter_info *alter_info,
3770
HA_CREATE_INFO altered_create_info(*create_info);
3771
Table *altered_table;
3773
char path[FN_REFLEN];
3775
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64,
3776
TMP_FILE_PREFIX, (unsigned long)current_pid, session->thread_id);
3777
/* Safety fix for InnoDB */
3778
if (lower_case_table_names)
3779
my_casedn_str(files_charset_info, tmp_name);
3780
altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3782
if ((error= create_temporary_table(session, table, new_db, tmp_name,
3783
&altered_create_info,
3784
alter_info, db_change)))
3789
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3791
altered_table= open_temporary_table(session, path, new_db, tmp_name, 1,
3793
return(altered_table);
3800
Perform a fast or on-line alter table
3803
mysql_fast_or_online_alter_table()
3804
session Thread handle
3805
table The original table
3806
altered_table A temporary table showing how we will change table
3807
create_info Information from the parsing phase about new
3809
alter_info Storage place for data used during different phases
3810
ha_alter_flags Bitmask that shows what will be changed
3811
keys_onoff Specifies if keys are to be enabled/disabled
3814
>0 An error occured during the on-line alter table operation
3815
-1 Error when re-opening table
3817
If mysql_alter_table does not need to copy the table, it is
3818
either a fast alter table where the storage engine does not
3819
need to know about the change, only the frm will change,
3820
or the storage engine supports performing the alter table
3821
operation directly, on-line without mysql having to copy
3824
int mysql_fast_or_online_alter_table(Session *session,
3826
Table *altered_table,
3827
HA_CREATE_INFO *create_info,
3828
HA_ALTER_INFO *alter_info,
3829
HA_ALTER_FLAGS *ha_alter_flags,
3830
enum enum_enable_or_disable keys_onoff)
3833
bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3839
Tell the handler to prepare for the online alter
3841
if ((error= table->file->alter_table_phase1(session,
3851
Tell the storage engine to perform the online alter table
3853
if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3854
we need to wrap the next call with a DDL lock.
3856
if ((error= table->file->alter_table_phase2(session,
3866
The final .frm file is already created as a temporary file
3867
and will be renamed to the original table name.
3869
pthread_mutex_lock(&LOCK_open);
3870
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3871
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3873
close_data_files_and_morph_locks(session,
3874
table->pos_in_table_list->db,
3875
table->pos_in_table_list->table_name);
3876
if (mysql_rename_table(NULL,
3877
altered_table->s->db.str,
3878
altered_table->s->table_name.str,
3880
table->s->table_name.str, FN_FROM_IS_TMP))
3883
pthread_mutex_unlock(&LOCK_open);
3886
broadcast_refresh();
3887
pthread_mutex_unlock(&LOCK_open);
3890
The ALTER Table is always in its own transaction.
3891
Commit must not be called while LOCK_open is locked. It could call
3892
wait_if_global_read_lock(), which could create a deadlock if called
3895
error= ha_autocommit_or_rollback(session, 0);
3897
if (ha_commit(session))
3903
pthread_mutex_lock(&LOCK_open);
3904
if (reopen_table(table))
3909
pthread_mutex_unlock(&LOCK_open);
3913
Tell the handler that the changed frm is on disk and table
3916
if ((error= t_table->file->alter_table_phase3(session, t_table)))
3922
We are going to reopen table down on the road, so we have to restore
3923
state of the Table object which we used for obtaining of handler
3924
object to make it suitable for reopening.
3926
assert(t_table == table);
3927
table->open_placeholder= 1;
3928
pthread_mutex_lock(&LOCK_open);
3929
close_handle_and_leave_table_as_lock(table);
3930
pthread_mutex_unlock(&LOCK_open);
3941
Prepare column and key definitions for CREATE TABLE in ALTER Table.
3943
This function transforms parse output of ALTER Table - lists of
3944
columns and keys to add, drop or modify into, essentially,
3945
CREATE TABLE definition - a list of columns and keys of the new
3946
table. While doing so, it also performs some (bug not all)
3949
This function is invoked when we know that we're going to
3950
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
3951
is not possible, perhaps because the ALTER statement contains
3952
instructions that require change in table data, not only in
3953
table definition or indexes.
3955
@param[in,out] session thread handle. Used as a memory pool
3956
and source of environment information.
3957
@param[in] table the source table, open and locked
3958
Used as an interface to the storage engine
3959
to acquire additional information about
3961
@param[in,out] create_info A blob with CREATE/ALTER Table
3963
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
3964
Originally create_info was used only in
3965
CREATE TABLE and alter_info only in ALTER Table.
3966
But since ALTER might end-up doing CREATE,
3967
this distinction is gone and we just carry
3968
around two structures.
3971
Fills various create_info members based on information retrieved
3972
from the storage engine.
3973
Sets create_info->varchar if the table has a VARCHAR column.
3974
Prepares alter_info->create_list and alter_info->key_list with
3975
columns and keys of the new table.
3976
@retval true error, out of memory or a semantical error in ALTER
3978
@retval false success
3982
mysql_prepare_alter_table(Session *session, Table *table,
3983
HA_CREATE_INFO *create_info,
3984
Alter_info *alter_info)
3986
/* New column definitions are added here */
3987
List<Create_field> new_create_list;
3988
/* New key definitions are added here */
3989
List<Key> new_key_list;
3990
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
3991
List_iterator<Create_field> def_it(alter_info->create_list);
3992
List_iterator<Alter_column> alter_it(alter_info->alter_list);
3993
List_iterator<Key> key_it(alter_info->key_list);
3994
List_iterator<Create_field> find_it(new_create_list);
3995
List_iterator<Create_field> field_it(new_create_list);
3996
List<Key_part_spec> key_parts;
3997
uint32_t db_create_options= (table->s->db_create_options
3998
& ~(HA_OPTION_PACK_RECORD));
3999
uint32_t used_fields= create_info->used_fields;
4000
KEY *key_info=table->key_info;
4004
create_info->varchar= false;
4005
/* Let new create options override the old ones */
4006
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
4007
create_info->min_rows= table->s->min_rows;
4008
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
4009
create_info->max_rows= table->s->max_rows;
4010
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
4011
create_info->avg_row_length= table->s->avg_row_length;
4012
if (!(used_fields & HA_CREATE_USED_BLOCK_SIZE))
4013
create_info->block_size= table->s->block_size;
4014
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
4015
create_info->default_table_charset= table->s->table_charset;
4016
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
4018
/* Table has an autoincrement, copy value to new table */
4019
table->file->info(HA_STATUS_AUTO);
4020
create_info->auto_increment_value= table->file->stats.auto_increment_value;
4022
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
4023
create_info->key_block_size= table->s->key_block_size;
4025
restore_record(table, s->default_values); // Empty record for DEFAULT
4029
First collect all fields from table which isn't in drop_list
4031
Field **f_ptr,*field;
4032
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
4034
/* Check if field should be dropped */
4037
while ((drop=drop_it++))
4039
if (drop->type == Alter_drop::COLUMN &&
4040
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
4042
/* Reset auto_increment value if it was dropped */
4043
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
4044
!(used_fields & HA_CREATE_USED_AUTO))
4046
create_info->auto_increment_value=0;
4047
create_info->used_fields|=HA_CREATE_USED_AUTO;
4057
/* Check if field is changed */
4059
while ((def=def_it++))
4062
!my_strcasecmp(system_charset_info,field->field_name, def->change))
4066
{ // Field is changed
4068
if (field->is_stored != def->is_stored)
4070
my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN,
4072
"Changing the STORED status");
4077
new_create_list.push_back(def);
4084
This field was not dropped and not changed, add it to the list
4087
def= new Create_field(field, field);
4088
new_create_list.push_back(def);
4089
alter_it.rewind(); // Change default if ALTER
4090
Alter_column *alter;
4091
while ((alter=alter_it++))
4093
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
4098
if (def->sql_type == DRIZZLE_TYPE_BLOB)
4100
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
4103
if ((def->def=alter->def)) // Use new default
4104
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
4106
def->flags|= NO_DEFAULT_VALUE_FLAG;
4112
while ((def=def_it++)) // Add new columns
4114
if (def->change && ! def->field)
4116
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
4120
Check that the DATE/DATETIME not null field we are going to add is
4121
either has a default value or the '0000-00-00' is allowed by the
4123
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
4124
flag to allow ALTER Table only if the table to be altered is empty.
4126
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
4127
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
4128
!alter_info->datetime_field &&
4129
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
4130
session->variables.sql_mode & MODE_NO_ZERO_DATE)
4132
alter_info->datetime_field= def;
4133
alter_info->error_if_not_empty= true;
4136
new_create_list.push_back(def);
4137
else if (def->after == first_keyword)
4138
new_create_list.push_front(def);
4143
while ((find=find_it++)) // Add new columns
4145
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
4150
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
4153
find_it.after(def); // Put element after this
4155
XXX: hack for Bug#28427.
4156
If column order has changed, force OFFLINE ALTER Table
4157
without querying engine capabilities. If we ever have an
4158
engine that supports online ALTER Table CHANGE COLUMN
4159
<name> AFTER <name1> (Falcon?), this fix will effectively
4160
disable the capability.
4161
TODO: detect the situation in compare_tables, behave based
4162
on engine capabilities.
4164
if (alter_info->build_method == HA_BUILD_ONLINE)
4166
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4169
alter_info->build_method= HA_BUILD_OFFLINE;
4172
if (alter_info->alter_list.elements)
4174
my_error(ER_BAD_FIELD_ERROR, MYF(0),
4175
alter_info->alter_list.head()->name, table->s->table_name.str);
4178
if (!new_create_list.elements)
4180
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
4186
Collect all keys which isn't in drop list. Add only those
4187
for which some fields exists.
4190
for (uint32_t i=0 ; i < table->s->keys ; i++,key_info++)
4192
char *key_name= key_info->name;
4195
while ((drop=drop_it++))
4197
if (drop->type == Alter_drop::KEY &&
4198
!my_strcasecmp(system_charset_info,key_name, drop->name))
4207
KEY_PART_INFO *key_part= key_info->key_part;
4209
for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
4211
if (!key_part->field)
4212
continue; // Wrong field (from UNIREG)
4213
const char *key_part_name=key_part->field->field_name;
4214
Create_field *cfield;
4216
while ((cfield=field_it++))
4220
if (!my_strcasecmp(system_charset_info, key_part_name,
4224
else if (!my_strcasecmp(system_charset_info,
4225
key_part_name, cfield->field_name))
4229
continue; // Field is removed
4230
uint32_t key_part_length=key_part->length;
4231
if (cfield->field) // Not new field
4234
If the field can't have only a part used in a key according to its
4235
new type, or should not be used partially according to its
4236
previous type, or the field length is less than the key part
4237
length, unset the key part length.
4239
We also unset the key part length if it is the same as the
4240
old field's length, so the whole new field will be used.
4242
BLOBs may have cfield->length == 0, which is why we test it before
4243
checking whether cfield->length < key_part_length (in chars).
4245
if (!Field::type_can_have_key_part(cfield->field->type()) ||
4246
!Field::type_can_have_key_part(cfield->sql_type) ||
4247
(cfield->field->field_length == key_part_length &&
4248
!f_is_blob(key_part->key_type)) ||
4249
(cfield->length && (cfield->length < key_part_length /
4250
key_part->field->charset()->mbmaxlen)))
4251
key_part_length= 0; // Use whole field
4253
key_part_length /= key_part->field->charset()->mbmaxlen;
4254
key_parts.push_back(new Key_part_spec(cfield->field_name,
4255
strlen(cfield->field_name),
4258
if (key_parts.elements)
4260
KEY_CREATE_INFO key_create_info;
4262
enum Key::Keytype key_type;
4263
memset(&key_create_info, 0, sizeof(key_create_info));
4265
key_create_info.algorithm= key_info->algorithm;
4266
if (key_info->flags & HA_USES_BLOCK_SIZE)
4267
key_create_info.block_size= key_info->block_size;
4268
if (key_info->flags & HA_USES_COMMENT)
4269
key_create_info.comment= key_info->comment;
4271
if (key_info->flags & HA_NOSAME)
4273
if (is_primary_key_name(key_name))
4274
key_type= Key::PRIMARY;
4276
key_type= Key::UNIQUE;
4279
key_type= Key::MULTIPLE;
4281
key= new Key(key_type, key_name, strlen(key_name),
4283
test(key_info->flags & HA_GENERATED_KEY),
4285
new_key_list.push_back(key);
4290
while ((key=key_it++)) // Add new keys
4292
if (key->type == Key::FOREIGN_KEY &&
4293
((Foreign_key *)key)->validate(new_create_list))
4295
if (key->type != Key::FOREIGN_KEY)
4296
new_key_list.push_back(key);
4297
if (key->name.str && is_primary_key_name(key->name.str))
4299
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
4305
if (alter_info->drop_list.elements)
4307
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4308
alter_info->drop_list.head()->name);
4311
if (alter_info->alter_list.elements)
4313
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4314
alter_info->alter_list.head()->name);
4318
if (!create_info->comment.str)
4320
create_info->comment.str= table->s->comment.str;
4321
create_info->comment.length= table->s->comment.length;
4324
table->file->update_create_info(create_info);
4325
if ((create_info->table_options &
4326
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
4327
(used_fields & HA_CREATE_USED_PACK_KEYS))
4328
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
4329
if (create_info->table_options &
4330
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
4331
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
4332
if (create_info->table_options &
4333
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
4334
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
4335
HA_OPTION_NO_DELAY_KEY_WRITE);
4336
create_info->table_options|= db_create_options;
4338
if (table->s->tmp_table)
4339
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
4342
alter_info->create_list.swap(new_create_list);
4343
alter_info->key_list.swap(new_key_list);
4354
session Thread handle
4355
new_db If there is a RENAME clause
4356
new_name If there is a RENAME clause
4357
create_info Information from the parsing phase about new
4359
table_list The table to change.
4360
alter_info Lists of fields, keys to be changed, added
4362
order_num How many order_st BY fields has been specified.
4363
order List of fields to order_st BY.
4364
ignore Whether we have ALTER IGNORE Table
4367
This is a veery long function and is everything but the kitchen sink :)
4368
It is used to alter a table and not only by ALTER Table but also
4369
CREATE|DROP INDEX are mapped on this function.
4371
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
4372
or both, then this function short cuts its operation by renaming
4373
the table and/or enabling/disabling the keys. In this case, the FRM is
4374
not changed, directly by mysql_alter_table. However, if there is a
4375
RENAME + change of a field, or an index, the short cut is not used.
4376
See how `create_list` is used to generate the new FRM regarding the
4377
structure of the fields. The same is done for the indices of the table.
4379
Important is the fact, that this function tries to do as little work as
4380
possible, by finding out whether a intermediate table is needed to copy
4381
data into and when finishing the altering to use it as the original table.
4382
For this reason the function compare_tables() is called, which decides
4383
based on all kind of data how similar are the new and the original
4391
bool mysql_alter_table(Session *session,char *new_db, char *new_name,
4392
HA_CREATE_INFO *create_info,
4393
TableList *table_list,
4394
Alter_info *alter_info,
4395
uint32_t order_num, order_st *order, bool ignore)
4397
Table *table, *new_table=0, *name_lock= 0;;
4398
string new_name_str;
4400
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
4401
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
4402
char path[FN_REFLEN];
4403
ha_rows copied= 0,deleted= 0;
4404
handlerton *old_db_type, *new_db_type, *save_old_db_type;
4406
new_name_buff[0]= '\0';
4408
if (table_list && table_list->schema_table)
4410
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
4415
Assign variables table_name, new_name, db, new_db, path
4416
to simplify further comparisons: we want to see if it's a RENAME
4417
later just by comparing the pointers, avoiding the need for strcmp.
4419
session->set_proc_info("init");
4420
table_name=table_list->table_name;
4421
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
4423
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
4425
build_table_filename(path, sizeof(path), db, table_name, "", 0);
4427
mysql_ha_rm_tables(session, table_list, false);
4429
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
4430
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
4431
/* Conditionally writes to binlog. */
4432
return(mysql_discard_or_import_tablespace(session,table_list,
4433
alter_info->tablespace_op));
4435
oss << drizzle_data_home << "/" << db << "/" << table_name << reg_ext;
4437
(void) unpack_filename(new_name_buff, oss.str().c_str());
4439
If this is just a rename of a view, short cut to the
4440
following scenario: 1) lock LOCK_open 2) do a RENAME
4441
2) unlock LOCK_open.
4442
This is a copy-paste added to make sure
4443
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
4444
as an independent branch in mysql_execute_command. The need
4445
for a copy-paste arose because the main code flow of ALTER Table
4446
... RENAME tries to use open_ltable, which does not work for views
4447
(open_ltable was never modified to merge table lists of child tables
4448
into the main table list, like open_tables does).
4449
This code is wrong and will be removed, please do not copy.
4452
if (!(table= open_n_lock_single_table(session, table_list, TL_WRITE_ALLOW_READ)))
4454
table->use_all_columns();
4456
/* Check that we are not trying to rename to an existing table */
4459
strcpy(new_name_buff,new_name);
4460
strcpy(new_alias= new_alias_buff, new_name);
4461
if (lower_case_table_names)
4463
if (lower_case_table_names != 2)
4465
my_casedn_str(files_charset_info, new_name_buff);
4466
new_alias= new_name; // Create lower case table name
4468
my_casedn_str(files_charset_info, new_name);
4471
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
4474
Source and destination table names are equal: make later check
4477
new_alias= new_name= table_name;
4481
if (table->s->tmp_table != NO_TMP_TABLE)
4483
if (find_temporary_table(session,new_db,new_name_buff))
4485
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
4491
if (lock_table_name_if_not_cached(session, new_db, new_name, &name_lock))
4495
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4499
build_table_filename(new_name_buff, sizeof(new_name_buff),
4500
new_db, new_name_buff, reg_ext, 0);
4501
if (!access(new_name_buff, F_OK))
4503
/* Table will be closed in do_command() */
4504
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4512
new_alias= (lower_case_table_names == 2) ? alias : table_name;
4513
new_name= table_name;
4516
old_db_type= table->s->db_type();
4517
if (!create_info->db_type)
4519
create_info->db_type= old_db_type;
4522
if (check_engine(session, new_name, create_info))
4524
new_db_type= create_info->db_type;
4526
if (new_db_type != old_db_type &&
4527
!table->file->can_switch_engines())
4530
my_error(ER_ROW_IS_REFERENCED, MYF(0));
4534
if (create_info->row_type == ROW_TYPE_NOT_USED)
4535
create_info->row_type= table->s->row_type;
4537
if (ha_check_storage_engine_flag(old_db_type, HTON_BIT_ALTER_NOT_SUPPORTED) ||
4538
ha_check_storage_engine_flag(new_db_type, HTON_BIT_ALTER_NOT_SUPPORTED))
4540
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
4544
session->set_proc_info("setup");
4545
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
4546
!table->s->tmp_table) // no need to touch frm
4548
switch (alter_info->keys_onoff) {
4553
wait_while_table_is_used() ensures that table being altered is
4554
opened only by this thread and that Table::TABLE_SHARE::version
4555
of Table object corresponding to this table is 0.
4556
The latter guarantees that no DML statement will open this table
4557
until ALTER Table finishes (i.e. until close_thread_tables())
4558
while the fact that the table is still open gives us protection
4559
from concurrent DDL statements.
4561
pthread_mutex_lock(&LOCK_open);
4562
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4563
pthread_mutex_unlock(&LOCK_open);
4564
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4565
/* COND_refresh will be signaled in close_thread_tables() */
4568
pthread_mutex_lock(&LOCK_open);
4569
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4570
pthread_mutex_unlock(&LOCK_open);
4571
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4572
/* COND_refresh will be signaled in close_thread_tables() */
4579
if (error == HA_ERR_WRONG_COMMAND)
4582
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4583
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4587
pthread_mutex_lock(&LOCK_open);
4589
Unlike to the above case close_cached_table() below will remove ALL
4590
instances of Table from table cache (it will also remove table lock
4591
held by this thread). So to make actual table renaming and writing
4592
to binlog atomic we have to put them into the same critical section
4593
protected by LOCK_open mutex. This also removes gap for races between
4594
access() and mysql_rename_table() calls.
4597
if (!error && (new_name != table_name || new_db != db))
4599
session->set_proc_info("rename");
4601
Then do a 'simple' rename of the table. First we need to close all
4602
instances of 'source' table.
4604
close_cached_table(session, table);
4606
Then, we want check once again that target table does not exist.
4607
Actually the order of these two steps does not matter since
4608
earlier we took name-lock on the target table, so we do them
4609
in this particular order only to be consistent with 5.0, in which
4610
we don't take this name-lock and where this order really matters.
4611
TODO: Investigate if we need this access() check at all.
4613
if (!access(new_name_buff,F_OK))
4615
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
4620
*fn_ext(new_name)=0;
4621
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
4625
mysql_rename_table(old_db_type, new_db, new_alias, db,
4632
if (error == HA_ERR_WRONG_COMMAND)
4635
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4636
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4642
write_bin_log(session, true, session->query, session->query_length);
4647
table->file->print_error(error, MYF(0));
2193
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2194
session->unlink_open_table(name_lock);
2200
if (is_if_not_exists)
4651
unlink_open_table(session, name_lock, false);
4652
pthread_mutex_unlock(&LOCK_open);
4653
table_list->table= NULL; // For query cache
4657
/* We have to do full alter table. */
4660
If the old table had partitions and we are doing ALTER Table ...
4661
engine= <new_engine>, the new table must preserve the original
4662
partitioning. That means that the new engine is still the
4663
partitioning engine, not the engine specified in the parser.
4664
This is discovered in prep_alter_part_table, which in such case
4665
updates create_info->db_type.
4666
Now we need to update the stack copy of create_info->db_type,
4667
as otherwise we won't be able to correctly move the files of the
4668
temporary table to the result table files.
4670
new_db_type= create_info->db_type;
4672
if (mysql_prepare_alter_table(session, table, create_info, alter_info))
4675
set_table_default_charset(session, create_info, db);
4678
if (session->variables.old_alter_table
4679
|| (table->s->db_type() != create_info->db_type)
4682
if (alter_info->build_method == HA_BUILD_ONLINE)
4684
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4687
alter_info->build_method= HA_BUILD_OFFLINE;
4690
if (alter_info->build_method != HA_BUILD_OFFLINE)
4692
Table *altered_table= 0;
4693
HA_ALTER_INFO ha_alter_info;
4694
HA_ALTER_FLAGS ha_alter_flags;
4695
uint32_t table_changes= IS_EQUAL_YES;
4696
bool need_copy_table= true;
4697
/* Check how much the tables differ. */
4698
if (compare_tables(session, table, alter_info,
4699
create_info, order_num,
4708
Check if storage engine supports altering the table
4714
If table is not renamed, changed database and
4715
some change was detected then check if engine
4716
can do the change on-line
4718
if (new_name == table_name && new_db == db &&
4719
ha_alter_flags.is_set())
4721
Alter_info tmp_alter_info(*alter_info, session->mem_root);
4725
check if table can be altered on-line
4727
if (!(altered_table= create_altered_table(session,
4732
!strcmp(db, new_db))))
4735
switch (table->file->check_if_supported_alter(altered_table,
4739
case HA_ALTER_SUPPORTED_WAIT_LOCK:
4740
case HA_ALTER_SUPPORTED_NO_LOCK:
4742
@todo: Currently we always acquire an exclusive name
4743
lock on the table metadata when performing fast or online
4744
ALTER Table. In future we may consider this unnecessary,
4745
and narrow the scope of the exclusive name lock to only
4746
cover manipulation with .frms. Storage engine API
4747
call check_if_supported_alter has provision for this
4750
need_copy_table= false;
4752
case HA_ALTER_NOT_SUPPORTED:
4753
if (alter_info->build_method == HA_BUILD_ONLINE)
4755
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4756
close_temporary_table(session, altered_table, 1, 1);
4759
need_copy_table= true;
4761
case HA_ALTER_ERROR:
4763
close_temporary_table(session, altered_table, 1, 1);
4768
/* TODO need to check if changes can be handled as fast ALTER Table */
4770
need_copy_table= true;
4772
if (!need_copy_table)
4774
error= mysql_fast_or_online_alter_table(session,
4780
alter_info->keys_onoff);
4783
mysql_unlock_tables(session, session->lock);
4786
close_temporary_table(session, altered_table, 1, 1);
4792
goto err_with_placeholders;
4799
pthread_mutex_lock(&LOCK_open);
4805
close_temporary_table(session, altered_table, 1, 1);
4808
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX,
4809
(unsigned long)current_pid, session->thread_id);
4810
/* Safety fix for innodb */
4811
if (lower_case_table_names)
4812
my_casedn_str(files_charset_info, tmp_name);
4815
/* Create a temporary table with the new format */
4816
if ((error= create_temporary_table(session, table, new_db, tmp_name,
4817
create_info, alter_info,
4818
!strcmp(db, new_db))))
4823
/* Open the table so we need to copy the data to it. */
4824
if (table->s->tmp_table)
4827
memset(&tbl, 0, sizeof(tbl));
4829
tbl.table_name= tbl.alias= tmp_name;
4830
/* Table is in session->temporary_tables */
4831
new_table= open_table(session, &tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
4835
char path[FN_REFLEN];
4836
/* table is a normal table: Create temporary table in same directory */
4837
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
4839
/* Open our intermediate table */
4840
new_table=open_temporary_table(session, path, new_db, tmp_name, 0, OTM_OPEN);
4845
/* Copy the data if necessary. */
4846
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
4847
session->cuted_fields=0L;
4848
session->set_proc_info("copy to tmp table");
4851
We do not copy data for MERGE tables. Only the children have data.
4852
MERGE tables have HA_NO_COPY_ON_ALTER set.
4854
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
4856
/* We don't want update TIMESTAMP fields during ALTER Table. */
4857
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
4858
new_table->next_number_field=new_table->found_next_number_field;
4859
error= copy_data_between_tables(table, new_table,
4860
alter_info->create_list, ignore,
4861
order_num, order, &copied, &deleted,
4862
alter_info->keys_onoff,
4863
alter_info->error_if_not_empty);
4867
pthread_mutex_lock(&LOCK_open);
4868
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4869
pthread_mutex_unlock(&LOCK_open);
4870
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
4871
alter_info->keys_onoff);
4872
error= ha_autocommit_or_rollback(session, 0);
4873
if (end_active_trans(session))
4876
session->count_cuted_fields= CHECK_FIELD_IGNORE;
4878
if (table->s->tmp_table != NO_TMP_TABLE)
4880
/* We changed a temporary table */
4883
/* Close lock if this is a transactional table */
4886
mysql_unlock_tables(session, session->lock);
4889
/* Remove link to old table and rename the new one */
4890
close_temporary_table(session, table, 1, 1);
4891
/* Should pass the 'new_name' as we store table name in the cache */
4892
if (rename_temporary_table(session, new_table, new_db, new_name))
4900
Close the intermediate table that will be the new table.
4901
Note that MERGE tables do not have their children attached here.
4903
intern_close_table(new_table);
4906
pthread_mutex_lock(&LOCK_open);
4909
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4910
pthread_mutex_unlock(&LOCK_open);
4915
Data is copied. Now we:
4916
1) Wait until all other threads close old version of table.
4917
2) Close instances of table open by this thread and replace them
4918
with exclusive name-locks.
4919
3) Rename the old table to a temp name, rename the new one to the
4921
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
4922
we reopen new version of table.
4923
5) Write statement to the binary log.
4924
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
4925
remove name-locks from list of open tables and table cache.
4926
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
4927
call to remove name-locks from table cache and list of open table.
4930
session->set_proc_info("rename result table");
4931
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX,
4932
(unsigned long)current_pid, session->thread_id);
4933
if (lower_case_table_names)
4934
my_casedn_str(files_charset_info, old_name);
4936
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
4937
close_data_files_and_morph_locks(session, db, table_name);
4940
save_old_db_type= old_db_type;
4943
This leads to the storage engine (SE) not being notified for renames in
4944
mysql_rename_table(), because we just juggle with the FRM and nothing
4945
more. If we have an intermediate table, then we notify the SE that
4946
it should become the actual table. Later, we will recycle the old table.
4947
However, in case of ALTER Table RENAME there might be no intermediate
4948
table. This is when the old and new tables are compatible, according to
4949
compare_table(). Then, we need one additional call to
4950
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
4951
actual rename in the SE and the FRM is not touched. Note that, if the
4952
table is renamed and the SE is also changed, then an intermediate table
4953
is created and the additional call will not take place.
4955
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
4959
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4961
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
4962
new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
4964
/* Try to get everything back. */
4966
quick_rm_table(new_db_type,new_db,new_alias, 0);
4967
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4968
mysql_rename_table(old_db_type, db, old_name, db, alias,
4974
/* This shouldn't happen. But let us play it safe. */
4975
goto err_with_placeholders;
4978
quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
4981
if (session->locked_tables && new_name == table_name && new_db == db)
4983
session->in_lock_tables= 1;
4984
error= reopen_tables(session, 1, 1);
4985
session->in_lock_tables= 0;
4987
goto err_with_placeholders;
4989
pthread_mutex_unlock(&LOCK_open);
4991
session->set_proc_info("end");
4993
assert(!(drizzle_bin_log.is_open() &&
4994
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
4995
write_bin_log(session, true, session->query, session->query_length);
4997
if (ha_check_storage_engine_flag(old_db_type, HTON_BIT_FLUSH_AFTER_RENAME))
5000
For the alter table to be properly flushed to the logs, we
5001
have to open the new table. If not, we get a problem on server
5002
shutdown. But we do not need to attach MERGE children.
5004
char path[FN_REFLEN];
5006
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
5007
t_table= open_temporary_table(session, path, new_db, tmp_name, false, OTM_OPEN);
5010
intern_close_table(t_table);
5014
sql_print_warning(_("Could not open table %s.%s after rename\n"),
5016
ha_flush_logs(old_db_type);
5018
table_list->table=0; // For query cache
5020
if (session->locked_tables && (new_name != table_name || new_db != db))
5023
If are we under LOCK TABLES and did ALTER Table with RENAME we need
5024
to remove placeholders for the old table and for the target table
5025
from the list of open tables and table cache. If we are not under
5026
LOCK TABLES we can rely on close_thread_tables() doing this job.
5028
pthread_mutex_lock(&LOCK_open);
5029
unlink_open_table(session, table, false);
5030
unlink_open_table(session, name_lock, false);
5031
pthread_mutex_unlock(&LOCK_open);
5035
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
5036
(ulong) (copied + deleted), (ulong) deleted,
5037
(ulong) session->cuted_fields);
5038
my_ok(session, copied + deleted, 0L, tmp_name);
5039
session->some_tables_deleted=0;
5045
/* close_temporary_table() frees the new_table pointer. */
5046
close_temporary_table(session, new_table, 1, 1);
5049
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
5053
No default value was provided for a DATE/DATETIME field, the
5054
current sql_mode doesn't allow the '0000-00-00' value and
5055
the table to be altered isn't empty.
5058
if (alter_info->error_if_not_empty && session->row_count)
5060
const char *f_val= 0;
5061
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
5062
switch (alter_info->datetime_field->sql_type)
5064
case DRIZZLE_TYPE_DATE:
5065
f_val= "0000-00-00";
5066
t_type= DRIZZLE_TIMESTAMP_DATE;
5068
case DRIZZLE_TYPE_DATETIME:
5069
f_val= "0000-00-00 00:00:00";
5070
t_type= DRIZZLE_TIMESTAMP_DATETIME;
5073
/* Shouldn't get here. */
5076
bool save_abort_on_warning= session->abort_on_warning;
5077
session->abort_on_warning= true;
5078
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5079
f_val, strlength(f_val), t_type,
5080
alter_info->datetime_field->field_name);
5081
session->abort_on_warning= save_abort_on_warning;
5085
pthread_mutex_lock(&LOCK_open);
5086
unlink_open_table(session, name_lock, false);
5087
pthread_mutex_unlock(&LOCK_open);
5091
err_with_placeholders:
5093
An error happened while we were holding exclusive name-lock on table
5094
being altered. To be safe under LOCK TABLES we should remove placeholders
5095
from list of open tables list and table cache.
5097
unlink_open_table(session, table, false);
5099
unlink_open_table(session, name_lock, false);
5100
pthread_mutex_unlock(&LOCK_open);
5103
/* mysql_alter_table */
5106
copy_data_between_tables(Table *from,Table *to,
5107
List<Create_field> &create,
5109
uint32_t order_num, order_st *order,
5112
enum enum_enable_or_disable keys_onoff,
5113
bool error_if_not_empty)
5116
Copy_field *copy,*copy_end;
5117
ulong found_count,delete_count;
5118
Session *session= current_session;
5120
SORT_FIELD *sortorder;
5124
List<Item> all_fields;
5125
ha_rows examined_rows;
5126
bool auto_increment_field_copied= 0;
5127
ulong save_sql_mode;
5128
uint64_t prev_insert_id;
5131
Turn off recovery logging since rollback of an alter table is to
5132
delete the new table so there is no need to log the changes to it.
5134
This needs to be done before external_lock
5136
error= ha_enable_transaction(session, false);
5140
if (!(copy= new Copy_field[to->s->fields]))
5141
return(-1); /* purecov: inspected */
5143
if (to->file->ha_external_lock(session, F_WRLCK))
5146
/* We need external lock before we can disable/enable keys */
5147
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
5149
/* We can abort alter table for any table type */
5150
session->abort_on_warning= !ignore;
5152
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5153
to->file->ha_start_bulk_insert(from->file->stats.records);
5155
save_sql_mode= session->variables.sql_mode;
5157
List_iterator<Create_field> it(create);
5160
for (Field **ptr=to->field ; *ptr ; ptr++)
5165
if (*ptr == to->next_number_field)
5166
auto_increment_field_copied= true;
5168
(copy_end++)->set(*ptr,def->field,0);
5173
found_count=delete_count=0;
5177
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
2202
5179
char warn_buff[DRIZZLE_ERRMSG_SIZE];
2203
5180
snprintf(warn_buff, sizeof(warn_buff),
2204
ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
2205
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2206
ER_TABLE_EXISTS_ERROR, warn_buff);
2210
my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
5181
_("order_st BY ignored because there is a user-defined clustered "
5182
"index in the table '%-.192s'"),
5183
from->s->table_name.str);
5184
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
5189
from->sort.io_cache= new IO_CACHE;
5190
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
5192
memset(&tables, 0, sizeof(tables));
5194
tables.alias= tables.table_name= from->s->table_name.str;
5195
tables.db= from->s->db.str;
5198
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
5199
setup_order(session, session->lex->select_lex.ref_pointer_array,
5200
&tables, fields, all_fields, order) ||
5201
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
5202
(from->sort.found_records= filesort(session, from, sortorder, length,
5203
(SQL_SELECT *) 0, HA_POS_ERROR,
5204
1, &examined_rows)) ==
5210
/* Tell handler that we have values for all columns in the to table */
5211
to->use_all_columns();
5212
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
5214
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
5215
session->row_count= 0;
5216
restore_record(to, s->default_values); // Create empty record
5217
while (!(error=info.read_record(&info)))
5219
if (session->killed)
5221
session->send_kill_message();
5225
session->row_count++;
5226
/* Return error if source table isn't empty. */
5227
if (error_if_not_empty)
5232
if (to->next_number_field)
5234
if (auto_increment_field_copied)
5235
to->auto_increment_field_not_null= true;
5237
to->next_number_field->reset();
5240
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
5242
copy_ptr->do_copy(copy_ptr);
5244
prev_insert_id= to->file->next_insert_id;
5245
update_virtual_fields_marked_for_write(to, false);
5246
error=to->file->ha_write_row(to->record[0]);
5247
to->auto_increment_field_not_null= false;
5251
to->file->is_fatal_error(error, HA_CHECK_DUP))
5253
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
5255
uint32_t key_nr= to->file->get_dup_key(error);
5256
if ((int) key_nr >= 0)
5258
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
5260
(to->key_info[0].key_part[0].field->flags &
5261
AUTO_INCREMENT_FLAG))
5262
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
5263
to->file->print_keydup_error(key_nr, err_msg);
5268
to->file->print_error(error,MYF(0));
5271
to->file->restore_auto_increment(prev_insert_id);
5277
end_read_record(&info);
5278
free_io_cache(from);
5279
delete [] copy; // This is never 0
5281
if (to->file->ha_end_bulk_insert() && error <= 0)
5283
to->file->print_error(my_errno,MYF(0));
5286
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
5288
if (ha_enable_transaction(session, true))
5295
Ensure that the new table is saved properly to disk so that we
5298
if (ha_autocommit_or_rollback(session, 0))
5300
if (end_active_trans(session))
5304
session->variables.sql_mode= save_sql_mode;
5305
session->abort_on_warning= 0;
5306
free_io_cache(from);
5307
*copied= found_count;
5308
*deleted=delete_count;
5309
to->file->ha_release_auto_increment();
5310
if (to->file->ha_external_lock(session,F_UNLCK))
5312
return(error > 0 ? -1 : 0);
5317
Recreates tables by calling mysql_alter_table().
5320
mysql_recreate_table()
5321
session Thread handler
5322
tables Tables to recreate
5325
Like mysql_alter_table().
5327
bool mysql_recreate_table(Session *session, TableList *table_list)
5329
HA_CREATE_INFO create_info;
5330
Alter_info alter_info;
5332
assert(!table_list->next_global);
5334
table_list->table has been closed and freed. Do not reference
5335
uninitialized data. open_tables() could fail.
5337
table_list->table= NULL;
5339
memset(&create_info, 0, sizeof(create_info));
5340
create_info.row_type=ROW_TYPE_NOT_USED;
5341
create_info.default_table_charset=default_charset_info;
5342
/* Force alter table to recreate table */
5343
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
5344
return(mysql_alter_table(session, NULL, NULL, &create_info,
5345
table_list, &alter_info, 0,
5346
(order_st *) 0, 0));
5350
bool mysql_checksum_table(Session *session, TableList *tables,
5351
HA_CHECK_OPT *check_opt)
5354
List<Item> field_list;
5356
Protocol *protocol= session->protocol;
5358
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
5359
item->maybe_null= 1;
5360
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
5361
MY_INT64_NUM_DECIMAL_DIGITS));
5362
item->maybe_null= 1;
5363
if (protocol->send_fields(&field_list,
5364
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
5367
/* Open one table after the other to keep lock time as short as possible. */
5368
for (table= tables; table; table= table->next_local)
5370
char table_name[NAME_LEN*2+2];
5373
sprintf(table_name,"%s.%s",table->db,table->table_name);
5375
t= table->table= open_n_lock_single_table(session, table, TL_READ);
5376
session->clear_error(); // these errors shouldn't get client
5378
protocol->prepare_for_resend();
5379
protocol->store(table_name, system_charset_info);
5383
/* Table didn't exist */
5384
protocol->store_null();
5385
session->clear_error();
5389
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
5390
!(check_opt->flags & T_EXTEND))
5391
protocol->store((uint64_t)t->file->checksum());
5392
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
5393
(check_opt->flags & T_QUICK))
5394
protocol->store_null();
5397
/* calculating table's checksum */
5399
unsigned char null_mask=256 - (1 << t->s->last_null_bit_pos);
5401
t->use_all_columns();
5403
if (t->file->ha_rnd_init(1))
5404
protocol->store_null();
5409
ha_checksum row_crc= 0;
5410
int error= t->file->rnd_next(t->record[0]);
5411
if (unlikely(error))
5413
if (error == HA_ERR_RECORD_DELETED)
5417
if (t->s->null_bytes)
5419
/* fix undefined null bits */
5420
t->record[0][t->s->null_bytes-1] |= null_mask;
5421
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
5422
t->record[0][0] |= 1;
5424
row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
5427
for (uint32_t i= 0; i < t->s->fields; i++ )
5429
Field *f= t->field[i];
5430
if ((f->type() == DRIZZLE_TYPE_BLOB) ||
5431
(f->type() == DRIZZLE_TYPE_VARCHAR))
5435
row_crc= my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
5438
row_crc= my_checksum(row_crc, f->ptr,
5444
protocol->store((uint64_t)crc);
5445
t->file->ha_rnd_end();
5448
session->clear_error();
5449
close_thread_tables(session);
5450
table->table=0; // For query cache
5452
if (protocol->write())
5460
close_thread_tables(session); // Shouldn't be needed
5466
static bool check_engine(Session *session, const char *table_name,
5467
HA_CREATE_INFO *create_info)
5469
handlerton **new_engine= &create_info->db_type;
5470
handlerton *req_engine= *new_engine;
5471
bool no_substitution= 1;
5472
if (!(*new_engine= ha_checktype(session, ha_legacy_type(req_engine),
5473
no_substitution, 1)))
2219
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2221
thr_lock_type lock_type = TL_READ_NO_INSERT;
2223
return(admin_table(session, tables, check_opt,
2224
"analyze", lock_type, true,
2225
&Cursor::ha_analyze));
2229
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2231
thr_lock_type lock_type = TL_READ_NO_INSERT;
2233
return(admin_table(session, tables, check_opt,
2236
&Cursor::ha_check));
2239
} /* namespace drizzled */
5476
if (req_engine && req_engine != *new_engine)
5478
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
5479
ER_WARN_USING_OTHER_HANDLER,
5480
ER(ER_WARN_USING_OTHER_HANDLER),
5481
ha_resolve_storage_engine_name(*new_engine),
5484
if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
5485
ha_check_storage_engine_flag(*new_engine, HTON_BIT_TEMPORARY_NOT_SUPPORTED))
5487
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5489
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
5490
ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
5494
*new_engine= myisam_hton;