1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 Sun Microsystems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
#include "drizzled/show.h"
28
#include "drizzled/lock.h"
29
#include "drizzled/session.h"
30
#include "drizzled/statement/alter_table.h"
31
#include "drizzled/global_charset_info.h"
34
#include "drizzled/gettext.h"
35
#include "drizzled/data_home.h"
36
#include "drizzled/sql_table.h"
37
#include "drizzled/table_proto.h"
38
#include "drizzled/optimizer/range.h"
39
#include "drizzled/time_functions.h"
40
#include "drizzled/records.h"
41
#include "drizzled/pthread_globals.h"
42
#include "drizzled/internal/my_sys.h"
43
#include "drizzled/internal/iocache.h"
45
#include "drizzled/transaction_services.h"
47
#include "drizzled/filesort.h"
49
#include "drizzled/message.h"
56
extern pid_t current_pid;
58
static int copy_data_between_tables(Session *session,
59
Table *from,Table *to,
60
List<CreateField> &create,
66
enum enum_enable_or_disable keys_onoff,
67
bool error_if_not_empty);
69
static bool mysql_prepare_alter_table(Session *session,
71
HA_CREATE_INFO *create_info,
72
const message::Table &original_proto,
73
message::Table &table_message,
74
AlterInfo *alter_info);
76
static int create_temporary_table(Session *session,
77
TableIdentifier &identifier,
78
HA_CREATE_INFO *create_info,
79
message::Table &create_message,
80
AlterInfo *alter_info);
82
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier);
84
bool statement::AlterTable::execute()
86
TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
87
TableList *all_tables= session->lex->query_tables;
88
assert(first_table == all_tables && first_table != 0);
89
Select_Lex *select_lex= &session->lex->select_lex;
90
bool need_start_waiting= false;
95
plugin::StorageEngine::findByName(*session, create_table_message.engine().name());
97
if (create_info.db_type == NULL)
99
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0),
100
create_table_message.engine().name().c_str());
106
/* Must be set in the parser */
107
assert(select_lex->db);
109
/* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
110
message::table::shared_ptr original_table_message;
112
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
113
if (plugin::StorageEngine::getTableDefinition(*session, identifier, original_table_message) != EEXIST)
116
identifier.getSQLPath(path);
117
my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
121
if (not create_info.db_type)
124
plugin::StorageEngine::findByName(*session, original_table_message->engine().name());
126
if (not create_info.db_type)
129
identifier.getSQLPath(path);
130
my_error(ER_BAD_TABLE_ERROR, MYF(0), path.c_str());
136
if (not validateCreateTableOption())
141
/* ALTER TABLE ends previous transaction */
142
if (not session->endActiveTransaction())
147
if (not (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
153
if (original_table_message->type() == message::Table::STANDARD )
155
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
156
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
157
session->lex->name.str ? session->lex->name.str : first_table->getTableName());
159
res= alter_table(session,
163
*original_table_message,
164
create_table_message,
167
select_lex->order_list.elements,
168
(Order *) select_lex->order_list.first,
169
session->lex->ignore);
173
TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
174
Table *table= session->find_temporary_table(catch22);
177
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
178
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
179
session->lex->name.str ? session->lex->name.str : first_table->getTableName(),
180
table->getMutableShare()->getPath());
182
res= alter_table(session,
186
*original_table_message,
187
create_table_message,
190
select_lex->order_list.elements,
191
(Order *) select_lex->order_list.first,
192
session->lex->ignore);
197
Release the protection against the global read lock and wake
198
everyone, who might want to set a global read lock.
200
session->startWaitingGlobalReadLock();
207
Prepare column and key definitions for CREATE TABLE in ALTER Table.
209
This function transforms parse output of ALTER Table - lists of
210
columns and keys to add, drop or modify into, essentially,
211
CREATE TABLE definition - a list of columns and keys of the new
212
table. While doing so, it also performs some (bug not all)
215
This function is invoked when we know that we're going to
216
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
217
is not possible, perhaps because the ALTER statement contains
218
instructions that require change in table data, not only in
219
table definition or indexes.
221
@param[in,out] session thread handle. Used as a memory pool
222
and source of environment information.
223
@param[in] table the source table, open and locked
224
Used as an interface to the storage engine
225
to acquire additional information about
227
@param[in,out] create_info A blob with CREATE/ALTER Table
229
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
230
Originally create_info was used only in
231
CREATE TABLE and alter_info only in ALTER Table.
232
But since ALTER might end-up doing CREATE,
233
this distinction is gone and we just carry
234
around two structures.
237
Fills various create_info members based on information retrieved
238
from the storage engine.
239
Sets create_info->varchar if the table has a VARCHAR column.
240
Prepares alter_info->create_list and alter_info->key_list with
241
columns and keys of the new table.
242
@retval true error, out of memory or a semantical error in ALTER
244
@retval false success
246
static bool mysql_prepare_alter_table(Session *session,
248
HA_CREATE_INFO *create_info,
249
const message::Table &original_proto,
250
message::Table &table_message,
251
AlterInfo *alter_info)
253
/* New column definitions are added here */
254
List<CreateField> new_create_list;
255
/* New key definitions are added here */
256
List<Key> new_key_list;
257
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
258
List_iterator<CreateField> def_it(alter_info->create_list);
259
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
260
List_iterator<Key> key_it(alter_info->key_list);
261
List_iterator<CreateField> find_it(new_create_list);
262
List_iterator<CreateField> field_it(new_create_list);
263
List<Key_part_spec> key_parts;
264
uint32_t used_fields= create_info->used_fields;
265
KeyInfo *key_info= table->key_info;
268
/* Let new create options override the old ones */
269
message::Table::TableOptions *table_options;
270
table_options= table_message.mutable_options();
272
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
273
create_info->default_table_charset= table->getShare()->table_charset;
274
if (! (used_fields & HA_CREATE_USED_AUTO) &&
275
table->found_next_number_field)
277
/* Table has an autoincrement, copy value to new table */
278
table->cursor->info(HA_STATUS_AUTO);
279
create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
280
if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
281
table_options->set_has_user_set_auto_increment_value(false);
283
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
286
/* First collect all fields from table which isn't in drop_list */
289
for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
291
/* Check if field should be dropped */
294
while ((drop= drop_it++))
296
if (drop->type == AlterDrop::COLUMN &&
297
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
299
/* Reset auto_increment value if it was dropped */
300
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
301
! (used_fields & HA_CREATE_USED_AUTO))
303
create_info->auto_increment_value= 0;
304
create_info->used_fields|= HA_CREATE_USED_AUTO;
315
/* Mark that we will read the field */
318
/* Check if field is changed */
320
while ((def= def_it++))
323
! my_strcasecmp(system_charset_info, field->field_name, def->change))
328
/* Field is changed */
332
new_create_list.push_back(def);
339
This field was not dropped and not changed, add it to the list
342
def= new CreateField(field, field);
343
new_create_list.push_back(def);
344
alter_it.rewind(); /* Change default if ALTER */
346
while ((alter= alter_it++))
348
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
353
if (def->sql_type == DRIZZLE_TYPE_BLOB)
355
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
358
if ((def->def= alter->def))
360
/* Use new default */
361
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
365
def->flags|= NO_DEFAULT_VALUE_FLAG;
372
while ((def= def_it++)) /* Add new columns */
374
if (def->change && ! def->field)
376
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
380
If we have been given a field which has no default value, and is not null then we need to bail.
382
if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
384
alter_info->error_if_not_empty= true;
388
new_create_list.push_back(def);
390
else if (def->after == first_keyword)
392
new_create_list.push_front(def);
398
while ((find= find_it++)) /* Add new columns */
400
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
405
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
408
find_it.after(def); /* Put element after this */
410
XXX: hack for Bug#28427.
411
If column order has changed, force OFFLINE ALTER Table
412
without querying engine capabilities. If we ever have an
413
engine that supports online ALTER Table CHANGE COLUMN
414
<name> AFTER <name1> (Falcon?), this fix will effectively
415
disable the capability.
416
TODO: detect the situation in compare_tables, behave based
417
on engine capabilities.
419
if (alter_info->build_method == HA_BUILD_ONLINE)
421
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
424
alter_info->build_method= HA_BUILD_OFFLINE;
427
if (alter_info->alter_list.elements)
429
my_error(ER_BAD_FIELD_ERROR,
431
alter_info->alter_list.head()->name,
432
table->getMutableShare()->getTableName());
435
if (! new_create_list.elements)
437
my_message(ER_CANT_REMOVE_ALL_FIELDS,
438
ER(ER_CANT_REMOVE_ALL_FIELDS),
444
Collect all keys which isn't in drop list. Add only those
445
for which some fields exists.
447
for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
449
char *key_name= key_info->name;
452
while ((drop= drop_it++))
454
if (drop->type == AlterDrop::KEY &&
455
! my_strcasecmp(system_charset_info, key_name, drop->name))
464
KeyPartInfo *key_part= key_info->key_part;
466
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
468
if (! key_part->field)
469
continue; /* Wrong field (from UNIREG) */
471
const char *key_part_name= key_part->field->field_name;
474
while ((cfield= field_it++))
478
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
481
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
485
continue; /* Field is removed */
487
uint32_t key_part_length= key_part->length;
488
if (cfield->field) /* Not new field */
491
If the field can't have only a part used in a key according to its
492
new type, or should not be used partially according to its
493
previous type, or the field length is less than the key part
494
length, unset the key part length.
496
We also unset the key part length if it is the same as the
497
old field's length, so the whole new field will be used.
499
BLOBs may have cfield->length == 0, which is why we test it before
500
checking whether cfield->length < key_part_length (in chars).
502
if (! Field::type_can_have_key_part(cfield->field->type()) ||
503
! Field::type_can_have_key_part(cfield->sql_type) ||
504
(cfield->field->field_length == key_part_length) ||
506
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
507
key_part_length= 0; /* Use whole field */
509
key_part_length/= key_part->field->charset()->mbmaxlen;
510
key_parts.push_back(new Key_part_spec(cfield->field_name,
511
strlen(cfield->field_name),
514
if (key_parts.elements)
516
KEY_CREATE_INFO key_create_info;
518
enum Key::Keytype key_type;
519
memset(&key_create_info, 0, sizeof(key_create_info));
521
key_create_info.algorithm= key_info->algorithm;
522
if (key_info->flags & HA_USES_BLOCK_SIZE)
523
key_create_info.block_size= key_info->block_size;
524
if (key_info->flags & HA_USES_COMMENT)
525
key_create_info.comment= key_info->comment;
527
if (key_info->flags & HA_NOSAME)
529
if (is_primary_key_name(key_name))
530
key_type= Key::PRIMARY;
532
key_type= Key::UNIQUE;
535
key_type= Key::MULTIPLE;
537
key= new Key(key_type,
541
test(key_info->flags & HA_GENERATED_KEY),
543
new_key_list.push_back(key);
547
/* Copy over existing foreign keys */
548
for (int j= 0; j < original_proto.fk_constraint_size(); j++)
552
while ((drop= drop_it++))
554
if (drop->type == AlterDrop::FOREIGN_KEY &&
555
! my_strcasecmp(system_charset_info, original_proto.fk_constraint(j).name().c_str(), drop->name))
566
message::Table::ForeignKeyConstraint *pfkey= table_message.add_fk_constraint();
567
*pfkey= original_proto.fk_constraint(j);
572
while ((key= key_it++)) /* Add new keys */
574
if (key->type == Key::FOREIGN_KEY)
576
if (((Foreign_key *)key)->validate(new_create_list))
581
Foreign_key *fkey= (Foreign_key*)key;
582
add_foreign_key_to_table_message(&table_message,
592
if (key->type != Key::FOREIGN_KEY)
593
new_key_list.push_back(key);
595
if (key->name.str && is_primary_key_name(key->name.str))
597
my_error(ER_WRONG_NAME_FOR_INDEX,
605
/* Fix names of foreign keys being added */
606
for (int j= 0; j < table_message.fk_constraint_size(); j++)
608
if (! table_message.fk_constraint(j).has_name())
610
std::string name(table->getMutableShare()->getTableName());
613
name.append("_ibfk_");
614
snprintf(number, sizeof(number), "%d", j+1);
617
message::Table::ForeignKeyConstraint *pfkey= table_message.mutable_fk_constraint(j);
618
pfkey->set_name(name);
622
if (alter_info->drop_list.elements)
624
my_error(ER_CANT_DROP_FIELD_OR_KEY,
626
alter_info->drop_list.head()->name);
629
if (alter_info->alter_list.elements)
631
my_error(ER_CANT_DROP_FIELD_OR_KEY,
633
alter_info->alter_list.head()->name);
637
if (not table_message.options().has_comment()
638
&& table->getMutableShare()->hasComment())
639
table_options->set_comment(table->getMutableShare()->getComment());
641
if (table->getShare()->getType())
643
table_message.set_type(message::Table::TEMPORARY);
646
table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
647
table_message.set_version(table->getShare()->getTableProto()->version());
648
table_message.set_uuid(table->getShare()->getTableProto()->uuid());
651
alter_info->create_list.swap(new_create_list);
652
alter_info->key_list.swap(new_key_list);
654
size_t num_engine_options= table_message.engine().options_size();
655
size_t original_num_engine_options= original_proto.engine().options_size();
656
for (size_t x= 0; x < original_num_engine_options; ++x)
660
for (size_t y= 0; y < num_engine_options; ++y)
662
found= not table_message.engine().options(y).name().compare(original_proto.engine().options(x).name());
670
message::Engine::Option *opt= table_message.mutable_engine()->add_options();
672
opt->set_name(original_proto.engine().options(x).name());
673
opt->set_state(original_proto.engine().options(x).state());
677
drizzled::message::update(table_message);
682
/* table_list should contain just one table */
683
static int mysql_discard_or_import_tablespace(Session *session,
684
TableList *table_list,
685
enum tablespace_op_type tablespace_op)
692
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
696
TransactionServices &transaction_services= TransactionServices::singleton();
697
session->set_proc_info("discard_or_import_tablespace");
699
discard= test(tablespace_op == DISCARD_TABLESPACE);
702
We set this flag so that ha_innobase::open and ::external_lock() do
703
not complain when we lock the table
705
session->tablespace_op= true;
706
if (!(table= session->openTableLock(table_list, TL_WRITE)))
708
session->tablespace_op= false;
712
error= table->cursor->ha_discard_or_import_tablespace(discard);
714
session->set_proc_info("end");
719
/* The ALTER Table is always in its own transaction */
720
error= transaction_services.autocommitOrRollback(session, false);
721
if (not session->endActiveTransaction())
727
write_bin_log(session, *session->getQueryString());
730
(void) transaction_services.autocommitOrRollback(session, error);
731
session->tablespace_op=false;
739
table->print_error(error, MYF(0));
745
Manages enabling/disabling of indexes for ALTER Table
748
alter_table_manage_keys()
750
indexes_were_disabled Whether the indexes of the from table
752
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
758
static bool alter_table_manage_keys(Session *session,
759
Table *table, int indexes_were_disabled,
760
enum enum_enable_or_disable keys_onoff)
763
switch (keys_onoff) {
765
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
768
if (not indexes_were_disabled)
770
/* fall-through: disabled indexes */
772
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
775
if (error == HA_ERR_WRONG_COMMAND)
777
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
778
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
779
table->getMutableShare()->getTableName());
782
table->print_error(error, MYF(0));
787
static bool lockTableIfDifferent(Session &session,
788
TableIdentifier &original_table_identifier,
789
TableIdentifier &new_table_identifier,
792
/* Check that we are not trying to rename to an existing table */
793
if (not (original_table_identifier == new_table_identifier))
795
if (original_table_identifier.isTmp())
798
if (session.find_temporary_table(new_table_identifier))
801
new_table_identifier.getSQLPath(path);
802
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
808
if (session.lock_table_name_if_not_cached(new_table_identifier, &name_lock))
816
new_table_identifier.getSQLPath(path);
817
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
821
if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
824
new_table_identifier.getSQLPath(path);
826
/* Table will be closed by Session::executeCommand() */
827
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
829
table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
830
session.unlink_open_table(name_lock);
831
table::Cache::singleton().mutex().unlock();
846
session Thread handle
847
new_db If there is a RENAME clause
848
new_name If there is a RENAME clause
849
create_info Information from the parsing phase about new
851
table_list The table to change.
852
alter_info Lists of fields, keys to be changed, added
854
order_num How many ORDER BY fields has been specified.
855
order List of fields to order_st BY.
856
ignore Whether we have ALTER IGNORE Table
859
This is a veery long function and is everything but the kitchen sink :)
860
It is used to alter a table and not only by ALTER Table but also
861
CREATE|DROP INDEX are mapped on this function.
863
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
864
or both, then this function short cuts its operation by renaming
865
the table and/or enabling/disabling the keys. In this case, the FRM is
866
not changed, directly by alter_table. However, if there is a
867
RENAME + change of a field, or an index, the short cut is not used.
868
See how `create_list` is used to generate the new FRM regarding the
869
structure of the fields. The same is done for the indices of the table.
871
Important is the fact, that this function tries to do as little work as
872
possible, by finding out whether a intermediate table is needed to copy
873
data into and when finishing the altering to use it as the original table.
874
For this reason the function compare_tables() is called, which decides
875
based on all kind of data how similar are the new and the original
883
static bool internal_alter_table(Session *session,
885
TableIdentifier &original_table_identifier,
886
TableIdentifier &new_table_identifier,
887
HA_CREATE_INFO *create_info,
888
const message::Table &original_proto,
889
message::Table &create_proto,
890
TableList *table_list,
891
AlterInfo *alter_info,
902
session->set_proc_info("init");
904
table->use_all_columns();
906
plugin::StorageEngine *new_engine;
907
plugin::StorageEngine *original_engine;
909
original_engine= table->getMutableShare()->getEngine();
911
if (not create_info->db_type)
913
create_info->db_type= original_engine;
915
new_engine= create_info->db_type;
918
create_proto.set_schema(new_table_identifier.getSchemaName());
919
create_proto.set_type(new_table_identifier.getType());
922
@todo Have a check on the table definition for FK in the future
923
to remove the need for the cursor. (aka can_switch_engines())
925
if (new_engine != original_engine &&
926
not table->cursor->can_switch_engines())
929
my_error(ER_ROW_IS_REFERENCED, MYF(0));
934
if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
935
new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
938
new_table_identifier.getSQLPath(path);
939
my_error(ER_ILLEGAL_HA, MYF(0), path.c_str());
944
session->set_proc_info("setup");
947
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
953
tmp.reset(ALTER_RENAME);
954
tmp.reset(ALTER_KEYS_ONOFF);
955
tmp&= alter_info->flags;
957
if (! (tmp.any()) && ! table->getShare()->getType()) // no need to touch frm
959
switch (alter_info->keys_onoff)
965
wait_while_table_is_used() ensures that table being altered is
966
opened only by this thread and that Table::TableShare::version
967
of Table object corresponding to this table is 0.
968
The latter guarantees that no DML statement will open this table
969
until ALTER Table finishes (i.e. until close_thread_tables())
970
while the fact that the table is still open gives us protection
971
from concurrent DDL statements.
973
table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
974
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
975
table::Cache::singleton().mutex().unlock();
976
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
977
/* COND_refresh will be signaled in close_thread_tables() */
980
table::Cache::singleton().mutex().lock(); /* DDL wait for/blocker */
981
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
982
table::Cache::singleton().mutex().unlock();
983
error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
984
/* COND_refresh will be signaled in close_thread_tables() */
992
if (error == HA_ERR_WRONG_COMMAND)
995
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
996
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1000
table::Cache::singleton().mutex().lock(); /* Lock to remove all instances of table from table cache before ALTER */
1002
Unlike to the above case close_cached_table() below will remove ALL
1003
instances of Table from table cache (it will also remove table lock
1004
held by this thread). So to make actual table renaming and writing
1005
to binlog atomic we have to put them into the same critical section
1006
protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
1007
access() and mysql_rename_table() calls.
1010
if (error == 0 && not (original_table_identifier == new_table_identifier))
1012
session->set_proc_info("rename");
1014
Then do a 'simple' rename of the table. First we need to close all
1015
instances of 'source' table.
1017
session->close_cached_table(table);
1019
Then, we want check once again that target table does not exist.
1020
Actually the order of these two steps does not matter since
1021
earlier we took name-lock on the target table, so we do them
1022
in this particular order only to be consistent with 5.0, in which
1023
we don't take this name-lock and where this order really matters.
1024
@todo Investigate if we need this access() check at all.
1026
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1029
new_table_identifier.getSQLPath(path);
1030
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
1035
if (mysql_rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1042
if (error == HA_ERR_WRONG_COMMAND)
1045
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1046
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1052
TransactionServices &transaction_services= TransactionServices::singleton();
1053
transaction_services.allocateNewTransactionId();
1054
write_bin_log(session, *session->getQueryString());
1059
table->print_error(error, MYF(0));
1063
table::Cache::singleton().mutex().unlock();
1064
table_list->table= NULL;
1070
/* We have to do full alter table. */
1071
new_engine= create_info->db_type;
1073
if (mysql_prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1078
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
1080
alter_info->build_method= HA_BUILD_OFFLINE;
1082
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1084
/* Create a temporary table with the new format */
1086
@note we make an internal temporary table unless the table is a temporary table. In last
1087
case we just use it as is. Neither of these tables require locks in order to be
1090
TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
1092
create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1093
message::Table::TEMPORARY);
1095
error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
1102
/* Open the table so we need to copy the data to it. */
1103
Table *new_table= open_alter_table(session, table, new_table_as_temporary);
1108
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1112
/* Copy the data if necessary. */
1114
/* We must not ignore bad input! */
1115
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; // calc cuted fields
1116
session->cuted_fields= 0L;
1117
session->set_proc_info("copy to tmp table");
1120
/* We don't want update TIMESTAMP fields during ALTER Table. */
1121
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1122
new_table->next_number_field= new_table->found_next_number_field;
1123
error= copy_data_between_tables(session,
1126
alter_info->create_list,
1132
alter_info->keys_onoff,
1133
alter_info->error_if_not_empty);
1135
/* We must not ignore bad input! */
1136
assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
1139
/* Now we need to resolve what just happened with the data copy. */
1145
No default value was provided for a DATE/DATETIME field, the
1146
current sql_mode doesn't allow the '0000-00-00' value and
1147
the table to be altered isn't empty.
1150
if (alter_info->error_if_not_empty && session->row_count)
1152
my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
1155
if (original_table_identifier.isTmp())
1159
/* close_temporary_table() frees the new_table pointer. */
1160
session->close_temporary_table(new_table);
1164
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1174
Close the intermediate table that will be the new table.
1175
Note that MERGE tables do not have their children attached here.
1177
new_table->intern_close_table();
1178
if (new_table->hasShare())
1180
delete new_table->getMutableShare();
1186
table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
1188
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1189
table::Cache::singleton().mutex().unlock();
1194
// Temporary table and success
1195
else if (original_table_identifier.isTmp())
1197
/* Close lock if this is a transactional table */
1200
session->unlockTables(session->lock);
1204
/* Remove link to old table and rename the new one */
1205
session->close_temporary_table(table);
1207
/* Should pass the 'new_name' as we store table name in the cache */
1208
new_table->getMutableShare()->setIdentifier(new_table_identifier);
1210
new_table_identifier.setPath(new_table_as_temporary.getPath());
1212
if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1217
// Normal table success
1223
Close the intermediate table that will be the new table.
1224
Note that MERGE tables do not have their children attached here.
1226
new_table->intern_close_table();
1228
if (new_table->hasShare())
1230
delete new_table->getMutableShare();
1236
table::Cache::singleton().mutex().lock(); /* ALTER TABLE */
1239
Data is copied. Now we:
1240
1) Wait until all other threads close old version of table.
1241
2) Close instances of table open by this thread and replace them
1242
with exclusive name-locks.
1243
3) Rename the old table to a temp name, rename the new one to the
1245
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1246
we reopen new version of table.
1247
5) Write statement to the binary log.
1248
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1249
remove name-locks from list of open tables and table cache.
1250
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1251
call to remove name-locks from table cache and list of open table.
1254
session->set_proc_info("rename result table");
1256
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1258
my_casedn_str(files_charset_info, old_name);
1260
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1261
session->close_data_files_and_morph_locks(original_table_identifier);
1266
This leads to the storage engine (SE) not being notified for renames in
1267
mysql_rename_table(), because we just juggle with the FRM and nothing
1268
more. If we have an intermediate table, then we notify the SE that
1269
it should become the actual table. Later, we will recycle the old table.
1270
However, in case of ALTER Table RENAME there might be no intermediate
1271
table. This is when the old and new tables are compatible, according to
1272
compare_table(). Then, we need one additional call to
1274
TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1275
old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1276
message::Table::TEMPORARY);
1278
if (mysql_rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1281
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1285
if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1287
/* Try to get everything back. */
1290
plugin::StorageEngine::dropTable(*session, new_table_identifier);
1292
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1294
mysql_rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1298
plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1305
An error happened while we were holding exclusive name-lock on table
1306
being altered. To be safe under LOCK TABLES we should remove placeholders
1307
from list of open tables list and table cache.
1309
session->unlink_open_table(table);
1310
table::Cache::singleton().mutex().unlock();
1315
table::Cache::singleton().mutex().unlock();
1317
session->set_proc_info("end");
1319
write_bin_log(session, *session->getQueryString());
1320
table_list->table= NULL;
1324
* Field::store() may have called my_error(). If this is
1325
* the case, we must not send an ok packet, since
1326
* Diagnostics_area::is_set() will fail an assert.
1328
if (session->is_error())
1330
/* my_error() was called. Return true (which means error...) */
1334
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1335
(ulong) (copied + deleted), (ulong) deleted,
1336
(ulong) session->cuted_fields);
1337
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1338
session->some_tables_deleted= 0;
1343
bool alter_table(Session *session,
1344
TableIdentifier &original_table_identifier,
1345
TableIdentifier &new_table_identifier,
1346
HA_CREATE_INFO *create_info,
1347
const message::Table &original_proto,
1348
message::Table &create_proto,
1349
TableList *table_list,
1350
AlterInfo *alter_info,
1358
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1360
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1361
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1364
session->set_proc_info("init");
1366
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1369
session->set_proc_info("gained write lock on table");
1372
Check that we are not trying to rename to an existing table,
1373
if one existed we get a lock, if we can't we error.
1376
Table *name_lock= NULL;
1378
if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1383
error= internal_alter_table(session,
1385
original_table_identifier,
1386
new_table_identifier,
1398
table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
1399
session->unlink_open_table(name_lock);
1400
table::Cache::singleton().mutex().unlock();
1409
copy_data_between_tables(Session *session,
1410
Table *from, Table *to,
1411
List<CreateField> &create,
1413
uint32_t order_num, Order *order,
1416
enum enum_enable_or_disable keys_onoff,
1417
bool error_if_not_empty)
1420
CopyField *copy,*copy_end;
1421
ulong found_count,delete_count;
1423
SortField *sortorder;
1427
List<Item> all_fields;
1428
ha_rows examined_rows;
1429
bool auto_increment_field_copied= 0;
1430
uint64_t prev_insert_id;
1433
Turn off recovery logging since rollback of an alter table is to
1434
delete the new table so there is no need to log the changes to it.
1436
This needs to be done before external_lock
1438
TransactionServices &transaction_services= TransactionServices::singleton();
1443
* Since open_temporary_table() doesn't invoke lockTables(), we
1444
* don't get the usual automatic call to StorageEngine::startStatement(), so
1445
* we manually call it here...
1447
to->getMutableShare()->getEngine()->startStatement(session);
1449
if (!(copy= new CopyField[to->getShare()->sizeFields()]))
1452
if (to->cursor->ha_external_lock(session, F_WRLCK))
1455
/* We need external lock before we can disable/enable keys */
1456
alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(), keys_onoff);
1458
/* We can abort alter table for any table type */
1459
session->abort_on_warning= !ignore;
1461
from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1462
to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1464
List_iterator<CreateField> it(create);
1467
for (Field **ptr= to->getFields(); *ptr ; ptr++)
1472
if (*ptr == to->next_number_field)
1473
auto_increment_field_copied= true;
1475
(copy_end++)->set(*ptr,def->field,0);
1480
found_count=delete_count=0;
1484
if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1486
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1487
snprintf(warn_buff, sizeof(warn_buff),
1488
_("order_st BY ignored because there is a user-defined clustered "
1489
"index in the table '%-.192s'"),
1490
from->getMutableShare()->getTableName());
1491
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1496
FileSort filesort(*session);
1497
from->sort.io_cache= new internal::IO_CACHE;
1499
memset(&tables, 0, sizeof(tables));
1501
tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
1502
tables.alias= const_cast<char *>(tables.getTableName());
1503
tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1506
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1507
setup_order(session, session->lex->select_lex.ref_pointer_array,
1508
&tables, fields, all_fields, order) ||
1509
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1510
(from->sort.found_records= filesort.run(from, sortorder, length,
1511
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1512
1, examined_rows)) == HA_POS_ERROR)
1519
/* Tell handler that we have values for all columns in the to table */
1520
to->use_all_columns();
1521
info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1523
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1524
session->row_count= 0;
1525
to->restoreRecordAsDefault(); // Create empty record
1526
while (!(error=info.read_record(&info)))
1528
if (session->getKilled())
1530
session->send_kill_message();
1534
session->row_count++;
1535
/* Return error if source table isn't empty. */
1536
if (error_if_not_empty)
1541
if (to->next_number_field)
1543
if (auto_increment_field_copied)
1544
to->auto_increment_field_not_null= true;
1546
to->next_number_field->reset();
1549
for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1551
if (not copy->to_field->hasDefault() and copy->from_null_ptr and *copy->from_null_ptr & copy->from_bit)
1553
copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1554
ER_WARN_DATA_TRUNCATED, 1);
1555
copy->to_field->reset();
1560
copy_ptr->do_copy(copy_ptr);
1568
prev_insert_id= to->cursor->next_insert_id;
1569
error= to->cursor->insertRecord(to->record[0]);
1570
to->auto_increment_field_not_null= false;
1574
if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1576
to->print_error(error, MYF(0));
1579
to->cursor->restore_auto_increment(prev_insert_id);
1588
info.end_read_record();
1589
from->free_io_cache();
1590
delete [] copy; // This is never 0
1592
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1594
to->print_error(errno, MYF(0));
1597
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1600
Ensure that the new table is saved properly to disk so that we
1603
if (transaction_services.autocommitOrRollback(session, false))
1605
if (! session->endActiveTransaction())
1609
session->abort_on_warning= 0;
1610
from->free_io_cache();
1611
*copied= found_count;
1612
*deleted=delete_count;
1613
to->cursor->ha_release_auto_increment();
1614
if (to->cursor->ha_external_lock(session,F_UNLCK))
1617
return(error > 0 ? -1 : 0);
1621
create_temporary_table(Session *session,
1622
TableIdentifier &identifier,
1623
HA_CREATE_INFO *create_info,
1624
message::Table &create_proto,
1625
AlterInfo *alter_info)
1630
Create a table with a temporary name.
1631
We don't log the statement, it will be logged later.
1633
create_proto.set_name(identifier.getTableName());
1635
create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1637
error= mysql_create_table(session,
1639
create_info, create_proto, alter_info, true, 0, false);
1644
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
1648
/* Open the table so we need to copy the data to it. */
1649
if (table->getShare()->getType())
1652
tbl.setSchemaName(const_cast<char *>(identifier.getSchemaName().c_str()));
1653
tbl.alias= const_cast<char *>(identifier.getTableName().c_str());
1654
tbl.setTableName(const_cast<char *>(identifier.getTableName().c_str()));
1656
/* Table is in session->temporary_tables */
1657
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
1661
/* Open our intermediate table */
1662
new_table= session->open_temporary_table(identifier, false);
1668
} /* namespace drizzled */