171
86
start_waiting_global_read_lock(session);
177
Prepare column and key definitions for CREATE TABLE in ALTER Table.
179
This function transforms parse output of ALTER Table - lists of
180
columns and keys to add, drop or modify into, essentially,
181
CREATE TABLE definition - a list of columns and keys of the new
182
table. While doing so, it also performs some (bug not all)
185
This function is invoked when we know that we're going to
186
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
187
is not possible, perhaps because the ALTER statement contains
188
instructions that require change in table data, not only in
189
table definition or indexes.
191
@param[in,out] session thread handle. Used as a memory pool
192
and source of environment information.
193
@param[in] table the source table, open and locked
194
Used as an interface to the storage engine
195
to acquire additional information about
197
@param[in,out] create_info A blob with CREATE/ALTER Table
199
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
200
Originally create_info was used only in
201
CREATE TABLE and alter_info only in ALTER Table.
202
But since ALTER might end-up doing CREATE,
203
this distinction is gone and we just carry
204
around two structures.
207
Fills various create_info members based on information retrieved
208
from the storage engine.
209
Sets create_info->varchar if the table has a VARCHAR column.
210
Prepares alter_info->create_list and alter_info->key_list with
211
columns and keys of the new table.
212
@retval true error, out of memory or a semantical error in ALTER
214
@retval false success
216
static bool mysql_prepare_alter_table(Session *session,
218
HA_CREATE_INFO *create_info,
219
message::Table &table_message,
220
AlterInfo *alter_info)
222
/* New column definitions are added here */
223
List<CreateField> new_create_list;
224
/* New key definitions are added here */
225
List<Key> new_key_list;
226
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
227
List_iterator<CreateField> def_it(alter_info->create_list);
228
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
229
List_iterator<Key> key_it(alter_info->key_list);
230
List_iterator<CreateField> find_it(new_create_list);
231
List_iterator<CreateField> field_it(new_create_list);
232
List<Key_part_spec> key_parts;
233
uint32_t used_fields= create_info->used_fields;
234
KEY *key_info= table->key_info;
237
/* Let new create options override the old ones */
238
message::Table::TableOptions *table_options;
239
table_options= table_message.mutable_options();
241
if (! (used_fields & HA_CREATE_USED_BLOCK_SIZE))
242
table_options->set_block_size(table->s->block_size);
243
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
244
create_info->default_table_charset= table->s->table_charset;
245
if (! (used_fields & HA_CREATE_USED_AUTO) &&
246
table->found_next_number_field)
248
/* Table has an autoincrement, copy value to new table */
249
table->cursor->info(HA_STATUS_AUTO);
250
create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
252
if (! (used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)
253
&& table->s->hasKeyBlockSize())
254
table_options->set_key_block_size(table->s->getKeyBlockSize());
256
if ((used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)
257
&& table_options->key_block_size() == 0)
258
table_options->clear_key_block_size();
260
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
263
/* First collect all fields from table which isn't in drop_list */
266
for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
268
/* Check if field should be dropped */
271
while ((drop= drop_it++))
273
if (drop->type == AlterDrop::COLUMN &&
274
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
276
/* Reset auto_increment value if it was dropped */
277
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
278
! (used_fields & HA_CREATE_USED_AUTO))
280
create_info->auto_increment_value= 0;
281
create_info->used_fields|= HA_CREATE_USED_AUTO;
292
/* Mark that we will read the field */
295
/* Check if field is changed */
297
while ((def= def_it++))
300
! my_strcasecmp(system_charset_info, field->field_name, def->change))
305
/* Field is changed */
309
new_create_list.push_back(def);
316
This field was not dropped and not changed, add it to the list
319
def= new CreateField(field, field);
320
new_create_list.push_back(def);
321
alter_it.rewind(); /* Change default if ALTER */
323
while ((alter= alter_it++))
325
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
330
if (def->sql_type == DRIZZLE_TYPE_BLOB)
332
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
335
if ((def->def= alter->def))
337
/* Use new default */
338
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
341
def->flags|= NO_DEFAULT_VALUE_FLAG;
347
while ((def= def_it++)) /* Add new columns */
349
if (def->change && ! def->field)
351
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
355
Check that the DATE/DATETIME not null field we are going to add is
356
either has a default value or the '0000-00-00' is allowed by the
358
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
359
flag to allow ALTER Table only if the table to be altered is empty.
361
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
362
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
363
! alter_info->datetime_field &&
364
! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
365
session->variables.sql_mode & MODE_NO_ZERO_DATE)
367
alter_info->datetime_field= def;
368
alter_info->error_if_not_empty= true;
371
new_create_list.push_back(def);
372
else if (def->after == first_keyword)
373
new_create_list.push_front(def);
378
while ((find= find_it++)) /* Add new columns */
380
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
385
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
388
find_it.after(def); /* Put element after this */
390
XXX: hack for Bug#28427.
391
If column order has changed, force OFFLINE ALTER Table
392
without querying engine capabilities. If we ever have an
393
engine that supports online ALTER Table CHANGE COLUMN
394
<name> AFTER <name1> (Falcon?), this fix will effectively
395
disable the capability.
396
TODO: detect the situation in compare_tables, behave based
397
on engine capabilities.
399
if (alter_info->build_method == HA_BUILD_ONLINE)
401
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query.c_str());
404
alter_info->build_method= HA_BUILD_OFFLINE;
407
if (alter_info->alter_list.elements)
409
my_error(ER_BAD_FIELD_ERROR,
411
alter_info->alter_list.head()->name,
412
table->s->table_name.str);
415
if (! new_create_list.elements)
417
my_message(ER_CANT_REMOVE_ALL_FIELDS,
418
ER(ER_CANT_REMOVE_ALL_FIELDS),
424
Collect all keys which isn't in drop list. Add only those
425
for which some fields exists.
427
for (uint32_t i= 0; i < table->s->keys; i++, key_info++)
429
char *key_name= key_info->name;
432
while ((drop= drop_it++))
434
if (drop->type == AlterDrop::KEY &&
435
! my_strcasecmp(system_charset_info, key_name, drop->name))
444
KEY_PART_INFO *key_part= key_info->key_part;
446
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
448
if (! key_part->field)
449
continue; /* Wrong field (from UNIREG) */
451
const char *key_part_name= key_part->field->field_name;
454
while ((cfield= field_it++))
458
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
461
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
465
continue; /* Field is removed */
467
uint32_t key_part_length= key_part->length;
468
if (cfield->field) /* Not new field */
471
If the field can't have only a part used in a key according to its
472
new type, or should not be used partially according to its
473
previous type, or the field length is less than the key part
474
length, unset the key part length.
476
We also unset the key part length if it is the same as the
477
old field's length, so the whole new field will be used.
479
BLOBs may have cfield->length == 0, which is why we test it before
480
checking whether cfield->length < key_part_length (in chars).
482
if (! Field::type_can_have_key_part(cfield->field->type()) ||
483
! Field::type_can_have_key_part(cfield->sql_type) ||
484
(cfield->field->field_length == key_part_length) ||
486
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
487
key_part_length= 0; /* Use whole field */
489
key_part_length/= key_part->field->charset()->mbmaxlen;
490
key_parts.push_back(new Key_part_spec(cfield->field_name,
491
strlen(cfield->field_name),
494
if (key_parts.elements)
496
KEY_CREATE_INFO key_create_info;
498
enum Key::Keytype key_type;
499
memset(&key_create_info, 0, sizeof(key_create_info));
501
key_create_info.algorithm= key_info->algorithm;
502
if (key_info->flags & HA_USES_BLOCK_SIZE)
503
key_create_info.block_size= key_info->block_size;
504
if (key_info->flags & HA_USES_COMMENT)
505
key_create_info.comment= key_info->comment;
507
if (key_info->flags & HA_NOSAME)
509
if (is_primary_key_name(key_name))
510
key_type= Key::PRIMARY;
512
key_type= Key::UNIQUE;
515
key_type= Key::MULTIPLE;
517
key= new Key(key_type,
521
test(key_info->flags & HA_GENERATED_KEY),
523
new_key_list.push_back(key);
528
while ((key= key_it++)) /* Add new keys */
530
if (key->type == Key::FOREIGN_KEY &&
531
((Foreign_key *)key)->validate(new_create_list))
533
if (key->type != Key::FOREIGN_KEY)
534
new_key_list.push_back(key);
535
if (key->name.str && is_primary_key_name(key->name.str))
537
my_error(ER_WRONG_NAME_FOR_INDEX,
545
if (alter_info->drop_list.elements)
547
my_error(ER_CANT_DROP_FIELD_OR_KEY,
549
alter_info->drop_list.head()->name);
552
if (alter_info->alter_list.elements)
554
my_error(ER_CANT_DROP_FIELD_OR_KEY,
556
alter_info->alter_list.head()->name);
560
if (not table_message.options().has_comment()
561
&& table->s->hasComment())
562
table_options->set_comment(table->s->getComment());
564
if (table->s->tmp_table)
566
table_message.set_type(message::Table::TEMPORARY);
569
table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
571
table_message.set_update_timestamp(time(NULL));
573
if (not table_message.options().has_comment()
574
&& table->s->hasComment())
575
table_options->set_comment(table->s->getComment());
578
alter_info->create_list.swap(new_create_list);
579
alter_info->key_list.swap(new_key_list);
584
/* table_list should contain just one table */
585
static int mysql_discard_or_import_tablespace(Session *session,
586
TableList *table_list,
587
enum tablespace_op_type tablespace_op)
594
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
598
TransactionServices &transaction_services= TransactionServices::singleton();
599
session->set_proc_info("discard_or_import_tablespace");
601
discard= test(tablespace_op == DISCARD_TABLESPACE);
604
We set this flag so that ha_innobase::open and ::external_lock() do
605
not complain when we lock the table
607
session->tablespace_op= true;
608
if (!(table= session->openTableLock(table_list, TL_WRITE)))
610
session->tablespace_op= false;
614
error= table->cursor->ha_discard_or_import_tablespace(discard);
616
session->set_proc_info("end");
621
/* The ALTER Table is always in its own transaction */
622
error= transaction_services.ha_autocommit_or_rollback(session, false);
623
if (! session->endActiveTransaction())
627
write_bin_log(session, session->query.c_str());
630
(void) transaction_services.ha_autocommit_or_rollback(session, error);
631
session->tablespace_op=false;
639
table->print_error(error, MYF(0));
645
Manages enabling/disabling of indexes for ALTER Table
648
alter_table_manage_keys()
650
indexes_were_disabled Whether the indexes of the from table
652
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
658
static bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
659
enum enum_enable_or_disable keys_onoff)
662
switch (keys_onoff) {
664
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
667
if (!indexes_were_disabled)
669
/* fall-through: disabled indexes */
671
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
674
if (error == HA_ERR_WRONG_COMMAND)
676
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
677
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
678
table->s->table_name.str);
681
table->print_error(error, MYF(0));
686
static bool lockTableIfDifferent(Session &session,
687
TableIdentifier &original_table_identifier,
688
TableIdentifier &new_table_identifier,
691
/* Check that we are not trying to rename to an existing table */
692
if (not (original_table_identifier == new_table_identifier))
694
if (original_table_identifier.isTmp())
697
if (session.find_temporary_table(new_table_identifier))
699
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
705
if (session.lock_table_name_if_not_cached(new_table_identifier, &name_lock))
712
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
716
if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
718
/* Table will be closed by Session::executeCommand() */
719
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
721
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
722
session.unlink_open_table(name_lock);
723
pthread_mutex_unlock(&LOCK_open);
738
session Thread handle
739
new_db If there is a RENAME clause
740
new_name If there is a RENAME clause
741
create_info Information from the parsing phase about new
743
table_list The table to change.
744
alter_info Lists of fields, keys to be changed, added
746
order_num How many ORDER BY fields has been specified.
747
order List of fields to order_st BY.
748
ignore Whether we have ALTER IGNORE Table
751
This is a veery long function and is everything but the kitchen sink :)
752
It is used to alter a table and not only by ALTER Table but also
753
CREATE|DROP INDEX are mapped on this function.
755
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
756
or both, then this function short cuts its operation by renaming
757
the table and/or enabling/disabling the keys. In this case, the FRM is
758
not changed, directly by alter_table. However, if there is a
759
RENAME + change of a field, or an index, the short cut is not used.
760
See how `create_list` is used to generate the new FRM regarding the
761
structure of the fields. The same is done for the indices of the table.
763
Important is the fact, that this function tries to do as little work as
764
possible, by finding out whether a intermediate table is needed to copy
765
data into and when finishing the altering to use it as the original table.
766
For this reason the function compare_tables() is called, which decides
767
based on all kind of data how similar are the new and the original
775
static bool internal_alter_table(Session *session,
777
TableIdentifier &original_table_identifier,
778
TableIdentifier &new_table_identifier,
779
HA_CREATE_INFO *create_info,
780
message::Table &create_proto,
781
TableList *table_list,
782
AlterInfo *alter_info,
787
Table *new_table= NULL;
794
message::Table *original_table_definition= table->s->getTableProto();
796
session->set_proc_info("init");
798
table->use_all_columns();
800
plugin::StorageEngine *new_engine;
801
plugin::StorageEngine *original_engine;
803
original_engine= table->s->getEngine();
805
if (not create_info->db_type)
807
create_info->db_type= original_engine;
809
new_engine= create_info->db_type;
812
create_proto.set_schema(new_table_identifier.getSchemaName());
813
create_proto.set_type(new_table_identifier.getType());
816
@todo Have a check on the table definition for FK in the future
817
to remove the need for the cursor. (aka can_switch_engines())
819
if (new_engine != original_engine &&
820
not table->cursor->can_switch_engines())
823
my_error(ER_ROW_IS_REFERENCED, MYF(0));
828
if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
829
new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
831
my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
836
if (create_info->row_type == ROW_TYPE_NOT_USED)
838
message::Table::TableOptions *table_options;
839
table_options= create_proto.mutable_options();
841
create_info->row_type= table->s->row_type;
842
table_options->set_row_type(original_table_definition->options().row_type());
845
session->set_proc_info("setup");
848
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
854
tmp.reset(ALTER_RENAME);
855
tmp.reset(ALTER_KEYS_ONOFF);
856
tmp&= alter_info->flags;
858
if (! (tmp.any()) && ! table->s->tmp_table) // no need to touch frm
860
switch (alter_info->keys_onoff)
866
wait_while_table_is_used() ensures that table being altered is
867
opened only by this thread and that Table::TableShare::version
868
of Table object corresponding to this table is 0.
869
The latter guarantees that no DML statement will open this table
870
until ALTER Table finishes (i.e. until close_thread_tables())
871
while the fact that the table is still open gives us protection
872
from concurrent DDL statements.
874
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
875
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
876
pthread_mutex_unlock(&LOCK_open);
877
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
878
/* COND_refresh will be signaled in close_thread_tables() */
881
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
882
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
883
pthread_mutex_unlock(&LOCK_open);
884
error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
885
/* COND_refresh will be signaled in close_thread_tables() */
893
if (error == HA_ERR_WRONG_COMMAND)
896
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
897
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
901
pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
903
Unlike to the above case close_cached_table() below will remove ALL
904
instances of Table from table cache (it will also remove table lock
905
held by this thread). So to make actual table renaming and writing
906
to binlog atomic we have to put them into the same critical section
907
protected by LOCK_open mutex. This also removes gap for races between
908
access() and mysql_rename_table() calls.
911
if (error == 0 && not (original_table_identifier == new_table_identifier))
913
session->set_proc_info("rename");
915
Then do a 'simple' rename of the table. First we need to close all
916
instances of 'source' table.
918
session->close_cached_table(table);
920
Then, we want check once again that target table does not exist.
921
Actually the order of these two steps does not matter since
922
earlier we took name-lock on the target table, so we do them
923
in this particular order only to be consistent with 5.0, in which
924
we don't take this name-lock and where this order really matters.
925
@todo Investigate if we need this access() check at all.
927
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
929
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
934
if (mysql_rename_table(original_engine, original_table_identifier, new_table_identifier, 0))
941
if (error == HA_ERR_WRONG_COMMAND)
944
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
945
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
951
write_bin_log(session, session->query.c_str());
956
table->print_error(error, MYF(0));
960
pthread_mutex_unlock(&LOCK_open);
961
table_list->table= NULL;
967
/* We have to do full alter table. */
968
new_engine= create_info->db_type;
970
if (mysql_prepare_alter_table(session, table, create_info, create_proto, alter_info))
975
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
977
alter_info->build_method= HA_BUILD_OFFLINE;
979
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
981
/* Create a temporary table with the new format */
983
@note we make an internal temporary table unless the table is a temporary table. In last
984
case we just use it as is. Neither of these tables require locks in order to be
987
TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
989
create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
990
message::Table::TEMPORARY);
992
error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
999
/* Open the table so we need to copy the data to it. */
1000
new_table= open_alter_table(session, table, new_table_as_temporary);
1004
quick_rm_table(*session, new_table_as_temporary);
1008
/* Copy the data if necessary. */
1010
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
1011
session->cuted_fields= 0L;
1012
session->set_proc_info("copy to tmp table");
1015
/* We don't want update TIMESTAMP fields during ALTER Table. */
1016
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1017
new_table->next_number_field= new_table->found_next_number_field;
1018
error= copy_data_between_tables(table,
1020
alter_info->create_list,
1026
alter_info->keys_onoff,
1027
alter_info->error_if_not_empty);
1029
/* We must not ignore bad input! */
1030
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1033
/* Now we need to resolve what just happened with the data copy. */
1039
No default value was provided for a DATE/DATETIME field, the
1040
current sql_mode doesn't allow the '0000-00-00' value and
1041
the table to be altered isn't empty.
1044
if (alter_info->error_if_not_empty && session->row_count)
1046
const char *f_val= 0;
1047
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1049
switch (alter_info->datetime_field->sql_type)
1051
case DRIZZLE_TYPE_DATE:
1052
f_val= "0000-00-00";
1053
t_type= DRIZZLE_TIMESTAMP_DATE;
1055
case DRIZZLE_TYPE_DATETIME:
1056
f_val= "0000-00-00 00:00:00";
1057
t_type= DRIZZLE_TIMESTAMP_DATETIME;
1060
/* Shouldn't get here. */
1063
bool save_abort_on_warning= session->abort_on_warning;
1064
session->abort_on_warning= true;
1065
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1066
f_val, internal::strlength(f_val), t_type,
1067
alter_info->datetime_field->field_name);
1068
session->abort_on_warning= save_abort_on_warning;
1071
if (original_table_identifier.isTmp())
1075
/* close_temporary_table() frees the new_table pointer. */
1076
session->close_temporary_table(new_table);
1080
quick_rm_table(*session, new_table_as_temporary);
1090
Close the intermediate table that will be the new table.
1091
Note that MERGE tables do not have their children attached here.
1093
new_table->intern_close_table();
1097
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1099
quick_rm_table(*session, new_table_as_temporary);
1100
pthread_mutex_unlock(&LOCK_open);
1105
// Temporary table and success
1106
else if (original_table_identifier.isTmp())
1108
/* Close lock if this is a transactional table */
1111
mysql_unlock_tables(session, session->lock);
1115
/* Remove link to old table and rename the new one */
1116
session->close_temporary_table(table);
1118
/* Should pass the 'new_name' as we store table name in the cache */
1119
if (new_table->renameAlterTemporaryTable(new_table_identifier))
1121
session->close_temporary_table(new_table);
1126
new_table_identifier.setPath(new_table_as_temporary.getPath());
1128
if (mysql_rename_table(new_engine, new_table_as_temporary, new_table_identifier, FN_FROM_IS_TMP) != 0)
1133
// Normal table success
1139
Close the intermediate table that will be the new table.
1140
Note that MERGE tables do not have their children attached here.
1142
new_table->intern_close_table();
1146
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1149
Data is copied. Now we:
1150
1) Wait until all other threads close old version of table.
1151
2) Close instances of table open by this thread and replace them
1152
with exclusive name-locks.
1153
3) Rename the old table to a temp name, rename the new one to the
1155
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1156
we reopen new version of table.
1157
5) Write statement to the binary log.
1158
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1159
remove name-locks from list of open tables and table cache.
1160
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1161
call to remove name-locks from table cache and list of open table.
1164
session->set_proc_info("rename result table");
1166
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1168
my_casedn_str(files_charset_info, old_name);
1170
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1171
session->close_data_files_and_morph_locks(original_table_identifier);
1176
This leads to the storage engine (SE) not being notified for renames in
1177
mysql_rename_table(), because we just juggle with the FRM and nothing
1178
more. If we have an intermediate table, then we notify the SE that
1179
it should become the actual table. Later, we will recycle the old table.
1180
However, in case of ALTER Table RENAME there might be no intermediate
1181
table. This is when the old and new tables are compatible, according to
1182
compare_table(). Then, we need one additional call to
1184
TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1185
old_name, message::Table::TEMPORARY);
1187
if (mysql_rename_table(original_engine, original_table_identifier, original_table_to_drop, FN_TO_IS_TMP))
1190
quick_rm_table(*session, new_table_as_temporary);
1194
if (mysql_rename_table(new_engine, new_table_as_temporary, new_table_identifier, FN_FROM_IS_TMP) != 0)
1196
/* Try to get everything back. */
1199
quick_rm_table(*session, new_table_identifier);
1201
quick_rm_table(*session, new_table_as_temporary);
1203
mysql_rename_table(original_engine, original_table_to_drop, original_table_identifier, FN_FROM_IS_TMP);
1207
quick_rm_table(*session, original_table_to_drop);
1214
An error happened while we were holding exclusive name-lock on table
1215
being altered. To be safe under LOCK TABLES we should remove placeholders
1216
from list of open tables list and table cache.
1218
session->unlink_open_table(table);
1219
pthread_mutex_unlock(&LOCK_open);
1224
pthread_mutex_unlock(&LOCK_open);
1226
session->set_proc_info("end");
1228
write_bin_log(session, session->query.c_str());
1229
table_list->table= NULL;
1233
* Field::store() may have called my_error(). If this is
1234
* the case, we must not send an ok packet, since
1235
* Diagnostics_area::is_set() will fail an assert.
1237
if (session->is_error())
1239
/* my_error() was called. Return true (which means error...) */
1243
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1244
(ulong) (copied + deleted), (ulong) deleted,
1245
(ulong) session->cuted_fields);
1246
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1247
session->some_tables_deleted= 0;
1252
bool alter_table(Session *session,
1253
TableIdentifier &original_table_identifier,
1254
TableIdentifier &new_table_identifier,
1255
HA_CREATE_INFO *create_info,
1256
message::Table &create_proto,
1257
TableList *table_list,
1258
AlterInfo *alter_info,
1266
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1268
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1269
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1272
session->set_proc_info("init");
1274
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1277
session->set_proc_info("gained write lock on table");
1280
Check that we are not trying to rename to an existing table,
1281
if one existed we get a lock, if we can't we error.
1284
Table *name_lock= NULL;
1286
if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1291
error= internal_alter_table(session,
1293
original_table_identifier,
1294
new_table_identifier,
1305
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1306
session->unlink_open_table(name_lock);
1307
pthread_mutex_unlock(&LOCK_open);
1316
copy_data_between_tables(Table *from, Table *to,
1317
List<CreateField> &create,
1319
uint32_t order_num, order_st *order,
1322
enum enum_enable_or_disable keys_onoff,
1323
bool error_if_not_empty)
1326
CopyField *copy,*copy_end;
1327
ulong found_count,delete_count;
1328
Session *session= current_session;
1330
SORT_FIELD *sortorder;
1334
List<Item> all_fields;
1335
ha_rows examined_rows;
1336
bool auto_increment_field_copied= 0;
1337
uint64_t prev_insert_id;
1340
Turn off recovery logging since rollback of an alter table is to
1341
delete the new table so there is no need to log the changes to it.
1343
This needs to be done before external_lock
1345
TransactionServices &transaction_services= TransactionServices::singleton();
1347
if (!(copy= new CopyField[to->s->fields]))
1350
if (to->cursor->ha_external_lock(session, F_WRLCK))
1353
/* We need external lock before we can disable/enable keys */
1354
alter_table_manage_keys(to, from->cursor->indexes_are_disabled(), keys_onoff);
1356
/* We can abort alter table for any table type */
1357
session->abort_on_warning= !ignore;
1359
from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1360
to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1362
List_iterator<CreateField> it(create);
1365
for (Field **ptr=to->field ; *ptr ; ptr++)
1370
if (*ptr == to->next_number_field)
1371
auto_increment_field_copied= true;
1373
(copy_end++)->set(*ptr,def->field,0);
1378
found_count=delete_count=0;
1382
if (to->s->primary_key != MAX_KEY && to->cursor->primary_key_is_clustered())
1384
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1385
snprintf(warn_buff, sizeof(warn_buff),
1386
_("order_st BY ignored because there is a user-defined clustered "
1387
"index in the table '%-.192s'"),
1388
from->s->table_name.str);
1389
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1394
from->sort.io_cache= new internal::IO_CACHE;
1395
memset(from->sort.io_cache, 0, sizeof(internal::IO_CACHE));
1397
memset(&tables, 0, sizeof(tables));
1399
tables.alias= tables.table_name= from->s->table_name.str;
1400
tables.db= const_cast<char *>(from->s->getSchemaName());
1403
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1404
setup_order(session, session->lex->select_lex.ref_pointer_array,
1405
&tables, fields, all_fields, order) ||
1406
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1407
(from->sort.found_records= filesort(session, from, sortorder, length,
1408
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1409
1, &examined_rows)) ==
1417
/* Tell handler that we have values for all columns in the to table */
1418
to->use_all_columns();
1419
init_read_record(&info, session, from, (optimizer::SqlSelect *) 0, 1,1);
1421
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1422
session->row_count= 0;
1423
to->restoreRecordAsDefault(); // Create empty record
1424
while (!(error=info.read_record(&info)))
1426
if (session->killed)
1428
session->send_kill_message();
1432
session->row_count++;
1433
/* Return error if source table isn't empty. */
1434
if (error_if_not_empty)
1439
if (to->next_number_field)
1441
if (auto_increment_field_copied)
1442
to->auto_increment_field_not_null= true;
1444
to->next_number_field->reset();
1447
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1449
copy_ptr->do_copy(copy_ptr);
1451
prev_insert_id= to->cursor->next_insert_id;
1452
error= to->cursor->ha_write_row(to->record[0]);
1453
to->auto_increment_field_not_null= false;
1457
to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1459
to->print_error(error, MYF(0));
1462
to->cursor->restore_auto_increment(prev_insert_id);
1468
end_read_record(&info);
1469
from->free_io_cache();
1470
delete [] copy; // This is never 0
1472
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1474
to->print_error(errno, MYF(0));
1477
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1480
Ensure that the new table is saved properly to disk so that we
1483
if (transaction_services.ha_autocommit_or_rollback(session, false))
1485
if (! session->endActiveTransaction())
1489
session->abort_on_warning= 0;
1490
from->free_io_cache();
1491
*copied= found_count;
1492
*deleted=delete_count;
1493
to->cursor->ha_release_auto_increment();
1494
if (to->cursor->ha_external_lock(session,F_UNLCK))
1496
return(error > 0 ? -1 : 0);
1500
create_temporary_table(Session *session,
1501
TableIdentifier &identifier,
1502
HA_CREATE_INFO *create_info,
1503
message::Table &create_proto,
1504
AlterInfo *alter_info)
1509
Create a table with a temporary name.
1510
We don't log the statement, it will be logged later.
1512
create_proto.set_name(identifier.getTableName());
1514
message::Table::StorageEngine *protoengine;
1515
protoengine= create_proto.mutable_engine();
1516
protoengine->set_name(create_info->db_type->getName());
1518
error= mysql_create_table(session,
1520
create_info, create_proto, alter_info, true, 0, false);
1525
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
1529
/* Open the table so we need to copy the data to it. */
1530
if (table->s->tmp_table)
1533
tbl.db= const_cast<char *>(identifier.getSchemaName().c_str());
1534
tbl.alias= const_cast<char *>(identifier.getTableName().c_str());
1535
tbl.table_name= const_cast<char *>(identifier.getTableName().c_str());
1537
/* Table is in session->temporary_tables */
1538
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
1542
/* Open our intermediate table */
1543
new_table= session->open_temporary_table(identifier, false);
1549
} /* namespace drizzled */