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())
139
/* ALTER TABLE ends previous transaction */
140
if (not session->endActiveTransaction())
143
if (not (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
147
if (original_table_message->type() == message::Table::STANDARD )
149
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
150
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
151
session->lex->name.str ? session->lex->name.str : first_table->getTableName());
153
res= alter_table(session,
157
*original_table_message,
158
create_table_message,
161
select_lex->order_list.elements,
162
(Order *) select_lex->order_list.first,
163
session->lex->ignore);
167
TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
168
Table *table= session->find_temporary_table(catch22);
171
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
172
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
173
session->lex->name.str ? session->lex->name.str : first_table->getTableName(),
174
table->getMutableShare()->getPath());
176
res= alter_table(session,
180
*original_table_message,
181
create_table_message,
184
select_lex->order_list.elements,
185
(Order *) select_lex->order_list.first,
186
session->lex->ignore);
191
Release the protection against the global read lock and wake
192
everyone, who might want to set a global read lock.
194
session->startWaitingGlobalReadLock();
201
Prepare column and key definitions for CREATE TABLE in ALTER Table.
203
This function transforms parse output of ALTER Table - lists of
204
columns and keys to add, drop or modify into, essentially,
205
CREATE TABLE definition - a list of columns and keys of the new
206
table. While doing so, it also performs some (bug not all)
209
This function is invoked when we know that we're going to
210
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
211
is not possible, perhaps because the ALTER statement contains
212
instructions that require change in table data, not only in
213
table definition or indexes.
215
@param[in,out] session thread handle. Used as a memory pool
216
and source of environment information.
217
@param[in] table the source table, open and locked
218
Used as an interface to the storage engine
219
to acquire additional information about
221
@param[in,out] create_info A blob with CREATE/ALTER Table
223
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
224
Originally create_info was used only in
225
CREATE TABLE and alter_info only in ALTER Table.
226
But since ALTER might end-up doing CREATE,
227
this distinction is gone and we just carry
228
around two structures.
231
Fills various create_info members based on information retrieved
232
from the storage engine.
233
Sets create_info->varchar if the table has a VARCHAR column.
234
Prepares alter_info->create_list and alter_info->key_list with
235
columns and keys of the new table.
236
@retval true error, out of memory or a semantical error in ALTER
238
@retval false success
240
static bool mysql_prepare_alter_table(Session *session,
242
HA_CREATE_INFO *create_info,
243
const message::Table &original_proto,
244
message::Table &table_message,
245
AlterInfo *alter_info)
247
/* New column definitions are added here */
248
List<CreateField> new_create_list;
249
/* New key definitions are added here */
250
List<Key> new_key_list;
251
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
252
List_iterator<CreateField> def_it(alter_info->create_list);
253
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
254
List_iterator<Key> key_it(alter_info->key_list);
255
List_iterator<CreateField> find_it(new_create_list);
256
List_iterator<CreateField> field_it(new_create_list);
257
List<Key_part_spec> key_parts;
258
uint32_t used_fields= create_info->used_fields;
259
KeyInfo *key_info= table->key_info;
262
/* Let new create options override the old ones */
263
message::Table::TableOptions *table_options;
264
table_options= table_message.mutable_options();
266
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
267
create_info->default_table_charset= table->getShare()->table_charset;
268
if (! (used_fields & HA_CREATE_USED_AUTO) &&
269
table->found_next_number_field)
271
/* Table has an autoincrement, copy value to new table */
272
table->cursor->info(HA_STATUS_AUTO);
273
create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
274
if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
275
table_options->set_has_user_set_auto_increment_value(false);
277
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
280
/* First collect all fields from table which isn't in drop_list */
283
for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
285
/* Check if field should be dropped */
288
while ((drop= drop_it++))
290
if (drop->type == AlterDrop::COLUMN &&
291
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
293
/* Reset auto_increment value if it was dropped */
294
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
295
! (used_fields & HA_CREATE_USED_AUTO))
297
create_info->auto_increment_value= 0;
298
create_info->used_fields|= HA_CREATE_USED_AUTO;
309
/* Mark that we will read the field */
312
/* Check if field is changed */
314
while ((def= def_it++))
317
! my_strcasecmp(system_charset_info, field->field_name, def->change))
322
/* Field is changed */
326
new_create_list.push_back(def);
333
This field was not dropped and not changed, add it to the list
336
def= new CreateField(field, field);
337
new_create_list.push_back(def);
338
alter_it.rewind(); /* Change default if ALTER */
340
while ((alter= alter_it++))
342
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
347
if (def->sql_type == DRIZZLE_TYPE_BLOB)
349
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
352
if ((def->def= alter->def))
354
/* Use new default */
355
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
359
def->flags|= NO_DEFAULT_VALUE_FLAG;
366
while ((def= def_it++)) /* Add new columns */
368
if (def->change && ! def->field)
370
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->getMutableShare()->getTableName());
374
If we have been given a field which has no default value, and is not null then we need to bail.
376
if (not (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) and not def->change)
378
alter_info->error_if_not_empty= true;
382
new_create_list.push_back(def);
384
else if (def->after == first_keyword)
386
new_create_list.push_front(def);
392
while ((find= find_it++)) /* Add new columns */
394
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
399
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
402
find_it.after(def); /* Put element after this */
404
XXX: hack for Bug#28427.
405
If column order has changed, force OFFLINE ALTER Table
406
without querying engine capabilities. If we ever have an
407
engine that supports online ALTER Table CHANGE COLUMN
408
<name> AFTER <name1> (Falcon?), this fix will effectively
409
disable the capability.
410
TODO: detect the situation in compare_tables, behave based
411
on engine capabilities.
413
if (alter_info->build_method == HA_BUILD_ONLINE)
415
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
418
alter_info->build_method= HA_BUILD_OFFLINE;
421
if (alter_info->alter_list.elements)
423
my_error(ER_BAD_FIELD_ERROR,
425
alter_info->alter_list.head()->name,
426
table->getMutableShare()->getTableName());
429
if (! new_create_list.elements)
431
my_message(ER_CANT_REMOVE_ALL_FIELDS,
432
ER(ER_CANT_REMOVE_ALL_FIELDS),
438
Collect all keys which isn't in drop list. Add only those
439
for which some fields exists.
441
for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
443
char *key_name= key_info->name;
446
while ((drop= drop_it++))
448
if (drop->type == AlterDrop::KEY &&
449
! my_strcasecmp(system_charset_info, key_name, drop->name))
458
KeyPartInfo *key_part= key_info->key_part;
460
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
462
if (! key_part->field)
463
continue; /* Wrong field (from UNIREG) */
465
const char *key_part_name= key_part->field->field_name;
468
while ((cfield= field_it++))
472
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
475
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
479
continue; /* Field is removed */
481
uint32_t key_part_length= key_part->length;
482
if (cfield->field) /* Not new field */
485
If the field can't have only a part used in a key according to its
486
new type, or should not be used partially according to its
487
previous type, or the field length is less than the key part
488
length, unset the key part length.
490
We also unset the key part length if it is the same as the
491
old field's length, so the whole new field will be used.
493
BLOBs may have cfield->length == 0, which is why we test it before
494
checking whether cfield->length < key_part_length (in chars).
496
if (! Field::type_can_have_key_part(cfield->field->type()) ||
497
! Field::type_can_have_key_part(cfield->sql_type) ||
498
(cfield->field->field_length == key_part_length) ||
500
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
501
key_part_length= 0; /* Use whole field */
503
key_part_length/= key_part->field->charset()->mbmaxlen;
504
key_parts.push_back(new Key_part_spec(cfield->field_name,
505
strlen(cfield->field_name),
508
if (key_parts.elements)
510
KEY_CREATE_INFO key_create_info;
512
enum Key::Keytype key_type;
513
memset(&key_create_info, 0, sizeof(key_create_info));
515
key_create_info.algorithm= key_info->algorithm;
516
if (key_info->flags & HA_USES_BLOCK_SIZE)
517
key_create_info.block_size= key_info->block_size;
518
if (key_info->flags & HA_USES_COMMENT)
519
key_create_info.comment= key_info->comment;
521
if (key_info->flags & HA_NOSAME)
523
if (is_primary_key_name(key_name))
524
key_type= Key::PRIMARY;
526
key_type= Key::UNIQUE;
529
key_type= Key::MULTIPLE;
531
key= new Key(key_type,
535
test(key_info->flags & HA_GENERATED_KEY),
537
new_key_list.push_back(key);
541
/* Copy over existing foreign keys */
542
for (int j= 0; j < original_proto.fk_constraint_size(); j++)
546
while ((drop= drop_it++))
548
if (drop->type == AlterDrop::FOREIGN_KEY &&
549
! my_strcasecmp(system_charset_info, original_proto.fk_constraint(j).name().c_str(), drop->name))
560
message::Table::ForeignKeyConstraint *pfkey= table_message.add_fk_constraint();
561
*pfkey= original_proto.fk_constraint(j);
566
while ((key= key_it++)) /* Add new keys */
568
if (key->type == Key::FOREIGN_KEY)
570
if (((Foreign_key *)key)->validate(new_create_list))
575
Foreign_key *fkey= (Foreign_key*)key;
576
add_foreign_key_to_table_message(&table_message,
586
if (key->type != Key::FOREIGN_KEY)
587
new_key_list.push_back(key);
589
if (key->name.str && is_primary_key_name(key->name.str))
591
my_error(ER_WRONG_NAME_FOR_INDEX,
599
/* Fix names of foreign keys being added */
600
for (int j= 0; j < table_message.fk_constraint_size(); j++)
602
if (! table_message.fk_constraint(j).has_name())
604
std::string name(table->getMutableShare()->getTableName());
607
name.append("_ibfk_");
608
snprintf(number, sizeof(number), "%d", j+1);
611
message::Table::ForeignKeyConstraint *pfkey= table_message.mutable_fk_constraint(j);
612
pfkey->set_name(name);
616
if (alter_info->drop_list.elements)
618
my_error(ER_CANT_DROP_FIELD_OR_KEY,
620
alter_info->drop_list.head()->name);
623
if (alter_info->alter_list.elements)
625
my_error(ER_CANT_DROP_FIELD_OR_KEY,
627
alter_info->alter_list.head()->name);
631
if (not table_message.options().has_comment()
632
&& table->getMutableShare()->hasComment())
633
table_options->set_comment(table->getMutableShare()->getComment());
635
if (table->getShare()->getType())
637
table_message.set_type(message::Table::TEMPORARY);
640
table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
641
table_message.set_version(table->getShare()->getTableProto()->version());
642
table_message.set_uuid(table->getShare()->getTableProto()->uuid());
645
alter_info->create_list.swap(new_create_list);
646
alter_info->key_list.swap(new_key_list);
648
size_t num_engine_options= table_message.engine().options_size();
649
size_t original_num_engine_options= original_proto.engine().options_size();
650
for (size_t x= 0; x < original_num_engine_options; ++x)
654
for (size_t y= 0; y < num_engine_options; ++y)
656
found= not table_message.engine().options(y).name().compare(original_proto.engine().options(x).name());
664
message::Engine::Option *opt= table_message.mutable_engine()->add_options();
666
opt->set_name(original_proto.engine().options(x).name());
667
opt->set_state(original_proto.engine().options(x).state());
671
drizzled::message::update(table_message);
676
/* table_list should contain just one table */
677
static int mysql_discard_or_import_tablespace(Session *session,
678
TableList *table_list,
679
enum tablespace_op_type tablespace_op)
686
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
690
TransactionServices &transaction_services= TransactionServices::singleton();
691
session->set_proc_info("discard_or_import_tablespace");
693
discard= test(tablespace_op == DISCARD_TABLESPACE);
696
We set this flag so that ha_innobase::open and ::external_lock() do
697
not complain when we lock the table
699
session->tablespace_op= true;
700
if (!(table= session->openTableLock(table_list, TL_WRITE)))
702
session->tablespace_op= false;
706
error= table->cursor->ha_discard_or_import_tablespace(discard);
708
session->set_proc_info("end");
713
/* The ALTER Table is always in its own transaction */
714
error= transaction_services.autocommitOrRollback(session, false);
715
if (not session->endActiveTransaction())
721
write_bin_log(session, *session->getQueryString());
724
(void) transaction_services.autocommitOrRollback(session, error);
725
session->tablespace_op=false;
733
table->print_error(error, MYF(0));
739
Manages enabling/disabling of indexes for ALTER Table
742
alter_table_manage_keys()
744
indexes_were_disabled Whether the indexes of the from table
746
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
752
static bool alter_table_manage_keys(Session *session,
753
Table *table, int indexes_were_disabled,
754
enum enum_enable_or_disable keys_onoff)
757
switch (keys_onoff) {
759
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
762
if (not indexes_were_disabled)
764
/* fall-through: disabled indexes */
766
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
769
if (error == HA_ERR_WRONG_COMMAND)
771
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
772
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
773
table->getMutableShare()->getTableName());
776
table->print_error(error, MYF(0));
781
static bool lockTableIfDifferent(Session &session,
782
TableIdentifier &original_table_identifier,
783
TableIdentifier &new_table_identifier,
786
/* Check that we are not trying to rename to an existing table */
787
if (not (original_table_identifier == new_table_identifier))
789
if (original_table_identifier.isTmp())
792
if (session.find_temporary_table(new_table_identifier))
795
new_table_identifier.getSQLPath(path);
796
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
802
if (session.lock_table_name_if_not_cached(new_table_identifier, &name_lock))
810
new_table_identifier.getSQLPath(path);
811
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
815
if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
818
new_table_identifier.getSQLPath(path);
820
/* Table will be closed by Session::executeCommand() */
821
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), path.c_str());
823
table::Cache::singleton().mutex().lock(); /* ALTER TABLe */
824
session.unlink_open_table(name_lock);
825
table::Cache::singleton().mutex().unlock();
840
session Thread handle
841
new_db If there is a RENAME clause
842
new_name If there is a RENAME clause
843
create_info Information from the parsing phase about new
845
table_list The table to change.
846
alter_info Lists of fields, keys to be changed, added
848
order_num How many ORDER BY fields has been specified.
849
order List of fields to order_st BY.
850
ignore Whether we have ALTER IGNORE Table
853
This is a veery long function and is everything but the kitchen sink :)
854
It is used to alter a table and not only by ALTER Table but also
855
CREATE|DROP INDEX are mapped on this function.
857
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
858
or both, then this function short cuts its operation by renaming
859
the table and/or enabling/disabling the keys. In this case, the FRM is
860
not changed, directly by alter_table. However, if there is a
861
RENAME + change of a field, or an index, the short cut is not used.
862
See how `create_list` is used to generate the new FRM regarding the
863
structure of the fields. The same is done for the indices of the table.
865
Important is the fact, that this function tries to do as little work as
866
possible, by finding out whether a intermediate table is needed to copy
867
data into and when finishing the altering to use it as the original table.
868
For this reason the function compare_tables() is called, which decides
869
based on all kind of data how similar are the new and the original
877
static bool internal_alter_table(Session *session,
879
TableIdentifier &original_table_identifier,
880
TableIdentifier &new_table_identifier,
881
HA_CREATE_INFO *create_info,
882
const message::Table &original_proto,
883
message::Table &create_proto,
884
TableList *table_list,
885
AlterInfo *alter_info,
896
if (not original_table_identifier.isValid())
899
if (not new_table_identifier.isValid())
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 */