2086
bool create_like_table(Session* session,
2087
identifier::Table::const_reference destination_identifier,
2088
identifier::Table::const_reference source_identifier,
2089
message::Table &create_table_proto,
2090
bool is_if_not_exists,
2914
bool mysql_create_like_table(Session* session, TableList* table, TableList* src_table,
2915
HA_CREATE_INFO *create_info)
2917
Table *name_lock= 0;
2918
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
2919
uint32_t dst_path_length;
2920
char *db= table->db;
2921
char *table_name= table->table_name;
2093
2923
bool res= true;
2094
bool table_exists= false;
2927
By opening source table we guarantee that it exists and no concurrent
2928
DDL operation will mess with it. Later we also take an exclusive
2929
name-lock on target table name, which makes copying of .frm file,
2930
call to ha_create_table() and binlogging atomic against concurrent DML
2931
and DDL operations on target table. Thus by holding both these "locks"
2932
we ensure that our statement is properly isolated from all concurrent
2933
operations which matter.
2935
if (open_tables(session, &src_table, ¬_used, 0))
2938
strxmov(src_path, src_table->table->s->path.str, reg_ext, NULL);
2097
2941
Check that destination tables does not exist. Note that its name
2098
2942
was already checked when it was added to the table list.
2100
For temporary tables we don't aim to grab locks.
2102
if (destination_identifier.isTmp())
2104
if (session->find_temporary_table(destination_identifier))
2110
bool was_created= create_table_wrapper(*session,
2112
destination_identifier,
2115
if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2117
(void) session->rm_temporary_table(destination_identifier, true);
2119
else if (not session->open_temporary_table(destination_identifier))
2121
// We created, but we can't open... also, a hack.
2122
(void) session->rm_temporary_table(destination_identifier, true);
2130
else // Standard table which will require locks.
2132
Table *name_lock= 0;
2134
if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2138
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2139
session->unlink_open_table(name_lock);
2149
else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2153
else // Otherwise we create the table
2157
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* We lock for CREATE TABLE LIKE to copy table definition */
2158
was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2159
source_identifier, is_engine_set);
2162
// So we blew the creation of the table, and we scramble to clean up
2163
// anything that might have been created (read... it is a hack)
2164
if (not was_created)
2166
plugin::StorageEngine::dropTable(*session, destination_identifier);
2944
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
2946
if (find_temporary_table(session, db, table_name))
2948
dst_path_length= build_tmptable_filename(session, dst_path, sizeof(dst_path));
2949
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
2953
if (lock_table_name_if_not_cached(session, db, table_name, &name_lock))
2957
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
2958
db, table_name, reg_ext, 0);
2959
if (!access(dst_path, F_OK))
2964
Create a new table by copying from source table
2966
Altough exclusive name-lock on target table protects us from concurrent
2967
DML and DDL operations on it we still want to wrap .FRM creation and call
2968
to ha_create_table() in critical section protected by LOCK_open in order
2969
to provide minimal atomicity against operations which disregard name-locks,
2970
like I_S implementation, for example. This is a temporary and should not
2971
be copied. Instead we should fix our code to always honor name-locks.
2973
Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2974
during the call to ha_create_table(). See bug #28614 for more info.
2976
pthread_mutex_lock(&LOCK_open);
2977
if (src_table->schema_table)
2979
if (mysql_create_like_schema_frm(session, src_table, dst_path, create_info))
2981
pthread_mutex_unlock(&LOCK_open);
2985
else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
2987
if (my_errno == ENOENT)
2988
my_error(ER_BAD_DB_ERROR,MYF(0),db);
2990
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
2991
pthread_mutex_unlock(&LOCK_open);
2996
As mysql_truncate don't work on a new table at this stage of
2997
creation, instead create the table directly (for both normal
2998
and temporary tables).
3000
dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
3001
if (session->variables.keep_files_on_create)
3002
create_info->options|= HA_CREATE_KEEP_FILES;
3003
err= ha_create_table(session, dst_path, db, table_name, create_info, 1);
3004
pthread_mutex_unlock(&LOCK_open);
3006
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
3008
if (err || !open_temporary_table(session, dst_path, db, table_name, 1,
3011
(void) rm_temporary_table(create_info->db_type,
3012
dst_path, false); /* purecov: inspected */
3013
goto err; /* purecov: inspected */
3018
(void) quick_rm_table(create_info->db_type, db,
3019
table_name, 0); /* purecov: inspected */
3020
goto err; /* purecov: inspected */
3024
We have to write the query before we unlock the tables.
3026
if (session->current_stmt_binlog_row_based)
3029
Since temporary tables are not replicated under row-based
3030
replication, CREATE TABLE ... LIKE ... needs special
3031
treatement. We have four cases to consider, according to the
3032
following decision table:
3034
==== ========= ========= ==============================
3035
Case Target Source Write to binary log
3036
==== ========= ========= ==============================
3037
1 normal normal Original statement
3038
2 normal temporary Generated statement
3039
3 temporary normal Nothing
3040
4 temporary temporary Nothing
3041
==== ========= ========= ==============================
3043
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
3045
if (src_table->table->s->tmp_table) // Case 2
3048
String query(buf, sizeof(buf), system_charset_info);
3049
query.length(0); // Have to zero it since constructor doesn't
3053
Here we open the destination table, on which we already have
3054
name-lock. This is needed for store_create_info() to work.
3055
The table will be closed by unlink_open_table() at the end
3058
table->table= name_lock;
3059
pthread_mutex_lock(&LOCK_open);
3060
if (reopen_name_locked_table(session, table, false))
3062
pthread_mutex_unlock(&LOCK_open);
3065
pthread_mutex_unlock(&LOCK_open);
3067
int result= store_create_info(session, table, &query,
3070
assert(result == 0); // store_create_info() always return 0
3071
write_bin_log(session, true, query.ptr(), query.length());
3074
write_bin_log(session, true, session->query, session->query_length);
3077
Case 3 and 4 does nothing under RBR
3081
write_bin_log(session, true, session->query, session->query_length);
3087
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
3089
char warn_buff[DRIZZLE_ERRMSG_SIZE];
3090
snprintf(warn_buff, sizeof(warn_buff),
3091
ER(ER_TABLE_EXISTS_ERROR), table_name);
3092
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3093
ER_TABLE_EXISTS_ERROR,warn_buff);
3097
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
3102
pthread_mutex_lock(&LOCK_open);
3103
unlink_open_table(session, name_lock, false);
3104
pthread_mutex_unlock(&LOCK_open);
3110
bool mysql_analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
3112
thr_lock_type lock_type = TL_READ_NO_INSERT;
3114
return(mysql_admin_table(session, tables, check_opt,
3115
"analyze", lock_type, 1, 0, 0, 0,
3116
&handler::ha_analyze));
3120
bool mysql_check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
3122
thr_lock_type lock_type = TL_READ_NO_INSERT;
3124
return(mysql_admin_table(session, tables, check_opt,
3126
0, 0, HA_OPEN_FOR_REPAIR, 0,
3127
&handler::ha_check));
3131
/* table_list should contain just one table */
3133
mysql_discard_or_import_tablespace(Session *session,
3134
TableList *table_list,
3135
enum tablespace_op_type tablespace_op)
3142
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
3146
session->set_proc_info("discard_or_import_tablespace");
3148
discard= test(tablespace_op == DISCARD_TABLESPACE);
3151
We set this flag so that ha_innobase::open and ::external_lock() do
3152
not complain when we lock the table
3154
session->tablespace_op= true;
3155
if (!(table=open_ltable(session, table_list, TL_WRITE, 0)))
3157
session->tablespace_op=false;
3161
error= table->file->ha_discard_or_import_tablespace(discard);
3163
session->set_proc_info("end");
3168
/* The ALTER Table is always in its own transaction */
3169
error = ha_autocommit_or_rollback(session, 0);
3170
if (end_active_trans(session))
3174
write_bin_log(session, false, session->query, session->query_length);
3177
ha_autocommit_or_rollback(session, error);
3178
session->tablespace_op=false;
3186
table->file->print_error(error, MYF(0));
3192
Copy all changes detected by parser to the HA_ALTER_FLAGS
3195
void setup_ha_alter_flags(Alter_info *alter_info, HA_ALTER_FLAGS *alter_flags)
3197
uint32_t flags= alter_info->flags;
3199
if (ALTER_ADD_COLUMN & flags)
3200
*alter_flags|= HA_ADD_COLUMN;
3201
if (ALTER_DROP_COLUMN & flags)
3202
*alter_flags|= HA_DROP_COLUMN;
3203
if (ALTER_RENAME & flags)
3204
*alter_flags|= HA_RENAME_TABLE;
3205
if (ALTER_CHANGE_COLUMN & flags)
3206
*alter_flags|= HA_CHANGE_COLUMN;
3207
if (ALTER_COLUMN_DEFAULT & flags)
3208
*alter_flags|= HA_COLUMN_DEFAULT_VALUE;
3209
if (ALTER_COLUMN_STORAGE & flags)
3210
*alter_flags|= HA_COLUMN_STORAGE;
3211
if (ALTER_COLUMN_FORMAT & flags)
3212
*alter_flags|= HA_COLUMN_FORMAT;
3213
if (ALTER_COLUMN_ORDER & flags)
3214
*alter_flags|= HA_ALTER_COLUMN_ORDER;
3215
if (ALTER_STORAGE & flags)
3216
*alter_flags|= HA_ALTER_STORAGE;
3217
if (ALTER_ROW_FORMAT & flags)
3218
*alter_flags|= HA_ALTER_ROW_FORMAT;
3219
if (ALTER_RECREATE & flags)
3220
*alter_flags|= HA_RECREATE;
3221
if (ALTER_FOREIGN_KEY & flags)
3222
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3227
@param session Thread
3228
@param table The original table.
3229
@param alter_info Alter options, fields and keys for the new
3231
@param create_info Create options for the new table.
3232
@param order_num Number of order list elements.
3233
@param[out] ha_alter_flags Flags that indicate what will be changed
3234
@param[out] ha_alter_info Data structures needed for on-line alter
3235
@param[out] table_changes Information about particular change
3237
First argument 'table' contains information of the original
3238
table, which includes all corresponding parts that the new
3239
table has in arguments create_list, key_list and create_info.
3241
By comparing the changes between the original and new table
3242
we can determine how much it has changed after ALTER Table
3243
and whether we need to make a copy of the table, or just change
3246
Mark any changes detected in the ha_alter_flags.
3248
If there are no data changes, but index changes, 'index_drop_buffer'
3249
and/or 'index_add_buffer' are populated with offsets into
3250
table->key_info or key_info_buffer respectively for the indexes
3251
that need to be dropped and/or (re-)created.
3254
@retval false success
3259
compare_tables(Session *session,
3261
Alter_info *alter_info,
3262
HA_CREATE_INFO *create_info,
3264
HA_ALTER_FLAGS *alter_flags,
3265
HA_ALTER_INFO *ha_alter_info,
3266
uint32_t *table_changes)
3268
Field **f_ptr, *field;
3269
uint32_t table_changes_local= 0;
3270
List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
3271
Create_field *new_field;
3272
KEY_PART_INFO *key_part;
3275
Remember if the new definition has new VARCHAR column;
3276
create_info->varchar will be reset in mysql_prepare_create_table.
3278
bool varchar= create_info->varchar;
3282
Create a copy of alter_info.
3283
To compare the new and old table definitions, we need to "prepare"
3284
the new definition - transform it from parser output to a format
3285
that describes the final table layout (all column defaults are
3286
initialized, duplicate columns are removed). This is done by
3287
mysql_prepare_create_table. Unfortunately,
3288
mysql_prepare_create_table performs its transformations
3289
"in-place", that is, modifies the argument. Since we would
3290
like to keep compare_tables() idempotent (not altering any
3291
of the arguments) we create a copy of alter_info here and
3292
pass it to mysql_prepare_create_table, then use the result
3293
to evaluate possibility of fast ALTER Table, and then
3296
Alter_info tmp_alter_info(*alter_info, session->mem_root);
3297
Session *session= table->in_use;
3298
uint32_t db_options= 0; /* not used */
3299
/* Create the prepared information. */
3300
if (mysql_prepare_create_table(session, create_info,
3302
(table->s->tmp_table != NO_TMP_TABLE),
3305
&ha_alter_info->key_info_buffer,
3306
&ha_alter_info->key_count,
3307
/* select_field_count */ 0))
3309
/* Allocate result buffers. */
3310
if (! (ha_alter_info->index_drop_buffer=
3311
(uint*) session->alloc(sizeof(uint) * table->s->keys)) ||
3312
! (ha_alter_info->index_add_buffer=
3313
(uint*) session->alloc(sizeof(uint) *
3314
tmp_alter_info.key_list.elements)))
3318
First we setup ha_alter_flags based on what was detected
3321
setup_ha_alter_flags(alter_info, alter_flags);
3325
Some very basic checks. If number of fields changes, or the
3326
handler, we need to run full ALTER Table. In the future
3327
new fields can be added and old dropped without copy, but
3330
Test also that engine was not given during ALTER Table, or
3331
we are force to run regular alter table (copy).
3332
E.g. ALTER Table tbl_name ENGINE=MyISAM.
3334
For the following ones we also want to run regular alter table:
3335
ALTER Table tbl_name order_st BY ..
3336
ALTER Table tbl_name CONVERT TO CHARACTER SET ..
3338
At the moment we can't handle altering temporary tables without a copy.
3339
We also test if OPTIMIZE Table was given and was mapped to alter table.
3340
In that case we always do full copy.
3342
There was a bug prior to mysql-4.0.25. Number of null fields was
3343
calculated incorrectly. As a result frm and data files gets out of
3344
sync after fast alter table. There is no way to determine by which
3345
mysql version (in 4.0 and 4.1 branches) table was created, thus we
3346
disable fast alter table for all tables created by mysql versions
3347
prior to 5.0 branch.
3350
if (table->s->fields != alter_info->create_list.elements ||
3351
table->s->db_type() != create_info->db_type ||
3352
table->s->tmp_table ||
3353
create_info->used_fields & HA_CREATE_USED_ENGINE ||
3354
create_info->used_fields & HA_CREATE_USED_CHARSET ||
3355
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
3356
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
3357
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
3359
!table->s->mysql_version ||
3360
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3362
*table_changes= IS_EQUAL_NO;
3364
Check what has changed and set alter_flags
3366
if (table->s->fields < alter_info->create_list.elements)
3367
*alter_flags|= HA_ADD_COLUMN;
3368
else if (table->s->fields > alter_info->create_list.elements)
3369
*alter_flags|= HA_DROP_COLUMN;
3370
if (create_info->db_type != table->s->db_type() ||
3371
create_info->used_fields & HA_CREATE_USED_ENGINE)
3372
*alter_flags|= HA_ALTER_STORAGE_ENGINE;
3373
if (create_info->used_fields & HA_CREATE_USED_CHARSET)
3374
*alter_flags|= HA_CHANGE_CHARACTER_SET;
3375
if (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET)
3376
*alter_flags|= HA_SET_DEFAULT_CHARACTER_SET;
3377
if (alter_info->flags & ALTER_RECREATE)
3378
*alter_flags|= HA_RECREATE;
3379
/* TODO check for ADD/DROP FOREIGN KEY */
3380
if (alter_info->flags & ALTER_FOREIGN_KEY)
3381
*alter_flags|= HA_ALTER_FOREIGN_KEY;
3382
if (!table->s->mysql_version ||
3383
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
3384
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3387
Go through fields and check if the original ones are compatible
3390
for (f_ptr= table->field, new_field= new_field_it++;
3391
(new_field && (field= *f_ptr));
3392
f_ptr++, new_field= new_field_it++)
3394
/* Make sure we have at least the default charset in use. */
3395
if (!new_field->charset)
3396
new_field->charset= create_info->default_table_charset;
3398
/* Don't pack rows in old tables if the user has requested this. */
3399
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
3400
(new_field->flags & BLOB_FLAG) ||
3401
(new_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED))
3402
create_info->table_options|= HA_OPTION_PACK_RECORD;
3404
/* Check how fields have been modified */
3405
if (alter_info->flags & ALTER_CHANGE_COLUMN)
3407
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
3408
if (!(table_changes_local= field->is_equal(new_field)))
3409
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3412
Check if the altered column is a stored virtual field.
3413
TODO: Mark such a column with an alter flag only if
3414
the expression functions are not equal.
3416
if (field->is_stored && field->vcol_info)
3417
*alter_flags|= HA_ALTER_STORED_VCOL;
3419
/* Check if field was renamed */
3420
field->flags&= ~FIELD_IS_RENAMED;
3421
if (my_strcasecmp(system_charset_info,
3423
new_field->field_name))
3425
field->flags|= FIELD_IS_RENAMED;
3426
*alter_flags|= HA_ALTER_COLUMN_NAME;
3429
*table_changes&= table_changes_local;
3430
if (table_changes_local == IS_EQUAL_PACK_LENGTH)
3431
*alter_flags|= HA_ALTER_COLUMN_TYPE;
3433
/* Check that NULL behavior is same for old and new fields */
3434
if ((new_field->flags & NOT_NULL_FLAG) !=
3435
(uint) (field->flags & NOT_NULL_FLAG))
3437
*table_changes= IS_EQUAL_NO;
3438
*alter_flags|= HA_ALTER_COLUMN_NULLABLE;
3442
/* Clear indexed marker */
3443
field->flags&= ~FIELD_IN_ADD_INDEX;
3447
Go through keys and check if the original ones are compatible
3451
KEY *table_key_end= table->key_info + table->s->keys;
3454
ha_alter_info->key_info_buffer + ha_alter_info->key_count;
3457
Step through all keys of the old table and search matching new keys.
3459
ha_alter_info->index_drop_count= 0;
3460
ha_alter_info->index_add_count= 0;
3461
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3463
KEY_PART_INFO *table_part;
3464
KEY_PART_INFO *table_part_end= table_key->key_part + table_key->key_parts;
3465
KEY_PART_INFO *new_part;
3467
/* Search a new key with the same name. */
3468
for (new_key= ha_alter_info->key_info_buffer;
3469
new_key < new_key_end;
3472
if (! strcmp(table_key->name, new_key->name))
3475
if (new_key >= new_key_end)
3477
/* Key not found. Add the offset of the key to the drop buffer. */
3478
ha_alter_info->index_drop_buffer
3479
[ha_alter_info->index_drop_count++]=
3480
table_key - table->key_info;
3481
if (table_key->flags & HA_NOSAME)
3483
/* Unique key. Check for "PRIMARY". */
3484
if (! my_strcasecmp(system_charset_info,
3485
table_key->name, primary_key_name))
3486
*alter_flags|= HA_DROP_PK_INDEX;
3488
*alter_flags|= HA_DROP_UNIQUE_INDEX;
3491
*alter_flags|= HA_DROP_INDEX;
3492
*table_changes= IS_EQUAL_NO;
3496
/* Check that the key types are compatible between old and new tables. */
3497
if ((table_key->algorithm != new_key->algorithm) ||
3498
((table_key->flags & HA_KEYFLAG_MASK) !=
3499
(new_key->flags & HA_KEYFLAG_MASK)) ||
3500
(table_key->key_parts != new_key->key_parts))
3502
if (table_key->flags & HA_NOSAME)
3504
// Unique key. Check for "PRIMARY".
3505
if (! my_strcasecmp(system_charset_info,
3506
table_key->name, primary_key_name))
3507
*alter_flags|= HA_ALTER_PK_INDEX;
3509
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3512
*alter_flags|= HA_ALTER_INDEX;
3517
Check that the key parts remain compatible between the old and
3520
for (table_part= table_key->key_part, new_part= new_key->key_part;
3521
table_part < table_part_end;
3522
table_part++, new_part++)
3525
Key definition has changed if we are using a different field or
3526
if the used key part length is different. We know that the fields
3527
did not change. Comparing field numbers is sufficient.
3529
if ((table_part->length != new_part->length) ||
3530
(table_part->fieldnr - 1 != new_part->fieldnr))
3532
if (table_key->flags & HA_NOSAME)
3534
/* Unique key. Check for "PRIMARY" */
3535
if (! my_strcasecmp(system_charset_info,
3536
table_key->name, primary_key_name))
3537
*alter_flags|= HA_ALTER_PK_INDEX;
3539
*alter_flags|= HA_ALTER_UNIQUE_INDEX;
3542
*alter_flags|= HA_ALTER_INDEX;
3549
/* Key modified. Add the offset of the key to both buffers. */
3550
ha_alter_info->index_drop_buffer
3551
[ha_alter_info->index_drop_count++]=
3552
table_key - table->key_info;
3553
ha_alter_info->index_add_buffer
3554
[ha_alter_info->index_add_count++]=
3555
new_key - ha_alter_info->key_info_buffer;
3556
key_part= new_key->key_part;
3557
end= key_part + new_key->key_parts;
3558
for(; key_part != end; key_part++)
3560
/* Mark field to be part of new key */
3561
if ((field= table->field[key_part->fieldnr]))
3562
field->flags|= FIELD_IN_ADD_INDEX;
3564
*table_changes= IS_EQUAL_NO;
3566
/*end of for (; table_key < table_key_end;) */
3569
Step through all keys of the new table and find matching old keys.
3571
for (new_key= ha_alter_info->key_info_buffer;
3572
new_key < new_key_end;
3575
/* Search an old key with the same name. */
3576
for (table_key= table->key_info; table_key < table_key_end; table_key++)
3578
if (! strcmp(table_key->name, new_key->name))
3581
if (table_key >= table_key_end)
3583
/* Key not found. Add the offset of the key to the add buffer. */
3584
ha_alter_info->index_add_buffer
3585
[ha_alter_info->index_add_count++]=
3586
new_key - ha_alter_info->key_info_buffer;
3587
key_part= new_key->key_part;
3588
end= key_part + new_key->key_parts;
3589
for(; key_part != end; key_part++)
3591
/* Mark field to be part of new key */
3592
if ((field= table->field[key_part->fieldnr]))
3593
field->flags|= FIELD_IN_ADD_INDEX;
3595
if (new_key->flags & HA_NOSAME)
3597
/* Unique key. Check for "PRIMARY" */
3598
if (! my_strcasecmp(system_charset_info,
3599
new_key->name, primary_key_name))
3600
*alter_flags|= HA_ADD_PK_INDEX;
3602
*alter_flags|= HA_ADD_UNIQUE_INDEX;
3605
*alter_flags|= HA_ADD_INDEX;
3606
*table_changes= IS_EQUAL_NO;
3615
Manages enabling/disabling of indexes for ALTER Table
3618
alter_table_manage_keys()
3620
indexes_were_disabled Whether the indexes of the from table
3622
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
3630
bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
3631
enum enum_enable_or_disable keys_onoff)
3634
switch (keys_onoff) {
3636
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3639
if (!indexes_were_disabled)
3641
/* fall-through: disabled indexes */
3643
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3646
if (error == HA_ERR_WRONG_COMMAND)
3648
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3649
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3650
table->s->table_name.str);
3653
table->file->print_error(error, MYF(0));
3658
int create_temporary_table(Session *session,
3662
HA_CREATE_INFO *create_info,
3663
Alter_info *alter_info,
3667
char index_file[FN_REFLEN], data_file[FN_REFLEN];
3668
handlerton *old_db_type, *new_db_type;
3669
old_db_type= table->s->db_type();
3670
new_db_type= create_info->db_type;
3672
Handling of symlinked tables:
3674
Create new data file and index file on the same disk as the
3675
old data and index files.
3677
Rename new data file over old data file and new index file over
3679
Symlinks are not changed.
3682
Create new data file and index file on the same disk as the
3683
old data and index files. Create also symlinks to point at
3686
At end, rename intermediate tables, and symlinks to intermediate
3687
table, to final table name.
3688
Remove old table and old symlinks
3690
If rename is made to another database:
3691
Create new tables in new database.
3693
Remove old table and symlinks.
3695
if (db_changed) // Ignore symlink if db changed
3697
if (create_info->index_file_name)
3699
/* Fix index_file_name to have 'tmp_name' as basename */
3700
my_stpcpy(index_file, tmp_name);
3701
create_info->index_file_name=fn_same(index_file,
3702
create_info->index_file_name,
3705
if (create_info->data_file_name)
3707
/* Fix data_file_name to have 'tmp_name' as basename */
3708
my_stpcpy(data_file, tmp_name);
3709
create_info->data_file_name=fn_same(data_file,
3710
create_info->data_file_name,
3715
create_info->data_file_name=create_info->index_file_name=0;
3718
Create a table with a temporary name.
3719
With create_info->frm_only == 1 this creates a .frm file only.
3720
We don't log the statement, it will be logged later.
3722
tmp_disable_binlog(session);
3723
error= mysql_create_table(session, new_db, tmp_name,
3724
create_info, alter_info, 1, 0);
3725
reenable_binlog(session);
3731
Create a temporary table that reflects what an alter table operation
3735
create_altered_table()
3736
session Thread handle
3737
table The original table
3738
create_info Information from the parsing phase about new
3740
alter_info Lists of fields, keys to be changed, added
3742
db_change Specifies if the table is moved to another database
3744
A temporary table with all changes
3747
The temporary table is created without storing it in any storage engine
3748
and is opened only to get the table struct and frm file reference.
3750
Table *create_altered_table(Session *session,
3753
HA_CREATE_INFO *create_info,
3754
Alter_info *alter_info,
3758
HA_CREATE_INFO altered_create_info(*create_info);
3759
Table *altered_table;
3761
char path[FN_REFLEN];
3763
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64,
3764
tmp_file_prefix, current_pid, session->thread_id);
3765
/* Safety fix for InnoDB */
3766
if (lower_case_table_names)
3767
my_casedn_str(files_charset_info, tmp_name);
3768
altered_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
3769
altered_create_info.frm_only= 1;
3770
if ((error= create_temporary_table(session, table, new_db, tmp_name,
3771
&altered_create_info,
3772
alter_info, db_change)))
3777
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
3779
altered_table= open_temporary_table(session, path, new_db, tmp_name, 1,
3781
return(altered_table);
3788
Perform a fast or on-line alter table
3791
mysql_fast_or_online_alter_table()
3792
session Thread handle
3793
table The original table
3794
altered_table A temporary table showing how we will change table
3795
create_info Information from the parsing phase about new
3797
alter_info Storage place for data used during different phases
3798
ha_alter_flags Bitmask that shows what will be changed
3799
keys_onoff Specifies if keys are to be enabled/disabled
3802
>0 An error occured during the on-line alter table operation
3803
-1 Error when re-opening table
3805
If mysql_alter_table does not need to copy the table, it is
3806
either a fast alter table where the storage engine does not
3807
need to know about the change, only the frm will change,
3808
or the storage engine supports performing the alter table
3809
operation directly, on-line without mysql having to copy
3812
int mysql_fast_or_online_alter_table(Session *session,
3814
Table *altered_table,
3815
HA_CREATE_INFO *create_info,
3816
HA_ALTER_INFO *alter_info,
3817
HA_ALTER_FLAGS *ha_alter_flags,
3818
enum enum_enable_or_disable keys_onoff)
3821
bool online= (table->file->ha_table_flags() & HA_ONLINE_ALTER)?true:false;
3827
Tell the handler to prepare for the online alter
3829
if ((error= table->file->alter_table_phase1(session,
3839
Tell the storage engine to perform the online alter table
3841
if check_if_supported_alter() returned HA_ALTER_SUPPORTED_WAIT_LOCK
3842
we need to wrap the next call with a DDL lock.
3844
if ((error= table->file->alter_table_phase2(session,
3854
The final .frm file is already created as a temporary file
3855
and will be renamed to the original table name.
3857
pthread_mutex_lock(&LOCK_open);
3858
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3859
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
3861
close_data_files_and_morph_locks(session,
3862
table->pos_in_table_list->db,
3863
table->pos_in_table_list->table_name);
3864
if (mysql_rename_table(NULL,
3865
altered_table->s->db.str,
3866
altered_table->s->table_name.str,
3868
table->s->table_name.str, FN_FROM_IS_TMP))
3871
pthread_mutex_unlock(&LOCK_open);
3874
broadcast_refresh();
3875
pthread_mutex_unlock(&LOCK_open);
3878
The ALTER Table is always in its own transaction.
3879
Commit must not be called while LOCK_open is locked. It could call
3880
wait_if_global_read_lock(), which could create a deadlock if called
3883
error= ha_autocommit_or_rollback(session, 0);
3885
if (ha_commit(session))
3891
pthread_mutex_lock(&LOCK_open);
3892
if (reopen_table(table))
3897
pthread_mutex_unlock(&LOCK_open);
3901
Tell the handler that the changed frm is on disk and table
3904
if ((error= t_table->file->alter_table_phase3(session, t_table)))
3910
We are going to reopen table down on the road, so we have to restore
3911
state of the Table object which we used for obtaining of handler
3912
object to make it suitable for reopening.
3914
assert(t_table == table);
3915
table->open_placeholder= 1;
3916
pthread_mutex_lock(&LOCK_open);
3917
close_handle_and_leave_table_as_lock(table);
3918
pthread_mutex_unlock(&LOCK_open);
3929
Prepare column and key definitions for CREATE TABLE in ALTER Table.
3931
This function transforms parse output of ALTER Table - lists of
3932
columns and keys to add, drop or modify into, essentially,
3933
CREATE TABLE definition - a list of columns and keys of the new
3934
table. While doing so, it also performs some (bug not all)
3937
This function is invoked when we know that we're going to
3938
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
3939
is not possible, perhaps because the ALTER statement contains
3940
instructions that require change in table data, not only in
3941
table definition or indexes.
3943
@param[in,out] session thread handle. Used as a memory pool
3944
and source of environment information.
3945
@param[in] table the source table, open and locked
3946
Used as an interface to the storage engine
3947
to acquire additional information about
3949
@param[in,out] create_info A blob with CREATE/ALTER Table
3951
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
3952
Originally create_info was used only in
3953
CREATE TABLE and alter_info only in ALTER Table.
3954
But since ALTER might end-up doing CREATE,
3955
this distinction is gone and we just carry
3956
around two structures.
3959
Fills various create_info members based on information retrieved
3960
from the storage engine.
3961
Sets create_info->varchar if the table has a VARCHAR column.
3962
Prepares alter_info->create_list and alter_info->key_list with
3963
columns and keys of the new table.
3964
@retval true error, out of memory or a semantical error in ALTER
3966
@retval false success
3970
mysql_prepare_alter_table(Session *session, Table *table,
3971
HA_CREATE_INFO *create_info,
3972
Alter_info *alter_info)
3974
/* New column definitions are added here */
3975
List<Create_field> new_create_list;
3976
/* New key definitions are added here */
3977
List<Key> new_key_list;
3978
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
3979
List_iterator<Create_field> def_it(alter_info->create_list);
3980
List_iterator<Alter_column> alter_it(alter_info->alter_list);
3981
List_iterator<Key> key_it(alter_info->key_list);
3982
List_iterator<Create_field> find_it(new_create_list);
3983
List_iterator<Create_field> field_it(new_create_list);
3984
List<Key_part_spec> key_parts;
3985
uint32_t db_create_options= (table->s->db_create_options
3986
& ~(HA_OPTION_PACK_RECORD));
3987
uint32_t used_fields= create_info->used_fields;
3988
KEY *key_info=table->key_info;
3992
create_info->varchar= false;
3993
/* Let new create options override the old ones */
3994
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
3995
create_info->min_rows= table->s->min_rows;
3996
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
3997
create_info->max_rows= table->s->max_rows;
3998
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
3999
create_info->avg_row_length= table->s->avg_row_length;
4000
if (!(used_fields & HA_CREATE_USED_BLOCK_SIZE))
4001
create_info->block_size= table->s->block_size;
4002
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
4003
create_info->default_table_charset= table->s->table_charset;
4004
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
4006
/* Table has an autoincrement, copy value to new table */
4007
table->file->info(HA_STATUS_AUTO);
4008
create_info->auto_increment_value= table->file->stats.auto_increment_value;
4010
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
4011
create_info->key_block_size= table->s->key_block_size;
4013
restore_record(table, s->default_values); // Empty record for DEFAULT
4017
First collect all fields from table which isn't in drop_list
4019
Field **f_ptr,*field;
4020
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
4022
/* Check if field should be dropped */
4025
while ((drop=drop_it++))
4027
if (drop->type == Alter_drop::COLUMN &&
4028
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
4030
/* Reset auto_increment value if it was dropped */
4031
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
4032
!(used_fields & HA_CREATE_USED_AUTO))
4034
create_info->auto_increment_value=0;
4035
create_info->used_fields|=HA_CREATE_USED_AUTO;
4045
/* Check if field is changed */
4047
while ((def=def_it++))
4050
!my_strcasecmp(system_charset_info,field->field_name, def->change))
4054
{ // Field is changed
4056
if (field->is_stored != def->is_stored)
4058
my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN,
4060
"Changing the STORED status");
4065
new_create_list.push_back(def);
4072
This field was not dropped and not changed, add it to the list
4075
def= new Create_field(field, field);
4076
new_create_list.push_back(def);
4077
alter_it.rewind(); // Change default if ALTER
4078
Alter_column *alter;
4079
while ((alter=alter_it++))
4081
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
4086
if (def->sql_type == DRIZZLE_TYPE_BLOB)
4088
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
4091
if ((def->def=alter->def)) // Use new default
4092
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
4094
def->flags|= NO_DEFAULT_VALUE_FLAG;
4100
while ((def=def_it++)) // Add new columns
4102
if (def->change && ! def->field)
4104
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
4108
Check that the DATE/DATETIME not null field we are going to add is
4109
either has a default value or the '0000-00-00' is allowed by the
4111
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
4112
flag to allow ALTER Table only if the table to be altered is empty.
4114
if ((def->sql_type == DRIZZLE_TYPE_NEWDATE ||
4115
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
4116
!alter_info->datetime_field &&
4117
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
4118
session->variables.sql_mode & MODE_NO_ZERO_DATE)
4120
alter_info->datetime_field= def;
4121
alter_info->error_if_not_empty= true;
4124
new_create_list.push_back(def);
4125
else if (def->after == first_keyword)
4126
new_create_list.push_front(def);
4131
while ((find=find_it++)) // Add new columns
4133
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
4138
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
4141
find_it.after(def); // Put element after this
4143
XXX: hack for Bug#28427.
4144
If column order has changed, force OFFLINE ALTER Table
4145
without querying engine capabilities. If we ever have an
4146
engine that supports online ALTER Table CHANGE COLUMN
4147
<name> AFTER <name1> (Falcon?), this fix will effectively
4148
disable the capability.
4149
TODO: detect the situation in compare_tables, behave based
4150
on engine capabilities.
4152
if (alter_info->build_method == HA_BUILD_ONLINE)
4154
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4157
alter_info->build_method= HA_BUILD_OFFLINE;
4160
if (alter_info->alter_list.elements)
4162
my_error(ER_BAD_FIELD_ERROR, MYF(0),
4163
alter_info->alter_list.head()->name, table->s->table_name.str);
4166
if (!new_create_list.elements)
4168
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
4174
Collect all keys which isn't in drop list. Add only those
4175
for which some fields exists.
4178
for (uint32_t i=0 ; i < table->s->keys ; i++,key_info++)
4180
char *key_name= key_info->name;
4183
while ((drop=drop_it++))
4185
if (drop->type == Alter_drop::KEY &&
4186
!my_strcasecmp(system_charset_info,key_name, drop->name))
4195
KEY_PART_INFO *key_part= key_info->key_part;
4197
for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
4199
if (!key_part->field)
4200
continue; // Wrong field (from UNIREG)
4201
const char *key_part_name=key_part->field->field_name;
4202
Create_field *cfield;
4204
while ((cfield=field_it++))
4208
if (!my_strcasecmp(system_charset_info, key_part_name,
4212
else if (!my_strcasecmp(system_charset_info,
4213
key_part_name, cfield->field_name))
4217
continue; // Field is removed
4218
uint32_t key_part_length=key_part->length;
4219
if (cfield->field) // Not new field
4222
If the field can't have only a part used in a key according to its
4223
new type, or should not be used partially according to its
4224
previous type, or the field length is less than the key part
4225
length, unset the key part length.
4227
We also unset the key part length if it is the same as the
4228
old field's length, so the whole new field will be used.
4230
BLOBs may have cfield->length == 0, which is why we test it before
4231
checking whether cfield->length < key_part_length (in chars).
4233
if (!Field::type_can_have_key_part(cfield->field->type()) ||
4234
!Field::type_can_have_key_part(cfield->sql_type) ||
4235
(cfield->field->field_length == key_part_length &&
4236
!f_is_blob(key_part->key_type)) ||
4237
(cfield->length && (cfield->length < key_part_length /
4238
key_part->field->charset()->mbmaxlen)))
4239
key_part_length= 0; // Use whole field
4241
key_part_length /= key_part->field->charset()->mbmaxlen;
4242
key_parts.push_back(new Key_part_spec(cfield->field_name,
4243
strlen(cfield->field_name),
4246
if (key_parts.elements)
4248
KEY_CREATE_INFO key_create_info;
4250
enum Key::Keytype key_type;
4251
memset(&key_create_info, 0, sizeof(key_create_info));
4253
key_create_info.algorithm= key_info->algorithm;
4254
if (key_info->flags & HA_USES_BLOCK_SIZE)
4255
key_create_info.block_size= key_info->block_size;
4256
if (key_info->flags & HA_USES_COMMENT)
4257
key_create_info.comment= key_info->comment;
4259
if (key_info->flags & HA_NOSAME)
4261
if (! my_strcasecmp(system_charset_info, key_name, primary_key_name))
4262
key_type= Key::PRIMARY;
4264
key_type= Key::UNIQUE;
4267
key_type= Key::MULTIPLE;
4269
key= new Key(key_type, key_name, strlen(key_name),
4271
test(key_info->flags & HA_GENERATED_KEY),
4273
new_key_list.push_back(key);
4278
while ((key=key_it++)) // Add new keys
4280
if (key->type == Key::FOREIGN_KEY &&
4281
((Foreign_key *)key)->validate(new_create_list))
4283
if (key->type != Key::FOREIGN_KEY)
4284
new_key_list.push_back(key);
4285
if (key->name.str &&
4286
!my_strcasecmp(system_charset_info, key->name.str, primary_key_name))
4288
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
4294
if (alter_info->drop_list.elements)
4296
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4297
alter_info->drop_list.head()->name);
4300
if (alter_info->alter_list.elements)
4302
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
4303
alter_info->alter_list.head()->name);
4307
if (!create_info->comment.str)
4309
create_info->comment.str= table->s->comment.str;
4310
create_info->comment.length= table->s->comment.length;
4313
table->file->update_create_info(create_info);
4314
if ((create_info->table_options &
4315
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
4316
(used_fields & HA_CREATE_USED_PACK_KEYS))
4317
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
4318
if (create_info->table_options &
4319
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
4320
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
4321
if (create_info->table_options &
4322
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
4323
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
4324
HA_OPTION_NO_DELAY_KEY_WRITE);
4325
create_info->table_options|= db_create_options;
4327
if (table->s->tmp_table)
4328
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
4331
alter_info->create_list.swap(new_create_list);
4332
alter_info->key_list.swap(new_key_list);
4343
session Thread handle
4344
new_db If there is a RENAME clause
4345
new_name If there is a RENAME clause
4346
create_info Information from the parsing phase about new
4348
table_list The table to change.
4349
alter_info Lists of fields, keys to be changed, added
4351
order_num How many order_st BY fields has been specified.
4352
order List of fields to order_st BY.
4353
ignore Whether we have ALTER IGNORE Table
4356
This is a veery long function and is everything but the kitchen sink :)
4357
It is used to alter a table and not only by ALTER Table but also
4358
CREATE|DROP INDEX are mapped on this function.
4360
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
4361
or both, then this function short cuts its operation by renaming
4362
the table and/or enabling/disabling the keys. In this case, the FRM is
4363
not changed, directly by mysql_alter_table. However, if there is a
4364
RENAME + change of a field, or an index, the short cut is not used.
4365
See how `create_list` is used to generate the new FRM regarding the
4366
structure of the fields. The same is done for the indices of the table.
4368
Important is the fact, that this function tries to do as little work as
4369
possible, by finding out whether a intermediate table is needed to copy
4370
data into and when finishing the altering to use it as the original table.
4371
For this reason the function compare_tables() is called, which decides
4372
based on all kind of data how similar are the new and the original
4380
bool mysql_alter_table(Session *session,char *new_db, char *new_name,
4381
HA_CREATE_INFO *create_info,
4382
TableList *table_list,
4383
Alter_info *alter_info,
4384
uint32_t order_num, order_st *order, bool ignore)
4386
Table *table, *new_table=0, *name_lock= 0;;
4388
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
4389
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
4390
char path[FN_REFLEN];
4391
ha_rows copied= 0,deleted= 0;
4392
handlerton *old_db_type, *new_db_type, *save_old_db_type;
4393
legacy_db_type table_type;
4395
if (table_list && table_list->schema_table)
4397
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.str);
4402
Assign variables table_name, new_name, db, new_db, path
4403
to simplify further comparisons: we want to see if it's a RENAME
4404
later just by comparing the pointers, avoiding the need for strcmp.
4406
session->set_proc_info("init");
4407
table_name=table_list->table_name;
4408
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
4410
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
4412
build_table_filename(path, sizeof(path), db, table_name, "", 0);
4414
mysql_ha_rm_tables(session, table_list, false);
4416
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
4417
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
4418
/* Conditionally writes to binlog. */
4419
return(mysql_discard_or_import_tablespace(session,table_list,
4420
alter_info->tablespace_op));
4421
char* pos= new_name_buff;
4422
char* pos_end= pos+strlen(new_name_buff)-1;
4423
pos= my_stpncpy(new_name_buff, drizzle_data_home, pos_end-pos);
4424
pos= my_stpncpy(new_name_buff, "/", pos_end-pos);
4425
pos= my_stpncpy(new_name_buff, db, pos_end-pos);
4426
pos= my_stpncpy(new_name_buff, "/", pos_end-pos);
4427
pos= my_stpncpy(new_name_buff, table_name, pos_end-pos);
4428
pos= my_stpncpy(new_name_buff, reg_ext, pos_end-pos);
4430
(void) unpack_filename(new_name_buff, new_name_buff);
4432
If this is just a rename of a view, short cut to the
4433
following scenario: 1) lock LOCK_open 2) do a RENAME
4434
2) unlock LOCK_open.
4435
This is a copy-paste added to make sure
4436
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
4437
as an independent branch in mysql_execute_command. The need
4438
for a copy-paste arose because the main code flow of ALTER Table
4439
... RENAME tries to use open_ltable, which does not work for views
4440
(open_ltable was never modified to merge table lists of child tables
4441
into the main table list, like open_tables does).
4442
This code is wrong and will be removed, please do not copy.
4444
(void)mysql_frm_type(session, new_name_buff, &table_type);
4446
if (!(table= open_n_lock_single_table(session, table_list, TL_WRITE_ALLOW_READ)))
4448
table->use_all_columns();
4450
/* Check that we are not trying to rename to an existing table */
4453
my_stpcpy(new_name_buff,new_name);
4454
my_stpcpy(new_alias= new_alias_buff, new_name);
4455
if (lower_case_table_names)
4457
if (lower_case_table_names != 2)
4459
my_casedn_str(files_charset_info, new_name_buff);
4460
new_alias= new_name; // Create lower case table name
4462
my_casedn_str(files_charset_info, new_name);
4465
!my_strcasecmp(table_alias_charset, new_name_buff, table_name))
4468
Source and destination table names are equal: make later check
4471
new_alias= new_name= table_name;
4475
if (table->s->tmp_table != NO_TMP_TABLE)
4477
if (find_temporary_table(session,new_db,new_name_buff))
4479
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
4485
if (lock_table_name_if_not_cached(session, new_db, new_name, &name_lock))
4489
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4493
build_table_filename(new_name_buff, sizeof(new_name_buff),
4494
new_db, new_name_buff, reg_ext, 0);
4495
if (!access(new_name_buff, F_OK))
4497
/* Table will be closed in do_command() */
4498
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
4506
new_alias= (lower_case_table_names == 2) ? alias : table_name;
4507
new_name= table_name;
4510
old_db_type= table->s->db_type();
4511
if (!create_info->db_type)
4513
create_info->db_type= old_db_type;
4516
if (check_engine(session, new_name, create_info))
4518
new_db_type= create_info->db_type;
4520
if (new_db_type != old_db_type &&
4521
!table->file->can_switch_engines())
4524
my_error(ER_ROW_IS_REFERENCED, MYF(0));
4528
if (create_info->row_type == ROW_TYPE_NOT_USED)
4529
create_info->row_type= table->s->row_type;
4531
if (ha_check_storage_engine_flag(old_db_type, HTON_ALTER_NOT_SUPPORTED) ||
4532
ha_check_storage_engine_flag(new_db_type, HTON_ALTER_NOT_SUPPORTED))
4534
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
4538
session->set_proc_info("setup");
4539
if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) &&
4540
!table->s->tmp_table) // no need to touch frm
4542
switch (alter_info->keys_onoff) {
4547
wait_while_table_is_used() ensures that table being altered is
4548
opened only by this thread and that Table::TABLE_SHARE::version
4549
of Table object corresponding to this table is 0.
4550
The latter guarantees that no DML statement will open this table
4551
until ALTER Table finishes (i.e. until close_thread_tables())
4552
while the fact that the table is still open gives us protection
4553
from concurrent DDL statements.
4555
pthread_mutex_lock(&LOCK_open);
4556
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4557
pthread_mutex_unlock(&LOCK_open);
4558
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4559
/* COND_refresh will be signaled in close_thread_tables() */
4562
pthread_mutex_lock(&LOCK_open);
4563
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4564
pthread_mutex_unlock(&LOCK_open);
4565
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
4566
/* COND_refresh will be signaled in close_thread_tables() */
4573
if (error == HA_ERR_WRONG_COMMAND)
4576
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4577
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4581
pthread_mutex_lock(&LOCK_open);
4583
Unlike to the above case close_cached_table() below will remove ALL
4584
instances of Table from table cache (it will also remove table lock
4585
held by this thread). So to make actual table renaming and writing
4586
to binlog atomic we have to put them into the same critical section
4587
protected by LOCK_open mutex. This also removes gap for races between
4588
access() and mysql_rename_table() calls.
4591
if (!error && (new_name != table_name || new_db != db))
4593
session->set_proc_info("rename");
4595
Then do a 'simple' rename of the table. First we need to close all
4596
instances of 'source' table.
4598
close_cached_table(session, table);
4600
Then, we want check once again that target table does not exist.
4601
Actually the order of these two steps does not matter since
4602
earlier we took name-lock on the target table, so we do them
4603
in this particular order only to be consistent with 5.0, in which
4604
we don't take this name-lock and where this order really matters.
4605
TODO: Investigate if we need this access() check at all.
4607
if (!access(new_name_buff,F_OK))
4609
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
4614
*fn_ext(new_name)=0;
4615
if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0))
4619
mysql_rename_table(old_db_type, new_db, new_alias, db,
4626
if (error == HA_ERR_WRONG_COMMAND)
4629
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
4630
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
4636
write_bin_log(session, true, session->query, session->query_length);
4641
table->file->print_error(error, MYF(0));
2176
boost_unique_lock_t lock(table::Cache::singleton().mutex()); /* unlink open tables for create table like*/
2177
session->unlink_open_table(name_lock);
2183
if (is_if_not_exists)
4645
unlink_open_table(session, name_lock, false);
4646
pthread_mutex_unlock(&LOCK_open);
4647
table_list->table= NULL; // For query cache
4651
/* We have to do full alter table. */
4654
If the old table had partitions and we are doing ALTER Table ...
4655
engine= <new_engine>, the new table must preserve the original
4656
partitioning. That means that the new engine is still the
4657
partitioning engine, not the engine specified in the parser.
4658
This is discovered in prep_alter_part_table, which in such case
4659
updates create_info->db_type.
4660
Now we need to update the stack copy of create_info->db_type,
4661
as otherwise we won't be able to correctly move the files of the
4662
temporary table to the result table files.
4664
new_db_type= create_info->db_type;
4666
if (mysql_prepare_alter_table(session, table, create_info, alter_info))
4669
set_table_default_charset(session, create_info, db);
4672
if (session->variables.old_alter_table
4673
|| (table->s->db_type() != create_info->db_type)
4676
if (alter_info->build_method == HA_BUILD_ONLINE)
4678
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4681
alter_info->build_method= HA_BUILD_OFFLINE;
4684
if (alter_info->build_method != HA_BUILD_OFFLINE)
4686
Table *altered_table= 0;
4687
HA_ALTER_INFO ha_alter_info;
4688
HA_ALTER_FLAGS ha_alter_flags;
4689
uint32_t table_changes= IS_EQUAL_YES;
4690
bool need_copy_table= true;
4691
/* Check how much the tables differ. */
4692
if (compare_tables(session, table, alter_info,
4693
create_info, order_num,
4702
Check if storage engine supports altering the table
4708
If table is not renamed, changed database and
4709
some change was detected then check if engine
4710
can do the change on-line
4712
if (new_name == table_name && new_db == db &&
4713
ha_alter_flags.is_set())
4715
Alter_info tmp_alter_info(*alter_info, session->mem_root);
4719
check if table can be altered on-line
4721
if (!(altered_table= create_altered_table(session,
4726
!strcmp(db, new_db))))
4729
switch (table->file->check_if_supported_alter(altered_table,
4733
case HA_ALTER_SUPPORTED_WAIT_LOCK:
4734
case HA_ALTER_SUPPORTED_NO_LOCK:
4736
@todo: Currently we always acquire an exclusive name
4737
lock on the table metadata when performing fast or online
4738
ALTER Table. In future we may consider this unnecessary,
4739
and narrow the scope of the exclusive name lock to only
4740
cover manipulation with .frms. Storage engine API
4741
call check_if_supported_alter has provision for this
4744
need_copy_table= false;
4746
case HA_ALTER_NOT_SUPPORTED:
4747
if (alter_info->build_method == HA_BUILD_ONLINE)
4749
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
4750
close_temporary_table(session, altered_table, 1, 1);
4753
need_copy_table= true;
4755
case HA_ALTER_ERROR:
4757
close_temporary_table(session, altered_table, 1, 1);
4762
/* TODO need to check if changes can be handled as fast ALTER Table */
4764
need_copy_table= true;
4766
if (!need_copy_table)
4768
error= mysql_fast_or_online_alter_table(session,
4774
alter_info->keys_onoff);
4777
mysql_unlock_tables(session, session->lock);
4780
close_temporary_table(session, altered_table, 1, 1);
4786
goto err_with_placeholders;
4793
pthread_mutex_lock(&LOCK_open);
4799
close_temporary_table(session, altered_table, 1, 1);
4802
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, tmp_file_prefix,
4803
current_pid, session->thread_id);
4804
/* Safety fix for innodb */
4805
if (lower_case_table_names)
4806
my_casedn_str(files_charset_info, tmp_name);
4809
/* Create a temporary table with the new format */
4810
if ((error= create_temporary_table(session, table, new_db, tmp_name,
4811
create_info, alter_info,
4812
!strcmp(db, new_db))))
4817
/* Open the table so we need to copy the data to it. */
4818
if (table->s->tmp_table)
4821
memset(&tbl, 0, sizeof(tbl));
4823
tbl.table_name= tbl.alias= tmp_name;
4824
/* Table is in session->temporary_tables */
4825
new_table= open_table(session, &tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
4829
char path[FN_REFLEN];
4830
/* table is a normal table: Create temporary table in same directory */
4831
build_table_filename(path, sizeof(path), new_db, tmp_name, "",
4833
/* Open our intermediate table */
4834
new_table=open_temporary_table(session, path, new_db, tmp_name, 0, OTM_OPEN);
4839
/* Copy the data if necessary. */
4840
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
4841
session->cuted_fields=0L;
4842
session->set_proc_info("copy to tmp table");
4845
We do not copy data for MERGE tables. Only the children have data.
4846
MERGE tables have HA_NO_COPY_ON_ALTER set.
4848
if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))
4850
/* We don't want update TIMESTAMP fields during ALTER Table. */
4851
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
4852
new_table->next_number_field=new_table->found_next_number_field;
4853
error= copy_data_between_tables(table, new_table,
4854
alter_info->create_list, ignore,
4855
order_num, order, &copied, &deleted,
4856
alter_info->keys_onoff,
4857
alter_info->error_if_not_empty);
4861
pthread_mutex_lock(&LOCK_open);
4862
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
4863
pthread_mutex_unlock(&LOCK_open);
4864
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
4865
alter_info->keys_onoff);
4866
error= ha_autocommit_or_rollback(session, 0);
4867
if (end_active_trans(session))
4870
session->count_cuted_fields= CHECK_FIELD_IGNORE;
4872
if (table->s->tmp_table != NO_TMP_TABLE)
4874
/* We changed a temporary table */
4877
/* Close lock if this is a transactional table */
4880
mysql_unlock_tables(session, session->lock);
4883
/* Remove link to old table and rename the new one */
4884
close_temporary_table(session, table, 1, 1);
4885
/* Should pass the 'new_name' as we store table name in the cache */
4886
if (rename_temporary_table(session, new_table, new_db, new_name))
4888
/* We don't replicate alter table statement on temporary tables */
4889
if (!session->current_stmt_binlog_row_based)
4890
write_bin_log(session, true, session->query, session->query_length);
4897
Close the intermediate table that will be the new table.
4898
Note that MERGE tables do not have their children attached here.
4900
intern_close_table(new_table);
4903
pthread_mutex_lock(&LOCK_open);
4906
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4907
pthread_mutex_unlock(&LOCK_open);
4912
Data is copied. Now we:
4913
1) Wait until all other threads close old version of table.
4914
2) Close instances of table open by this thread and replace them
4915
with exclusive name-locks.
4916
3) Rename the old table to a temp name, rename the new one to the
4918
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
4919
we reopen new version of table.
4920
5) Write statement to the binary log.
4921
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
4922
remove name-locks from list of open tables and table cache.
4923
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
4924
call to remove name-locks from table cache and list of open table.
4927
session->set_proc_info("rename result table");
4928
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, tmp_file_prefix,
4929
current_pid, session->thread_id);
4930
if (lower_case_table_names)
4931
my_casedn_str(files_charset_info, old_name);
4933
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
4934
close_data_files_and_morph_locks(session, db, table_name);
4937
save_old_db_type= old_db_type;
4940
This leads to the storage engine (SE) not being notified for renames in
4941
mysql_rename_table(), because we just juggle with the FRM and nothing
4942
more. If we have an intermediate table, then we notify the SE that
4943
it should become the actual table. Later, we will recycle the old table.
4944
However, in case of ALTER Table RENAME there might be no intermediate
4945
table. This is when the old and new tables are compatible, according to
4946
compare_table(). Then, we need one additional call to
4947
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
4948
actual rename in the SE and the FRM is not touched. Note that, if the
4949
table is renamed and the SE is also changed, then an intermediate table
4950
is created and the additional call will not take place.
4952
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
4956
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4958
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
4959
new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && 0))
4961
/* Try to get everything back. */
4963
quick_rm_table(new_db_type,new_db,new_alias, 0);
4964
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
4965
mysql_rename_table(old_db_type, db, old_name, db, alias,
4971
/* This shouldn't happen. But let us play it safe. */
4972
goto err_with_placeholders;
4975
quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
4978
if (session->locked_tables && new_name == table_name && new_db == db)
4980
session->in_lock_tables= 1;
4981
error= reopen_tables(session, 1, 1);
4982
session->in_lock_tables= 0;
4984
goto err_with_placeholders;
4986
pthread_mutex_unlock(&LOCK_open);
4988
session->set_proc_info("end");
4990
assert(!(mysql_bin_log.is_open() &&
4991
session->current_stmt_binlog_row_based &&
4992
(create_info->options & HA_LEX_CREATE_TMP_TABLE)));
4993
write_bin_log(session, true, session->query, session->query_length);
4995
if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME))
4998
For the alter table to be properly flushed to the logs, we
4999
have to open the new table. If not, we get a problem on server
5000
shutdown. But we do not need to attach MERGE children.
5002
char path[FN_REFLEN];
5004
build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
5005
t_table= open_temporary_table(session, path, new_db, tmp_name, false, OTM_OPEN);
5008
intern_close_table(t_table);
5012
sql_print_warning(_("Could not open table %s.%s after rename\n"),
5014
ha_flush_logs(old_db_type);
5016
table_list->table=0; // For query cache
5018
if (session->locked_tables && (new_name != table_name || new_db != db))
5021
If are we under LOCK TABLES and did ALTER Table with RENAME we need
5022
to remove placeholders for the old table and for the target table
5023
from the list of open tables and table cache. If we are not under
5024
LOCK TABLES we can rely on close_thread_tables() doing this job.
5026
pthread_mutex_lock(&LOCK_open);
5027
unlink_open_table(session, table, false);
5028
unlink_open_table(session, name_lock, false);
5029
pthread_mutex_unlock(&LOCK_open);
5033
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
5034
(ulong) (copied + deleted), (ulong) deleted,
5035
(ulong) session->cuted_fields);
5036
my_ok(session, copied + deleted, 0L, tmp_name);
5037
session->some_tables_deleted=0;
5043
/* close_temporary_table() frees the new_table pointer. */
5044
close_temporary_table(session, new_table, 1, 1);
5047
quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
5051
No default value was provided for a DATE/DATETIME field, the
5052
current sql_mode doesn't allow the '0000-00-00' value and
5053
the table to be altered isn't empty.
5056
if (alter_info->error_if_not_empty && session->row_count)
5058
const char *f_val= 0;
5059
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
5060
switch (alter_info->datetime_field->sql_type)
5062
case DRIZZLE_TYPE_NEWDATE:
5063
f_val= "0000-00-00";
5064
t_type= DRIZZLE_TIMESTAMP_DATE;
5066
case DRIZZLE_TYPE_DATETIME:
5067
f_val= "0000-00-00 00:00:00";
5068
t_type= DRIZZLE_TIMESTAMP_DATETIME;
5071
/* Shouldn't get here. */
5074
bool save_abort_on_warning= session->abort_on_warning;
5075
session->abort_on_warning= true;
5076
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
5077
f_val, strlength(f_val), t_type,
5078
alter_info->datetime_field->field_name);
5079
session->abort_on_warning= save_abort_on_warning;
5083
pthread_mutex_lock(&LOCK_open);
5084
unlink_open_table(session, name_lock, false);
5085
pthread_mutex_unlock(&LOCK_open);
5089
err_with_placeholders:
5091
An error happened while we were holding exclusive name-lock on table
5092
being altered. To be safe under LOCK TABLES we should remove placeholders
5093
from list of open tables list and table cache.
5095
unlink_open_table(session, table, false);
5097
unlink_open_table(session, name_lock, false);
5098
pthread_mutex_unlock(&LOCK_open);
5101
/* mysql_alter_table */
5104
copy_data_between_tables(Table *from,Table *to,
5105
List<Create_field> &create,
5107
uint32_t order_num, order_st *order,
5110
enum enum_enable_or_disable keys_onoff,
5111
bool error_if_not_empty)
5114
Copy_field *copy,*copy_end;
5115
ulong found_count,delete_count;
5116
Session *session= current_session;
5118
SORT_FIELD *sortorder;
5122
List<Item> all_fields;
5123
ha_rows examined_rows;
5124
bool auto_increment_field_copied= 0;
5125
ulong save_sql_mode;
5126
uint64_t prev_insert_id;
5129
Turn off recovery logging since rollback of an alter table is to
5130
delete the new table so there is no need to log the changes to it.
5132
This needs to be done before external_lock
5134
error= ha_enable_transaction(session, false);
5138
if (!(copy= new Copy_field[to->s->fields]))
5139
return(-1); /* purecov: inspected */
5141
if (to->file->ha_external_lock(session, F_WRLCK))
5144
/* We need external lock before we can disable/enable keys */
5145
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
5147
/* We can abort alter table for any table type */
5148
session->abort_on_warning= !ignore;
5150
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
5151
to->file->ha_start_bulk_insert(from->file->stats.records);
5153
save_sql_mode= session->variables.sql_mode;
5155
List_iterator<Create_field> it(create);
5158
for (Field **ptr=to->field ; *ptr ; ptr++)
5163
if (*ptr == to->next_number_field)
5164
auto_increment_field_copied= true;
5166
(copy_end++)->set(*ptr,def->field,0);
5171
found_count=delete_count=0;
5175
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
2185
5177
char warn_buff[DRIZZLE_ERRMSG_SIZE];
2186
snprintf(warn_buff, sizeof(warn_buff),
2187
ER(ER_TABLE_EXISTS_ERROR), destination_identifier.getTableName().c_str());
2188
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2189
ER_TABLE_EXISTS_ERROR, warn_buff);
2193
my_error(ER_TABLE_EXISTS_ERROR, destination_identifier);
5178
snprintf(warn_buff, sizeof(warn_buff),
5179
_("order_st BY ignored because there is a user-defined clustered "
5180
"index in the table '%-.192s'"),
5181
from->s->table_name.str);
5182
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
5187
from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
5188
MYF(MY_FAE | MY_ZEROFILL));
5189
memset(&tables, 0, sizeof(tables));
5191
tables.alias= tables.table_name= from->s->table_name.str;
5192
tables.db= from->s->db.str;
5195
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
5196
setup_order(session, session->lex->select_lex.ref_pointer_array,
5197
&tables, fields, all_fields, order) ||
5198
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
5199
(from->sort.found_records= filesort(session, from, sortorder, length,
5200
(SQL_SELECT *) 0, HA_POS_ERROR,
5201
1, &examined_rows)) ==
5207
/* Tell handler that we have values for all columns in the to table */
5208
to->use_all_columns();
5209
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
5211
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
5212
session->row_count= 0;
5213
restore_record(to, s->default_values); // Create empty record
5214
while (!(error=info.read_record(&info)))
5216
if (session->killed)
5218
session->send_kill_message();
5222
session->row_count++;
5223
/* Return error if source table isn't empty. */
5224
if (error_if_not_empty)
5229
if (to->next_number_field)
5231
if (auto_increment_field_copied)
5232
to->auto_increment_field_not_null= true;
5234
to->next_number_field->reset();
5237
for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
5239
copy_ptr->do_copy(copy_ptr);
5241
prev_insert_id= to->file->next_insert_id;
5242
update_virtual_fields_marked_for_write(to, false);
5243
error=to->file->ha_write_row(to->record[0]);
5244
to->auto_increment_field_not_null= false;
5248
to->file->is_fatal_error(error, HA_CHECK_DUP))
5250
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
5252
uint32_t key_nr= to->file->get_dup_key(error);
5253
if ((int) key_nr >= 0)
5255
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
5257
(to->key_info[0].key_part[0].field->flags &
5258
AUTO_INCREMENT_FLAG))
5259
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
5260
to->file->print_keydup_error(key_nr, err_msg);
5265
to->file->print_error(error,MYF(0));
5268
to->file->restore_auto_increment(prev_insert_id);
5274
end_read_record(&info);
5275
free_io_cache(from);
5276
delete [] copy; // This is never 0
5278
if (to->file->ha_end_bulk_insert() && error <= 0)
5280
to->file->print_error(my_errno,MYF(0));
5283
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
5285
if (ha_enable_transaction(session, true))
5292
Ensure that the new table is saved properly to disk so that we
5295
if (ha_autocommit_or_rollback(session, 0))
5297
if (end_active_trans(session))
5301
session->variables.sql_mode= save_sql_mode;
5302
session->abort_on_warning= 0;
5303
free_io_cache(from);
5304
*copied= found_count;
5305
*deleted=delete_count;
5306
to->file->ha_release_auto_increment();
5307
if (to->file->ha_external_lock(session,F_UNLCK))
5309
return(error > 0 ? -1 : 0);
5314
Recreates tables by calling mysql_alter_table().
5317
mysql_recreate_table()
5318
session Thread handler
5319
tables Tables to recreate
5322
Like mysql_alter_table().
5324
bool mysql_recreate_table(Session *session, TableList *table_list)
5326
HA_CREATE_INFO create_info;
5327
Alter_info alter_info;
5329
assert(!table_list->next_global);
5331
table_list->table has been closed and freed. Do not reference
5332
uninitialized data. open_tables() could fail.
5334
table_list->table= NULL;
5336
memset(&create_info, 0, sizeof(create_info));
5337
create_info.row_type=ROW_TYPE_NOT_USED;
5338
create_info.default_table_charset=default_charset_info;
5339
/* Force alter table to recreate table */
5340
alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
5341
return(mysql_alter_table(session, NULL, NULL, &create_info,
5342
table_list, &alter_info, 0,
5343
(order_st *) 0, 0));
5347
bool mysql_checksum_table(Session *session, TableList *tables,
5348
HA_CHECK_OPT *check_opt)
5351
List<Item> field_list;
5353
Protocol *protocol= session->protocol;
5355
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
5356
item->maybe_null= 1;
5357
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
5358
MY_INT64_NUM_DECIMAL_DIGITS));
5359
item->maybe_null= 1;
5360
if (protocol->send_fields(&field_list,
5361
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
5364
/* Open one table after the other to keep lock time as short as possible. */
5365
for (table= tables; table; table= table->next_local)
5367
char table_name[NAME_LEN*2+2];
5370
strxmov(table_name, table->db ,".", table->table_name, NULL);
5372
t= table->table= open_n_lock_single_table(session, table, TL_READ);
5373
session->clear_error(); // these errors shouldn't get client
5375
protocol->prepare_for_resend();
5376
protocol->store(table_name, system_charset_info);
5380
/* Table didn't exist */
5381
protocol->store_null();
5382
session->clear_error();
5386
if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
5387
!(check_opt->flags & T_EXTEND))
5388
protocol->store((uint64_t)t->file->checksum());
5389
else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
5390
(check_opt->flags & T_QUICK))
5391
protocol->store_null();
5394
/* calculating table's checksum */
5396
unsigned char null_mask=256 - (1 << t->s->last_null_bit_pos);
5398
t->use_all_columns();
5400
if (t->file->ha_rnd_init(1))
5401
protocol->store_null();
5406
ha_checksum row_crc= 0;
5407
int error= t->file->rnd_next(t->record[0]);
5408
if (unlikely(error))
5410
if (error == HA_ERR_RECORD_DELETED)
5414
if (t->s->null_bytes)
5416
/* fix undefined null bits */
5417
t->record[0][t->s->null_bytes-1] |= null_mask;
5418
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
5419
t->record[0][0] |= 1;
5421
row_crc= my_checksum(row_crc, t->record[0], t->s->null_bytes);
5424
for (uint32_t i= 0; i < t->s->fields; i++ )
5426
Field *f= t->field[i];
5427
if ((f->type() == DRIZZLE_TYPE_BLOB) ||
5428
(f->type() == DRIZZLE_TYPE_VARCHAR))
5432
row_crc= my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
5435
row_crc= my_checksum(row_crc, f->ptr,
5441
protocol->store((uint64_t)crc);
5442
t->file->ha_rnd_end();
5445
session->clear_error();
5446
close_thread_tables(session);
5447
table->table=0; // For query cache
5449
if (protocol->write())
5457
close_thread_tables(session); // Shouldn't be needed
5463
static bool check_engine(Session *session, const char *table_name,
5464
HA_CREATE_INFO *create_info)
5466
handlerton **new_engine= &create_info->db_type;
5467
handlerton *req_engine= *new_engine;
5468
bool no_substitution= 1;
5469
if (!(*new_engine= ha_checktype(session, ha_legacy_type(req_engine),
5470
no_substitution, 1)))
2202
bool analyze_table(Session* session, TableList* tables, HA_CHECK_OPT* check_opt)
2204
thr_lock_type lock_type = TL_READ_NO_INSERT;
2206
return(admin_table(session, tables, check_opt,
2207
"analyze", lock_type, true,
2208
&Cursor::ha_analyze));
2212
bool check_table(Session* session, TableList* tables,HA_CHECK_OPT* check_opt)
2214
thr_lock_type lock_type = TL_READ_NO_INSERT;
2216
return(admin_table(session, tables, check_opt,
2219
&Cursor::ha_check));
2222
} /* namespace drizzled */
5473
if (req_engine && req_engine != *new_engine)
5475
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
5476
ER_WARN_USING_OTHER_HANDLER,
5477
ER(ER_WARN_USING_OTHER_HANDLER),
5478
ha_resolve_storage_engine_name(*new_engine),
5481
if (create_info->options & HA_LEX_CREATE_TMP_TABLE &&
5482
ha_check_storage_engine_flag(*new_engine, HTON_TEMPORARY_NOT_SUPPORTED))
5484
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
5486
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
5487
ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
5491
*new_engine= myisam_hton;